From da340fbcc20778c9810dd8980061a6bb7b4cf097 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:23:02 +0000 Subject: [PATCH 01/33] Get smart account balances --- .../account/src/BiconomySmartAccountV2.ts | 78 +++++++++++ packages/account/src/utils/Types.ts | 13 ++ packages/account/tests/account.e2e.spec.ts | 21 +++ packages/modules/src/utils/Constants.ts | 1 + yarn.lock | 125 ++++++++++-------- 5 files changed, 180 insertions(+), 58 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index e5a7bfb48..8358c650f 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -15,6 +15,9 @@ import { GetContractReturnType, getContract, decodeFunctionData, + parseAbi, + formatUnits, + zeroAddress, } from "viem"; import { BaseSmartContractAccount, @@ -49,6 +52,7 @@ import { BiconomySmartAccountV2ConfigConstructorProps, PaymasterUserOperationDto, SimulationType, + BalancePayload, } from "./utils/Types.js"; import { ADDRESS_RESOLVER_ADDRESS, @@ -65,6 +69,7 @@ import { BiconomyAccountAbi } from "./abi/SmartAccount.js"; import { AccountResolverAbi } from "./abi/AccountResolver.js"; import { Logger } from "@biconomy/common"; import { FeeQuotesOrDataDto, FeeQuotesOrDataResponse } from "@biconomy/paymaster"; +import { ERC20_ABI } from "@biconomy/modules"; type UserOperationKey = keyof UserOperationStruct; @@ -252,6 +257,79 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { return this.accountAddress; } + /** + * Returns token balances of Smart Account + * + * This method will fetch the token balances of the BiconomySmartAccountV2 instance. + * If left empty, it will return the balance of the native token, where the address is 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. + * + * @param tokenAddresses - Optional. Array of token addresses to fetch the balances of. + * @returns Promise> - An array of token balances (or native token balance) of the BiconomySmartAccountV2 instance. + * @throws An error if something is wrong with the smart account instance creation. + * + * @example + * import { createClient } from "viem" + * import { createSmartAccountClient, BiconomySmartAccountV2 } from "@biconomy/account" + * import { createWalletClient, http } from "viem"; + * import { polygonMumbai } from "viem/chains"; + * + * const signer = createWalletClient({ + * account, + * chain: polygonMumbai, + * transport: http(), + * }); + * + * const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); + * const [usdtBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); + * + * console.log(usdtBalanceFromSmartAccount); + * + * // { + * // amount: 1000000000000000n, + * // decimals: 6, + * // address: "0xda5289fcaaf71d52a80a254da614a192b693e977", + * // formattedAmount: "1000000", + * // chainId: 80001 + * // } + * + */ + public async getBalances(tokenAddresses: Array): Promise> { + const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + + if (!tokenAddresses) { + const balance = await this.provider.getBalance({ address: accountAddress }); + return [ + { + amount: balance, + decimals: 18, + address: "0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + formattedAmount: formatUnits(balance, 18), + chainId: this.chainId, + }, + ]; + } + const tokenContracts = tokenAddresses.map((address) => + getContract({ + address, + abi: parseAbi(ERC20_ABI), + client: this.provider, + }), + ); + + const balancePromises = tokenContracts.map((tokenContract) => tokenContract.read.balanceOf([accountAddress])) as Promise[]; + const decimalsPromises = tokenContracts.map((tokenContract) => tokenContract.read.decimals()) as Promise[]; + const [balances, decimalsPerToken] = await Promise.all([Promise.all(balancePromises), Promise.all(decimalsPromises)]); + + return balances.map((amount, index) => ({ + amount, + decimals: decimalsPerToken[index], + address: tokenAddresses[index], + formattedAmount: formatUnits(amount, decimalsPerToken[index]), + chainId: this.chainId, + })); + } + /** * Return the account's address. This value is valid even before deploying the contract. */ diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts index 0967d0f8f..10ffd9858 100644 --- a/packages/account/src/utils/Types.ts +++ b/packages/account/src/utils/Types.ts @@ -26,6 +26,19 @@ export type SmartAccountConfig = { bundler?: IBundler; }; +export interface BalancePayload { + /** address: The address of the account */ + address: string; + /** chainId: The chainId of the network */ + chainId: number; + /** amount: The amount of the balance */ + amount: bigint; + /** decimals: The number of decimals */ + decimals: number; + /** formattedAmount: The amount of the balance formatted */ + formattedAmount: string; +} + export interface GasOverheads { /** fixed: fixed gas overhead */ fixed: number; diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index c7594b732..fbfe2227b 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -456,4 +456,25 @@ describe("Account Tests", () => { expect(ecdsaOwnershipModule).toBe(smartAccount.activeValidationModule.getAddress()); }); + + it("should fetch balances for smartAccount", async () => { + const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + const { + whale: { viemWallet: signer }, + bundlerUrl, + publicClient, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const usdcBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress(), usdt); + const [usdtBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); + + expect(usdcBalanceBefore).toBe(usdtBalanceFromSmartAccount.amount); + }); }); diff --git a/packages/modules/src/utils/Constants.ts b/packages/modules/src/utils/Constants.ts index 407e374d0..afed7bc33 100644 --- a/packages/modules/src/utils/Constants.ts +++ b/packages/modules/src/utils/Constants.ts @@ -48,4 +48,5 @@ export const ERC20_ABI = [ "function approve(address spender, uint256 value) external returns (bool)", "function allowance(address owner, address spender) external view returns (uint256)", "function balanceOf(address owner) external view returns (uint256)", + "function decimals() external view returns (uint8)", ]; diff --git a/yarn.lock b/yarn.lock index 3a06bfd22..6620584b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2648,7 +2648,7 @@ args@5.0.3: leven "2.1.0" mri "1.1.4" -array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: +array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== @@ -2736,7 +2736,7 @@ array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -arraybuffer.prototype.slice@^1.0.2: +arraybuffer.prototype.slice@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== @@ -3170,15 +3170,16 @@ cacache@^17.0.0: tar "^6.1.11" unique-filename "^3.0.0" -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" - integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: + es-define-property "^1.0.0" es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.3" - set-function-length "^1.2.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -3800,14 +3801,13 @@ defaults@^1.0.3: clone "^1.0.2" define-data-property@^1.0.1, define-data-property@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.2.tgz#f3c33b4f0102360cd7c0f5f28700f5678510b63a" - integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: + es-define-property "^1.0.0" es-errors "^1.3.0" - get-intrinsic "^1.2.2" gopd "^1.0.1" - has-property-descriptors "^1.0.1" define-lazy-prop@^2.0.0: version "2.0.0" @@ -3937,9 +3937,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.648: - version "1.4.665" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz#681700bd590b0e5a3be66e3e2874ce62abcf5da5" - integrity sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw== + version "1.4.668" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz#5cfed14f3240cdc70a359a49790cb295b1f097f1" + integrity sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ== elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" @@ -4036,61 +4036,70 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + version "1.22.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.4.tgz#26eb2e7538c3271141f5754d31aabfdb215f27bf" + integrity sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg== dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.6" + call-bind "^1.0.7" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.2" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" has-proto "^1.0.1" has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.1" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.0" + safe-regex-test "^1.0.3" string.prototype.trim "^1.2.8" string.prototype.trimend "^1.0.7" string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" + typed-array-buffer "^1.0.1" typed-array-byte-length "^1.0.0" typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" + which-typed-array "^1.1.14" es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-set-tostringtag@^2.0.1: +es-set-tostringtag@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== @@ -4942,7 +4951,7 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: +get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== @@ -5259,12 +5268,12 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.2.2" + es-define-property "^1.0.0" has-proto@^1.0.1: version "1.0.1" @@ -5305,7 +5314,7 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== @@ -5549,7 +5558,7 @@ inquirer@^8.2.4: through "^2.3.6" wrap-ansi "^6.0.1" -internal-slot@^1.0.5: +internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== @@ -5573,7 +5582,7 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" -is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: +is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== @@ -5788,7 +5797,7 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.13, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.13, is-typed-array@^1.1.9: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -7592,7 +7601,7 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.2, object.assign@^4.1.4: +object.assign@^4.1.2, object.assign@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== @@ -8263,7 +8272,7 @@ regexp-tree@~0.1.1: resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== -regexp.prototype.flags@^1.5.1: +regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== @@ -8421,7 +8430,7 @@ rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.1: +safe-array-concat@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== @@ -8441,7 +8450,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.0: +safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== @@ -8524,7 +8533,7 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -set-function-length@^1.2.0: +set-function-length@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== @@ -9291,7 +9300,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -typed-array-buffer@^1.0.0: +typed-array-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz#0608ffe6bca71bf15a45bff0ca2604107a1325f5" integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== @@ -9550,9 +9559,9 @@ validate-npm-package-name@^3.0.0: builtins "^1.0.3" viem@^2.5.0, viem@^2.7.3: - version "2.7.8" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.8.tgz#ca60552190cdc501cf4e1d1140d8da7625b1b1f4" - integrity sha512-5r5pkBDBmihCvMx4b3MqtP0FoZCRWE2ML1DssU80+vhJQur0PKd4yHdLbbvoiGGVD6bYiA394juhfdSvXIGgFA== + version "2.7.9" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.9.tgz#0d2b0c4722530b53fbef449d70f0cedc1bb867b0" + integrity sha512-iDfc8TwaZFp1K95zlsxYh6Cs0OWCt35Tqs8uYgXKSxtz7w075mZ0H5SJ8zSyJGoEaticVDhtdmRRX6TtcW9EeQ== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -9625,7 +9634,7 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.13, which-typed-array@^1.1.14: +which-typed-array@^1.1.14: version "1.1.14" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== From f8a1b2e4af5e95f980367b2ef98463c2bb36dd97 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:27:46 +0000 Subject: [PATCH 02/33] lint:fix --- packages/account/src/BiconomySmartAccountV2.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 8358c650f..d92422def 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -17,7 +17,6 @@ import { decodeFunctionData, parseAbi, formatUnits, - zeroAddress, } from "viem"; import { BaseSmartContractAccount, From b7e0d987f073ff28ca125bd126c6c5c652bd4c8b Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:30:36 +0000 Subject: [PATCH 03/33] fix comments --- packages/account/src/BiconomySmartAccountV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index d92422def..ed73d520c 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -259,16 +259,16 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { /** * Returns token balances of Smart Account * - * This method will fetch the token balances of the BiconomySmartAccountV2 instance. + * This method will fetch the token balances of the smartAccount instance. * If left empty, it will return the balance of the native token, where the address is 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. * * @param tokenAddresses - Optional. Array of token addresses to fetch the balances of. - * @returns Promise> - An array of token balances (or native token balance) of the BiconomySmartAccountV2 instance. + * @returns Promise> - An array of token balances (or native token balance) of the smartAccount instance. * @throws An error if something is wrong with the smart account instance creation. * * @example * import { createClient } from "viem" - * import { createSmartAccountClient, BiconomySmartAccountV2 } from "@biconomy/account" + * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; * import { polygonMumbai } from "viem/chains"; * From d8d2cb29b6c601c8f0ac9953a51944afa3681f1e Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:31:45 +0000 Subject: [PATCH 04/33] remove log --- packages/account/src/BiconomySmartAccountV2.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index ed73d520c..0eb90627d 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -282,8 +282,6 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); * const [usdtBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); * - * console.log(usdtBalanceFromSmartAccount); - * * // { * // amount: 1000000000000000n, * // decimals: 6, From 66eb3c43031f82a2f8c94693c0ce88e1df988301 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:43:34 +0000 Subject: [PATCH 05/33] fix build --- .../account/src/BiconomySmartAccountV2.ts | 7 +- packages/account/src/utils/Constants.ts | 10 + yarn.lock | 632 +++++------------- 3 files changed, 167 insertions(+), 482 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 0eb90627d..69e90e58f 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -39,6 +39,7 @@ import { UserOpResponse, extractChainIdFromBundlerUrl, convertSigner, + NATIVE_TOKEN_ALIAS, } from "./index.js"; import { BiconomyTokenPaymasterRequest, @@ -62,13 +63,13 @@ import { ADDRESS_ZERO, DEFAULT_ENTRYPOINT_ADDRESS, ERROR_MESSAGES, + ERC20_ABI, } from "./utils/Constants.js"; import { BiconomyFactoryAbi } from "./abi/Factory.js"; import { BiconomyAccountAbi } from "./abi/SmartAccount.js"; import { AccountResolverAbi } from "./abi/AccountResolver.js"; import { Logger } from "@biconomy/common"; import { FeeQuotesOrDataDto, FeeQuotesOrDataResponse } from "@biconomy/paymaster"; -import { ERC20_ABI } from "@biconomy/modules"; type UserOperationKey = keyof UserOperationStruct; @@ -260,7 +261,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * Returns token balances of Smart Account * * This method will fetch the token balances of the smartAccount instance. - * If left empty, it will return the balance of the native token, where the address is 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. + * If left empty, it will return the balance of the native token, with the address set to 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. * * @param tokenAddresses - Optional. Array of token addresses to fetch the balances of. * @returns Promise> - An array of token balances (or native token balance) of the smartAccount instance. @@ -300,7 +301,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { { amount: balance, decimals: 18, - address: "0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + address: NATIVE_TOKEN_ALIAS, formattedAmount: formatUnits(balance, 18), chainId: this.chainId, }, diff --git a/packages/account/src/utils/Constants.ts b/packages/account/src/utils/Constants.ts index d6f52fc7a..171938f0f 100644 --- a/packages/account/src/utils/Constants.ts +++ b/packages/account/src/utils/Constants.ts @@ -62,3 +62,13 @@ export const ERROR_MESSAGES = { NO_FEE_QUOTE: "FeeQuote was not provided, please call smartAccount.getTokenFees() to get feeQuote", FAILED_FEE_QUOTE_FETCH: "Failed to fetch fee quote", }; + +export const NATIVE_TOKEN_ALIAS = "0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"; +export const ERC20_ABI = [ + "function transfer(address to, uint256 value) external returns (bool)", + "function transferFrom(address from, address to, uint256 value) external returns (bool)", + "function approve(address spender, uint256 value) external returns (bool)", + "function allowance(address owner, address spender) external view returns (uint256)", + "function balanceOf(address owner) external view returns (uint256)", + "function decimals() external view returns (uint8)", +]; diff --git a/yarn.lock b/yarn.lock index 6620584b7..1c5c8ad54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -324,42 +324,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@chainsafe/as-sha256@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" - integrity sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg== - -"@chainsafe/persistent-merkle-tree@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz#4c9ee80cc57cd3be7208d98c40014ad38f36f7ff" - integrity sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/persistent-merkle-tree@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz#2b4a62c9489a5739dedd197250d8d2f5427e9f63" - integrity sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/ssz@^0.10.0": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.10.2.tgz#c782929e1bb25fec66ba72e75934b31fd087579e" - integrity sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.5.0" - -"@chainsafe/ssz@^0.9.2": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.9.4.tgz#696a8db46d6975b600f8309ad3a12f7c0e310497" - integrity sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.4.2" - case "^1.6.3" - "@colors/colors@1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" @@ -542,7 +506,7 @@ ethereum-cryptography "^2.0.0" micro-ftch "^0.3.1" -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": +"@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== @@ -557,7 +521,7 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": +"@ethersproject/abstract-provider@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== @@ -570,7 +534,7 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/web" "^5.7.0" -"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": +"@ethersproject/abstract-signer@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== @@ -581,7 +545,7 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": +"@ethersproject/address@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -592,22 +556,14 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/rlp" "^5.7.0" -"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": +"@ethersproject/base64@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== dependencies: "@ethersproject/bytes" "^5.7.0" -"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": +"@ethersproject/bignumber@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== @@ -616,37 +572,21 @@ "@ethersproject/logger" "^5.7.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": +"@ethersproject/constants@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== dependencies: "@ethersproject/bignumber" "^5.7.0" -"@ethersproject/contracts@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": +"@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -661,44 +601,7 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": +"@ethersproject/keccak256@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== @@ -706,68 +609,26 @@ "@ethersproject/bytes" "^5.7.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": +"@ethersproject/logger@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": +"@ethersproject/networks@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": +"@ethersproject/properties@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": +"@ethersproject/rlp@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== @@ -775,16 +636,7 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": +"@ethersproject/signing-key@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== @@ -796,19 +648,7 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": +"@ethersproject/strings@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== @@ -817,7 +657,7 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": +"@ethersproject/transactions@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -832,37 +672,7 @@ "@ethersproject/rlp" "^5.7.0" "@ethersproject/signing-key" "^5.7.0" -"@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/wallet@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": +"@ethersproject/web@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== @@ -873,17 +683,6 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@fastify/busboy@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" @@ -1324,139 +1123,141 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/ethereumjs-block@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" - integrity sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" +"@nomicfoundation/ethereumjs-block@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.4.tgz#ff2acb98a86b9290e35e315a6abfb9aebb9cf39e" + integrity sha512-AcyacJ9eX/uPEvqsPiB+WO1ymE+kyH48qGGiGV+YTojdtas8itUTW5dehDSOXEEItWGbbzEJ4PRqnQZlWaPvDw== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-trie" "6.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" ethereum-cryptography "0.1.3" - ethers "^5.7.1" -"@nomicfoundation/ethereumjs-blockchain@7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz#45323b673b3d2fab6b5008535340d1b8fea7d446" - integrity sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-ethash" "3.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - abstract-level "^1.0.3" +"@nomicfoundation/ethereumjs-blockchain@7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.4.tgz#b77511b389290b186c8d999e70f4b15c27ef44ea" + integrity sha512-jYsd/kwzbmpnxx86tXsYV8wZ5xGvFL+7/P0c6OlzpClHsbFzeF41KrYA9scON8Rg6bZu3ZTv6JOAgj3t7USUfg== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.4" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-ethash" "3.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-trie" "6.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" debug "^4.3.3" ethereum-cryptography "0.1.3" - level "^8.0.0" - lru-cache "^5.1.1" - memory-level "^1.0.0" + lru-cache "^10.0.0" -"@nomicfoundation/ethereumjs-common@4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz#a15d1651ca36757588fdaf2a7d381a150662a3c3" - integrity sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg== +"@nomicfoundation/ethereumjs-common@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" + integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.2" - crc-32 "^1.2.0" + "@nomicfoundation/ethereumjs-util" "9.0.4" -"@nomicfoundation/ethereumjs-ethash@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz#da77147f806401ee996bfddfa6487500118addca" - integrity sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - abstract-level "^1.0.3" - bigint-crypto-utils "^3.0.23" +"@nomicfoundation/ethereumjs-ethash@3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.4.tgz#06cb2502b3012fb6c11cffd44af08aecf71310da" + integrity sha512-xvIrwIMl9sSaiYKRem68+O7vYdj7Q2XWv5P7JXiIkn83918QzWHvqbswTRsH7+r6X1UEvdsURRnZbvZszEjAaQ== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + bigint-crypto-utils "^3.2.2" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-evm@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz#4c2f4b84c056047102a4fa41c127454e3f0cfcf6" - integrity sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ== - dependencies: - "@ethersproject/providers" "^5.7.1" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" +"@nomicfoundation/ethereumjs-evm@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.4.tgz#c9c761767283ac53946185474362230b169f8f63" + integrity sha512-lTyZZi1KpeMHzaO6cSVisR2tjiTTedjo7PcmhI/+GNFo9BmyY6QYzGeSti0sFttmjbEMioHgXxl5yrLNRg6+1w== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-statemanager" "2.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + "@types/debug" "^4.1.9" debug "^4.3.3" ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" + rustbn-wasm "^0.2.0" -"@nomicfoundation/ethereumjs-rlp@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz#4fee8dc58a53ac6ae87fb1fca7c15dc06c6b5dea" - integrity sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA== +"@nomicfoundation/ethereumjs-rlp@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" + integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== -"@nomicfoundation/ethereumjs-statemanager@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz#3ba4253b29b1211cafe4f9265fee5a0d780976e0" - integrity sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA== +"@nomicfoundation/ethereumjs-statemanager@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.4.tgz#bf14415e1f31b5ea8b98a0c027c547d0555059b6" + integrity sha512-HPDjeFrxw6llEi+BzqXkZ+KkvFnTOPczuHBtk21hRlDiuKuZz32dPzlhpRsDBGV1b5JTmRDUVqCS1lp3Gghw4Q== dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-trie" "6.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" debug "^4.3.3" ethereum-cryptography "0.1.3" - ethers "^5.7.1" js-sdsl "^4.1.4" + lru-cache "^10.0.0" -"@nomicfoundation/ethereumjs-trie@6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz#9a6dbd28482dca1bc162d12b3733acab8cd12835" - integrity sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ== +"@nomicfoundation/ethereumjs-trie@6.0.4": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.4.tgz#688a3f76646c209365ee6d959c3d7330ede5e609" + integrity sha512-3nSwQiFMvr2VFe/aZUyinuohYvtytUqZCUCvIWcPJ/BwJH6oQdZRB42aNFBJ/8nAh2s3OcroWpBLskzW01mFKA== dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" "@types/readable-stream" "^2.3.13" ethereum-cryptography "0.1.3" + lru-cache "^10.0.0" readable-stream "^3.6.0" -"@nomicfoundation/ethereumjs-tx@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz#117813b69c0fdc14dd0446698a64be6df71d7e56" - integrity sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g== - dependencies: - "@chainsafe/ssz" "^0.9.2" - "@ethersproject/providers" "^5.7.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" +"@nomicfoundation/ethereumjs-tx@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" + integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-util@9.0.2": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz#16bdc1bb36f333b8a3559bbb4b17dac805ce904d" - integrity sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ== +"@nomicfoundation/ethereumjs-util@9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" + integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== dependencies: - "@chainsafe/ssz" "^0.10.0" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-vm@7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz#3b0852cb3584df0e18c182d0672a3596c9ca95e6" - integrity sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-blockchain" "7.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-evm" "2.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-statemanager" "2.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" +"@nomicfoundation/ethereumjs-verkle@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-verkle/-/ethereumjs-verkle-0.0.2.tgz#7686689edec775b2efea5a71548f417c18f7dea4" + integrity sha512-bjnfZElpYGK/XuuVRmLS3yDvr+cDs85D9oonZ0YUa5A3lgFgokWMp76zXrxX2jVQ0BfHaw12y860n1+iOi6yFQ== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + lru-cache "^10.0.0" + rust-verkle-wasm "^0.0.1" + +"@nomicfoundation/ethereumjs-vm@7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.4.tgz#e5a6eec4877dc62dda93003c6d7afd1fe4b9625b" + integrity sha512-gsA4IhmtWHI4BofKy3kio9W+dqZQs5Ji5mLjLYxHCkat+JQBUt5szjRKra2F9nGDJ2XcI/wWb0YWUFNgln4zRQ== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.4" + "@nomicfoundation/ethereumjs-blockchain" "7.0.4" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-evm" "2.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-statemanager" "2.0.4" + "@nomicfoundation/ethereumjs-trie" "6.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" debug "^4.3.3" ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": version "0.1.1" @@ -1869,7 +1670,7 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.4": +"@scure/base@^1.1.1", "@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.4": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== @@ -2445,19 +2246,6 @@ abstract-level@1.0.3: module-error "^1.0.1" queue-microtask "^1.2.3" -abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3, abstract-level@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.4.tgz#3ad8d684c51cc9cbc9cf9612a7100b716c414b57" - integrity sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - abstract-leveldown@7.2.0, abstract-leveldown@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" @@ -2495,11 +2283,6 @@ adm-zip@^0.4.16: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2875,17 +2658,12 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== -bigint-crypto-utils@^3.0.23: +bigint-crypto-utils@^3.2.2: version "3.3.0" resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" integrity sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg== @@ -2970,16 +2748,6 @@ brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-level@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" - integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.1" - module-error "^1.0.2" - run-parallel-limit "^1.1.0" - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -3215,12 +2983,7 @@ caniuse-lite@^1.0.30001580: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881" integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== -case@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" - integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== - -catering@^2.0.0, catering@^2.1.0, catering@^2.1.1: +catering@^2.0.0, catering@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== @@ -3318,17 +3081,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== -classic-level@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.4.1.tgz#169ecf9f9c6200ad42a98c8576af449c1badbaee" - integrity sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.0" - module-error "^1.0.1" - napi-macros "^2.2.2" - node-gyp-build "^4.3.0" - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3659,11 +3411,6 @@ cosmiconfig@^8.2.0: parse-json "^5.2.0" path-type "^4.0.0" -crc-32@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" - integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -4420,42 +4167,6 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethers@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -4850,11 +4561,6 @@ function.prototype.name@^1.1.6: es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -5199,22 +4905,23 @@ hard-rejection@^2.1.0: integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== hardhat@^2.17.3: - version "2.19.5" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.19.5.tgz#6017c35ae2844b669e9bcc84c3d05346d4ef031c" - integrity sha512-vx8R7zWCYVgM56vA6o0Wqx2bIIptkN4TMs9QwDqZVNGRhMzBfzqUeEYbp+69gxWp1neg2V2nYQUaaUv7aom1kw== + version "2.20.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.20.0.tgz#b28da8038fa5db0663a3b93668b261d3d4e7fb3d" + integrity sha512-TtWZ4mKOH5YA+PCDAGAjG7Gub2NA+egAX7RIHq5XnGrEALNXAbyP3S0I9vOE1MWCgZhn+XOFUNfDuHgkBOPoRw== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-blockchain" "7.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-evm" "2.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-statemanager" "2.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - "@nomicfoundation/ethereumjs-vm" "7.0.2" + "@nomicfoundation/ethereumjs-block" "5.0.4" + "@nomicfoundation/ethereumjs-blockchain" "7.0.4" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-evm" "2.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-statemanager" "2.0.4" + "@nomicfoundation/ethereumjs-trie" "6.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + "@nomicfoundation/ethereumjs-verkle" "0.0.2" + "@nomicfoundation/ethereumjs-vm" "7.0.4" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" @@ -6575,15 +6282,6 @@ level-transcoder@^1.0.1: buffer "^6.0.3" module-error "^1.0.1" -level@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/level/-/level-8.0.1.tgz#737161db1bc317193aca4e7b6f436e7e1df64379" - integrity sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ== - dependencies: - abstract-level "^1.0.4" - browser-level "^1.0.1" - classic-level "^1.2.0" - leveldown@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" @@ -6725,7 +6423,7 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": +lru-cache@^10.0.0, lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": version "10.2.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== @@ -6873,11 +6571,6 @@ marked@^4.3.0: resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== -mcl-wasm@^0.7.1: - version "0.7.9" - resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" - integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -6887,15 +6580,6 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -memory-level@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" - integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== - dependencies: - abstract-level "^1.0.0" - functional-red-black-tree "^1.0.1" - module-error "^1.0.1" - memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -7187,7 +6871,7 @@ modify-values@^1.0.1: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -module-error@^1.0.1, module-error@^1.0.2: +module-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== @@ -7237,11 +6921,6 @@ mz@^2.4.0: object-assign "^4.0.1" thenify-all "^1.0.0" -napi-macros@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" - integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== - napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" @@ -8404,13 +8083,6 @@ run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-parallel-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" - integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== - dependencies: - queue-microtask "^1.2.2" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -8418,10 +8090,17 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rustbn.js@~0.2.0: +rust-verkle-wasm@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/rust-verkle-wasm/-/rust-verkle-wasm-0.0.1.tgz#fd8396a7060d8ee8ea10da50ab6e862948095a74" + integrity sha512-BN6fiTsxcd2dCECz/cHtGTt9cdLJR925nh7iAuRcj8ymKw7OOaPmCneQZ7JePOJ/ia27TjEL91VdOi88Yf+mcA== + +rustbn-wasm@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== + resolved "https://registry.yarnpkg.com/rustbn-wasm/-/rustbn-wasm-0.2.0.tgz#0407521fb55ae69eeb4968d01885d63efd1c4ff9" + integrity sha512-FThvYFNTqrEKGqXuseeg0zR7yROh/6U1617mCHF68OVqrN1tNKRN7Tdwy4WayPVsCmmK+eMxtIZX1qL6JxTkMg== + dependencies: + "@scure/base" "^1.1.1" rxjs@^7.5.5, rxjs@^7.8.1: version "7.8.1" @@ -8476,7 +8155,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scrypt-js@3.0.1, scrypt-js@^3.0.0: +scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== @@ -9793,11 +9472,6 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - ws@8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" From 8a7eb0d7e07d8cfe4b8d2abcd9a814468acb7f7e Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 14 Feb 2024 14:52:37 +0000 Subject: [PATCH 06/33] continued --- packages/modules/src/utils/Constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/modules/src/utils/Constants.ts b/packages/modules/src/utils/Constants.ts index afed7bc33..407e374d0 100644 --- a/packages/modules/src/utils/Constants.ts +++ b/packages/modules/src/utils/Constants.ts @@ -48,5 +48,4 @@ export const ERC20_ABI = [ "function approve(address spender, uint256 value) external returns (bool)", "function allowance(address owner, address spender) external view returns (uint256)", "function balanceOf(address owner) external view returns (uint256)", - "function decimals() external view returns (uint8)", ]; From e6cd7dba04f9f241df8dad19c883f0ebe0d48c90 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Mon, 26 Feb 2024 11:10:33 +0000 Subject: [PATCH 07/33] fix yarn Auto stash before merge of "feature/SMA-599_balances" and "origin/develop" Add withdrawal tests jsdoc comments continued Fix comments comments continued Make `getBalance` available with no arguments rename tokenAdress -> address Throw when no amount + no paymaster is set Tweak comment --- jest.config.ts | 6 + .../account/src/BiconomySmartAccountV2.ts | 160 +++++++++--- packages/account/src/utils/Constants.ts | 3 +- packages/account/src/utils/Types.ts | 7 + packages/account/src/utils/Utils.ts | 2 + packages/account/tests/account.e2e.spec.ts | 247 +++++++++++++++++- tests/utils.ts | 17 +- yarn.lock | 102 +++----- 8 files changed, 441 insertions(+), 103 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index 7cc8b4123..844398aba 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -74,6 +74,12 @@ const config: Config = { // "node_modules" // ], + workerThreads: true, + // This is experimental feature. Keep in mind that the worker threads use structured clone instead of JSON.stringify() to serialize messages. + // This means that built-in JavaScript objects as BigInt, Map or Set will get serialized properly. + // However extra properties set on Error, Map or Set will not be passed on through the serialization step. + // For more details see the article on structured clone. + // An array of file extensions your modules use moduleFileExtensions: ["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"], diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 69e90e58f..7c811b75d 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -26,7 +26,7 @@ import { BatchUserOperationCallData, SmartAccountSigner, } from "@alchemy/aa-core"; -import { isNullOrUndefined, packUserOp } from "./utils/Utils.js"; +import { addressEquals, isNullOrUndefined, packUserOp } from "./utils/Utils.js"; import { BaseValidationModule, ModuleInfo, SendUserOpParams, createECDSAOwnershipValidationModule } from "@biconomy/modules"; import { IHybridPaymaster, @@ -53,6 +53,7 @@ import { PaymasterUserOperationDto, SimulationType, BalancePayload, + WithdrawalRequest, } from "./utils/Types.js"; import { ADDRESS_RESOLVER_ADDRESS, @@ -257,13 +258,105 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { return this.accountAddress; } + /** + * Transfers funds from Smart Account to recipient (usually EOA) + * @param recipient - Address of the recipient + * @param withdrawalRequests - Array of withdrawal requests {@link WithdrawalRequest}. If withdrawal request is an empty array, it will transfer the balance of the native token. Using a paymaster will ensure no dust remains in the smart account. + * @param buildUseropDto - Optional. {@link BuildUserOpOptions} + * + * @returns Promise - An object containing the status of the transaction. + * + * @example + * import { createClient } from "viem" + * import { createSmartAccountClient, NATIVE_TOKEN_ALIAS } from "@biconomy/account" + * import { createWalletClient, http } from "viem"; + * import { polygonMumbai } from "viem/chains"; + * + * const USDT = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const signer = createWalletClient({ + * account, + * chain: polygonMumbai, + * transport: http(), + * }); + * + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); + * + * const { wait } = await smartAccount.withdraw( + * account.pubKey, // recipient + * [ + * { address: USDT, amount: BigInt(1) }, + * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + * ], + * { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * } + * ); + * + * // OR to withdraw all of the native token, leaving no dust in the smart account + * + * const { wait } = await smartAccount.withdraw(account.pubKey, [], { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * }); + * + * const { success } = await wait(); + */ + public async withdraw( + recipient: Hex, + withdrawalRequests?: WithdrawalRequest[] | null, + buildUseropDto?: BuildUserOpOptions, + ): Promise { + const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + + // Remove the native token from the withdrawal requests + let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; + + // Check if the amount is not present in all withdrawal requests + const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount); + + // Get the balances of the tokens if the amount is not present in the withdrawal requests + if (shouldFetchMaxBalances) { + const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); + tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ address, amount: amount ?? balances[i].amount })); + } + + // Create the transactions + const txs: Transaction[] = tokenRequests.map(({ address, amount }) => ({ + to: address, + data: encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: "transfer", + args: [recipient, amount], + }), + })); + + // Check if eth alias is present in the original withdrawal requests + const nativeTokenRequest = withdrawalRequests?.find(({ address }) => addressEquals(address, NATIVE_TOKEN_ALIAS)); + const hasNoRequests = !withdrawalRequests?.length; + if (!!nativeTokenRequest || hasNoRequests) { + // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster. + if (!nativeTokenRequest?.amount && !buildUseropDto?.paymasterServiceData?.mode) { + throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + } + + // get eth balance if not present in withdrawal requests + const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); + + txs.push({ + to: recipient, + value: nativeTokenAmountToWithdraw, + }); + } + + return this.sendTransaction(txs, buildUseropDto); + } + /** * Returns token balances of Smart Account * * This method will fetch the token balances of the smartAccount instance. - * If left empty, it will return the balance of the native token, with the address set to 0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE. + * The balance of the native token will always be returned as the last element in the reponse array, with the address set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. * - * @param tokenAddresses - Optional. Array of token addresses to fetch the balances of. + * @param addresses - Optional. Array of asset addresses to fetch the balances of. * @returns Promise> - An array of token balances (or native token balance) of the smartAccount instance. * @throws An error if something is wrong with the smart account instance creation. * @@ -292,40 +385,47 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * // } * */ - public async getBalances(tokenAddresses: Array): Promise> { + public async getBalances(addresses?: Array): Promise> { const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + const result: BalancePayload[] = []; + + if (addresses) { + const tokenContracts = addresses + .filter((address) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) + .map((address) => + getContract({ + address, + abi: parseAbi(ERC20_ABI), + client: this.provider, + }), + ); - if (!tokenAddresses) { - const balance = await this.provider.getBalance({ address: accountAddress }); - return [ - { - amount: balance, - decimals: 18, - address: NATIVE_TOKEN_ALIAS, - formattedAmount: formatUnits(balance, 18), + const balancePromises = tokenContracts.map((tokenContract) => tokenContract.read.balanceOf([accountAddress])) as Promise[]; + const decimalsPromises = tokenContracts.map((tokenContract) => tokenContract.read.decimals()) as Promise[]; + const [balances, decimalsPerToken] = await Promise.all([Promise.all(balancePromises), Promise.all(decimalsPromises)]); + + balances.forEach((amount, index) => + result.push({ + amount, + decimals: decimalsPerToken[index], + address: addresses[index], + formattedAmount: formatUnits(amount, decimalsPerToken[index]), chainId: this.chainId, - }, - ]; + }), + ); } - const tokenContracts = tokenAddresses.map((address) => - getContract({ - address, - abi: parseAbi(ERC20_ABI), - client: this.provider, - }), - ); - const balancePromises = tokenContracts.map((tokenContract) => tokenContract.read.balanceOf([accountAddress])) as Promise[]; - const decimalsPromises = tokenContracts.map((tokenContract) => tokenContract.read.decimals()) as Promise[]; - const [balances, decimalsPerToken] = await Promise.all([Promise.all(balancePromises), Promise.all(decimalsPromises)]); + const balance = await this.provider.getBalance({ address: accountAddress }); - return balances.map((amount, index) => ({ - amount, - decimals: decimalsPerToken[index], - address: tokenAddresses[index], - formattedAmount: formatUnits(amount, decimalsPerToken[index]), + result.push({ + amount: balance, + decimals: 18, + address: NATIVE_TOKEN_ALIAS, + formattedAmount: formatUnits(balance, 18), chainId: this.chainId, - })); + }); + + return result; } /** diff --git a/packages/account/src/utils/Constants.ts b/packages/account/src/utils/Constants.ts index 171938f0f..6163f5e42 100644 --- a/packages/account/src/utils/Constants.ts +++ b/packages/account/src/utils/Constants.ts @@ -61,9 +61,10 @@ export const ERROR_MESSAGES = { SPENDER_REQUIRED: "spender is required for ERC20 mode", NO_FEE_QUOTE: "FeeQuote was not provided, please call smartAccount.getTokenFees() to get feeQuote", FAILED_FEE_QUOTE_FETCH: "Failed to fetch fee quote", + NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT: "'Amount' is required for withdrawal of native token without using a paymaster", }; -export const NATIVE_TOKEN_ALIAS = "0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"; +export const NATIVE_TOKEN_ALIAS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; export const ERC20_ABI = [ "function transfer(address to, uint256 value) external returns (bool)", "function transferFrom(address from, address to, uint256 value) external returns (bool)", diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts index 10ffd9858..870d406ca 100644 --- a/packages/account/src/utils/Types.ts +++ b/packages/account/src/utils/Types.ts @@ -39,6 +39,13 @@ export interface BalancePayload { formattedAmount: string; } +export interface WithdrawalRequest { + /** The address of the tokenAddress */ + address: Hex; + /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ + amount?: bigint; +} + export interface GasOverheads { /** fixed: fixed gas overhead */ fixed: number; diff --git a/packages/account/src/utils/Utils.ts b/packages/account/src/utils/Utils.ts index d905506c9..11356c8a8 100644 --- a/packages/account/src/utils/Utils.ts +++ b/packages/account/src/utils/Utils.ts @@ -40,6 +40,8 @@ export function packUserOp(op: Partial, forSignature = true } } +export const addressEquals = (a?: string, b?: string): boolean => !!a && !!b && a?.toLowerCase() === b.toLowerCase(); + export const isNullOrUndefined = (value: any): value is undefined => { return value === null || value === undefined; }; diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index fbfe2227b..8964c0b6d 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -1,6 +1,6 @@ import { TestData } from "../../../tests"; -import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, IHybridPaymaster, PaymasterMode } from "../src/index"; -import { Hex, encodeFunctionData, getContract, parseAbi } from "viem"; +import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, IHybridPaymaster, NATIVE_TOKEN_ALIAS, PaymasterMode } from "../src/index"; +import { Hex, encodeFunctionData, getContract, parseAbi, parseEther } from "viem"; import { UserOperationStruct } from "@alchemy/aa-core"; import { checkBalance, entryPointABI } from "../../../tests/utils"; import { ERC20_ABI } from "@biconomy/modules"; @@ -78,7 +78,6 @@ describe("Account Tests", () => { { to: recipient, value: 1, - data: "0x", }, { simulationType: "validation_and_execution", @@ -477,4 +476,246 @@ describe("Account Tests", () => { expect(usdcBalanceBefore).toBe(usdtBalanceFromSmartAccount.amount); }); + + it("should check native token balance for smartAccount", async () => { + const { + whale: { viemWallet: signer }, + bundlerUrl, + biconomyPaymasterApiKey, + chainId, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const [ethBalanceFromSmartAccount] = await smartAccount.getBalances(); + + expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n); + expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS); + expect(ethBalanceFromSmartAccount.chainId).toBe(chainId); + expect(ethBalanceFromSmartAccount.decimals).toBe(18); + }, 60000); + + it("should check balance responses", async () => { + const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + const { + whale: { viemWallet: signer }, + bundlerUrl, + biconomyPaymasterApiKey, + chainId, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const [usdtBalanceFromSmartAccount, ethBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); // last result is always eth balance + + expect(usdtBalanceFromSmartAccount.amount).toBeGreaterThan(0n); + expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n); + expect(usdtBalanceFromSmartAccount.address).toBe(usdt); + expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS); + expect(usdtBalanceFromSmartAccount.chainId).toBe(chainId); + expect(ethBalanceFromSmartAccount.chainId).toBe(chainId); + expect(usdtBalanceFromSmartAccount.decimals).toBe(6); + expect(ethBalanceFromSmartAccount.decimals).toBe(18); + expect(usdtBalanceFromSmartAccount.formattedAmount).toBeTruthy(); + expect(ethBalanceFromSmartAccount.formattedAmount).toBeTruthy(); + }); + + it("should withdraw erc20 balances", async () => { + const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner, account }, + bundlerUrl, + publicClient, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const smartAccountAddress = await smartAccount.getAddress(); + const usdtBalanceOfSABefore = await checkBalance(publicClient, smartAccountAddress, usdt); + const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); + + const { wait } = await smartAccount.withdraw(smartAccountOwner, [{ address: usdt, amount: BigInt(1) }]); + + const { + receipt: { transactionHash }, + userOpHash, + success, + } = await wait(); + + expect(userOpHash).toBeTruthy(); + expect(success).toBe("true"); + expect(transactionHash).toBeTruthy(); + + const usdtBalanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress, usdt)) as bigint; + const usdtBalanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner, usdt)) as bigint; + + expect(usdtBalanceOfSAAfter - usdtBalanceOfSABefore).toBe(-1n); + expect(usdtBalanceOfRecipientAfter - usdtBalanceOfRecipientBefore).toBe(1n); + }, 60000); + + it("should gaslessly withdraw nativeToken", async () => { + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner }, + bundlerUrl, + publicClient, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const smartAccountAddress = await smartAccount.getAddress(); + const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + + const { wait } = await smartAccount.withdraw(smartAccountOwner, [{ address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }], { + paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + }); + + const { + receipt: { transactionHash }, + userOpHash, + success, + } = await wait(); + + expect(userOpHash).toBeTruthy(); + expect(success).toBe("true"); + expect(transactionHash).toBeTruthy(); + + const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + + expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n); + expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n); + }, 60000); + + it("should withdraw nativeToken and an erc20 token", async () => { + const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner }, + bundlerUrl, + publicClient, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const smartAccountAddress = await smartAccount.getAddress(); + const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + const usdtBalanceOfSABefore = await checkBalance(publicClient, smartAccountAddress, usdt); + const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); + + const { wait } = await smartAccount.withdraw( + smartAccountOwner, + [ + { address: usdt, amount: BigInt(1) }, + { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }, + ], + { + paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + }, + ); + + const { + receipt: { transactionHash }, + userOpHash, + success, + } = await wait(); + + expect(userOpHash).toBeTruthy(); + expect(success).toBe("true"); + expect(transactionHash).toBeTruthy(); + + const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + const usdtBalanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress, usdt)) as bigint; + const usdtBalanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner, usdt)) as bigint; + + expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n); + expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n); + expect(usdtBalanceOfSAAfter - usdtBalanceOfSABefore).toBe(-1n); + expect(usdtBalanceOfRecipientAfter - usdtBalanceOfRecipientBefore).toBe(1n); + }, 60000); + + it("should withdraw all native token", async () => { + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner, account }, + bundlerUrl, + viemChain, + publicClient, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const smartAccountAddress = await smartAccount.getAddress(); + const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + + const { wait } = await smartAccount.withdraw(smartAccountOwner, undefined /* null or undefined or [] */, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED }, // Will leave no dust + }); + + const { + receipt: { transactionHash }, + userOpHash, + success, + } = await wait(); + + expect(userOpHash).toBeTruthy(); + expect(success).toBe("true"); + expect(transactionHash).toBeTruthy(); + + const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; + const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; + + expect(balanceOfSAAfter).toBe(0n); + expect(balanceOfRecipientAfter).toBe(balanceOfSABefore + balanceOfRecipientBefore); + + // Teardown: send back the native token to the smart account + const teardownHash = await signer.sendTransaction({ to: smartAccountAddress, value: balanceOfSABefore, account, chain: viemChain }); + expect(teardownHash).toBeTruthy(); + }, 60000); + + it("should error when withdraw all of native token is attempted without an amount explicitly set", async () => { + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner }, + bundlerUrl, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + expect(async () => smartAccount.withdraw(smartAccountOwner)).rejects.toThrow(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + }, 60000); }); diff --git a/tests/utils.ts b/tests/utils.ts index c010435f6..ba3a311c1 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,17 +1,16 @@ import { Hex, PublicClient, parseAbi } from "viem"; -export const checkBalance = (publicClient: PublicClient, address: Hex, tokenAddress?: Hex) => { +export const checkBalance = (publicClient: PublicClient, address: Hex, tokenAddress?: Hex): Promise => { if (!tokenAddress) { return publicClient.getBalance({ address }); - } else { - return publicClient.readContract({ - address: tokenAddress, - abi: parseAbi(["function balanceOf(address owner) view returns (uint balance)"]), - functionName: "balanceOf", - // @ts-ignore - args: [address], - }); } + return publicClient.readContract({ + address: tokenAddress, + abi: parseAbi(["function balanceOf(address owner) view returns (uint balance)"]), + functionName: "balanceOf", + // @ts-ignore + args: [address], + }); }; // TODO(Joe): Make human readable diff --git a/yarn.lock b/yarn.lock index cbf7c942e..84e3ec4fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -563,8 +563,6 @@ dependencies: "@ethersproject/bytes" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/basex@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" @@ -573,7 +571,6 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/properties" "^5.7.0" ->>>>>>> origin/develop "@ethersproject/bignumber@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" @@ -612,8 +609,6 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/hdnode@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" @@ -651,7 +646,6 @@ aes-js "3.0.0" scrypt-js "3.0.1" ->>>>>>> origin/develop "@ethersproject/keccak256@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" @@ -672,8 +666,6 @@ dependencies: "@ethersproject/logger" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/pbkdf2@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" @@ -682,7 +674,6 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/sha2" "^5.7.0" ->>>>>>> origin/develop "@ethersproject/properties@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" @@ -690,8 +681,6 @@ dependencies: "@ethersproject/logger" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" @@ -726,7 +715,6 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/logger" "^5.7.0" ->>>>>>> origin/develop "@ethersproject/rlp@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" @@ -735,8 +723,6 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/logger" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/sha2@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" @@ -746,7 +732,6 @@ "@ethersproject/logger" "^5.7.0" hash.js "1.1.7" ->>>>>>> origin/develop "@ethersproject/signing-key@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" @@ -783,8 +768,6 @@ "@ethersproject/rlp" "^5.7.0" "@ethersproject/signing-key" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/wallet@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" @@ -806,7 +789,6 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/wordlists" "^5.7.0" ->>>>>>> origin/develop "@ethersproject/web@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" @@ -818,8 +800,6 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -<<<<<<< HEAD -======= "@ethersproject/wordlists@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" @@ -831,7 +811,6 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" ->>>>>>> origin/develop "@fastify/busboy@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" @@ -1788,9 +1767,9 @@ uuid "^8.3.2" "@particle-network/chains@*": - version "1.3.16" - resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.16.tgz#5b56104b0d7a6c87d17eb7f2d597ee358a430cd9" - integrity sha512-vr30c56QmMMxXP59hL4MysdmKNHCD2JmMEdhfly5C+HB+N4p/a7ioblioatRIukgZPP9/Qnc7TPJISGlQaGWpA== + version "1.3.18" + resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.18.tgz#ce763a845f88ff118c27148579de6934ff376298" + integrity sha512-R38ddazbt5Xt8noVA4Fproc89Mm7UmaRvc7Xkl0XP0sp+HaUJjEwFpL4zTCATYb2sUx3cJgV46fVOuD7/2QWIA== "@particle-network/crypto@^1.0.1": version "1.0.1" @@ -2178,9 +2157,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.11.10": - version "20.11.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.18.tgz#06912d152e47c2ac0a393c62141e623ca6005d46" - integrity sha512-ABT5VWnnYneSBcNWYSCuR05M826RoMyMSGiFivXGx6ZUIsXb9vn4643IEwkg2zbEOSgAiSogtapN2fgc4mAPlw== + version "20.11.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195" + integrity sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ== dependencies: undici-types "~5.26.4" @@ -2432,6 +2411,11 @@ adm-zip@^0.4.16: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2716,7 +2700,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: +available-typed-arrays@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== @@ -2807,6 +2791,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" @@ -3128,9 +3117,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001587" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881" - integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== + version "1.0.30001588" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz#07f16b65a7f95dba82377096923947fb25bce6e3" + integrity sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ== catering@^2.0.0, catering@^2.1.0: version "2.1.1" @@ -3832,17 +3821,10 @@ ejs@^3.1.7: dependencies: jake "^10.8.5" -<<<<<<< HEAD -electron-to-chromium@^1.4.648: - version "1.4.668" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz#5cfed14f3240cdc70a359a49790cb295b1f097f1" - integrity sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ== -======= electron-to-chromium@^1.4.668: - version "1.4.670" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.670.tgz#0fc5ac92ada8371e898ea72d577ffc888167a017" - integrity sha512-hcijYOWjOtjKrKPtNA6tuLlA/bTLO3heFG8pQA6mLpq7dRydSWicXova5lyxDzp1iVJaYhK7J2OQlGE52KYn7A== ->>>>>>> origin/develop + version "1.4.673" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.673.tgz#1f077d9a095761804aec7ec6346c3f4b69b56534" + integrity sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw== elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" @@ -5061,15 +5043,9 @@ hard-rejection@^2.1.0: integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== hardhat@^2.17.3: -<<<<<<< HEAD - version "2.20.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.20.0.tgz#b28da8038fa5db0663a3b93668b261d3d4e7fb3d" - integrity sha512-TtWZ4mKOH5YA+PCDAGAjG7Gub2NA+egAX7RIHq5XnGrEALNXAbyP3S0I9vOE1MWCgZhn+XOFUNfDuHgkBOPoRw== -======= version "2.20.1" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.20.1.tgz#3ad8f2b003a96c9ce80a55fec3575580ff2ddcd4" integrity sha512-q75xDQiQtCZcTMBwjTovrXEU5ECr49baxr4/OBkIu/ULTPzlB20yk1dRWNmD2IFbAeAeXggaWvQAdpiScaHtPw== ->>>>>>> origin/develop dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" @@ -7104,9 +7080,9 @@ neo-async@^2.6.2: integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== nock@^13.2.9: - version "13.5.1" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.1.tgz#4e40f9877ad0d43b7cdb474261c190f3715dd806" - integrity sha512-+s7b73fzj5KnxbKH4Oaqz07tQ8degcMilU4rrmnKvI//b0JMBU4wEXFQ8zqr+3+L4eWSfU3H/UoIVGUV0tue1Q== + version "13.5.3" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.3.tgz#9858adf5b840696a410baf98bda720d5fad4f075" + integrity sha512-2NlGmHIK2rTeyy7UaY1ZNg0YZfEJMxghXgZi0b4DBsUyoDNTTxZeCSG1nmirAWF44RkkoV8NnegLVQijgVapNQ== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" @@ -8317,7 +8293,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scrypt-js@^3.0.0: +scrypt-js@3.0.1, scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== @@ -9161,15 +9137,16 @@ typed-array-byte-length@^1.0.0: is-typed-array "^1.1.10" typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.1.tgz#5e2bcc1d93e1a332d50e8b363a48604a134692f8" + integrity sha512-tcqKMrTRXjqvHN9S3553NPCaGL0VPgFI92lXszmrE8DMhiDPLBYLlvo8Uu4WZAAX/aGqp/T1sbA4ph8EWjDF9Q== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.6" + call-bind "^1.0.7" for-each "^0.3.3" + gopd "^1.0.1" has-proto "^1.0.1" - is-typed-array "^1.1.10" + is-typed-array "^1.1.13" typed-array-length@^1.0.4: version "1.0.4" @@ -9400,9 +9377,9 @@ validate-npm-package-name@^3.0.0: builtins "^1.0.3" viem@^2.5.0, viem@^2.7.3: - version "2.7.9" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.9.tgz#0d2b0c4722530b53fbef449d70f0cedc1bb867b0" - integrity sha512-iDfc8TwaZFp1K95zlsxYh6Cs0OWCt35Tqs8uYgXKSxtz7w075mZ0H5SJ8zSyJGoEaticVDhtdmRRX6TtcW9EeQ== + version "2.7.10" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.10.tgz#344fa51e28a57c36830f8eb940769e1f486628c3" + integrity sha512-mpm/A3Rbq6hhRovOw6btkrLeDe0DlEGLoCmO2LCbH/MuTQgLNd0cWJSIov9TL/8/Pz+qC2e+bh9zohQnKA+6PQ== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -9634,6 +9611,11 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + ws@8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" From b689dc9fb2d8b1413d1ee0b46aec0d622ec043b7 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Mon, 26 Feb 2024 11:16:41 +0000 Subject: [PATCH 08/33] fix comment --- packages/account/src/utils/Types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts index 2b4177988..4e974e94a 100644 --- a/packages/account/src/utils/Types.ts +++ b/packages/account/src/utils/Types.ts @@ -40,7 +40,7 @@ export interface BalancePayload { } export interface WithdrawalRequest { - /** The address of the tokenAddress */ + /** The address of the asset */ address: Hex; /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ amount?: bigint; From 4bb17a78f1f9f730b06808948df0f33602f20bc3 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Mon, 26 Feb 2024 16:56:10 +0000 Subject: [PATCH 09/33] default recipient --- .../account/src/BiconomySmartAccountV2.ts | 21 ++++-- packages/account/src/utils/Constants.ts | 4 +- packages/account/src/utils/Types.ts | 2 + packages/account/tests/account.e2e.spec.ts | 73 +++++++++---------- ...batchedSessionValidationModule.e2e.spec.ts | 8 +- .../multiChainValidationModule.e2e.spec.ts | 5 +- .../tests/sessionValidationModule.e2e.spec.ts | 7 +- 7 files changed, 65 insertions(+), 55 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index a1979bb8c..535c2c013 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -306,11 +306,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); * * const { wait } = await smartAccount.withdraw( - * account.pubKey, // recipient * [ * { address: USDT, amount: BigInt(1) }, * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } * ], + * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request * { * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, * } @@ -318,19 +318,23 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * // OR to withdraw all of the native token, leaving no dust in the smart account * - * const { wait } = await smartAccount.withdraw(account.pubKey, [], { + * const { wait } = await smartAccount.withdraw([], account.pubKey, { * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, * }); * * const { success } = await wait(); */ public async withdraw( - recipient: Hex, withdrawalRequests?: WithdrawalRequest[] | null, + defaultRecipient?: Hex | null, buildUseropDto?: BuildUserOpOptions, ): Promise { const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + if (!defaultRecipient && withdrawalRequests?.some(({ recipient }) => !recipient)) { + throw new Error(ERROR_MESSAGES.NO_RECIPIENT); + } + // Remove the native token from the withdrawal requests let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; @@ -340,16 +344,19 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { // Get the balances of the tokens if the amount is not present in the withdrawal requests if (shouldFetchMaxBalances) { const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); - tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ address, amount: amount ?? balances[i].amount })); + tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ + address, + amount: amount ?? balances[i].amount, + })); } // Create the transactions - const txs: Transaction[] = tokenRequests.map(({ address, amount }) => ({ + const txs: Transaction[] = tokenRequests.map(({ address, amount, recipient: recipientFromRequest }) => ({ to: address, data: encodeFunctionData({ abi: parseAbi(ERC20_ABI), functionName: "transfer", - args: [recipient, amount], + args: [recipientFromRequest ?? defaultRecipient, amount], }), })); @@ -366,7 +373,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); txs.push({ - to: recipient, + to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex, value: nativeTokenAmountToWithdraw, }); } diff --git a/packages/account/src/utils/Constants.ts b/packages/account/src/utils/Constants.ts index 6163f5e42..8d4f2ac38 100644 --- a/packages/account/src/utils/Constants.ts +++ b/packages/account/src/utils/Constants.ts @@ -1,3 +1,4 @@ +import { Hex } from "viem"; import { EntryPointAddresses, BiconomyFactories, @@ -58,13 +59,14 @@ export const DefaultGasLimit = { }; export const ERROR_MESSAGES = { + NO_RECIPIENT: "One or more of your withdrawals is missing a recipient", SPENDER_REQUIRED: "spender is required for ERC20 mode", NO_FEE_QUOTE: "FeeQuote was not provided, please call smartAccount.getTokenFees() to get feeQuote", FAILED_FEE_QUOTE_FETCH: "Failed to fetch fee quote", NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT: "'Amount' is required for withdrawal of native token without using a paymaster", }; -export const NATIVE_TOKEN_ALIAS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; +export const NATIVE_TOKEN_ALIAS: Hex = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; export const ERC20_ABI = [ "function transfer(address to, uint256 value) external returns (bool)", "function transferFrom(address from, address to, uint256 value) external returns (bool)", diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts index 488ea7920..c862eed60 100644 --- a/packages/account/src/utils/Types.ts +++ b/packages/account/src/utils/Types.ts @@ -44,6 +44,8 @@ export interface WithdrawalRequest { address: Hex; /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ amount?: bigint; + /** The destination address of the funds. The first argument from the `withdraw(...)` function will be used as the default if left unset. */ + recipient?: Hex; } export interface GasOverheads { diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index cc6d63daf..5e515ed31 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -32,7 +32,7 @@ describe("Account Tests", () => { bundlerUrl, }); - const reciepientSmartAccount = await createSmartAccountClient({ + const recipientSmartAccount = await createSmartAccountClient({ signer: recipientSigner, bundlerUrl, }); @@ -42,7 +42,7 @@ describe("Account Tests", () => { bundlerUrl: bundlerUrlBase, }); - const reciepientSmartAccountBase = await createSmartAccountClient({ + const recipientSmartAccountBase = await createSmartAccountClient({ signer: recipientSignerBase, bundlerUrl: bundlerUrlBase, }); @@ -51,11 +51,11 @@ describe("Account Tests", () => { sender, smartAccount.getAddress(), recipient, - reciepientSmartAccount.getAddress(), + recipientSmartAccount.getAddress(), senderBase, smartAccountBase.getAddress(), recipientBase, - reciepientSmartAccountBase.getAddress(), + recipientSmartAccountBase.getAddress(), ]); expect(addresses.every(Boolean)).toBeTruthy(); }); @@ -453,41 +453,15 @@ describe("Account Tests", () => { const { whale: { viemWallet: signer }, bundlerUrl, - viemChain, } = mumbai; const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, - rpcUrl: viemChain.rpcUrls.default.http[0], }); expect(ecdsaOwnershipModule).toBe(smartAccount.activeValidationModule.getAddress()); }); - it("should fetch balances for smartAccount", async () => { - - it("should get supported tokens from the paymaster", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = mumbai; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const tokens = await smartAccount.getSupportedTokens(); - - expect(tokens.length).toBeGreaterThan(0); - expect(tokens[0]).toHaveProperty("tokenAddress"); - expect(tokens[0]).toHaveProperty("symbol"); - expect(tokens[0]).toHaveProperty("decimal"); - expect(tokens[0]).toHaveProperty("premiumPercentage"); - expect(tokens[0]).toHaveProperty("logoUrl"); - }, 60000); it("should fetch balances for smartAccount", async () => { const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; @@ -580,7 +554,7 @@ describe("Account Tests", () => { const usdtBalanceOfSABefore = await checkBalance(publicClient, smartAccountAddress, usdt); const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); - const { wait } = await smartAccount.withdraw(smartAccountOwner, [{ address: usdt, amount: BigInt(1) }]); + const { wait } = await smartAccount.withdraw([{ address: usdt, amount: BigInt(1), recipient: smartAccountOwner }]); const { receipt: { transactionHash }, @@ -597,7 +571,7 @@ describe("Account Tests", () => { expect(usdtBalanceOfSAAfter - usdtBalanceOfSABefore).toBe(-1n); expect(usdtBalanceOfRecipientAfter - usdtBalanceOfRecipientBefore).toBe(1n); - }, 60000); + }, 15000); it("should gaslessly withdraw nativeToken", async () => { const { @@ -617,7 +591,7 @@ describe("Account Tests", () => { const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - const { wait } = await smartAccount.withdraw(smartAccountOwner, [{ address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }], { + const { wait } = await smartAccount.withdraw([{ address: NATIVE_TOKEN_ALIAS, amount: BigInt(1), recipient: smartAccountAddress }], null, { paymasterServiceData: { mode: PaymasterMode.SPONSORED }, }); @@ -636,7 +610,7 @@ describe("Account Tests", () => { expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n); expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n); - }, 60000); + }, 12000); it("should withdraw nativeToken and an erc20 token", async () => { const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; @@ -661,11 +635,11 @@ describe("Account Tests", () => { const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); const { wait } = await smartAccount.withdraw( - smartAccountOwner, [ { address: usdt, amount: BigInt(1) }, { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }, ], + smartAccountOwner, { paymasterServiceData: { mode: PaymasterMode.SPONSORED }, }, @@ -711,7 +685,7 @@ describe("Account Tests", () => { const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - const { wait } = await smartAccount.withdraw(smartAccountOwner, undefined /* null or undefined or [] */, { + const { wait } = await smartAccount.withdraw([] /* null or undefined or [] */, smartAccountOwner, { paymasterServiceData: { mode: PaymasterMode.SPONSORED }, // Will leave no dust }); @@ -736,6 +710,29 @@ describe("Account Tests", () => { expect(teardownHash).toBeTruthy(); }, 60000); + it("should error if no recipient exists", async () => { + const usdt: Hex = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + + const { + whale: { viemWallet: signer, publicAddress: smartAccountOwner }, + bundlerUrl, + biconomyPaymasterApiKey, + } = mumbai; + + const smartAccount = await createSmartAccountClient({ + signer, + biconomyPaymasterApiKey, + bundlerUrl, + }); + + const txs = [ + { address: usdt, amount: BigInt(1), recipient: smartAccountOwner }, + { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }, + ]; + + expect(async () => smartAccount.withdraw(txs)).rejects.toThrow(ERROR_MESSAGES.NO_RECIPIENT); + }); + it("should error when withdraw all of native token is attempted without an amount explicitly set", async () => { const { whale: { viemWallet: signer, publicAddress: smartAccountOwner }, @@ -749,6 +746,6 @@ describe("Account Tests", () => { bundlerUrl, }); - expect(async () => smartAccount.withdraw(smartAccountOwner)).rejects.toThrow(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); - }, 60000); + expect(async () => smartAccount.withdraw(null, smartAccountOwner)).rejects.toThrow(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + }, 6000); }); diff --git a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts b/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts index 026b61bbe..3dc243d8f 100644 --- a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts +++ b/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts @@ -10,6 +10,7 @@ import { encodeAbiParameters, encodeFunctionData, parseAbi, parseUnits } from "v import { TestData } from "../../../tests"; import { checkBalance } from "../../../tests/utils"; import { PaymasterMode } from "@biconomy/paymaster"; +import { Logger } from "@biconomy/common"; describe("Batched Session Router Tests", () => { let mumbai: TestData; @@ -55,7 +56,7 @@ describe("Batched Session Router Tests", () => { expect(sessionSigner).toBeTruthy(); const smartAccountAddress = await smartAccount.getAddress(); - console.log("Smart Account Address: ", smartAccountAddress); + Logger.log("Smart Account Address: ", smartAccountAddress); // First we need to check if smart account is deployed // if not deployed, send an empty transaction to deploy it @@ -144,7 +145,7 @@ describe("Batched Session Router Tests", () => { const userOpResponse1 = await smartAccount.sendTransaction(txArray, { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); // this user op will enable the modules and setup session allowed calls const transactionDetails = await userOpResponse1.wait(); - console.log("Tx Hash: ", transactionDetails.receipt.transactionHash); + Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash); const usdcBalance = await checkBalance(publicClient, await smartAccount.getAccountAddress(), "0xdA5289fCAAF71d52a80A254da614a192b693e977"); expect(usdcBalance).toBeGreaterThan(0); @@ -198,7 +199,6 @@ describe("Batched Session Router Tests", () => { }, }); - const receipt = await userOpResponse2.wait(); expect(receipt.success).toBe("true"); @@ -210,6 +210,6 @@ describe("Batched Session Router Tests", () => { expect(maticBalanceAfter).toEqual(maticBalanceBefore); - console.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); + Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); }, 60000); }); diff --git a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts b/packages/modules/tests/multiChainValidationModule.e2e.spec.ts index 4d7cb123c..a7dc390e4 100644 --- a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts +++ b/packages/modules/tests/multiChainValidationModule.e2e.spec.ts @@ -3,6 +3,7 @@ import { TestData } from "../../../tests"; import { createSmartAccountClient } from "../../account/src/index"; import { Hex, encodeFunctionData, parseAbi } from "viem"; import { DEFAULT_MULTICHAIN_MODULE, MultiChainValidationModule } from "@biconomy/modules"; +import { Logger } from "@biconomy/common"; describe("MultiChainValidation Module Tests", () => { let mumbai: TestData; @@ -93,8 +94,8 @@ describe("MultiChainValidation Module Tests", () => { const userOpResponse1 = await baseAccount.sendSignedUserOp(returnedOps[0] as any); const userOpResponse2 = await polygonAccount.sendSignedUserOp(returnedOps[1] as any); - console.log(userOpResponse1.userOpHash, "MULTICHAIN BASE USER OP HASH"); - console.log(userOpResponse2.userOpHash, "MULTICHAIN POLYGON USER OP HASH"); + Logger.log(userOpResponse1.userOpHash, "MULTICHAIN BASE USER OP HASH"); + Logger.log(userOpResponse2.userOpHash, "MULTICHAIN POLYGON USER OP HASH"); expect(userOpResponse1.userOpHash).toBeTruthy(); expect(userOpResponse2.userOpHash).toBeTruthy(); diff --git a/packages/modules/tests/sessionValidationModule.e2e.spec.ts b/packages/modules/tests/sessionValidationModule.e2e.spec.ts index 6cb6e0605..6709bacad 100644 --- a/packages/modules/tests/sessionValidationModule.e2e.spec.ts +++ b/packages/modules/tests/sessionValidationModule.e2e.spec.ts @@ -5,6 +5,7 @@ import { Hex, encodeAbiParameters, encodeFunctionData, parseAbi, parseUnits } fr import { TestData } from "../../../tests"; import { checkBalance } from "../../../tests/utils"; import { PaymasterMode } from "@biconomy/paymaster"; +import { Logger } from "@biconomy/common"; describe("Session Validation Module Tests", () => { let mumbai: TestData; @@ -94,7 +95,7 @@ describe("Session Validation Module Tests", () => { txArray.push(enableModuleTrx); txArray.push(setSessionAllowedTrx); } else { - console.log("MODULE ALREADY ENABLED"); + Logger.log("MODULE ALREADY ENABLED"); txArray.push(setSessionAllowedTrx); } @@ -102,7 +103,7 @@ describe("Session Validation Module Tests", () => { const userOpResponse1 = await smartAccount.sendUserOp(userOp); const transactionDetails = await userOpResponse1.wait(); - console.log("Tx Hash: ", transactionDetails.receipt.transactionHash); + Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash); const encodedCall = encodeFunctionData({ abi: parseAbi(["function transfer(address _to, uint256 _value)"]), @@ -150,6 +151,6 @@ describe("Session Validation Module Tests", () => { expect(maticBalanceAfter).toEqual(maticBalanceBefore); - console.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); + Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); }, 60000); }); From fa30abb54ab02e83921757c164e0b349b13a12df Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Mon, 26 Feb 2024 16:57:08 +0000 Subject: [PATCH 10/33] default with empty string --- packages/account/src/BiconomySmartAccountV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 535c2c013..33fbbae26 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -356,7 +356,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { data: encodeFunctionData({ abi: parseAbi(ERC20_ABI), functionName: "transfer", - args: [recipientFromRequest ?? defaultRecipient, amount], + args: [recipientFromRequest || defaultRecipient, amount], }), })); From e4f067cea3bd196f77f1dc4289faec72567f06ee Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Fri, 1 Mar 2024 11:12:07 +0000 Subject: [PATCH 11/33] usdt fix --- packages/account/tests/account.e2e.spec.ts | 1 + yarn.lock | 203 +++++++++++---------- 2 files changed, 105 insertions(+), 99 deletions(-) diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index e1b01a510..29ba33da7 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -604,6 +604,7 @@ describe("Account Tests", () => { }); it("should fetch balances for smartAccount", async () => { + const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; const { whale: { viemWallet: signer }, bundlerUrl, diff --git a/yarn.lock b/yarn.lock index c4cad678c..3190ae991 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,12 +23,12 @@ zod "^3.22.4" "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": version "7.23.5" @@ -44,20 +44,20 @@ integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz#b028820718000f267870822fec434820e9b1e4d1" - integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.0.tgz#56cbda6b185ae9d9bed369816a8f4423c5f2ff1b" + integrity sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.23.5" "@babel/generator" "^7.23.6" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.9" - "@babel/parser" "^7.23.9" - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/helpers" "^7.24.0" + "@babel/parser" "^7.24.0" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.0" + "@babel/types" "^7.24.0" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -124,9 +124,9 @@ "@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" - integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" + integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== "@babel/helper-simple-access@^7.22.5": version "7.22.5" @@ -157,14 +157,14 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.9.tgz#c3e20bbe7f7a7e10cb9b178384b4affdf5995c7d" - integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== +"@babel/helpers@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.0.tgz#a3dd462b41769c95db8091e49cfe019389a9409b" + integrity sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA== dependencies: - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.0" + "@babel/types" "^7.24.0" "@babel/highlight@^7.23.4": version "7.23.4" @@ -175,10 +175,10 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac" + integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -279,25 +279,25 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/runtime@^7.21.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" + integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.15", "@babel/template@^7.23.9", "@babel/template@^7.3.3": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a" - integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== dependencies: "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" -"@babel/traverse@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.9.tgz#2f9d6aead6b564669394c5ce0f9302bb65b9d950" - integrity sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg== +"@babel/traverse@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" + integrity sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw== dependencies: "@babel/code-frame" "^7.23.5" "@babel/generator" "^7.23.6" @@ -305,15 +305,15 @@ "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.3.3": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" - integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.3.3": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== dependencies: "@babel/helper-string-parser" "^7.23.4" "@babel/helper-validator-identifier" "^7.22.20" @@ -812,9 +812,9 @@ "@ethersproject/strings" "^5.7.0" "@fastify/busboy@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" - integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== "@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": version "1.1.3" @@ -1065,24 +1065,24 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz#9b18145d26cf33d08576cf4c7665b28554480ed7" - integrity sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw== +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: - "@jridgewell/set-array" "^1.0.1" + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" @@ -1097,10 +1097,10 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.23" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz#afc96847f3f07841477f303eed687707a5aacd80" - integrity sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24": + version "0.3.24" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.24.tgz#e5640be1cab4085e4012a94c132ae86138f90f48" + integrity sha512-+VaWXDa6+l6MhflBvVXjIEAzb59nQ2JUK3bwRp2zRpPtU+8TFRy9Gg/5oIcNlkEL5PGlBFGfemUVvIgLnTzq7Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -1767,9 +1767,9 @@ uuid "^8.3.2" "@particle-network/chains@*": - version "1.3.19" - resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.19.tgz#63013cbbebf36c37e970f83406ef955f08309499" - integrity sha512-cQOGS0dH6LMDyJ7bkaLj6FShYSyz8OZ2hBvtBPdTtuMCsTlQPFcXKR6QI2CpJZBbb6m1fIXZEXlFYFZzY/t6ng== + version "1.3.21" + resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.21.tgz#82d2b098e165fc198e6e6e3e4c8b2154235e3aa1" + integrity sha512-tuUVuOPf+el+kDlHLFMyDy4IkoGjk+P3QvVrxT7WnmEma1NgWTE7RaNsniwqn6SYkAwAxksL/D9aADUXZxqPmw== "@particle-network/crypto@^1.0.1": version "1.0.1" @@ -2157,9 +2157,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.11.10": - version "20.11.20" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.20.tgz#f0a2aee575215149a62784210ad88b3a34843659" - integrity sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg== + version "20.11.24" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.24.tgz#cc207511104694e84e9fb17f9a0c4c42d4517792" + integrity sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long== dependencies: undici-types "~5.26.4" @@ -3824,9 +3824,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.668: - version "1.4.682" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.682.tgz#27577b88ccccc810e09b05093345cf1830f1bd65" - integrity sha512-oCglfs8yYKs9RQjJFOHonSnhikPK3y+0SvSYc/YpYJV//6rqc0/hbwd0c7vgK4vrl6y2gJAwjkhkSGWK+z4KRA== + version "1.4.689" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.689.tgz#94fe370b800d978b606a2b4c0c5db5c8c98db4f2" + integrity sha512-GatzRKnGPS1go29ep25reM94xxd1Wj8ritU0yRhCJ/tr1Bg8gKnm6R9O/yPOhGQBoLMZ9ezfrpghNaTw97C/PQ== elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" @@ -3923,17 +3923,17 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.4.tgz#26eb2e7538c3271141f5754d31aabfdb215f27bf" - integrity sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg== + version "1.22.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" + integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.6" + available-typed-arrays "^1.0.7" call-bind "^1.0.7" es-define-property "^1.0.0" es-errors "^1.3.0" - es-set-tostringtag "^2.0.2" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" get-intrinsic "^1.2.4" @@ -3941,15 +3941,15 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: globalthis "^1.0.3" gopd "^1.0.1" has-property-descriptors "^1.0.2" - has-proto "^1.0.1" + has-proto "^1.0.3" has-symbols "^1.0.3" hasown "^2.0.1" internal-slot "^1.0.7" is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" is-typed-array "^1.1.13" is-weakref "^1.0.2" @@ -3962,10 +3962,10 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: string.prototype.trim "^1.2.8" string.prototype.trimend "^1.0.7" string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.1" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.5" unbox-primitive "^1.0.2" which-typed-array "^1.1.14" @@ -3986,7 +3986,7 @@ es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-set-tostringtag@^2.0.2: +es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== @@ -5542,7 +5542,7 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-negative-zero@^2.0.2: +is-negative-zero@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== @@ -5599,7 +5599,7 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.2: +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== @@ -8432,11 +8432,11 @@ shiki@^0.14.7: vscode-textmate "^8.0.0" side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" es-errors "^1.3.0" get-intrinsic "^1.2.4" object-inspect "^1.13.1" @@ -8926,13 +8926,18 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@0.2.1, tmp@~0.2.1: +tmp@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== dependencies: rimraf "^3.0.0" +tmp@~0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -9125,7 +9130,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -typed-array-buffer@^1.0.1: +typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== @@ -9134,7 +9139,7 @@ typed-array-buffer@^1.0.1: es-errors "^1.3.0" is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: +typed-array-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== @@ -9145,7 +9150,7 @@ typed-array-byte-length@^1.0.0: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: +typed-array-byte-offset@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== @@ -9157,7 +9162,7 @@ typed-array-byte-offset@^1.0.0: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.4: +typed-array-length@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== @@ -9389,9 +9394,9 @@ validate-npm-package-name@^3.0.0: builtins "^1.0.3" viem@^2.5.0, viem@^2.7.3: - version "2.7.15" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.15.tgz#0dfdcb75be196c85839950b0ccb88be0b377609c" - integrity sha512-I2RMQpg1/MC7fXVjHxeXRPU9k/WEOvZajK/KZSr7DChS0AaZ7uovsQWppwBn2wvZWguTCIRAHqzMwIEGku95yQ== + version "2.7.16" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.16.tgz#99e66bbec661b2284bc32061474f20a90381bdcb" + integrity sha512-yOPa9yaoJUm44m0Qe3ugHnkHol3QQlFxN3jT+bq+lQip7X7cWdPfmguyfLWX2viCXcmYZUDiQdeFbkPW9lw11Q== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" From e2193ad11706da53e9a68c6033bc496672ad5e48 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Fri, 1 Mar 2024 17:40:43 +0000 Subject: [PATCH 12/33] cont. --- yarn.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 42aa3cec3..2b137143a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9393,11 +9393,7 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -<<<<<<< HEAD -viem@^2.5.0, viem@^2.7.3: -======= viem@^2.7.12, viem@^2.7.8: ->>>>>>> origin/develop version "2.7.16" resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.16.tgz#99e66bbec661b2284bc32061474f20a90381bdcb" integrity sha512-yOPa9yaoJUm44m0Qe3ugHnkHol3QQlFxN3jT+bq+lQip7X7cWdPfmguyfLWX2viCXcmYZUDiQdeFbkPW9lw11Q== From de029809ea3892b7013a2d693da06fe7b27638c4 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Mon, 4 Mar 2024 13:48:40 +0000 Subject: [PATCH 13/33] reinclude publicClient --- packages/account/tests/account.e2e.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index a31cec8d8..2073c7b0e 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -185,6 +185,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer, publicAddress: recipient }, bundlerUrl, nftAddress, + publicClient } = mumbai; const smartAccount = await createSmartAccountClient({ From 007b70335aa270344cdcd82eb7e081a6feddfb8d Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 6 Mar 2024 15:30:37 +0000 Subject: [PATCH 14/33] lint: fix --- packages/account/src/BiconomySmartAccountV2.ts | 3 +-- packages/account/src/utils/Utils.ts | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 98b3b85d6..f8c5e86bd 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -26,7 +26,7 @@ import { BatchUserOperationCallData, SmartAccountSigner, } from "@alchemy/aa-core"; -import { addressEquals, isNullOrUndefined, isValidRpcUrl, packUserOp, compareChainIds } from "./utils/Utils.js"; +import { isNullOrUndefined, isValidRpcUrl, packUserOp, compareChainIds } from "./utils/Utils.js"; import { BaseValidationModule, ModuleInfo, SendUserOpParams, createECDSAOwnershipValidationModule } from "@biconomy/modules"; import { IHybridPaymaster, @@ -53,7 +53,6 @@ import { PaymasterUserOperationDto, SimulationType, BalancePayload, - WithdrawalRequest, SupportedToken, } from "./utils/Types.js"; import { diff --git a/packages/account/src/utils/Utils.ts b/packages/account/src/utils/Utils.ts index c590a99d1..4321c4bd9 100644 --- a/packages/account/src/utils/Utils.ts +++ b/packages/account/src/utils/Utils.ts @@ -88,8 +88,6 @@ export const isValidRpcUrl = (url: string): boolean => { return regex.test(url); }; -export const addressEquals = (a?: string, b?: string): boolean => !!a && !!b && a?.toLowerCase() === b.toLowerCase(); - /** * Utility method for converting a chainId to a {@link Chain} object * From f256712bbf7dc0de40b82c70ad183c59bf5f39f9 Mon Sep 17 00:00:00 2001 From: Vasile Gabriel Marian <56271768+VGabriel45@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:01:16 +0200 Subject: [PATCH 15/33] Fix wrong falsy check for user op nonce (#455) * fixed issue with wrong falsy value check * updated yarn.lock --------- Co-authored-by: GabiDev --- .../account/src/BiconomySmartAccountV2.ts | 2 +- yarn.lock | 92 +++++++++---------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 3aa81a4e2..16ff648b6 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -574,7 +574,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { validateUserOp(userOp: Partial, requiredFields: UserOperationKey[]): boolean { for (const field of requiredFields) { - if (!userOp[field]) { + if (isNullOrUndefined(userOp[field])) { throw new Error(`${String(field)} is missing in the UserOp`); } } diff --git a/yarn.lock b/yarn.lock index 02caba64f..a4e0e28a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,9 +13,9 @@ integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== "@alchemy/aa-core@^3.1.1": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.4.0.tgz#08e514bf2f97a9c1452424a7f7915aa48daf4db2" - integrity sha512-kEqsMwweMxQU6b8mKNmkUacyZRxdU7WBBiAYNmGxJK5djOdsGlfCBZGHu2AyAb8ogfrGWX8J+uVuYTnCIZS6ew== + version "3.4.2" + resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.4.2.tgz#3bb3e508bb29586a29c5a025056f11c474bcee19" + integrity sha512-oPE8iUT/38S0hEfthtauIcidQq1kyN/t1VGpq5JSEFanFs6uV8UFyjjj9heO4UnA1uJDiVbvY6A5NZcM92j8RA== dependencies: abitype "^0.8.3" eventemitter3 "^5.0.1" @@ -2111,9 +2111,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.11.10": - version "20.11.25" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.25.tgz#0f50d62f274e54dd7a49f7704cc16bfbcccaf49f" - integrity sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw== + version "20.11.26" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.26.tgz#3fbda536e51d5c79281e1d9657dcb0131baabd2d" + integrity sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ== dependencies: undici-types "~5.26.4" @@ -2646,7 +2646,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: +available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== @@ -3060,9 +3060,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001596" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz#da06b79c3d9c3d9958eb307aa832ac68ead79bee" - integrity sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ== + version "1.0.30001597" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz#8be94a8c1d679de23b22fbd944232aa1321639e6" + integrity sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w== catering@^2.0.0, catering@^2.1.0: version "2.1.1" @@ -3628,7 +3628,7 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-data-property@^1.0.1, define-data-property@^1.1.2, define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -3765,9 +3765,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.668: - version "1.4.695" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.695.tgz#1753f4017e8d7e72a1ce5058c0fc66c8b67bab8e" - integrity sha512-eMijZmeqPtm774pCZIOrfUHMs/7ls++W1sLhxwqgu8KQ8E2WmMtzwyqOMt0XXUJ3HTIPfuwlfwF+I5cwnfItBA== + version "1.4.701" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz#7335e5761331774b4dea54cd24a1b84861d45cdf" + integrity sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA== elliptic@6.5.4: version "6.5.4" @@ -4705,7 +4705,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -5062,7 +5062,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== @@ -5079,7 +5079,7 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -5109,9 +5109,9 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: minimalistic-assert "^1.0.1" hasown@^2.0.0, hasown@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" - integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -8185,12 +8185,12 @@ rxjs@^7.5.5, rxjs@^7.8.1: tslib "^2.1.0" safe-array-concat@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" @@ -8288,16 +8288,16 @@ set-blocking@^2.0.0: integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-function-length@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - define-data-property "^1.1.2" + define-data-property "^1.1.4" es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.3" + get-intrinsic "^1.2.4" gopd "^1.0.1" - has-property-descriptors "^1.0.1" + has-property-descriptors "^1.0.2" set-function-name@^2.0.1: version "2.0.2" @@ -8923,9 +8923,9 @@ triple-beam@^1.3.0: integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== ts-api-utils@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" - integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-jest@^29.1.1: version "29.1.2" @@ -9110,9 +9110,9 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typedoc@^0.25.7: - version "0.25.11" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.11.tgz#75080c594c1e26b7676f90faebb367fb5a32dc8d" - integrity sha512-5MbI1W/FOG6oXsd8bdssQidSTeKh8Kt3xA5uKVzI+K99uzP8EGN45uPnPvQesyaWdD+89s4wCQdtWEd8QUbiRg== + version "0.25.12" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.12.tgz#f73f0a8d3731d418cc604d4230f95a857799e27a" + integrity sha512-F+qhkK2VoTweDXd1c42GS/By2DvI2uDF4/EpG424dTexSHdtCH52C6IcAvMA6jR3DzAWZjHpUOW+E02kyPNUNw== dependencies: lunr "^2.3.9" marked "^4.3.0" @@ -9324,9 +9324,9 @@ validate-npm-package-name@^3.0.0: builtins "^1.0.3" viem@^2.7.12, viem@^2.7.8: - version "2.7.20" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.7.20.tgz#c0d517c3ce5a19b963d624b378d706bd3c45efc6" - integrity sha512-S31a24LWEjqXAjw1A+3/xALo+4eiYKklAjLtlLdPhA0cp+Kv6GcgruNVTktP8pKIGNYvpyQ+HA9PJyUhVXPdDw== + version "2.8.4" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.8.4.tgz#553996181d2d22237e31476218178d3fe96e2e3d" + integrity sha512-zBC8+YNKzo+XeUsCyXdrFzimH9Ei/nRfUKldPmVRoR/lR56/sqkDPyfCE1yvzwwmA9AJ9m9m2HtSPgl9NiTReA== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -9400,15 +9400,15 @@ which-boxed-primitive@^1.0.2: is-symbol "^1.0.3" which-typed-array@^1.1.14: - version "1.1.14" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.1" + has-tostringtag "^1.0.2" which@^1.2.10, which@^1.2.14: version "1.3.1" From fd832fe2e286a5d3e57d3292cfa395e388b07b96 Mon Sep 17 00:00:00 2001 From: GabiDev Date: Wed, 3 Apr 2024 19:44:11 +0300 Subject: [PATCH 16/33] added 1271 support + tests --- .../account/src/BiconomySmartAccountV2.ts | 9 + packages/account/src/abi/SmartAccount.ts | 908 ++++-------------- packages/account/tests/account.e2e.spec.ts | 115 ++- .../account/tests/account.read.e2e.spec.ts | 14 +- packages/account/tests/account.spec.ts | 3 +- yarn.lock | 621 ++++++------ 6 files changed, 622 insertions(+), 1048 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 16ff648b6..a2499fbb3 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -1283,9 +1283,18 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { if (signature.slice(0, 2) !== "0x") { signature = "0x" + signature; } + signature = encodeAbiParameters(parseAbiParameters("bytes, address"), [signature as Hex, this.defaultValidationModule.getAddress()]); return signature as Hex; } + async getIsValidSignatureData(messageHash: Hex, signature: Hex): Promise { + return encodeFunctionData({ + abi: BiconomyAccountAbi, + functionName: "isValidSignature", + args: [messageHash, signature], + }); + } + async enableModule(moduleAddress: Hex): Promise { const tx: Transaction = await this.getEnableModuleData(moduleAddress); const partialUserOp = await this.buildUserOp([tx]); diff --git a/packages/account/src/abi/SmartAccount.ts b/packages/account/src/abi/SmartAccount.ts index 3542c17d1..73eb8fb91 100644 --- a/packages/account/src/abi/SmartAccount.ts +++ b/packages/account/src/abi/SmartAccount.ts @@ -1,321 +1,109 @@ export const BiconomyAccountAbi = [ - { - inputs: [], - name: "AlreadyInitialized", - type: "error", - }, - { - inputs: [], - name: "BaseImplementationCannotBeZero", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "CallerIsNotAnEntryPoint", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "CallerIsNotEntryPoint", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "CallerIsNotEntryPointOrOwner", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "CallerIsNotEntryPointOrSelf", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "CallerIsNotOwner", - type: "error", - }, - { - inputs: [], - name: "DelegateCallsOnly", - type: "error", - }, - { - inputs: [], - name: "EntryPointCannotBeZero", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "implementationAddress", - type: "address", - }, - ], - name: "InvalidImplementation", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "caller", - type: "address", - }, - ], - name: "MixedAuthFail", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "module", - type: "address", - }, - ], - name: "ModuleAlreadyEnabled", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "expectedModule", - type: "address", - }, - { - internalType: "address", - name: "returnedModule", - type: "address", - }, - { - internalType: "address", - name: "prevModule", - type: "address", - }, + { inputs: [{ internalType: "contract IEntryPoint", name: "anEntryPoint", type: "address" }], stateMutability: "nonpayable", type: "constructor" }, + { inputs: [], name: "AlreadyInitialized", type: "error" }, + { inputs: [], name: "BaseImplementationCannotBeZero", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotAnEntryPoint", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPoint", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPointOrOwner", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPointOrSelf", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotOwner", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotSelf", type: "error" }, + { inputs: [], name: "DelegateCallsOnly", type: "error" }, + { inputs: [], name: "EntryPointCannotBeZero", type: "error" }, + { inputs: [], name: "HandlerCannotBeZero", type: "error" }, + { inputs: [{ internalType: "address", name: "implementationAddress", type: "address" }], name: "InvalidImplementation", type: "error" }, + { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "MixedAuthFail", type: "error" }, + { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleAlreadyEnabled", type: "error" }, + { + inputs: [ + { internalType: "address", name: "expectedModule", type: "address" }, + { internalType: "address", name: "returnedModule", type: "address" }, + { internalType: "address", name: "prevModule", type: "address" }, ], name: "ModuleAndPrevModuleMismatch", type: "error", }, + { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleCannotBeZeroOrSentinel", type: "error" }, + { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleNotEnabled", type: "error" }, + { inputs: [], name: "ModulesAlreadyInitialized", type: "error" }, + { inputs: [], name: "ModulesSetupExecutionFailed", type: "error" }, + { inputs: [], name: "OwnerCanNotBeSelf", type: "error" }, + { inputs: [], name: "OwnerCannotBeZero", type: "error" }, + { inputs: [], name: "OwnerProvidedIsSame", type: "error" }, + { inputs: [], name: "TransferToZeroAddressAttempt", type: "error" }, { inputs: [ - { - internalType: "address", - name: "module", - type: "address", - }, - ], - name: "ModuleCannotBeZeroOrSentinel", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "module", - type: "address", - }, - ], - name: "ModuleNotEnabled", - type: "error", - }, - { - inputs: [], - name: "ModulesAlreadyInitialized", - type: "error", - }, - { - inputs: [], - name: "ModulesSetupExecutionFailed", - type: "error", - }, - { - inputs: [], - name: "OwnerCanNotBeSelf", - type: "error", - }, - { - inputs: [], - name: "OwnerCannotBeZero", - type: "error", - }, - { - inputs: [], - name: "OwnerProvidedIsSame", - type: "error", - }, - { - inputs: [], - name: "TransferToZeroAddressAttempt", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "destLength", - type: "uint256", - }, - { - internalType: "uint256", - name: "valueLength", - type: "uint256", - }, - { - internalType: "uint256", - name: "funcLength", - type: "uint256", - }, - { - internalType: "uint256", - name: "operationLength", - type: "uint256", - }, + { internalType: "uint256", name: "destLength", type: "uint256" }, + { internalType: "uint256", name: "valueLength", type: "uint256" }, + { internalType: "uint256", name: "funcLength", type: "uint256" }, + { internalType: "uint256", name: "operationLength", type: "uint256" }, ], name: "WrongBatchProvided", type: "error", }, + { inputs: [{ internalType: "bytes", name: "contractSignature", type: "bytes" }], name: "WrongContractSignature", type: "error" }, { inputs: [ - { - internalType: "bytes", - name: "contractSignature", - type: "bytes", - }, - ], - name: "WrongContractSignature", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "uintS", - type: "uint256", - }, - { - internalType: "uint256", - name: "contractSignatureLength", - type: "uint256", - }, - { - internalType: "uint256", - name: "signatureLength", - type: "uint256", - }, + { internalType: "uint256", name: "uintS", type: "uint256" }, + { internalType: "uint256", name: "contractSignatureLength", type: "uint256" }, + { internalType: "uint256", name: "signatureLength", type: "uint256" }, ], name: "WrongContractSignatureFormat", type: "error", }, + { inputs: [{ internalType: "address", name: "moduleAddressProvided", type: "address" }], name: "WrongValidationModule", type: "error" }, { + anonymous: false, inputs: [ - { - internalType: "address", - name: "moduleAddressProvided", - type: "address", - }, + { indexed: true, internalType: "address", name: "previousHandler", type: "address" }, + { indexed: true, internalType: "address", name: "handler", type: "address" }, ], - name: "WrongValidationModule", - type: "error", + name: "ChangedFallbackHandler", + type: "event", }, + { anonymous: false, inputs: [{ indexed: false, internalType: "address", name: "module", type: "address" }], name: "DisabledModule", type: "event" }, + { anonymous: false, inputs: [{ indexed: false, internalType: "address", name: "module", type: "address" }], name: "EnabledModule", type: "event" }, { anonymous: false, inputs: [ - { - indexed: false, - internalType: "address", - name: "module", - type: "address", - }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, + { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, + { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { indexed: false, internalType: "uint256", name: "txGas", type: "uint256" }, ], - name: "DisabledModule", + name: "ExecutionFailure", type: "event", }, { anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "module", - type: "address", - }, - ], - name: "EnabledModule", + inputs: [{ indexed: true, internalType: "address", name: "module", type: "address" }], + name: "ExecutionFromModuleFailure", type: "event", }, { anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "module", - type: "address", - }, - ], - name: "ExecutionFromModuleFailure", + inputs: [{ indexed: true, internalType: "address", name: "module", type: "address" }], + name: "ExecutionFromModuleSuccess", type: "event", }, { anonymous: false, inputs: [ - { - indexed: true, - internalType: "address", - name: "module", - type: "address", - }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, + { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, + { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { indexed: false, internalType: "uint256", name: "txGas", type: "uint256" }, ], - name: "ExecutionFromModuleSuccess", + name: "ExecutionSuccess", type: "event", }, { anonymous: false, inputs: [ - { - indexed: true, - internalType: "address", - name: "oldImplementation", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "newImplementation", - type: "address", - }, + { indexed: true, internalType: "address", name: "oldImplementation", type: "address" }, + { indexed: true, internalType: "address", name: "newImplementation", type: "address" }, ], name: "ImplementationUpdated", type: "event", @@ -323,36 +111,11 @@ export const BiconomyAccountAbi = [ { anonymous: false, inputs: [ - { - indexed: false, - internalType: "address", - name: "module", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - indexed: false, - internalType: "bytes", - name: "data", - type: "bytes", - }, - { - indexed: false, - internalType: "enum Enum.Operation", - name: "operation", - type: "uint8", - }, + { indexed: false, internalType: "address", name: "module", type: "address" }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "value", type: "uint256" }, + { indexed: false, internalType: "bytes", name: "data", type: "bytes" }, + { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, ], name: "ModuleTransaction", type: "event", @@ -360,54 +123,19 @@ export const BiconomyAccountAbi = [ { anonymous: false, inputs: [ - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, - { - indexed: true, - internalType: "uint256", - name: "value", - type: "uint256", - }, + { indexed: true, internalType: "address", name: "sender", type: "address" }, + { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, ], name: "SmartAccountReceivedNativeToken", type: "event", }, - { - inputs: [], - name: "VERSION", - outputs: [ - { - internalType: "string", - name: "", - type: "string", - }, - ], - stateMutability: "pure", - type: "function", - }, - { - inputs: [], - name: "addDeposit", - outputs: [], - stateMutability: "payable", - type: "function", - }, + { stateMutability: "nonpayable", type: "fallback" }, + { inputs: [], name: "VERSION", outputs: [{ internalType: "string", name: "", type: "string" }], stateMutability: "view", type: "function" }, + { inputs: [], name: "addDeposit", outputs: [], stateMutability: "payable", type: "function" }, { inputs: [ - { - internalType: "address", - name: "prevModule", - type: "address", - }, - { - internalType: "address", - name: "module", - type: "address", - }, + { internalType: "address", name: "prevModule", type: "address" }, + { internalType: "address", name: "module", type: "address" }, ], name: "disableModule", outputs: [], @@ -415,13 +143,7 @@ export const BiconomyAccountAbi = [ type: "function", }, { - inputs: [ - { - internalType: "address", - name: "module", - type: "address", - }, - ], + inputs: [{ internalType: "address", name: "module", type: "address" }], name: "enableModule", outputs: [], stateMutability: "nonpayable", @@ -430,179 +152,67 @@ export const BiconomyAccountAbi = [ { inputs: [], name: "entryPoint", - outputs: [ - { - internalType: "contract IEntryPoint", - name: "", - type: "address", - }, - ], + outputs: [{ internalType: "contract IEntryPoint", name: "", type: "address" }], stateMutability: "view", type: "function", }, { inputs: [ - { - internalType: "address[]", - name: "to", - type: "address[]", - }, - { - internalType: "uint256[]", - name: "value", - type: "uint256[]", - }, - { - internalType: "bytes[]", - name: "data", - type: "bytes[]", - }, - { - internalType: "enum Enum.Operation[]", - name: "operations", - type: "uint8[]", - }, + { internalType: "address[]", name: "to", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "data", type: "bytes[]" }, + { internalType: "enum Enum.Operation[]", name: "operations", type: "uint8[]" }, ], name: "execBatchTransactionFromModule", - outputs: [ - { - internalType: "bool", - name: "success", - type: "bool", - }, - ], + outputs: [{ internalType: "bool", name: "success", type: "bool" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - { - internalType: "enum Enum.Operation", - name: "operation", - type: "uint8", - }, - { - internalType: "uint256", - name: "txGas", - type: "uint256", - }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { internalType: "uint256", name: "txGas", type: "uint256" }, ], name: "execTransactionFromModule", - outputs: [ - { - internalType: "bool", - name: "success", - type: "bool", - }, - ], + outputs: [{ internalType: "bool", name: "success", type: "bool" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - { - internalType: "enum Enum.Operation", - name: "operation", - type: "uint8", - }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, ], name: "execTransactionFromModule", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], + outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - { - internalType: "enum Enum.Operation", - name: "operation", - type: "uint8", - }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, ], name: "execTransactionFromModuleReturnData", outputs: [ - { - internalType: "bool", - name: "success", - type: "bool", - }, - { - internalType: "bytes", - name: "returnData", - type: "bytes", - }, + { internalType: "bool", name: "success", type: "bool" }, + { internalType: "bytes", name: "returnData", type: "bytes" }, ], stateMutability: "nonpayable", type: "function", }, { inputs: [ - { - internalType: "address", - name: "dest", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "func", - type: "bytes", - }, + { internalType: "address", name: "dest", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "func", type: "bytes" }, ], name: "execute", outputs: [], @@ -611,21 +221,9 @@ export const BiconomyAccountAbi = [ }, { inputs: [ - { - internalType: "address[]", - name: "dest", - type: "address[]", - }, - { - internalType: "uint256[]", - name: "value", - type: "uint256[]", - }, - { - internalType: "bytes[]", - name: "func", - type: "bytes[]", - }, + { internalType: "address[]", name: "dest", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" }, ], name: "executeBatch", outputs: [], @@ -634,21 +232,9 @@ export const BiconomyAccountAbi = [ }, { inputs: [ - { - internalType: "address[]", - name: "dest", - type: "address[]", - }, - { - internalType: "uint256[]", - name: "value", - type: "uint256[]", - }, - { - internalType: "bytes[]", - name: "func", - type: "bytes[]", - }, + { internalType: "address[]", name: "dest", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" }, ], name: "executeBatch_y6U", outputs: [], @@ -657,181 +243,118 @@ export const BiconomyAccountAbi = [ }, { inputs: [ - { - internalType: "address", - name: "dest", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "func", - type: "bytes", - }, + { internalType: "address", name: "dest", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "func", type: "bytes" }, ], name: "execute_ncC", outputs: [], stateMutability: "nonpayable", type: "function", }, + { inputs: [], name: "getDeposit", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", type: "function" }, { inputs: [], - name: "getDeposit", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], + name: "getFallbackHandler", + outputs: [{ internalType: "address", name: "_handler", type: "address" }], stateMutability: "view", type: "function", }, { inputs: [], name: "getImplementation", - outputs: [ - { - internalType: "address", - name: "_implementation", - type: "address", - }, - ], + outputs: [{ internalType: "address", name: "_implementation", type: "address" }], stateMutability: "view", type: "function", }, { inputs: [ - { - internalType: "address", - name: "start", - type: "address", - }, - { - internalType: "uint256", - name: "pageSize", - type: "uint256", - }, + { internalType: "address", name: "start", type: "address" }, + { internalType: "uint256", name: "pageSize", type: "uint256" }, ], name: "getModulesPaginated", outputs: [ - { - internalType: "address[]", - name: "array", - type: "address[]", - }, - { - internalType: "address", - name: "next", - type: "address", - }, + { internalType: "address[]", name: "array", type: "address[]" }, + { internalType: "address", name: "next", type: "address" }, ], stateMutability: "view", type: "function", }, { inputs: [ - { - internalType: "address", - name: "handler", - type: "address", - }, - { - internalType: "address", - name: "moduleSetupContract", - type: "address", - }, - { - internalType: "bytes", - name: "moduleSetupData", - type: "bytes", - }, + { internalType: "address", name: "handler", type: "address" }, + { internalType: "address", name: "moduleSetupContract", type: "address" }, + { internalType: "bytes", name: "moduleSetupData", type: "bytes" }, ], name: "init", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], + outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "nonpayable", type: "function", }, { - inputs: [ - { - internalType: "address", - name: "module", - type: "address", - }, - ], + inputs: [{ internalType: "address", name: "module", type: "address" }], name: "isModuleEnabled", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], + outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "view", type: "function", }, { inputs: [ - { - internalType: "uint192", - name: "_key", - type: "uint192", - }, + { internalType: "bytes32", name: "dataHash", type: "bytes32" }, + { internalType: "bytes", name: "signature", type: "bytes" }, ], + name: "isValidSignature", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint192", name: "_key", type: "uint192" }], name: "nonce", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "noncesDeprecated", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "ownerDeprecated", + outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", type: "function", }, + { + inputs: [{ internalType: "address", name: "handler", type: "address" }], + name: "setFallbackHandler", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, { inputs: [ - { - internalType: "address", - name: "setupContract", - type: "address", - }, - { - internalType: "bytes", - name: "setupData", - type: "bytes", - }, + { internalType: "address", name: "setupContract", type: "address" }, + { internalType: "bytes", name: "setupData", type: "bytes" }, ], name: "setupAndEnableModule", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], + outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "nonpayable", type: "function", }, { - inputs: [ - { - internalType: "address", - name: "_implementation", - type: "address", - }, - ], + inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_implementation", type: "address" }], name: "updateImplementation", outputs: [], stateMutability: "nonpayable", @@ -841,104 +364,39 @@ export const BiconomyAccountAbi = [ inputs: [ { components: [ - { - internalType: "address", - name: "sender", - type: "address", - }, - { - internalType: "uint256", - name: "nonce", - type: "uint256", - }, - { - internalType: "bytes", - name: "initCode", - type: "bytes", - }, - { - internalType: "bytes", - name: "callData", - type: "bytes", - }, - { - internalType: "uint256", - name: "callGasLimit", - type: "uint256", - }, - { - internalType: "uint256", - name: "verificationGasLimit", - type: "uint256", - }, - { - internalType: "uint256", - name: "preVerificationGas", - type: "uint256", - }, - { - internalType: "uint256", - name: "maxFeePerGas", - type: "uint256", - }, - { - internalType: "uint256", - name: "maxPriorityFeePerGas", - type: "uint256", - }, - { - internalType: "bytes", - name: "paymasterAndData", - type: "bytes", - }, - { - internalType: "bytes", - name: "signature", - type: "bytes", - }, + { internalType: "address", name: "sender", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "bytes", name: "initCode", type: "bytes" }, + { internalType: "bytes", name: "callData", type: "bytes" }, + { internalType: "uint256", name: "callGasLimit", type: "uint256" }, + { internalType: "uint256", name: "verificationGasLimit", type: "uint256" }, + { internalType: "uint256", name: "preVerificationGas", type: "uint256" }, + { internalType: "uint256", name: "maxFeePerGas", type: "uint256" }, + { internalType: "uint256", name: "maxPriorityFeePerGas", type: "uint256" }, + { internalType: "bytes", name: "paymasterAndData", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" }, ], internalType: "struct UserOperation", name: "userOp", type: "tuple", }, - { - internalType: "bytes32", - name: "userOpHash", - type: "bytes32", - }, - { - internalType: "uint256", - name: "missingAccountFunds", - type: "uint256", - }, + { internalType: "bytes32", name: "userOpHash", type: "bytes32" }, + { internalType: "uint256", name: "missingAccountFunds", type: "uint256" }, ], name: "validateUserOp", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], + outputs: [{ internalType: "uint256", name: "validationData", type: "uint256" }], stateMutability: "nonpayable", type: "function", }, { inputs: [ - { - internalType: "address payable", - name: "withdrawAddress", - type: "address", - }, - { - internalType: "uint256", - name: "amount", - type: "uint256", - }, + { internalType: "address payable", name: "withdrawAddress", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, ], name: "withdrawDepositTo", outputs: [], stateMutability: "payable", type: "function", }, + { stateMutability: "payable", type: "receive" }, ] as const; diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index 82f9649f1..21a0f44a5 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -1,19 +1,19 @@ import { TestData } from "../../../tests"; -import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, NATIVE_TOKEN_ALIAS, PaymasterMode } from "../src/index"; -import { Hex, createWalletClient, encodeFunctionData, getContract, http, parseAbi } from "viem"; +import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, PaymasterMode } from "../src/index"; +import { Hex, createWalletClient, encodeAbiParameters, encodeFunctionData, getContract, hashMessage, http, parseAbi, parseAbiParameters } from "viem"; import { UserOperationStruct } from "@alchemy/aa-core"; import { checkBalance, entryPointABI } from "../../../tests/utils"; import { ERC20_ABI } from "@biconomy/modules"; -import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; +import { privateKeyToAccount, generatePrivateKey, signMessage } from "viem/accounts"; +import { BiconomyAccountAbi } from "../src/abi/SmartAccount"; describe("Account Tests", () => { - let mumbai: TestData; let baseSepolia: TestData; let optimism: TestData; beforeEach(() => { // @ts-ignore: Comes from setup-e2e-tests - [mumbai, baseSepolia, optimism] = testDataPerChain; + [baseSepolia, baseSepolia, optimism] = testDataPerChain; }); it("should have addresses", async () => { @@ -21,7 +21,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer, publicAddress: sender }, minnow: { viemWallet: recipientSigner, publicAddress: recipient }, bundlerUrl, - } = mumbai; + } = baseSepolia; const { whale: { viemWallet: signerBase, publicAddress: senderBase }, @@ -88,7 +88,7 @@ describe("Account Tests", () => { minnow: { publicAddress: recipient }, bundlerUrl, publicClient, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -118,7 +118,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer }, bundlerUrl, paymasterUrl, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -135,10 +135,10 @@ describe("Account Tests", () => { const { whale: { viemWallet: signer, publicAddress: recipient }, bundlerUrl, - paymasterUrl, publicClient, + paymasterUrl, nftAddress, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -185,8 +185,8 @@ describe("Account Tests", () => { whale: { viemWallet: signer, publicAddress: recipient }, bundlerUrl, nftAddress, - publicClient - } = mumbai; + publicClient, + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -244,7 +244,7 @@ describe("Account Tests", () => { bundlerUrl, biconomyPaymasterApiKey, nftAddress, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -276,7 +276,7 @@ describe("Account Tests", () => { paymasterUrl, publicClient, nftAddress, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -373,7 +373,7 @@ describe("Account Tests", () => { bundlerUrl, biconomyPaymasterApiKey, nftAddress, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -417,7 +417,7 @@ describe("Account Tests", () => { entryPointAddress, publicClient, paymasterUrl, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -457,7 +457,7 @@ describe("Account Tests", () => { bundlerUrl, publicClient, paymasterUrl, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -478,7 +478,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer }, bundlerUrl, viemChain, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -492,7 +492,7 @@ describe("Account Tests", () => { it("Should throw, chain id from signer and bundlerUrl do not match", async () => { const { whale: { viemWallet: signer }, - } = mumbai; + } = baseSepolia; const createAccount = createSmartAccountClient({ signer, @@ -505,7 +505,7 @@ describe("Account Tests", () => { it("Should throw, chain id from paymasterUrl and bundlerUrl do not match", async () => { const { whale: { viemWallet: signer }, - } = mumbai; + } = baseSepolia; const createAccount = createSmartAccountClient({ signer, @@ -521,9 +521,9 @@ describe("Account Tests", () => { biconomyPaymasterApiKey, viemChain, publicClient, - whale: { viemWallet: signer, publicAddress, account }, + whale: { viemWallet: signer, account }, deploymentCost, - } = mumbai; + } = baseSepolia; const newPrivateKey = generatePrivateKey(); const newAccount = privateKeyToAccount(newPrivateKey); @@ -557,7 +557,7 @@ describe("Account Tests", () => { }, 60000); it("should deploy a smart account with sponsorship", async () => { - const { bundlerUrl, biconomyPaymasterApiKey, viemChain, publicClient } = mumbai; + const { bundlerUrl, biconomyPaymasterApiKey, viemChain, publicClient } = baseSepolia; const newPrivateKey = generatePrivateKey(); const newAccount = privateKeyToAccount(newPrivateKey); @@ -589,7 +589,7 @@ describe("Account Tests", () => { }, 60000); it("should fail to deploy a smart account if no native token balance or paymaster", async () => { - const { bundlerUrl, biconomyPaymasterApiKey, viemChain } = mumbai; + const { bundlerUrl, biconomyPaymasterApiKey, viemChain } = baseSepolia; const newPrivateKey = generatePrivateKey(); const newAccount = privateKeyToAccount(newPrivateKey); @@ -614,7 +614,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer }, bundlerUrl, biconomyPaymasterApiKey, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -637,7 +637,7 @@ describe("Account Tests", () => { whale: { viemWallet: signer }, bundlerUrl, biconomyPaymasterApiKey, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -655,7 +655,7 @@ describe("Account Tests", () => { bundlerUrl, publicClient, biconomyPaymasterApiKey, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -668,4 +668,65 @@ describe("Account Tests", () => { expect(usdcBalanceBefore).toBe(usdtBalanceFromSmartAccount.amount); }); + + it("should verify a correct signature through isValidSignature", async () => { + const { + whale: { viemWallet: signer }, + bundlerUrl, + publicClient, + } = baseSepolia; + + const smartAccount = await createSmartAccountClient({ + signer, + bundlerUrl, + }); + + const eip1271MagicValue = "0x1626ba7e"; + const message = "Some message from dApp"; + const messageHash = hashMessage(message); + const signature = await smartAccount.signMessage(messageHash); + + const response = await publicClient.readContract({ + address: await smartAccount.getAccountAddress(), + abi: BiconomyAccountAbi, + functionName: "isValidSignature", + args: [messageHash, signature], + }); + + expect(response).toBe(eip1271MagicValue); + }); + + it("should throw an error if signature is not valid", async () => { + const { + whale: { viemWallet: signer }, + bundlerUrl, + publicClient, + } = baseSepolia; + + const randomPrivKey = generatePrivateKey(); + const randomWallet = privateKeyToAccount(randomPrivKey); + + const smartAccount = await createSmartAccountClient({ + signer, + bundlerUrl, + }); + + const eip1271MagicValue = "0xffffffff"; + const message = "Some message from dApp"; + const messageHash = hashMessage(message); + const signature = await randomWallet.signMessage({ message: messageHash }); + const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters("bytes, address"), [ + signature, + smartAccount.defaultValidationModule.getAddress(), + ]); + + const response = await publicClient.readContract({ + address: await smartAccount.getAccountAddress(), + abi: BiconomyAccountAbi, + functionName: "isValidSignature", + args: [messageHash, signatureWithModuleAddress], + }); + + expect(response).toBe(eip1271MagicValue); + }); }); diff --git a/packages/account/tests/account.read.e2e.spec.ts b/packages/account/tests/account.read.e2e.spec.ts index 80abf9d21..32af9dc26 100644 --- a/packages/account/tests/account.read.e2e.spec.ts +++ b/packages/account/tests/account.read.e2e.spec.ts @@ -3,18 +3,18 @@ import { createSmartAccountClient } from "../src/index"; import { DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules"; describe("Account Tests", () => { - let mumbai: TestData; + let baseSepolia: TestData; beforeEach(() => { // @ts-ignore: Comes from setup-e2e-tests - [mumbai] = testDataPerChain; + [baseSepolia] = testDataPerChain; }); it("should check if module is enabled on the smart account", async () => { const { whale: { viemWallet: signer }, bundlerUrl, - } = mumbai; + } = baseSepolia; const smartWallet = await createSmartAccountClient({ signer, @@ -33,7 +33,7 @@ describe("Account Tests", () => { }, bundlerUrl, biconomyPaymasterApiKey, - } = mumbai; + } = baseSepolia; const smartAccount = await createSmartAccountClient({ signer, @@ -51,7 +51,7 @@ describe("Account Tests", () => { const { whale: { viemWallet: signer }, bundlerUrl, - } = mumbai; + } = baseSepolia; const smartWallet = await createSmartAccountClient({ signer, @@ -66,7 +66,7 @@ describe("Account Tests", () => { const { whale: { viemWallet: signer }, bundlerUrl, - } = mumbai; + } = baseSepolia; const smartWallet = await createSmartAccountClient({ signer, @@ -83,7 +83,7 @@ describe("Account Tests", () => { const { whale: { viemWallet: signer }, bundlerUrl, - } = mumbai; + } = baseSepolia; const smartWallet = await createSmartAccountClient({ signer, diff --git a/packages/account/tests/account.spec.ts b/packages/account/tests/account.spec.ts index 42cc90355..9e76f2f89 100644 --- a/packages/account/tests/account.spec.ts +++ b/packages/account/tests/account.spec.ts @@ -1,4 +1,4 @@ -import { Bundler, Paymaster, createBundler, createSmartAccountClient } from "../src"; +import { Paymaster, createBundler, createSmartAccountClient } from "../src"; import { Chain, createWalletClient, http } from "viem"; import { localhost } from "viem/chains"; import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; @@ -32,7 +32,6 @@ describe("Account Tests", () => { it("should create a whale smartAccountClient from an ethers signer", async () => { const { - bundlerUrl, whale: { ethersSigner: signer }, } = ganache; diff --git a/yarn.lock b/yarn.lock index a4e0e28a9..6224f5ea9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,13 +13,13 @@ integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== "@alchemy/aa-core@^3.1.1": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.4.2.tgz#3bb3e508bb29586a29c5a025056f11c474bcee19" - integrity sha512-oPE8iUT/38S0hEfthtauIcidQq1kyN/t1VGpq5JSEFanFs6uV8UFyjjj9heO4UnA1uJDiVbvY6A5NZcM92j8RA== + version "3.6.1" + resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.6.1.tgz#af718313276458910d06030ee0aa946168e442f9" + integrity sha512-WVDacDuXcuePTHQSlKZ0nZvRHNSB48iUhh7fVSqchiStjq7BybdGg35AZf8eg5vcepkwSHekNKCp5LxKwpFCQg== dependencies: abitype "^0.8.3" eventemitter3 "^5.0.1" - viem "^2.7.8" + viem "^2.8.6" zod "^3.22.4" "@ampproject/remapping@^2.2.0": @@ -30,33 +30,33 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" "@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.1.tgz#31c1f66435f2a9c329bb5716a6d6186c516c3742" + integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.0.tgz#56cbda6b185ae9d9bed369816a8f4423c5f2ff1b" - integrity sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw== + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.3.tgz#568864247ea10fbd4eff04dda1e05f9e2ea985c3" + integrity sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.1" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.0" - "@babel/parser" "^7.24.0" + "@babel/helpers" "^7.24.1" + "@babel/parser" "^7.24.1" "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" convert-source-map "^2.0.0" debug "^4.1.0" @@ -64,14 +64,14 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.6", "@babel/generator@^7.7.2": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== +"@babel/generator@^7.24.1", "@babel/generator@^7.7.2": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" + integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.24.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" "@babel/helper-compilation-targets@^7.23.6": @@ -106,11 +106,11 @@ "@babel/types" "^7.22.5" "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.24.0" "@babel/helper-module-transforms@^7.23.3": version "7.23.3" @@ -123,7 +123,7 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.20" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== @@ -143,9 +143,9 @@ "@babel/types" "^7.22.5" "@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" @@ -157,28 +157,29 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.0.tgz#a3dd462b41769c95db8091e49cfe019389a9409b" - integrity sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA== +"@babel/helpers@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.1.tgz#183e44714b9eba36c3038e442516587b1e0a1a94" + integrity sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg== dependencies: "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== +"@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== dependencies: "@babel/helper-validator-identifier" "^7.22.20" chalk "^2.4.2" js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac" - integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" + integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -216,11 +217,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" - integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -272,16 +273,16 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" - integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/runtime@^7.21.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" - integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57" + integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ== dependencies: regenerator-runtime "^0.14.0" @@ -294,23 +295,23 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" - integrity sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw== +"@babel/traverse@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" + integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.1" + "@babel/generator" "^7.24.1" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.0" + "@babel/parser" "^7.24.1" "@babel/types" "^7.24.0" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== @@ -836,9 +837,9 @@ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -1065,7 +1066,7 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1097,7 +1098,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1251,65 +1252,65 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/edr-darwin-arm64@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.2.1.tgz#10c1a07add192583ce8b2d4cc93439f52b390a41" - integrity sha512-aMYaRaZVQ/TmyNJIoXf1bU4k0zfinaL9Sy1day4yGlL6eiQPFfRGj9W6TZaZIoYG0XTx/mQWD7dkXJ7LdrleJA== +"@nomicfoundation/edr-darwin-arm64@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz#0618dbdf1c832f8e61c77540e7188c13fdd5b658" + integrity sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ== -"@nomicfoundation/edr-darwin-x64@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.2.1.tgz#eaa29d2ba9f91ddb5f59b872c5a54f94a6fe3095" - integrity sha512-ma0SLcjHm5L3nPHcKFJB0jv/gKGSKaxr5Z65rurX/eaYUQJ7YGMsb8er9bSCo9rjzOtxf4FoPj3grL3zGpOj8A== +"@nomicfoundation/edr-darwin-x64@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz#567ee0bca8d019085e8dd95330e7c03f16c66a79" + integrity sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg== -"@nomicfoundation/edr-linux-arm64-gnu@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.2.1.tgz#8149db0d742157405effe82d485ea9bfefddc795" - integrity sha512-NX3G4pBhRitWrjSGY3HTyCq3wKSm5YqrKVOCNQGl9/jcjSovqxlgzFMiTx4YZCzGntfJ/1om9AI84OWxYJjoDw== +"@nomicfoundation/edr-linux-arm64-gnu@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz#3956b4d7a0127e2259351626c92698c4ce6ecf05" + integrity sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA== -"@nomicfoundation/edr-linux-arm64-musl@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.2.1.tgz#7d53afe5607eb406d199a199d00209a6304ff07b" - integrity sha512-gdQ3QHkt9XRkdtOGQ8fMwS11MXdjLeZgLrqoial4V4qtMaamIMMhVczK+VEvUhD8p7G4BVmp6kmkvcsthmndmw== +"@nomicfoundation/edr-linux-arm64-musl@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz#139f801939ed467f1719a2ab014993838008eefb" + integrity sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q== -"@nomicfoundation/edr-linux-x64-gnu@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.2.1.tgz#b762c95368fcb88bbbabba4d8be5380f38967413" - integrity sha512-OqabFY37vji6mYbLD9CvG28lja68czeVw58oWByIhFV3BpBu/cyP1oAbhzk3LieylujabS3Ekpvjw2Tkf0A9RQ== +"@nomicfoundation/edr-linux-x64-gnu@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz#b5994caa1a8bb4afca5f079ad7dd99edb26c6c45" + integrity sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA== -"@nomicfoundation/edr-linux-x64-musl@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.2.1.tgz#522448c42bff7d2abd52ddcf11ae6ca3dfdd6db4" - integrity sha512-vHfFFK2EPISuQUQge+bdjXamb0EUjfl8srYSog1qfiwyLwLeuSbpyyFzDeITAgPpkkFuedTfJW553K0Hipspyg== +"@nomicfoundation/edr-linux-x64-musl@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz#536c1d1dfd2fc7d7ad6ed6e14ed9a12322d88ba6" + integrity sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw== -"@nomicfoundation/edr-win32-arm64-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.2.1.tgz#ccfa443c274e49de93016a1060be810096dc6f1d" - integrity sha512-K/mui67RCKxghbSyvhvW3rvyVN1pa9M1Q9APUx1PtWjSSdXDFpqEY1NYsv2syb47Ca8ObJwVMF+LvnB6GvhUOQ== +"@nomicfoundation/edr-win32-arm64-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz#f71609644d8585c2ec71580bf75c2fd036ee58b0" + integrity sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA== -"@nomicfoundation/edr-win32-ia32-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.2.1.tgz#822b19d3e67d6dcfa5394cb6a4d55d8bab1b2f26" - integrity sha512-HHK0mXEtjvfjJrJlqcYgQCy3lZIXS1KNl2GaP8bwEIuEwx++XxXs/ThLjPepM1nhCGICij8IGy7p3KrkzRelsw== +"@nomicfoundation/edr-win32-ia32-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz#baa5eaacb1fff107d02f0e6a33dee9521fd2bf37" + integrity sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w== -"@nomicfoundation/edr-win32-x64-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.2.1.tgz#7b56ff742b2724779cc9f3385815b394f76de8df" - integrity sha512-FY4eQJdj1/y8ST0RyQycx63yr+lvdYNnUkzgWf4X+vPH1lOhXae+L2NDcNCQlTDAfQcD6yz0bkBUkLrlJ8pTww== +"@nomicfoundation/edr-win32-x64-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz#7562e061b2481f87bb1ace30513a2ad38c469836" + integrity sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w== -"@nomicfoundation/edr@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.2.1.tgz#a3d2a542dcd5dc5a8d757116d52baea05f370531" - integrity sha512-Dleau3ItHJh2n85G2J6AIPBoLgu/mOWkmrh26z3VsJE2tp/e00hUk/dqz85ncsVcBYEc6/YOn/DomWu0wSF9tQ== +"@nomicfoundation/edr@^0.3.1": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.3.3.tgz#0ed8619ea2ac644bf87cdc09dd1a8f465a859bcc" + integrity sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ== optionalDependencies: - "@nomicfoundation/edr-darwin-arm64" "0.2.1" - "@nomicfoundation/edr-darwin-x64" "0.2.1" - "@nomicfoundation/edr-linux-arm64-gnu" "0.2.1" - "@nomicfoundation/edr-linux-arm64-musl" "0.2.1" - "@nomicfoundation/edr-linux-x64-gnu" "0.2.1" - "@nomicfoundation/edr-linux-x64-musl" "0.2.1" - "@nomicfoundation/edr-win32-arm64-msvc" "0.2.1" - "@nomicfoundation/edr-win32-ia32-msvc" "0.2.1" - "@nomicfoundation/edr-win32-x64-msvc" "0.2.1" + "@nomicfoundation/edr-darwin-arm64" "0.3.3" + "@nomicfoundation/edr-darwin-x64" "0.3.3" + "@nomicfoundation/edr-linux-arm64-gnu" "0.3.3" + "@nomicfoundation/edr-linux-arm64-musl" "0.3.3" + "@nomicfoundation/edr-linux-x64-gnu" "0.3.3" + "@nomicfoundation/edr-linux-x64-musl" "0.3.3" + "@nomicfoundation/edr-win32-arm64-msvc" "0.3.3" + "@nomicfoundation/edr-win32-ia32-msvc" "0.3.3" + "@nomicfoundation/edr-win32-x64-msvc" "0.3.3" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -1721,9 +1722,9 @@ uuid "^8.3.2" "@particle-network/chains@*": - version "1.3.21" - resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.21.tgz#82d2b098e165fc198e6e6e3e4c8b2154235e3aa1" - integrity sha512-tuUVuOPf+el+kDlHLFMyDy4IkoGjk+P3QvVrxT7WnmEma1NgWTE7RaNsniwqn6SYkAwAxksL/D9aADUXZxqPmw== + version "1.3.27" + resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.27.tgz#dca4f2714d23957cc68cb1301de1f310895658db" + integrity sha512-+my+i0jqZjUoP+mNXxsPc2D7o3Cijl6uRvvWyTT0DmpyK1P+9yFpUuhEHUVmZMriTGKXv6synner16CD8/AkpQ== "@particle-network/crypto@^1.0.1": version "1.0.1" @@ -1753,9 +1754,9 @@ integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== "@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.4": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" - integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== "@scure/bip32@1.1.5": version "1.1.5" @@ -1960,9 +1961,9 @@ utf-8-validate "6.0.3" "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -2111,9 +2112,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.11.10": - version "20.11.26" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.26.tgz#3fbda536e51d5c79281e1d9657dcb0131baabd2d" - integrity sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ== + version "20.12.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.3.tgz#d6658c2c7776c1cad93534bb45428195ed840c65" + integrity sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw== dependencies: undici-types "~5.26.4" @@ -2529,14 +2530,15 @@ array-ify@^1.0.0: integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^1.0.1: @@ -2556,26 +2558,16 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.filter@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz#423771edeb417ff5914111fff4277ea0624c0d0e" - integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - array.prototype.findlastindex@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz#d1c50f0b3a9da191981ff8942a0aedd82794404f" - integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" + es-abstract "^1.23.2" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.2: @@ -2654,11 +2646,11 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" axios@^1.0.0, axios@^1.3.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" - integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + version "1.6.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== dependencies: - follow-redirects "^1.15.4" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -2755,9 +2747,9 @@ bignumber.js@^9.0.1: integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bl@^4.0.3, bl@^4.1.0: version "4.1.0" @@ -3060,9 +3052,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001597" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz#8be94a8c1d679de23b22fbd944232aa1321639e6" - integrity sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w== + version "1.0.30001605" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz#ca12d7330dd8bcb784557eb9aa64f0037870d9d6" + integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== catering@^2.0.0, catering@^2.1.0: version "2.1.1" @@ -3552,6 +3544,33 @@ dargs@^7.0.0: resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" @@ -3765,9 +3784,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.668: - version "1.4.701" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz#7335e5761331774b4dea54cd24a1b84861d45cdf" - integrity sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA== + version "1.4.724" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz#e0a86fe4d3d0e05a4d7b032549d79608078f830d" + integrity sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA== elliptic@6.5.4: version "6.5.4" @@ -3876,17 +3895,21 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" - integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" available-typed-arrays "^1.0.7" call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" es-define-property "^1.0.0" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" @@ -3897,10 +3920,11 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: has-property-descriptors "^1.0.2" has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.1" + hasown "^2.0.2" internal-slot "^1.0.7" is-array-buffer "^3.0.4" is-callable "^1.2.7" + is-data-view "^1.0.1" is-negative-zero "^2.0.3" is-regex "^1.1.4" is-shared-array-buffer "^1.0.3" @@ -3911,22 +3935,17 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: object-keys "^1.1.1" object.assign "^4.1.5" regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.0" + safe-array-concat "^1.1.2" safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" typed-array-buffer "^1.0.2" typed-array-byte-length "^1.0.1" typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.5" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.14" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + which-typed-array "^1.1.15" es-define-property@^1.0.0: version "1.0.0" @@ -3935,11 +3954,18 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" @@ -4543,10 +4569,10 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.12.1, follow-redirects@^1.15.4: - version "1.15.5" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" - integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== +follow-redirects@^1.12.1, follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: version "0.3.3" @@ -4870,15 +4896,15 @@ glob@8.1.0, glob@^8.0.1: once "^1.3.0" glob@^10.2.2, glob@^10.3.7: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.5" + jackspeak "^2.3.6" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" + minipass "^7.0.4" + path-scurry "^1.10.2" glob@^7.0.3, glob@^7.1.3, glob@^7.1.4: version "7.2.3" @@ -4999,13 +5025,13 @@ hard-rejection@^2.1.0: integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== hardhat@^2.17.3: - version "2.21.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.21.0.tgz#2e23126310a6c77cd7e149e6af1dd67626b7a74f" - integrity sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw== + version "2.22.2" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.2.tgz#0cadd7ec93bf39bab09f81603e75bc5e92acea3d" + integrity sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.2.0" + "@nomicfoundation/edr" "^0.3.1" "@nomicfoundation/ethereumjs-common" "4.0.4" "@nomicfoundation/ethereumjs-tx" "5.0.4" "@nomicfoundation/ethereumjs-util" "9.0.4" @@ -5108,7 +5134,7 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0, hasown@^2.0.1: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -5440,6 +5466,13 @@ is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-m dependencies: hasown "^2.0.0" +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -5700,7 +5733,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.5: +jackspeak@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== @@ -6505,7 +6538,7 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": +lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== @@ -6769,7 +6802,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -6797,6 +6830,13 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -6897,7 +6937,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== @@ -6923,9 +6963,9 @@ mnemonist@^0.38.0: obliterator "^2.0.0" mocha@^10.0.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.3.0.tgz#0e185c49e6dccf582035c05fa91084a4ff6e3fe9" - integrity sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg== + version "10.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" + integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== dependencies: ansi-colors "4.1.1" browser-stdout "1.3.1" @@ -6989,7 +7029,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mute-stream@~1.0.0: +mute-stream@^1.0.0, mute-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== @@ -7373,42 +7413,41 @@ object.assign@^4.1.2, object.assign@^4.1.5: object-keys "^1.1.1" object.entries@^1.1.5: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" - integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.groupby@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.2.tgz#494800ff5bab78fd0eff2835ec859066e00192ec" - integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - array.prototype.filter "^1.0.3" - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" + es-abstract "^1.23.2" object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" obliterator@^2.0.0: version "2.0.4" @@ -7695,12 +7734,12 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1, path-scurry@^1.6.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.10.2, path-scurry@^1.6.1: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-type@^3.0.0: @@ -7848,11 +7887,11 @@ prompts@^2.0.1: sisteransi "^1.0.5" promzard@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.0.tgz#3246f8e6c9895a77c0549cefb65828ac0f6c006b" - integrity sha512-KQVDEubSUHGSt5xLakaToDFrSoZhStB8dXLzk2xvwR67gJktrHFvpR63oZgHyK19WKbHFLXJqCPXdVR3aBP8Ig== + version "1.0.1" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" + integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== dependencies: - read "^2.0.0" + read "^3.0.1" propagate@^2.0.0: version "2.0.1" @@ -7880,9 +7919,9 @@ punycode@^2.1.0: integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" - integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== query-string@^8.1.0: version "8.2.0" @@ -7991,6 +8030,13 @@ read@^2.0.0: dependencies: mute-stream "~1.0.0" +read@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" + integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== + dependencies: + mute-stream "^1.0.0" + readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -8184,7 +8230,7 @@ rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.1.0: +safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== @@ -8614,32 +8660,33 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -8782,9 +8829,9 @@ tar@6.1.11: yallist "^4.0.0" tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: - version "6.2.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" - integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -9092,10 +9139,10 @@ typed-array-byte-offset@^1.0.2: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" - integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: call-bind "^1.0.7" for-each "^0.3.3" @@ -9120,9 +9167,9 @@ typedoc@^0.25.7: shiki "^0.14.7" "typescript@>=3 < 6", typescript@^5.3.3: - version "5.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" - integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + version "5.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" + integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== uglify-js@^3.1.4: version "3.17.4" @@ -9145,9 +9192,9 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici@^5.14.0: - version "5.28.3" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" - integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: "@fastify/busboy" "^2.0.0" @@ -9323,10 +9370,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -viem@^2.7.12, viem@^2.7.8: - version "2.8.4" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.8.4.tgz#553996181d2d22237e31476218178d3fe96e2e3d" - integrity sha512-zBC8+YNKzo+XeUsCyXdrFzimH9Ei/nRfUKldPmVRoR/lR56/sqkDPyfCE1yvzwwmA9AJ9m9m2HtSPgl9NiTReA== +viem@^2.7.12, viem@^2.8.6: + version "2.9.8" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.8.tgz#15288cc5332292617786d21db0aa3571db29c4c9" + integrity sha512-vetoTZ6UF2okS/1I0+1p/QYdC4yA6uf4PeWwTBp3kD5wC6eQcmeh7zP+unNdnYHGGC63x7BTGldK1ep2IFVKcQ== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -9399,7 +9446,7 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.14: +which-typed-array@^1.1.14, which-typed-array@^1.1.15: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== From 28422f19bfe48dd79954e53a22757eb7f92f92c8 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 3 Apr 2024 18:07:26 +0100 Subject: [PATCH 17/33] continued --- .../account/src/BiconomySmartAccountV2.ts | 103 +++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index f8c5e86bd..25172e003 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -26,7 +26,7 @@ import { BatchUserOperationCallData, SmartAccountSigner, } from "@alchemy/aa-core"; -import { isNullOrUndefined, isValidRpcUrl, packUserOp, compareChainIds } from "./utils/Utils.js"; +import { isNullOrUndefined, isValidRpcUrl, packUserOp, compareChainIds, addressEquals } from "./utils/Utils.js"; import { BaseValidationModule, ModuleInfo, SendUserOpParams, createECDSAOwnershipValidationModule } from "@biconomy/modules"; import { IHybridPaymaster, @@ -54,6 +54,7 @@ import { SimulationType, BalancePayload, SupportedToken, + WithdrawalRequest, } from "./utils/Types.js"; import { ADDRESS_RESOLVER_ADDRESS, @@ -359,6 +360,106 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { return result; } + /** + * Transfers funds from Smart Account to recipient (usually EOA) + * @param recipient - Address of the recipient + * @param withdrawalRequests - Array of withdrawal requests {@link WithdrawalRequest}. If withdrawal request is an empty array, it will transfer the balance of the native token. Using a paymaster will ensure no dust remains in the smart account. + * @param buildUseropDto - Optional. {@link BuildUserOpOptions} + * + * @returns Promise - An object containing the status of the transaction. + * + * @example + * import { createClient } from "viem" + * import { createSmartAccountClient, NATIVE_TOKEN_ALIAS } from "@biconomy/account" + * import { createWalletClient, http } from "viem"; + * import { polygonMumbai } from "viem/chains"; + * + * const USDT = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const signer = createWalletClient({ + * account, + * chain: polygonMumbai, + * transport: http(), + * }); + * + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); + * + * const { wait } = await smartAccount.withdraw( + * [ + * { address: USDT, amount: BigInt(1) }, + * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + * ], + * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request + * { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * } + * ); + * + * // OR to withdraw all of the native token, leaving no dust in the smart account + * + * const { wait } = await smartAccount.withdraw([], account.pubKey, { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * }); + * + * const { success } = await wait(); + */ + public async withdraw( + withdrawalRequests?: WithdrawalRequest[] | null, + defaultRecipient?: Hex | null, + buildUseropDto?: BuildUserOpOptions, + ): Promise { + const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + + if (!defaultRecipient && withdrawalRequests?.some(({ recipient }) => !recipient)) { + throw new Error(ERROR_MESSAGES.NO_RECIPIENT); + } + + // Remove the native token from the withdrawal requests + let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; + + // Check if the amount is not present in all withdrawal requests + const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount); + + // Get the balances of the tokens if the amount is not present in the withdrawal requests + if (shouldFetchMaxBalances) { + const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); + tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ + address, + amount: amount ?? balances[i].amount, + })); + } + + // Create the transactions + const txs: Transaction[] = tokenRequests.map(({ address, amount, recipient: recipientFromRequest }) => ({ + to: address, + data: encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: "transfer", + args: [recipientFromRequest || defaultRecipient, amount], + }), + })); + + // Check if eth alias is present in the original withdrawal requests + const nativeTokenRequest = withdrawalRequests?.find(({ address }) => addressEquals(address, NATIVE_TOKEN_ALIAS)); + const hasNoRequests = !withdrawalRequests?.length; + if (!!nativeTokenRequest || hasNoRequests) { + // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster. + if (!nativeTokenRequest?.amount && !buildUseropDto?.paymasterServiceData?.mode) { + throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + } + + // get eth balance if not present in withdrawal requests + const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); + + txs.push({ + to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex, + value: nativeTokenAmountToWithdraw, + }); + } + + return this.sendTransaction(txs, buildUseropDto); + } + + /** * Return the account's address. This value is valid even before deploying the contract. */ From 079def2f16e5494ee45af171f744784aecf5a85a Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 3 Apr 2024 18:08:58 +0100 Subject: [PATCH 18/33] lint:fix --- .../account/src/BiconomySmartAccountV2.ts | 193 +++++++++--------- 1 file changed, 96 insertions(+), 97 deletions(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 52b946970..4a7f5ac61 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -361,104 +361,103 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { } /** - * Transfers funds from Smart Account to recipient (usually EOA) - * @param recipient - Address of the recipient - * @param withdrawalRequests - Array of withdrawal requests {@link WithdrawalRequest}. If withdrawal request is an empty array, it will transfer the balance of the native token. Using a paymaster will ensure no dust remains in the smart account. - * @param buildUseropDto - Optional. {@link BuildUserOpOptions} - * - * @returns Promise - An object containing the status of the transaction. - * - * @example - * import { createClient } from "viem" - * import { createSmartAccountClient, NATIVE_TOKEN_ALIAS } from "@biconomy/account" - * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; - * - * const USDT = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - * const signer = createWalletClient({ - * account, - * chain: polygonMumbai, - * transport: http(), - * }); - * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); - * - * const { wait } = await smartAccount.withdraw( - * [ - * { address: USDT, amount: BigInt(1) }, - * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } - * ], - * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request - * { - * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - * } - * ); - * - * // OR to withdraw all of the native token, leaving no dust in the smart account - * - * const { wait } = await smartAccount.withdraw([], account.pubKey, { - * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - * }); - * - * const { success } = await wait(); - */ - public async withdraw( - withdrawalRequests?: WithdrawalRequest[] | null, - defaultRecipient?: Hex | null, - buildUseropDto?: BuildUserOpOptions, - ): Promise { - const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); - - if (!defaultRecipient && withdrawalRequests?.some(({ recipient }) => !recipient)) { - throw new Error(ERROR_MESSAGES.NO_RECIPIENT); - } - - // Remove the native token from the withdrawal requests - let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; - - // Check if the amount is not present in all withdrawal requests - const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount); - - // Get the balances of the tokens if the amount is not present in the withdrawal requests - if (shouldFetchMaxBalances) { - const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); - tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ - address, - amount: amount ?? balances[i].amount, - })); - } - - // Create the transactions - const txs: Transaction[] = tokenRequests.map(({ address, amount, recipient: recipientFromRequest }) => ({ - to: address, - data: encodeFunctionData({ - abi: parseAbi(ERC20_ABI), - functionName: "transfer", - args: [recipientFromRequest || defaultRecipient, amount], - }), - })); - - // Check if eth alias is present in the original withdrawal requests - const nativeTokenRequest = withdrawalRequests?.find(({ address }) => addressEquals(address, NATIVE_TOKEN_ALIAS)); - const hasNoRequests = !withdrawalRequests?.length; - if (!!nativeTokenRequest || hasNoRequests) { - // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster. - if (!nativeTokenRequest?.amount && !buildUseropDto?.paymasterServiceData?.mode) { - throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); - } - - // get eth balance if not present in withdrawal requests - const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); - - txs.push({ - to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex, - value: nativeTokenAmountToWithdraw, - }); - } - - return this.sendTransaction(txs, buildUseropDto); - } + * Transfers funds from Smart Account to recipient (usually EOA) + * @param recipient - Address of the recipient + * @param withdrawalRequests - Array of withdrawal requests {@link WithdrawalRequest}. If withdrawal request is an empty array, it will transfer the balance of the native token. Using a paymaster will ensure no dust remains in the smart account. + * @param buildUseropDto - Optional. {@link BuildUserOpOptions} + * + * @returns Promise - An object containing the status of the transaction. + * + * @example + * import { createClient } from "viem" + * import { createSmartAccountClient, NATIVE_TOKEN_ALIAS } from "@biconomy/account" + * import { createWalletClient, http } from "viem"; + * import { polygonMumbai } from "viem/chains"; + * + * const USDT = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const signer = createWalletClient({ + * account, + * chain: polygonMumbai, + * transport: http(), + * }); + * + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); + * + * const { wait } = await smartAccount.withdraw( + * [ + * { address: USDT, amount: BigInt(1) }, + * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + * ], + * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request + * { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * } + * ); + * + * // OR to withdraw all of the native token, leaving no dust in the smart account + * + * const { wait } = await smartAccount.withdraw([], account.pubKey, { + * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + * }); + * + * const { success } = await wait(); + */ + public async withdraw( + withdrawalRequests?: WithdrawalRequest[] | null, + defaultRecipient?: Hex | null, + buildUseropDto?: BuildUserOpOptions, + ): Promise { + const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + + if (!defaultRecipient && withdrawalRequests?.some(({ recipient }) => !recipient)) { + throw new Error(ERROR_MESSAGES.NO_RECIPIENT); + } + + // Remove the native token from the withdrawal requests + let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; + + // Check if the amount is not present in all withdrawal requests + const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount); + + // Get the balances of the tokens if the amount is not present in the withdrawal requests + if (shouldFetchMaxBalances) { + const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); + tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ + address, + amount: amount ?? balances[i].amount, + })); + } + // Create the transactions + const txs: Transaction[] = tokenRequests.map(({ address, amount, recipient: recipientFromRequest }) => ({ + to: address, + data: encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: "transfer", + args: [recipientFromRequest || defaultRecipient, amount], + }), + })); + + // Check if eth alias is present in the original withdrawal requests + const nativeTokenRequest = withdrawalRequests?.find(({ address }) => addressEquals(address, NATIVE_TOKEN_ALIAS)); + const hasNoRequests = !withdrawalRequests?.length; + if (!!nativeTokenRequest || hasNoRequests) { + // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster. + if (!nativeTokenRequest?.amount && !buildUseropDto?.paymasterServiceData?.mode) { + throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + } + + // get eth balance if not present in withdrawal requests + const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); + + txs.push({ + to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex, + value: nativeTokenAmountToWithdraw, + }); + } + + return this.sendTransaction(txs, buildUseropDto); + } /** * Return the account's address. This value is valid even before deploying the contract. From eaef0633bc0897e975306372768a0db498208664 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 3 Apr 2024 18:55:21 +0100 Subject: [PATCH 19/33] yarn lock --- yarn.lock | 621 +++++++++++++++++++++++++++++------------------------- 1 file changed, 334 insertions(+), 287 deletions(-) diff --git a/yarn.lock b/yarn.lock index a4e0e28a9..5e8085597 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,13 +13,13 @@ integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== "@alchemy/aa-core@^3.1.1": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.4.2.tgz#3bb3e508bb29586a29c5a025056f11c474bcee19" - integrity sha512-oPE8iUT/38S0hEfthtauIcidQq1kyN/t1VGpq5JSEFanFs6uV8UFyjjj9heO4UnA1uJDiVbvY6A5NZcM92j8RA== + version "3.6.1" + resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.6.1.tgz#af718313276458910d06030ee0aa946168e442f9" + integrity sha512-WVDacDuXcuePTHQSlKZ0nZvRHNSB48iUhh7fVSqchiStjq7BybdGg35AZf8eg5vcepkwSHekNKCp5LxKwpFCQg== dependencies: abitype "^0.8.3" eventemitter3 "^5.0.1" - viem "^2.7.8" + viem "^2.8.6" zod "^3.22.4" "@ampproject/remapping@^2.2.0": @@ -30,33 +30,33 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" "@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.0.tgz#56cbda6b185ae9d9bed369816a8f4423c5f2ff1b" - integrity sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" + integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.0" - "@babel/parser" "^7.24.0" + "@babel/helpers" "^7.24.4" + "@babel/parser" "^7.24.4" "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" convert-source-map "^2.0.0" debug "^4.1.0" @@ -64,14 +64,14 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.6", "@babel/generator@^7.7.2": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== +"@babel/generator@^7.24.1", "@babel/generator@^7.24.4", "@babel/generator@^7.7.2": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498" + integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.24.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" "@babel/helper-compilation-targets@^7.23.6": @@ -106,11 +106,11 @@ "@babel/types" "^7.22.5" "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.24.0" "@babel/helper-module-transforms@^7.23.3": version "7.23.3" @@ -123,7 +123,7 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.20" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== @@ -143,9 +143,9 @@ "@babel/types" "^7.22.5" "@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" @@ -157,28 +157,29 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.0.tgz#a3dd462b41769c95db8091e49cfe019389a9409b" - integrity sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA== +"@babel/helpers@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" + integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== dependencies: "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== +"@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== dependencies: "@babel/helper-validator-identifier" "^7.22.20" chalk "^2.4.2" js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac" - integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -216,11 +217,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" - integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -272,16 +273,16 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" - integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/runtime@^7.21.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" - integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== dependencies: regenerator-runtime "^0.14.0" @@ -294,23 +295,23 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" - integrity sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw== +"@babel/traverse@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" + integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.1" + "@babel/generator" "^7.24.1" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.0" + "@babel/parser" "^7.24.1" "@babel/types" "^7.24.0" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== @@ -836,9 +837,9 @@ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -1065,7 +1066,7 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1097,7 +1098,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1251,65 +1252,65 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/edr-darwin-arm64@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.2.1.tgz#10c1a07add192583ce8b2d4cc93439f52b390a41" - integrity sha512-aMYaRaZVQ/TmyNJIoXf1bU4k0zfinaL9Sy1day4yGlL6eiQPFfRGj9W6TZaZIoYG0XTx/mQWD7dkXJ7LdrleJA== +"@nomicfoundation/edr-darwin-arm64@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz#0618dbdf1c832f8e61c77540e7188c13fdd5b658" + integrity sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ== -"@nomicfoundation/edr-darwin-x64@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.2.1.tgz#eaa29d2ba9f91ddb5f59b872c5a54f94a6fe3095" - integrity sha512-ma0SLcjHm5L3nPHcKFJB0jv/gKGSKaxr5Z65rurX/eaYUQJ7YGMsb8er9bSCo9rjzOtxf4FoPj3grL3zGpOj8A== +"@nomicfoundation/edr-darwin-x64@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz#567ee0bca8d019085e8dd95330e7c03f16c66a79" + integrity sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg== -"@nomicfoundation/edr-linux-arm64-gnu@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.2.1.tgz#8149db0d742157405effe82d485ea9bfefddc795" - integrity sha512-NX3G4pBhRitWrjSGY3HTyCq3wKSm5YqrKVOCNQGl9/jcjSovqxlgzFMiTx4YZCzGntfJ/1om9AI84OWxYJjoDw== +"@nomicfoundation/edr-linux-arm64-gnu@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz#3956b4d7a0127e2259351626c92698c4ce6ecf05" + integrity sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA== -"@nomicfoundation/edr-linux-arm64-musl@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.2.1.tgz#7d53afe5607eb406d199a199d00209a6304ff07b" - integrity sha512-gdQ3QHkt9XRkdtOGQ8fMwS11MXdjLeZgLrqoial4V4qtMaamIMMhVczK+VEvUhD8p7G4BVmp6kmkvcsthmndmw== +"@nomicfoundation/edr-linux-arm64-musl@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz#139f801939ed467f1719a2ab014993838008eefb" + integrity sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q== -"@nomicfoundation/edr-linux-x64-gnu@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.2.1.tgz#b762c95368fcb88bbbabba4d8be5380f38967413" - integrity sha512-OqabFY37vji6mYbLD9CvG28lja68czeVw58oWByIhFV3BpBu/cyP1oAbhzk3LieylujabS3Ekpvjw2Tkf0A9RQ== +"@nomicfoundation/edr-linux-x64-gnu@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz#b5994caa1a8bb4afca5f079ad7dd99edb26c6c45" + integrity sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA== -"@nomicfoundation/edr-linux-x64-musl@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.2.1.tgz#522448c42bff7d2abd52ddcf11ae6ca3dfdd6db4" - integrity sha512-vHfFFK2EPISuQUQge+bdjXamb0EUjfl8srYSog1qfiwyLwLeuSbpyyFzDeITAgPpkkFuedTfJW553K0Hipspyg== +"@nomicfoundation/edr-linux-x64-musl@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz#536c1d1dfd2fc7d7ad6ed6e14ed9a12322d88ba6" + integrity sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw== -"@nomicfoundation/edr-win32-arm64-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.2.1.tgz#ccfa443c274e49de93016a1060be810096dc6f1d" - integrity sha512-K/mui67RCKxghbSyvhvW3rvyVN1pa9M1Q9APUx1PtWjSSdXDFpqEY1NYsv2syb47Ca8ObJwVMF+LvnB6GvhUOQ== +"@nomicfoundation/edr-win32-arm64-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz#f71609644d8585c2ec71580bf75c2fd036ee58b0" + integrity sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA== -"@nomicfoundation/edr-win32-ia32-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.2.1.tgz#822b19d3e67d6dcfa5394cb6a4d55d8bab1b2f26" - integrity sha512-HHK0mXEtjvfjJrJlqcYgQCy3lZIXS1KNl2GaP8bwEIuEwx++XxXs/ThLjPepM1nhCGICij8IGy7p3KrkzRelsw== +"@nomicfoundation/edr-win32-ia32-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz#baa5eaacb1fff107d02f0e6a33dee9521fd2bf37" + integrity sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w== -"@nomicfoundation/edr-win32-x64-msvc@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.2.1.tgz#7b56ff742b2724779cc9f3385815b394f76de8df" - integrity sha512-FY4eQJdj1/y8ST0RyQycx63yr+lvdYNnUkzgWf4X+vPH1lOhXae+L2NDcNCQlTDAfQcD6yz0bkBUkLrlJ8pTww== +"@nomicfoundation/edr-win32-x64-msvc@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz#7562e061b2481f87bb1ace30513a2ad38c469836" + integrity sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w== -"@nomicfoundation/edr@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.2.1.tgz#a3d2a542dcd5dc5a8d757116d52baea05f370531" - integrity sha512-Dleau3ItHJh2n85G2J6AIPBoLgu/mOWkmrh26z3VsJE2tp/e00hUk/dqz85ncsVcBYEc6/YOn/DomWu0wSF9tQ== +"@nomicfoundation/edr@^0.3.1": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.3.3.tgz#0ed8619ea2ac644bf87cdc09dd1a8f465a859bcc" + integrity sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ== optionalDependencies: - "@nomicfoundation/edr-darwin-arm64" "0.2.1" - "@nomicfoundation/edr-darwin-x64" "0.2.1" - "@nomicfoundation/edr-linux-arm64-gnu" "0.2.1" - "@nomicfoundation/edr-linux-arm64-musl" "0.2.1" - "@nomicfoundation/edr-linux-x64-gnu" "0.2.1" - "@nomicfoundation/edr-linux-x64-musl" "0.2.1" - "@nomicfoundation/edr-win32-arm64-msvc" "0.2.1" - "@nomicfoundation/edr-win32-ia32-msvc" "0.2.1" - "@nomicfoundation/edr-win32-x64-msvc" "0.2.1" + "@nomicfoundation/edr-darwin-arm64" "0.3.3" + "@nomicfoundation/edr-darwin-x64" "0.3.3" + "@nomicfoundation/edr-linux-arm64-gnu" "0.3.3" + "@nomicfoundation/edr-linux-arm64-musl" "0.3.3" + "@nomicfoundation/edr-linux-x64-gnu" "0.3.3" + "@nomicfoundation/edr-linux-x64-musl" "0.3.3" + "@nomicfoundation/edr-win32-arm64-msvc" "0.3.3" + "@nomicfoundation/edr-win32-ia32-msvc" "0.3.3" + "@nomicfoundation/edr-win32-x64-msvc" "0.3.3" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -1721,9 +1722,9 @@ uuid "^8.3.2" "@particle-network/chains@*": - version "1.3.21" - resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.21.tgz#82d2b098e165fc198e6e6e3e4c8b2154235e3aa1" - integrity sha512-tuUVuOPf+el+kDlHLFMyDy4IkoGjk+P3QvVrxT7WnmEma1NgWTE7RaNsniwqn6SYkAwAxksL/D9aADUXZxqPmw== + version "1.3.27" + resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.27.tgz#dca4f2714d23957cc68cb1301de1f310895658db" + integrity sha512-+my+i0jqZjUoP+mNXxsPc2D7o3Cijl6uRvvWyTT0DmpyK1P+9yFpUuhEHUVmZMriTGKXv6synner16CD8/AkpQ== "@particle-network/crypto@^1.0.1": version "1.0.1" @@ -1753,9 +1754,9 @@ integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== "@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.4": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" - integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== "@scure/bip32@1.1.5": version "1.1.5" @@ -1960,9 +1961,9 @@ utf-8-validate "6.0.3" "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -2111,9 +2112,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.11.10": - version "20.11.26" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.26.tgz#3fbda536e51d5c79281e1d9657dcb0131baabd2d" - integrity sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ== + version "20.12.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.3.tgz#d6658c2c7776c1cad93534bb45428195ed840c65" + integrity sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw== dependencies: undici-types "~5.26.4" @@ -2529,14 +2530,15 @@ array-ify@^1.0.0: integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^1.0.1: @@ -2556,26 +2558,16 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.filter@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz#423771edeb417ff5914111fff4277ea0624c0d0e" - integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - array.prototype.findlastindex@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz#d1c50f0b3a9da191981ff8942a0aedd82794404f" - integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" + es-abstract "^1.23.2" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.2: @@ -2654,11 +2646,11 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" axios@^1.0.0, axios@^1.3.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" - integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + version "1.6.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== dependencies: - follow-redirects "^1.15.4" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -2755,9 +2747,9 @@ bignumber.js@^9.0.1: integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bl@^4.0.3, bl@^4.1.0: version "4.1.0" @@ -3060,9 +3052,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001597" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz#8be94a8c1d679de23b22fbd944232aa1321639e6" - integrity sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w== + version "1.0.30001605" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz#ca12d7330dd8bcb784557eb9aa64f0037870d9d6" + integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== catering@^2.0.0, catering@^2.1.0: version "2.1.1" @@ -3552,6 +3544,33 @@ dargs@^7.0.0: resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" @@ -3765,9 +3784,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.668: - version "1.4.701" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz#7335e5761331774b4dea54cd24a1b84861d45cdf" - integrity sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA== + version "1.4.724" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz#e0a86fe4d3d0e05a4d7b032549d79608078f830d" + integrity sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA== elliptic@6.5.4: version "6.5.4" @@ -3876,17 +3895,21 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" - integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" available-typed-arrays "^1.0.7" call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" es-define-property "^1.0.0" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" @@ -3897,10 +3920,11 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: has-property-descriptors "^1.0.2" has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.1" + hasown "^2.0.2" internal-slot "^1.0.7" is-array-buffer "^3.0.4" is-callable "^1.2.7" + is-data-view "^1.0.1" is-negative-zero "^2.0.3" is-regex "^1.1.4" is-shared-array-buffer "^1.0.3" @@ -3911,22 +3935,17 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: object-keys "^1.1.1" object.assign "^4.1.5" regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.0" + safe-array-concat "^1.1.2" safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" typed-array-buffer "^1.0.2" typed-array-byte-length "^1.0.1" typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.5" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.14" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + which-typed-array "^1.1.15" es-define-property@^1.0.0: version "1.0.0" @@ -3935,11 +3954,18 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" @@ -4543,10 +4569,10 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.12.1, follow-redirects@^1.15.4: - version "1.15.5" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" - integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== +follow-redirects@^1.12.1, follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: version "0.3.3" @@ -4870,15 +4896,15 @@ glob@8.1.0, glob@^8.0.1: once "^1.3.0" glob@^10.2.2, glob@^10.3.7: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.5" + jackspeak "^2.3.6" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" + minipass "^7.0.4" + path-scurry "^1.10.2" glob@^7.0.3, glob@^7.1.3, glob@^7.1.4: version "7.2.3" @@ -4999,13 +5025,13 @@ hard-rejection@^2.1.0: integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== hardhat@^2.17.3: - version "2.21.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.21.0.tgz#2e23126310a6c77cd7e149e6af1dd67626b7a74f" - integrity sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw== + version "2.22.2" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.2.tgz#0cadd7ec93bf39bab09f81603e75bc5e92acea3d" + integrity sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.2.0" + "@nomicfoundation/edr" "^0.3.1" "@nomicfoundation/ethereumjs-common" "4.0.4" "@nomicfoundation/ethereumjs-tx" "5.0.4" "@nomicfoundation/ethereumjs-util" "9.0.4" @@ -5108,7 +5134,7 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0, hasown@^2.0.1: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -5440,6 +5466,13 @@ is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-m dependencies: hasown "^2.0.0" +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -5700,7 +5733,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.5: +jackspeak@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== @@ -6505,7 +6538,7 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": +lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== @@ -6769,7 +6802,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -6797,6 +6830,13 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -6897,7 +6937,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== @@ -6923,9 +6963,9 @@ mnemonist@^0.38.0: obliterator "^2.0.0" mocha@^10.0.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.3.0.tgz#0e185c49e6dccf582035c05fa91084a4ff6e3fe9" - integrity sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg== + version "10.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" + integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== dependencies: ansi-colors "4.1.1" browser-stdout "1.3.1" @@ -6989,7 +7029,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mute-stream@~1.0.0: +mute-stream@^1.0.0, mute-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== @@ -7373,42 +7413,41 @@ object.assign@^4.1.2, object.assign@^4.1.5: object-keys "^1.1.1" object.entries@^1.1.5: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" - integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.groupby@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.2.tgz#494800ff5bab78fd0eff2835ec859066e00192ec" - integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - array.prototype.filter "^1.0.3" - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" + es-abstract "^1.23.2" object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" obliterator@^2.0.0: version "2.0.4" @@ -7695,12 +7734,12 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1, path-scurry@^1.6.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.10.2, path-scurry@^1.6.1: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-type@^3.0.0: @@ -7848,11 +7887,11 @@ prompts@^2.0.1: sisteransi "^1.0.5" promzard@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.0.tgz#3246f8e6c9895a77c0549cefb65828ac0f6c006b" - integrity sha512-KQVDEubSUHGSt5xLakaToDFrSoZhStB8dXLzk2xvwR67gJktrHFvpR63oZgHyK19WKbHFLXJqCPXdVR3aBP8Ig== + version "1.0.1" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" + integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== dependencies: - read "^2.0.0" + read "^3.0.1" propagate@^2.0.0: version "2.0.1" @@ -7880,9 +7919,9 @@ punycode@^2.1.0: integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" - integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== query-string@^8.1.0: version "8.2.0" @@ -7991,6 +8030,13 @@ read@^2.0.0: dependencies: mute-stream "~1.0.0" +read@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" + integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== + dependencies: + mute-stream "^1.0.0" + readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -8184,7 +8230,7 @@ rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.1.0: +safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== @@ -8614,32 +8660,33 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -8782,9 +8829,9 @@ tar@6.1.11: yallist "^4.0.0" tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: - version "6.2.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" - integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -9092,10 +9139,10 @@ typed-array-byte-offset@^1.0.2: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" - integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: call-bind "^1.0.7" for-each "^0.3.3" @@ -9120,9 +9167,9 @@ typedoc@^0.25.7: shiki "^0.14.7" "typescript@>=3 < 6", typescript@^5.3.3: - version "5.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" - integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + version "5.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" + integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== uglify-js@^3.1.4: version "3.17.4" @@ -9145,9 +9192,9 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici@^5.14.0: - version "5.28.3" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" - integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: "@fastify/busboy" "^2.0.0" @@ -9323,10 +9370,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -viem@^2.7.12, viem@^2.7.8: - version "2.8.4" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.8.4.tgz#553996181d2d22237e31476218178d3fe96e2e3d" - integrity sha512-zBC8+YNKzo+XeUsCyXdrFzimH9Ei/nRfUKldPmVRoR/lR56/sqkDPyfCE1yvzwwmA9AJ9m9m2HtSPgl9NiTReA== +viem@^2.7.12, viem@^2.8.6: + version "2.9.8" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.8.tgz#15288cc5332292617786d21db0aa3571db29c4c9" + integrity sha512-vetoTZ6UF2okS/1I0+1p/QYdC4yA6uf4PeWwTBp3kD5wC6eQcmeh7zP+unNdnYHGGC63x7BTGldK1ep2IFVKcQ== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -9399,7 +9446,7 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.14: +which-typed-array@^1.1.14, which-typed-array@^1.1.15: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== From 44d2529216f916c4178267d3138824559578ffef Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 3 Apr 2024 19:01:46 +0100 Subject: [PATCH 20/33] fix comment --- packages/account/src/utils/Types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts index 03b925355..be406b4cb 100644 --- a/packages/account/src/utils/Types.ts +++ b/packages/account/src/utils/Types.ts @@ -44,7 +44,7 @@ export interface WithdrawalRequest { address: Hex; /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ amount?: bigint; - /** The destination address of the funds. The first argument from the `withdraw(...)` function will be used as the default if left unset. */ + /** The destination address of the funds. The second argument from the `withdraw(...)` function will be used as the default if left unset. */ recipient?: Hex; } From cb4b60a4ca797c680a13f47d8ad00efe745eeec1 Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 3 Apr 2024 19:05:52 +0100 Subject: [PATCH 21/33] fix comment --- packages/account/src/BiconomySmartAccountV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts index 4a7f5ac61..93f54e6cf 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/packages/account/src/BiconomySmartAccountV2.ts @@ -385,7 +385,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * const { wait } = await smartAccount.withdraw( * [ - * { address: USDT, amount: BigInt(1) }, + * { address: USDT }, // omit the amount to withdraw the full balance * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } * ], * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request From f963c10b7a56ff4ee6ee8396e49f5272a37327ed Mon Sep 17 00:00:00 2001 From: GabiDev Date: Thu, 4 Apr 2024 00:08:30 +0300 Subject: [PATCH 22/33] renamed test and remove redundant variable --- packages/account/tests/account.e2e.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts index 21a0f44a5..0ba8cde57 100644 --- a/packages/account/tests/account.e2e.spec.ts +++ b/packages/account/tests/account.e2e.spec.ts @@ -13,7 +13,7 @@ describe("Account Tests", () => { beforeEach(() => { // @ts-ignore: Comes from setup-e2e-tests - [baseSepolia, baseSepolia, optimism] = testDataPerChain; + [baseSepolia, optimism] = testDataPerChain; }); it("should have addresses", async () => { @@ -696,7 +696,7 @@ describe("Account Tests", () => { expect(response).toBe(eip1271MagicValue); }); - it("should throw an error if signature is not valid", async () => { + it("should confirm that signature is not valid", async () => { const { whale: { viemWallet: signer }, bundlerUrl, From 7c594fa74e81650b4cb5043afb4cd1153e638a19 Mon Sep 17 00:00:00 2001 From: joepegler Date: Fri, 19 Apr 2024 10:48:20 +0100 Subject: [PATCH 23/33] chore: modernise tooling and reduce package size (#466) * modernise tooling and reduce package size --- .changeset/README.md | 8 + .changeset/config.json | 14 + .env.example | 8 +- .eslintignore | 14 - .eslintrc.js | 49 - .github/ISSUE_TEMPLATE/1_general_issue.yml | 26 + .../{bug_report.yml => 2_bug_report.yml} | 7 +- .github/ISSUE_TEMPLATE/3_feature_request.yml | 31 + .github/ISSUE_TEMPLATE/4_security_report.yml | 31 + .../ISSUE_TEMPLATE/5_document_improvement.yml | 33 + .../6_build_deployment_issue.yml | 33 + .github/ISSUE_TEMPLATE/config.yml | 8 - .github/ISSUE_TEMPLATE/feature_request.md | 27 - .../pull_request_template.md | 22 + .github/actions/build/action.yml | 16 + .../actions/install-dependencies/action.yml | 14 + .github/pull_request_template.md | 35 - .github/workflows/build.yml | 14 + .github/workflows/check_branch_name.yml | 21 - .github/workflows/coverage.yml | 44 + .github/workflows/docs.yml | 26 +- .github/workflows/mainnet_tests.yml | 32 - .github/workflows/mark_stale.yml | 22 - .github/workflows/pr-lint.yml | 17 + .github/workflows/pull_request_approved.yml | 34 - .github/workflows/push_check.yml | 44 - .github/workflows/size-report.yml | 29 + .github/workflows/test-read.yml | 28 + .github/workflows/test-write.yml | 58 + .gitignore | 171 +- .nvmrc | 1 - .nycrc.json | 3 - .prettierignore | 14 - .prettierrc.json | 7 - .size-limit.json | 31 + CHANGELOG.md | 167 +- CODE_OF_CONDUCT.md | 46 + CONTRIBUTING.md | 64 - LICENSE.md => LICENSE | 2 +- README.md | 120 +- SECURITY.md | 57 + assets/readme/biconomy-client-sdk.png | Bin 61005 -> 0 bytes assets/readme/biconomy-sdk.png | Bin 163491 -> 0 bytes biome.json | 46 + bun.lockb | Bin 0 -> 262560 bytes jest.config.e2e.ts | 6 - jest.config.ts | 198 - lerna.json | 11 - link.sh | 5 - linkAll.sh | 3 - package.json | 171 +- packages/account/.esbuild.js | 58 - packages/account/CHANGELOG.md | 166 - packages/account/Readme.md | 138 - packages/account/package.json | 77 - packages/account/src/index.ts | 49 - packages/account/src/utils/Types.ts | 313 - packages/account/src/utils/Utils.ts | 105 - packages/account/src/utils/index.ts | 3 - packages/account/tests/account.e2e.spec.ts | 995 -- .../tests/account.optimism.e2e.spec.ts | 118 - .../account/tests/account.read.e2e.spec.ts | 108 - packages/account/tests/account.spec.ts | 283 - packages/account/tests/utils.spec.ts | 130 - packages/account/tsconfig.build.json | 32 - packages/account/tsconfig.json | 13 - packages/bundler/.esbuild.js | 58 - packages/bundler/CHANGELOG.md | 94 - packages/bundler/Readme.md | 99 - packages/bundler/package.json | 69 - packages/bundler/src/index.ts | 8 - packages/bundler/src/interfaces/IBundler.ts | 21 - packages/bundler/src/utils/Utils.ts | 22 - packages/bundler/tests/bundler.e2e.spec.ts | 19 - packages/bundler/tests/bundler.spec.ts | 14 - packages/bundler/tsconfig.build.json | 32 - packages/bundler/tsconfig.json | 13 - packages/common/.esbuild.js | 58 - packages/common/README.md | 11 - packages/common/package.json | 67 - packages/common/src/index.ts | 6 - packages/common/src/utils/Constants.ts | 7 - packages/common/src/utils/EthersSigner.ts | 39 - .../common/src/utils/Helpers/convertSigner.ts | 62 - packages/common/src/utils/Helpers/index.ts | 1 - packages/common/src/utils/HttpRequests.ts | 65 - packages/common/src/utils/Types.ts | 23 - packages/common/tsconfig.build.json | 32 - packages/common/tsconfig.json | 13 - packages/modules/.esbuild.js | 58 - packages/modules/CHANGELOG.md | 64 - packages/modules/README.md | 0 packages/modules/package.json | 70 - packages/modules/src/BaseValidationModule.ts | 46 - .../modules/src/BatchedSessionRouterModule.ts | 278 - .../modules/src/MultichainValidationModule.ts | 163 - packages/modules/src/index.ts | 26 - .../src/interfaces/IValidationModule.ts | 11 - .../session-storage/SessionLocalStorage.ts | 179 - packages/modules/src/utils/Constants.ts | 53 - packages/modules/src/utils/Helper.ts | 74 - ...batchedSessionValidationModule.e2e.spec.ts | 217 - .../tests/ecdsaValidationModule.e2e.spec.ts | 63 - packages/modules/tests/modules.e2e.spec.ts | 62 - packages/modules/tests/modules.spec.ts | 48 - .../multiChainValidationModule.e2e.spec.ts | 122 - .../tests/sessionValidationModule.e2e.spec.ts | 166 - packages/modules/tests/utils/customSession.ts | 230 - .../tests/utils/sessionStorageData/.gitkeep | 0 packages/modules/tsconfig.build.json | 32 - packages/modules/tsconfig.json | 13 - packages/particle-auth/.esbuild.js | 58 - packages/particle-auth/CHANGELOG.md | 66 - packages/particle-auth/README.md | 41 - packages/particle-auth/package.json | 68 - packages/particle-auth/src/index.ts | 4 - .../particle-auth/tests/particle-auth.spec.ts | 5 - packages/particle-auth/tsconfig.build.json | 32 - packages/particle-auth/tsconfig.json | 12 - packages/paymaster/.esbuild.js | 58 - packages/paymaster/CHANGELOG.md | 78 - packages/paymaster/Readme.md | 74 - packages/paymaster/package.json | 66 - packages/paymaster/src/index.ts | 8 - .../src/interfaces/IHybridPaymaster.ts | 16 - .../paymaster/src/interfaces/IPaymaster.ts | 8 - packages/paymaster/src/utils/Types.ts | 176 - .../paymaster/tests/paymaster.e2e.spec.ts | 19 - packages/paymaster/tests/paymaster.spec.ts | 14 - packages/paymaster/tsconfig.build.json | 32 - packages/paymaster/tsconfig.json | 12 - packages/transak/.esbuild.js | 58 - packages/transak/CHANGELOG.md | 62 - packages/transak/README.md | 13 - packages/transak/package.json | 65 - packages/transak/src/index.ts | 42 - packages/transak/src/interface.ts | 64 - packages/transak/tests/transak.spec.ts | 5 - packages/transak/tsconfig.build.json | 32 - packages/transak/tsconfig.json | 13 - rebuild.sh | 43 - src/account/BaseSmartContractAccount.ts | 354 + .../account}/BiconomySmartAccountV2.ts | 1422 ++- .../src/abi => src/account}/Factory.ts | 68 +- .../src/abi => src/account}/SmartAccount.ts | 446 +- .../account}/abi/AccountResolver.ts | 62 +- src/account/abi/EntryPointAbi.ts | 1309 +++ src/account/abi/Factory.ts | 141 + src/account/abi/SmartAccount.ts | 636 ++ src/account/index.ts | 11 + src/account/signers/local-account.ts | 55 + src/account/signers/wallet-client.ts | 48 + .../src => src/account}/utils/Constants.ts | 89 +- src/account/utils/EthersSigner.ts | 41 + src/account/utils/HttpRequests.ts | 72 + .../src => src/account}/utils/Logger.ts | 28 +- src/account/utils/Types.ts | 597 + src/account/utils/Utils.ts | 160 + src/account/utils/convertSigner.ts | 101 + src/account/utils/getChain.ts | 18 + src/account/utils/index.ts | 8 + .../bundler/src => src/bundler}/Bundler.ts | 314 +- src/bundler/IBundler.ts | 26 + src/bundler/index.ts | 8 + src/bundler/interfaces/IBundler.ts | 29 + .../src => src/bundler}/utils/Constants.ts | 25 +- .../bundler}/utils/HelperFunction.ts | 26 +- .../src => src/bundler}/utils/Types.ts | 158 +- src/bundler/utils/Utils.ts | 23 + src/bundler/utils/getAAError.ts | 68 + src/index.ts | 4 + src/modules/BaseValidationModule.ts | 51 + src/modules/BatchedSessionRouterModule.ts | 363 + .../ECDSAOwnershipValidationModule.ts | 103 +- src/modules/MultichainValidationModule.ts | 212 + .../modules}/PasskeyValidationModule.ts | 0 .../modules}/SessionKeyManagerModule.ts | 283 +- src/modules/index.ts | 30 + .../modules}/interfaces/ISessionStorage.ts | 57 +- .../interfaces/ISessionValidationModule.ts | 4 +- src/modules/interfaces/IValidationModule.ts | 11 + .../session-storage/SessionFileStorage.ts | 273 + .../session-storage/SessionLocalStorage.ts | 208 + .../session-storage/SessionMemoryStorage.ts | 219 + .../ERC20SessionValidationModule.ts | 60 +- src/modules/utils/Constants.ts | 35 + src/modules/utils/Helper.ts | 105 + .../src => src/modules}/utils/Types.ts | 165 +- .../modules/src => src/modules}/utils/Uid.ts | 12 +- .../paymaster}/BiconomyPaymaster.ts | 337 +- src/paymaster/index.ts | 8 + src/paymaster/interfaces/IHybridPaymaster.ts | 29 + src/paymaster/interfaces/IPaymaster.ts | 12 + .../src => src/paymaster}/utils/Constants.ts | 11 +- .../src => src/paymaster}/utils/Helpers.ts | 4 +- src/paymaster/utils/Types.ts | 125 + tests/account/read.test.ts | 705 ++ tests/account/write.test.ts | 264 + tests/bundler/read.test.ts | 202 + tests/bundler/write.test.ts | 119 + tests/chains.config.ts | 61 - tests/globalSetup.ts | 5 + tests/index.d.ts | 29 - tests/modules/read.test.ts | 247 + tests/modules/write.test.ts | 585 + tests/paymaster/read.test.ts | 145 + tests/paymaster/write.test.ts | 303 + tests/setup-e2e-tests.ts | 150 - tests/setup-unit-tests.ts | 64 - tests/setupFiles.ts | 9 + tests/utils.ts | 223 +- tests/vitest.config.ts | 35 + tsconfig.eslint.json | 4 - tsconfig.json | 22 - tsconfig.settings.json | 27 - tsconfig/tsconfig.base.json | 32 + tsconfig/tsconfig.cjs.json | 10 + tsconfig/tsconfig.esm.json | 8 + tsconfig/tsconfig.json | 16 + tsconfig/tsconfig.types.json | 12 + packages/account/typedoc.json => typedoc.json | 0 yarn.lock | 9707 ----------------- 222 files changed, 11595 insertions(+), 18961 deletions(-) create mode 100644 .changeset/README.md create mode 100644 .changeset/config.json delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 .github/ISSUE_TEMPLATE/1_general_issue.yml rename .github/ISSUE_TEMPLATE/{bug_report.yml => 2_bug_report.yml} (94%) create mode 100644 .github/ISSUE_TEMPLATE/3_feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/4_security_report.yml create mode 100644 .github/ISSUE_TEMPLATE/5_document_improvement.yml create mode 100644 .github/ISSUE_TEMPLATE/6_build_deployment_issue.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/actions/build/action.yml create mode 100644 .github/actions/install-dependencies/action.yml delete mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/check_branch_name.yml create mode 100644 .github/workflows/coverage.yml delete mode 100644 .github/workflows/mainnet_tests.yml delete mode 100644 .github/workflows/mark_stale.yml create mode 100644 .github/workflows/pr-lint.yml delete mode 100644 .github/workflows/pull_request_approved.yml delete mode 100644 .github/workflows/push_check.yml create mode 100644 .github/workflows/size-report.yml create mode 100644 .github/workflows/test-read.yml create mode 100644 .github/workflows/test-write.yml delete mode 100644 .nvmrc delete mode 100644 .nycrc.json delete mode 100644 .prettierignore delete mode 100644 .prettierrc.json create mode 100644 .size-limit.json create mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md rename LICENSE.md => LICENSE (97%) create mode 100644 SECURITY.md delete mode 100644 assets/readme/biconomy-client-sdk.png delete mode 100644 assets/readme/biconomy-sdk.png create mode 100644 biome.json create mode 100755 bun.lockb delete mode 100644 jest.config.e2e.ts delete mode 100644 jest.config.ts delete mode 100644 lerna.json delete mode 100755 link.sh delete mode 100755 linkAll.sh delete mode 100644 packages/account/.esbuild.js delete mode 100644 packages/account/CHANGELOG.md delete mode 100644 packages/account/Readme.md delete mode 100644 packages/account/package.json delete mode 100644 packages/account/src/index.ts delete mode 100644 packages/account/src/utils/Types.ts delete mode 100644 packages/account/src/utils/Utils.ts delete mode 100644 packages/account/src/utils/index.ts delete mode 100644 packages/account/tests/account.e2e.spec.ts delete mode 100644 packages/account/tests/account.optimism.e2e.spec.ts delete mode 100644 packages/account/tests/account.read.e2e.spec.ts delete mode 100644 packages/account/tests/account.spec.ts delete mode 100644 packages/account/tests/utils.spec.ts delete mode 100644 packages/account/tsconfig.build.json delete mode 100644 packages/account/tsconfig.json delete mode 100644 packages/bundler/.esbuild.js delete mode 100644 packages/bundler/CHANGELOG.md delete mode 100644 packages/bundler/Readme.md delete mode 100644 packages/bundler/package.json delete mode 100644 packages/bundler/src/index.ts delete mode 100644 packages/bundler/src/interfaces/IBundler.ts delete mode 100644 packages/bundler/src/utils/Utils.ts delete mode 100644 packages/bundler/tests/bundler.e2e.spec.ts delete mode 100644 packages/bundler/tests/bundler.spec.ts delete mode 100644 packages/bundler/tsconfig.build.json delete mode 100644 packages/bundler/tsconfig.json delete mode 100644 packages/common/.esbuild.js delete mode 100644 packages/common/README.md delete mode 100644 packages/common/package.json delete mode 100644 packages/common/src/index.ts delete mode 100644 packages/common/src/utils/Constants.ts delete mode 100644 packages/common/src/utils/EthersSigner.ts delete mode 100644 packages/common/src/utils/Helpers/convertSigner.ts delete mode 100644 packages/common/src/utils/Helpers/index.ts delete mode 100644 packages/common/src/utils/HttpRequests.ts delete mode 100644 packages/common/src/utils/Types.ts delete mode 100644 packages/common/tsconfig.build.json delete mode 100644 packages/common/tsconfig.json delete mode 100644 packages/modules/.esbuild.js delete mode 100644 packages/modules/CHANGELOG.md delete mode 100644 packages/modules/README.md delete mode 100644 packages/modules/package.json delete mode 100644 packages/modules/src/BaseValidationModule.ts delete mode 100644 packages/modules/src/BatchedSessionRouterModule.ts delete mode 100644 packages/modules/src/MultichainValidationModule.ts delete mode 100644 packages/modules/src/index.ts delete mode 100644 packages/modules/src/interfaces/IValidationModule.ts delete mode 100644 packages/modules/src/session-storage/SessionLocalStorage.ts delete mode 100644 packages/modules/src/utils/Constants.ts delete mode 100644 packages/modules/src/utils/Helper.ts delete mode 100644 packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts delete mode 100644 packages/modules/tests/ecdsaValidationModule.e2e.spec.ts delete mode 100644 packages/modules/tests/modules.e2e.spec.ts delete mode 100644 packages/modules/tests/modules.spec.ts delete mode 100644 packages/modules/tests/multiChainValidationModule.e2e.spec.ts delete mode 100644 packages/modules/tests/sessionValidationModule.e2e.spec.ts delete mode 100644 packages/modules/tests/utils/customSession.ts delete mode 100644 packages/modules/tests/utils/sessionStorageData/.gitkeep delete mode 100644 packages/modules/tsconfig.build.json delete mode 100644 packages/modules/tsconfig.json delete mode 100644 packages/particle-auth/.esbuild.js delete mode 100644 packages/particle-auth/CHANGELOG.md delete mode 100644 packages/particle-auth/README.md delete mode 100644 packages/particle-auth/package.json delete mode 100644 packages/particle-auth/src/index.ts delete mode 100644 packages/particle-auth/tests/particle-auth.spec.ts delete mode 100644 packages/particle-auth/tsconfig.build.json delete mode 100644 packages/particle-auth/tsconfig.json delete mode 100644 packages/paymaster/.esbuild.js delete mode 100644 packages/paymaster/CHANGELOG.md delete mode 100644 packages/paymaster/Readme.md delete mode 100644 packages/paymaster/package.json delete mode 100644 packages/paymaster/src/index.ts delete mode 100644 packages/paymaster/src/interfaces/IHybridPaymaster.ts delete mode 100644 packages/paymaster/src/interfaces/IPaymaster.ts delete mode 100644 packages/paymaster/src/utils/Types.ts delete mode 100644 packages/paymaster/tests/paymaster.e2e.spec.ts delete mode 100644 packages/paymaster/tests/paymaster.spec.ts delete mode 100644 packages/paymaster/tsconfig.build.json delete mode 100644 packages/paymaster/tsconfig.json delete mode 100644 packages/transak/.esbuild.js delete mode 100644 packages/transak/CHANGELOG.md delete mode 100644 packages/transak/README.md delete mode 100644 packages/transak/package.json delete mode 100644 packages/transak/src/index.ts delete mode 100644 packages/transak/src/interface.ts delete mode 100644 packages/transak/tests/transak.spec.ts delete mode 100644 packages/transak/tsconfig.build.json delete mode 100644 packages/transak/tsconfig.json delete mode 100755 rebuild.sh create mode 100644 src/account/BaseSmartContractAccount.ts rename {packages/account/src => src/account}/BiconomySmartAccountV2.ts (55%) rename {packages/account/src/abi => src/account}/Factory.ts (76%) rename {packages/account/src/abi => src/account}/SmartAccount.ts (58%) rename {packages/account/src => src/account}/abi/AccountResolver.ts (81%) create mode 100644 src/account/abi/EntryPointAbi.ts create mode 100644 src/account/abi/Factory.ts create mode 100644 src/account/abi/SmartAccount.ts create mode 100644 src/account/index.ts create mode 100644 src/account/signers/local-account.ts create mode 100644 src/account/signers/wallet-client.ts rename {packages/account/src => src/account}/utils/Constants.ts (58%) create mode 100644 src/account/utils/EthersSigner.ts create mode 100644 src/account/utils/HttpRequests.ts rename {packages/common/src => src/account}/utils/Logger.ts (69%) create mode 100644 src/account/utils/Types.ts create mode 100644 src/account/utils/Utils.ts create mode 100644 src/account/utils/convertSigner.ts create mode 100644 src/account/utils/getChain.ts create mode 100644 src/account/utils/index.ts rename {packages/bundler/src => src/bundler}/Bundler.ts (55%) create mode 100644 src/bundler/IBundler.ts create mode 100644 src/bundler/index.ts create mode 100644 src/bundler/interfaces/IBundler.ts rename {packages/bundler/src => src/bundler}/utils/Constants.ts (61%) rename {packages/bundler/src => src/bundler}/utils/HelperFunction.ts (52%) rename {packages/bundler/src => src/bundler}/utils/Types.ts (51%) create mode 100644 src/bundler/utils/Utils.ts create mode 100644 src/bundler/utils/getAAError.ts create mode 100644 src/index.ts create mode 100644 src/modules/BaseValidationModule.ts create mode 100644 src/modules/BatchedSessionRouterModule.ts rename {packages/modules/src => src/modules}/ECDSAOwnershipValidationModule.ts (55%) create mode 100644 src/modules/MultichainValidationModule.ts rename {packages/modules/src => src/modules}/PasskeyValidationModule.ts (100%) rename {packages/modules/src => src/modules}/SessionKeyManagerModule.ts (54%) create mode 100644 src/modules/index.ts rename {packages/modules/src => src/modules}/interfaces/ISessionStorage.ts (71%) rename {packages/modules/src => src/modules}/interfaces/ISessionValidationModule.ts (84%) create mode 100644 src/modules/interfaces/IValidationModule.ts create mode 100644 src/modules/session-storage/SessionFileStorage.ts create mode 100644 src/modules/session-storage/SessionLocalStorage.ts create mode 100644 src/modules/session-storage/SessionMemoryStorage.ts rename {packages/modules/src => src/modules}/session-validation-modules/ERC20SessionValidationModule.ts (54%) create mode 100644 src/modules/utils/Constants.ts create mode 100644 src/modules/utils/Helper.ts rename {packages/modules/src => src/modules}/utils/Types.ts (58%) rename {packages/modules/src => src/modules}/utils/Uid.ts (62%) rename {packages/paymaster/src => src/paymaster}/BiconomyPaymaster.ts (55%) create mode 100644 src/paymaster/index.ts create mode 100644 src/paymaster/interfaces/IHybridPaymaster.ts create mode 100644 src/paymaster/interfaces/IPaymaster.ts rename {packages/paymaster/src => src/paymaster}/utils/Constants.ts (83%) rename {packages/paymaster/src => src/paymaster}/utils/Helpers.ts (77%) create mode 100644 src/paymaster/utils/Types.ts create mode 100644 tests/account/read.test.ts create mode 100644 tests/account/write.test.ts create mode 100644 tests/bundler/read.test.ts create mode 100644 tests/bundler/write.test.ts delete mode 100644 tests/chains.config.ts create mode 100644 tests/globalSetup.ts delete mode 100644 tests/index.d.ts create mode 100644 tests/modules/read.test.ts create mode 100644 tests/modules/write.test.ts create mode 100644 tests/paymaster/read.test.ts create mode 100644 tests/paymaster/write.test.ts delete mode 100644 tests/setup-e2e-tests.ts delete mode 100644 tests/setup-unit-tests.ts create mode 100644 tests/setupFiles.ts create mode 100644 tests/vitest.config.ts delete mode 100644 tsconfig.eslint.json delete mode 100644 tsconfig.json delete mode 100644 tsconfig.settings.json create mode 100644 tsconfig/tsconfig.base.json create mode 100644 tsconfig/tsconfig.cjs.json create mode 100644 tsconfig/tsconfig.esm.json create mode 100644 tsconfig/tsconfig.json create mode 100644 tsconfig/tsconfig.types.json rename packages/account/typedoc.json => typedoc.json (100%) delete mode 100644 yarn.lock diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 000000000..e5b6d8d6a --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000..765c9d223 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { + "onlyUpdatePeerDependentsWhenOutOfRange": true + }, + "ignore": [] +} diff --git a/.env.example b/.env.example index fdf442b9d..764c9ab79 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ E2E_PRIVATE_KEY_ONE= E2E_PRIVATE_KEY_TWO= -E2E_BICO_PAYMASTER_KEY_MUMBAI= +BUNDLER_URL=https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 +E2E_BICO_PAYMASTER_KEY_AMOY= E2E_BICO_PAYMASTER_KEY_BASE= -E2E_BICO_PAYMASTER_KEY_OP= -BICONOMY_SDK_DEBUG=true -WITH_MAINNET_TESTS=false \ No newline at end of file +CHAIN_ID=80002 +CODECOV_TOKEN= \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index bc013db12..000000000 --- a/.eslintignore +++ /dev/null @@ -1,14 +0,0 @@ -# Ignore node_modules in the root and in all packages -**/node_modules/ - -# Ignore build or dist directories -**/dist/ -**/build/ -**/coverage/ - -# Ignore any auto-generated files -**/typechain/ - -# Ignore any config files -*.config.js -*.config.ts \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index ce0d3c84a..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,49 +0,0 @@ -module.exports = { - parser: "@typescript-eslint/parser", - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "airbnb-typescript/base", - "plugin:import/typescript", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:prettier/recommended", - ], - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - project: "./tsconfig.eslint.json", - }, - env: { - node: true, - es6: true, - }, - plugins: ["@typescript-eslint", "prettier", "security", "import"], - rules: { - "prettier/prettier": "error", - "no-var": "error", - "prefer-const": "error", - "no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], // needs to be set to "error" later - "no-console": "warn", - "@typescript-eslint/naming-convention": "off", // needs to be removed later - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - "security/detect-object-injection": "warn", - "security/detect-unsafe-regex": "error", - "security/detect-object-injection": "off", // turning off Injection Sink rule - "@typescript-eslint/no-throw-literal": "off", // temp deactivated needs to be removed once fixed - "@typescript-eslint/ban-ts-ignore": "off", - "@typescript-eslint/ban-ts-comment": "off", - "import/extensions": ["error", "ignorePackages"], - "import/no-unresolved": "off", - }, - settings: {}, - overrides: [ - { - files: ["*.ts", "*.tsx"], - rules: { - "@typescript-eslint/explicit-function-return-type": ["warn", { allowExpressions: true }], - }, - }, - ], -}; diff --git a/.github/ISSUE_TEMPLATE/1_general_issue.yml b/.github/ISSUE_TEMPLATE/1_general_issue.yml new file mode 100644 index 000000000..1e2fac688 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_general_issue.yml @@ -0,0 +1,26 @@ +name: 💡 General Inquiry & Suggestions +description: Share general questions or suggestions that don't fit other categories +title: "[GENERAL] " +labels: ["question", "enhancement"] +body: + - type: markdown + attributes: + value: "Got a question or suggestion? We're all ears!" + - type: textarea + attributes: + label: Inquiry or Suggestion + description: What would you like to share with us? + placeholder: "I'm wondering about..." + validations: + required: false + - type: input + attributes: + label: Relevant Links or References + description: Optionally, add any relevant links or references. + placeholder: "e.g., https://github.com/example" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/2_bug_report.yml similarity index 94% rename from .github/ISSUE_TEMPLATE/bug_report.yml rename to .github/ISSUE_TEMPLATE/2_bug_report.yml index 45f4d6bf0..038107e78 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/2_bug_report.yml @@ -1,6 +1,7 @@ -name: Bug Report -description: File a bug/issue -title: "bug: " +name: 🐛 Bug Report & Test Failures +description: Report unexpected behaviors or failing tests +title: "[BUG] " +labels: ["bug", "help wanted"] body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/3_feature_request.yml b/.github/ISSUE_TEMPLATE/3_feature_request.yml new file mode 100644 index 000000000..9d1cc0b6e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_feature_request.yml @@ -0,0 +1,31 @@ +name: ✨ Feature Requests & Performance Improvements +description: Suggest a new feature or performance enhancement +title: "[FEATURE] " +labels: ["enhancement", "good first issue"] +body: + - type: markdown + attributes: + value: "Your suggestions inspire us to improve. Share your ideas below!" + - type: input + attributes: + label: Feature or Improvement Description + description: Describe the feature or improvement you're suggesting. + placeholder: "e.g., Add support for platform Z." + validations: + required: true + - type: textarea + attributes: + label: Benefits & Outcomes + description: Explain the benefits of your suggestion and the expected outcomes. + placeholder: "This improvement will improve performance by 30%..." + - type: input + attributes: + label: Any References? + description: Provide links or references to similar features or standards. + placeholder: "EIP-1234, https://github.com/example" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/4_security_report.yml b/.github/ISSUE_TEMPLATE/4_security_report.yml new file mode 100644 index 000000000..6fc0ef4fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_security_report.yml @@ -0,0 +1,31 @@ +name: 🔒 Security Pre-Screening +description: Pre-screening for security-related reports +title: "[SECURITY PRE-SCREEN] " +labels: ["security", "triage needed"] +body: + - type: markdown + attributes: + value: "Security is our top priority. If you've discovered a potential security issue please proceed." + - type: checkboxes + attributes: + label: Security Level Acknowledgement + options: + - label: "I understand this issue will be public. It is NOT critical or high risk and does not endanger deployed contracts. If it is please email: security@biconomy.io" + required: true + - type: input + attributes: + label: Overview + description: Provide a summary of the non-critical security concern or question. + placeholder: "e.g., Questions about the audit process." + validations: + required: true + - type: textarea + attributes: + label: Additional Details + description: Offer more detail on your concern or question. + placeholder: "Provide any additional context..." + - type: input + attributes: + label: Suggestions for Mitigation + description: (Optional) Suggest ways to address the concern. + placeholder: "Potential mitigation steps include..." diff --git a/.github/ISSUE_TEMPLATE/5_document_improvement.yml b/.github/ISSUE_TEMPLATE/5_document_improvement.yml new file mode 100644 index 000000000..a4b0b5257 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/5_document_improvement.yml @@ -0,0 +1,33 @@ +name: 📚 Documentation Improvement +description: Propose improvements or report issues with documentation +title: "[DOCS] " +labels: ["documentation"] +body: + - type: markdown + attributes: + value: "Help us enhance our documentation for everyone." + - type: input + attributes: + label: Documentation Page/Section + description: Which page or section are you referring to? + placeholder: "e.g., README.md, TSDoc guidelines." + validations: + required: true + - type: textarea + attributes: + label: Suggested Improvements + description: Detail the improvements or corrections needed. + placeholder: "The section on XYZ could clarify..." + validations: + required: true + - type: input + attributes: + label: Additional Comments + description: Any other comments or suggestions? + placeholder: "Consider adding examples for..." + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml new file mode 100644 index 000000000..e0034b17e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml @@ -0,0 +1,33 @@ +name: 🛠 Build & Deployment Issues +description: Report issues +title: "[BUILD/DEPLOY] " +labels: ["bug", "help wanted"] +body: + - type: markdown + attributes: + value: "Help us identify build or deployment problems to improve our processes." + - type: input + attributes: + label: Issue Summary + description: Briefly describe the issue encountered. + placeholder: "e.g., Failed to deploy contract due to..." + validations: + required: true + - type: textarea + attributes: + label: Error Logs & Messages + description: Provide any error logs or messages seen. + placeholder: "Error: Failed to..." + validations: + required: true + - type: input + attributes: + label: Environment & Tools + description: Mention the tools and environment where the issue occurred. + placeholder: "e.g., Truffle v5.3, Rinkeby testnet" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 5b7de7d5d..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Ask Question - url: https://github.com/bcnmy/biconomy-client-sdk/discussions - about: Ask questions and discuss with other community members - - name: Request Feature - url: https://github.com/bcnmy/biconomy-client-sdk/discussions - about: Requests features or brainstorm ideas for new functionality diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 3e93355fb..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Feature Request -about: Propose an enhancement or new feature to improve the project -title: "Feature: <Your Feature>" -labels: feature-request, needs-review -assignees: "" ---- - -**Problem You're Facing** - -<!-- Briefly describe the problem you're trying to solve or the limitation you've encountered. --> - -**Proposed Solution** - -<!-- What would you like to see happen? --> - -**Alternatives Considered** - -<!-- Any other solutions or features you've considered. --> - -## Use Cases - -<!-- Help us understand the broader context by providing some typical use cases where this feature would be helpful. --> - -**Additional Info** - -<!-- Provide any additional details, context, or screenshots about the feature request. --> diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 000000000..fca427abe --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,22 @@ +## Pull Request for Smart Contract Improvement + +**Describe your changes:** + +<!-- Briefly describe what you're changing or fixing. --> + +**Link any related issues:** + +<!-- Link any related issues here. --> + +**Testing:** + +<!-- Describe how the changes were tested. Include steps if applicable. --> + +**Note:** Please ensure all tests and lint checks pass before requesting a review. If there are any errors, fix them prior to submission. + +**Checklist:** + +- [ ] I have performed a self-review of my own code. +- [ ] I have added tests that prove my fix is effective or that my feature works. +- [ ] I have made corresponding changes to the documentation, if applicable. +- [ ] My changes generate no new warnings or errors. diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 000000000..1cd962cb5 --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,16 @@ +name: "Build" +description: "Prepare repository, all dependencies and build" + +runs: + using: "composite" + steps: + - name: Set up Bun + uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + shell: bash + run: bun install --frozen-lockfile + + - name: Build + shell: bash + run: bun run build diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml new file mode 100644 index 000000000..303914370 --- /dev/null +++ b/.github/actions/install-dependencies/action.yml @@ -0,0 +1,14 @@ +name: "Install dependencies" +description: "Prepare repository and all dependencies" + +runs: + using: "composite" + steps: + - name: Set up Bun + uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + shell: bash + run: | + bun install buffer + bun install --frozen-lockfile diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 9b66596c9..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,35 +0,0 @@ -# Summary - -<!-- Please provide a brief summary of the changes and the issue number this PR addresses. --> - -Related Issue: # (issue number) - -## Change Type - -- [ ] Bug Fix -- [ ] Refactor -- [ ] New Feature -- [ ] Breaking Change -- [ ] Documentation Update -- [ ] Performance Improvement -- [ ] Other - -# Checklist - -- [ ] My code follows this project's style guidelines -- [ ] I've reviewed my own code -- [ ] I've added comments for any hard-to-understand areas -- [ ] I've updated the documentation if necessary -- [ ] My changes generate no new warnings -- [ ] I've added tests that prove my fix is effective or my feature works -- [ ] All unit tests pass locally with my changes -- [ ] Any dependent changes have been merged and published - -# Additional Information - -<!-- Any additional information or context about the PR. --> - -# Branch Naming - -<!-- Make sure your branch name follows the pattern: `features/`, `fixes/`, or `releases/`. --> -<!-- **Note**: The person creating the PR is responsible for merging and deleting the branch. Ensure the code has been tested, commented, linted, and documents updated if needed. --> diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..08c18cd34 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,14 @@ +name: build +on: + workflow_dispatch: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] +jobs: + build: + name: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Build + uses: ./.github/actions/build diff --git a/.github/workflows/check_branch_name.yml b/.github/workflows/check_branch_name.yml deleted file mode 100644 index 39422432d..000000000 --- a/.github/workflows/check_branch_name.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Check Branch Name - -on: - create: - types: [branch] - -jobs: - check-branch-name: - runs-on: ubuntu-latest - if: github.event.ref_type == 'branch' - steps: - - name: Ensure branch name follows GitFlow conventions - run: | - BRANCH_NAME="${{ github.ref#refs/heads/ }}" - echo "Created branch: $BRANCH_NAME" - - # Checking against GitFlow naming conventions for branches - if [[ ! $BRANCH_NAME =~ ^(features/|fixes/|releases/) ]]; then - echo "error: Branch names should follow GitFlow naming convention (features/, fixes/, releases/)." - exit 1 - fi diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 000000000..653e7b1e3 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,44 @@ +name: coverage +on: + workflow_dispatch: + push: + branches: + - main +jobs: + coverage: + name: coverage + permissions: write-all + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Run the tests + run: bun run test:coverage + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 + + - name: report coverage + uses: davelosert/vitest-coverage-report-action@v2 + with: + json-summary-path: ./coverage/coverage-summary.json + json-final-path: "./coverage/coverage-final.json" + vite-config-path: ./tests/vitest.config.ts + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + slug: bcnmy/biconomy-client-sdk diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 188b963b1..078b083ba 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,26 +1,30 @@ -name: Build and Deploy Documentation +name: deploy docs on: workflow_dispatch: push: branches: - - docs + - main permissions: contents: write jobs: - build-docs-and-deploy: + deploy-docs: runs-on: ubuntu-latest steps: - - name: Checkout 🛎️ - uses: actions/checkout@v3 + - uses: actions/checkout@v3 + - run: git config --global user.email "gh@runner.com" + - run: git config --global user.name "gh-runner" - - name: Install and Build - run: | - yarn - yarn build - yarn --cwd ./packages/account docs + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Set remote url + run: git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/bcnmy/biconomy-client-sdk.git + + - name: Run the tests + run: bun run docs:deploy - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@v4 with: - folder: ./packages/account/docs + folder: ./docs diff --git a/.github/workflows/mainnet_tests.yml b/.github/workflows/mainnet_tests.yml deleted file mode 100644 index 3118a1e94..000000000 --- a/.github/workflows/mainnet_tests.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: E2E Test workflow - with mainnet tests -on: - workflow_dispatch: -jobs: - e2e_test: - name: E2E tests - with mainnet tests - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - - steps: - - name: Checkout - uses: "actions/checkout@main" - - - name: Set Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: yarn install --frozen-lockfile && yarn build - - - name: Run tests - env: - E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} - E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} - E2E_BICO_PAYMASTER_KEY_MUMBAI: ${{ secrets.E2E_BICO_PAYMASTER_KEY_MUMBAI }} - E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} - E2E_BICO_PAYMASTER_KEY_OP: ${{ secrets.E2E_BICO_PAYMASTER_KEY_OP }} - WITH_MAINNET_TESTS: true - run: yarn test:e2e diff --git a/.github/workflows/mark_stale.yml b/.github/workflows/mark_stale.yml deleted file mode 100644 index 1864296c5..000000000 --- a/.github/workflows/mark_stale.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Mark Inactive Issues and PRs - -on: - schedule: - - cron: "0 0 * * *" - -jobs: - stale: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/stale@v5 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: "This issue has been inactive for 30 days. It will be closed due to inactivity. If this issue is still relevant, please comment to keep it open. Alternatively, you can create a new issue with updated information." - stale-pr-message: "This PR has been inactive for 30 days. If it's waiting for a review, please reach out to the team. Otherwise, please update the PR or it will be closed due to inactivity." - stale-issue-label: "inactive-issue" - stale-pr-label: "inactive-pr" - days-before-stale: 30 diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 000000000..3e77f7837 --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,17 @@ +name: pr lint +on: + workflow_dispatch: + pull_request: + types: [opened, reopened, synchronize, ready_for_review, edited] +jobs: + enforce_title: + name: pr lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Use commitlint to check PR title + run: echo "${{ github.event.pull_request.title }}" | bun commitlint diff --git a/.github/workflows/pull_request_approved.yml b/.github/workflows/pull_request_approved.yml deleted file mode 100644 index 84688b90b..000000000 --- a/.github/workflows/pull_request_approved.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: E2E Test workflow -on: - pull_request_review: - types: [submitted] - workflow_dispatch: -jobs: - e2e_test: - if: github.event.review.state == 'approved' - name: E2E tests - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - - steps: - - name: Checkout - uses: "actions/checkout@main" - - - name: Set Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: yarn install --frozen-lockfile && yarn build - - - name: Run tests - env: - E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} - E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} - E2E_BICO_PAYMASTER_KEY_MUMBAI: ${{ secrets.E2E_BICO_PAYMASTER_KEY_MUMBAI }} - E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} - E2E_BICO_PAYMASTER_KEY_OP: ${{ secrets.E2E_BICO_PAYMASTER_KEY_OP }} - run: yarn test:e2e diff --git a/.github/workflows/push_check.yml b/.github/workflows/push_check.yml deleted file mode 100644 index 35705a430..000000000 --- a/.github/workflows/push_check.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Test workflow -on: [push, workflow_dispatch] - -jobs: - lint: - name: Lint sources - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - - steps: - - name: Checkout - uses: "actions/checkout@main" - - - name: Set Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Install dependencies - run: yarn install --frozen-lockfile - - name: Lint sources - run: yarn run lint - - unit_test: - name: Unit tests - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - - steps: - - name: Checkout - uses: "actions/checkout@main" - - - name: Set Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: yarn install --frozen-lockfile && yarn build - - name: Run tests - run: yarn test diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml new file mode 100644 index 000000000..5dabd450e --- /dev/null +++ b/.github/workflows/size-report.yml @@ -0,0 +1,29 @@ +name: size report +on: + workflow_dispatch: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + size-report: + name: size report + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: write-all + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Report bundle size + uses: andresz1/size-limit-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + package_manager: bun diff --git a/.github/workflows/test-read.yml b/.github/workflows/test-read.yml new file mode 100644 index 000000000..a972a2fea --- /dev/null +++ b/.github/workflows/test-read.yml @@ -0,0 +1,28 @@ +name: test:read +on: + workflow_dispatch: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] +jobs: + test-read: + name: test-read + permissions: write-all + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Run the tests + run: bun run test:ci -t=Read + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 diff --git a/.github/workflows/test-write.yml b/.github/workflows/test-write.yml new file mode 100644 index 000000000..12487e077 --- /dev/null +++ b/.github/workflows/test-write.yml @@ -0,0 +1,58 @@ +name: test-write +on: + workflow_dispatch: + pull_request_review: + types: [submitted] +jobs: + test-write: + name: test-write + permissions: write-all + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-test-write + cancel-in-progress: true + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/actions/install-dependencies + + - name: Run the account tests + run: bun run test:ci -t=Account:Write + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 + + - name: Run the bundler tests + run: bun run test:ci -t=Bundler:Write + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 + + - name: Run the paymaster tests + run: bun run test:ci -t=Paymaster:Write + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 + + - name: Run the modules tests + run: bun run test:ci -t=Modules:Write + env: + E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }} + E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }} + BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44 + E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }} + E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }} + CHAIN_ID: 80002 diff --git a/.gitignore b/.gitignore index ac3583499..41980e0af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,75 +1,180 @@ +_cjs +_esm +_types + # Logs + logs -*.log +_.log +npm-debug.log_ yarn-debug.log* yarn-error.log* -lockfiles +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache # Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -# Coverage directory used by tools like istanbul +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover coverage +lib-cov + +# Coverage directory used by tools like istanbul *.lcov # nyc test coverage + .nyc_output -# Compiled binary addons -build/ -dist/ +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release # Dependency directories + node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo # Optional npm cache directory + .npm # Optional eslint cache + .eslintcache +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + # Yarn Integrity file + .yarn-integrity -# dotenv environment variables file +# dotenv environment variable files + .env -.env.test +.env.development.local +.env.test.local +.env.production.local .env.local +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + # Stores VSCode versions used for testing VSCode extensions + .vscode .vscode-test # yarn v2 + .yarn/cache .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz .pnp.* -# macOS +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config .DS_Store -# Hardhat files -cache -artifacts -deployments - -# lockfiles -packages/account/package-lock.json -packages/modules/package-lock.json -packages/bundler/package-lock.json -packages/paymaster/package-lock.json -packages/particle-auth/package-lock.json -packages/transak/package-lock.json -package-lock.json - -#ignore sessionStorageData files -packages/modules/tests/utils/sessionStorageData/* -#except sessionStorageData folder -!packages/modules/tests/utils/sessionStorageData/.gitkeep - -openapi/ - -# docs -packages/account/docs/* \ No newline at end of file +docs + +tests/sessionStorageData \ No newline at end of file diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index b1215e876..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v18.16.0 \ No newline at end of file diff --git a/.nycrc.json b/.nycrc.json deleted file mode 100644 index 5d9f97afe..000000000 --- a/.nycrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "include": ["src/**/*.ts"] -} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index bc013db12..000000000 --- a/.prettierignore +++ /dev/null @@ -1,14 +0,0 @@ -# Ignore node_modules in the root and in all packages -**/node_modules/ - -# Ignore build or dist directories -**/dist/ -**/build/ -**/coverage/ - -# Ignore any auto-generated files -**/typechain/ - -# Ignore any config files -*.config.js -*.config.ts \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 6b3f54736..000000000 --- a/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "printWidth": 150, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "tabWidth": 2 -} diff --git a/.size-limit.json b/.size-limit.json new file mode 100644 index 000000000..86c157518 --- /dev/null +++ b/.size-limit.json @@ -0,0 +1,31 @@ +[ + { + "name": "core (esm)", + "path": "./dist/_esm/index.js", + "limit": "10 kB", + "import": "*" + }, + { + "name": "core (cjs)", + "path": "./dist/_cjs/index.js", + "limit": "25 kB" + }, + { + "name": "smartAccount (tree-shaking)", + "path": "./dist/_esm/index.js", + "limit": "5 kB", + "import": "{ createSmartAccountClient }" + }, + { + "name": "bundler (tree-shaking)", + "path": "./dist/_esm/bundler/index.js", + "limit": "5 kB", + "import": "{ createBundler }" + }, + { + "name": "paymaster (tree-shaking)", + "path": "./dist/_esm/paymaster/index.js", + "limit": "5 kB", + "import": "{ createPaymaster }" + } +] diff --git a/CHANGELOG.md b/CHANGELOG.md index b950ebfb7..34ab2aa28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,162 @@ -# Change Log +# @biconomy/account -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 4.1.1 (2023-07-03) + +- Added missing extensions ([fdbec6](https://github.com/bcnmy/biconomy-client-sdk/pull/451/commits/fdbec68625f4d7f436dc39d4c1779cdbb7c53e6d)) +- Fixed issue reporting format ([815e9440](https://github.com/bcnmy/biconomy-client-sdk/pull/450/commits/815e9440db03ebae98bb24edfcb3bbcabf9b2a61)) + +## 4.1.0 (2023-04-03) + +Features: + +- Added Speed optimisation, removing redundant gasEstimate call to bundler ([2371b2](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2371b230cd5806ec4c7c95ba604d6f924b4be768)) +- Added smartAccount.getBalances() method ([4b8bae](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/4b8bae412577b846e700b168976cefa6b0803ff6)) +- Added smartAccount.getSupportedTokens() method ([6d2fb27](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/6d2fb27d6f9b424e440e45990ea06820a9d16d4b)) +- Added smartAccount.deploy() method ([be9dc4](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/be9dc4d74a3e5a22e69416983436997cf2ea417c)) +- Increased checking of the chainId from the bundler, paymaster and the provider ([5d2f3](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5d2f34d8f0fb4f9ff7c7ddc00336471e57efdcfd)) +- Added entity name to Logger calls ([9278ec](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/9278ecc21e060ef75ab29a0d054d95d69cd4ae27)) +- Export a 'getChain' by id helper, which returns a viem chain ([ab2ba](https://github.com/bcnmy/biconomy-client-sdk/pull/449/commits/ab2ba2c518ce867c52bf90b9018dfc1b4ec3b4d4)) +- Add "stateOverride" optional param ([20fd54](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/20fd54c817d2dcbc6b7d9a247d890d91b19a9c2f)) + +Fixes: + +- Fix for encodeAbiParameters inside batched session module ([b27061](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/b27061e2eec7bafb0620e88e6d94e56e9a13cb76)) +- added flag to skip calldata approval patch ([75698](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/75698c827015533e32acb1f535bdf6b738876217)) +- Fixed the particle auth build + +Chores: + +- Added tests for ecdsa module ([1a8f29](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/1a8f296c26c9fedd57023f8f6423d7662a3adfee)) +- Increased test coverage ([329003](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/329003cebb6b4034496e41651985804cdec0d311)) +- Improved issue reporting guidelines ([8b9fb5d](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/8b9fb5de9556870611307c12e57df333619d9252)) +- Added e2e tests for optimism, ran from GH actions ([5051ba](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5051ba5ff14220ad616f1ec3bc93a3f42d6f8887)) +- Added ABI SVM test ([49c96](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/49c968220e2db0aeee5cc6419f45df2b98f9792c)) +- Added tests for batched session router testing ([2eb9765](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2eb9765d066fcb7b35d08223257aeb9b38c7a78b)) + +## 4.0.3 (2023-28-02) + +VERSION Bump Only. + +## 4.0.2 (2023-26-02) + +### Bug Fixes + +Particle Auth Fix + +## 4.0.1 (2023-02-22) ### Bug Fixes -- init param ([6bbccfb](https://github.com/bcnmy/biconomy-client-sdk/commit/6bbccfbff8834fa96160685f80bab7d64ec0f135)) +- Fix for RPC endpoints (Quiknode, Blast Sepolia etc) failing to respond because of custom headers being set + +## 4.0.0 (2023-02-06) + +### Features + +- Export bundler / paymaster instances + helpers from master package ([1d1f9d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/1d1f9dafddf11bde0e1a75383bc935b22448bedd)) +- Export modules aliases from master package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00)) +- Added sendTransaction abstraction for buildUserOp + sendUserOp ([335c6e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/335c6e7bfc5ca1ad240e7cbfd678d905c7f16812)) +- Reduced bundle size ([765a3e3](https://github.com/bcnmy/biconomy-client-sdk/commit/765a3e337fb9ad8f1f8dc92b5edcb1ed0940f94d)) +- Added bundler abstraction during SmartAccount init ([591bbb4](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/591bbb4e37774b16cbe801d583d31b3a14608bc1)) +- Added e2e tests that speak with prod bundler / paymasters ([4b4a53a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4b4a53aabdf9e22485599872332b3d63e8ddd87a)) +- Added support for simultaneous ethers + viem signers ([8e4b2c8](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8e4b2c86b871130befbf3b733cf503d24f7226a5)) +- E2E tests for multichain modules ([ecc86e2](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/ecc86e2c7146046a981c3b6fd4bb29e4828b278b)) +- E2E tests for session validation modules ([4ad7ea7](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4ad7ea7f8eb6a28854dcce83834b2b7ff9ad3287)) +- Added [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) ([638dae](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/638daee0ed6924f67c5151a2d0e5a02d32e4bf23)) +- Make txs more typesafe and default with valueOrData ([b1e5b5e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b1e5b5e02ab3a7fb99faa1d45b55e3cbe8d6bc93)) +- Added createSmartAccountClient alias ([232472](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/232472c788bed0619cf6295ade076b6ec3a9e0f8)) +- Improve dx of using paymster to build userOps ([bb54888](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/bb548884e76a94a20329e49b18994503de9e3888)) +- Add ethers v6 signer support ([9727fd](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/9727fd51e47d62904399d17d48f5c9d6b9e591e5)) +- Improved dx of using gas payments with erc20 ([741806](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/741806da68457eba262e1a49be77fcc24360ba36)) + +### Chores + +- Removed SmartAccount Base class in favour of Alchemy's ([be82732](https://github.com/bcnmy/biconomy-client-sdk/commit/be827327fafa858b1551ade0c8389293034cacbb)) +- Migrate to viem v2 ([8ce04a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8ce04a56f6dcdfd1f44d9534f43e3c6eb8b3885d)) +- Remove common + core-types dependencies ([673514](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/6735141fbd21a855aadf69011bc06c69e20f811b)) +- Reincluded simulation flags ([25d2be](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/25d2bee339afd9d8c143fe6dad1898e28034be17)) + +### Bug Fixes + +- Make silently failing paymaster calls throw an error instead ([693bf0](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/693bf08591427c03e317d64d0491e23b1c96ea30)) +- Added string as a supported Transaction value type ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11)) +- Removed skipBundlerGasEstimation option ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11)) +- Ingest rpcUrl from SupportedSigners (ethers + viem) ([f56b4d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/f56b4da08f47af577c01a641b81a3ef9e354cf97)) + +## 3.1.3 (2023-12-28) + +VERSION Bump Only. + +## 3.1.2 (2023-12-28) + +### Features + +- Make entryPointAddress optional in config([cf35c4a](https://github.com/bcnmy/biconomy-client-sdk/pull/336/commits/cf35c4a8266d27648035d8c9d63f1b9157553128)) + +### Bug Fixes + +- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3)) +- change receipt status type from boolean to string to be compatible with bundler response. ([317f986](https://github.com/bcnmy/biconomy-client-sdk/pull/342/commits/317f986b7e8f08d3ccf1e68f12a0696f1116de6b)) + +## 3.1.1 (2023-11-09) + +### Bug Fixes + +- optimistic implementation for getNonce() and cache for isAccountDeployed ([5b1d4bf](https://github.com/bcnmy/biconomy-client-sdk/commit/5b1d4bfd7b5062d05bbb97286b833d879cd972b0)) + +### Reverts + +- update paymaster check in estimateUserOpGas ([2eb0237](https://github.com/bcnmy/biconomy-client-sdk/commit/2eb0237b37425da3558801bbe9d0ce5d6fd696c9)) + +## 3.1.0 (2023-09-20) + +Modular Account Abstraction is here. Contains BiconomySmartAccountV2 - an API for modular smart account. + +### Bug Fixes + +- add 10sec timeout limit for a test ([5d12fe7](https://github.com/bcnmy/biconomy-client-sdk/commit/5d12fe7d4b32e5c4628b971d22f6fc9cfcc6b414)) +- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b)) +- BiconomySmartAccountV2 API Specs ([69a580e](https://github.com/bcnmy/biconomy-client-sdk/commit/69a580ea9e309141b500274aa95e20e24365b522)) +- build errors ([9fb0475](https://github.com/bcnmy/biconomy-client-sdk/commit/9fb047534935b0600bd08a4de7e68fd91a8a089a)) +- comments [#296](https://github.com/bcnmy/biconomy-client-sdk/issues/296) ([55b7376](https://github.com/bcnmy/biconomy-client-sdk/commit/55b7376336886226967b5bec5f11ba3ab750c5b6)) +- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388)) +- gitInitCode cache issue ([4df3502](https://github.com/bcnmy/biconomy-client-sdk/commit/4df3502204e3c6c0c6faa90ba2c8aa0d6e826e48)) +- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) +- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7)) + +### Features + +- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7)) +- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4)) +- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206)) + +## 3.0.0 (2023-08-28) + +VERSION Bump Only. + +Modular SDK - consists stable version of below updates done in Alphas. + +## 3.1.1-alpha.0 (2023-08-02) + +### Bug Fixes + +VERSION Bump Only. + +# 3.1.0-alpha.0 (2023-07-24) + +### Bug Fixes + +- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b)) + +## 3.0.0-alpha.0 (2023-07-12) ### Bug Fixes -- build ([6fb012a](https://github.com/bcnmy/biconomy-client-sdk/commit/6fb012a7d2004d5a5bad616a0ed025f1ee0a93b8)) -- optional sign flag ([0d689d2](https://github.com/bcnmy/biconomy-client-sdk/commit/0d689d214fc7abf32f4f2deabcce61041b73d642)) -- smart account response type ([f457f79](https://github.com/bcnmy/biconomy-client-sdk/commit/f457f794e27999ccc069c4afb7eb7644e224b61e)) -- ui bugs ([f7a4f47](https://github.com/bcnmy/biconomy-client-sdk/commit/f7a4f47c6076fd78515131ec59b128f312687a06)) +- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388)) +- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7)) ### Features -- added email input and light mode ([741301a](https://github.com/bcnmy/biconomy-client-sdk/commit/741301a526774ed45805e477fac461b1d6afd8ac)) -- increased bg opacity ([aabbb2f](https://github.com/bcnmy/biconomy-client-sdk/commit/aabbb2fc7bab637de7a6c29fead0636979e6f6d0)) -- smart account signer ([9fcb5b1](https://github.com/bcnmy/biconomy-client-sdk/commit/9fcb5b106519b1d8fe658ab0924d722b0d102351)) -- social login ui added ([4772065](https://github.com/bcnmy/biconomy-client-sdk/commit/477206546e0518af5a1d835f7370d70d586420c0)) -- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a)) -- web3auth modal UI ([7b7e510](https://github.com/bcnmy/biconomy-client-sdk/commit/7b7e5104ad5b1828e083f70a185328b566e9d456)) -- whitelist logic added ([53c2140](https://github.com/bcnmy/biconomy-client-sdk/commit/53c2140ef9b9d79d9d9c0e0c2c80e82b1df7f8b9)) +- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7)) +- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4)) +- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..6d58094ee --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at graeme.barnes@biconomy.io or joe.pegler@biconomy.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other project leadership members. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a0c7d7050..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,64 +0,0 @@ -# Contributing to Biconomy Projects 🚀 - -First off, thank you for considering contributing to Biconomy! We truly appreciate your effort and contributions from the community are what make Biconomy awesome. 🙌 - -Your contributions are valued and will help in driving the decentralized web forward. - -> If you're passionate about our mission but can't contribute directly, there are other ways to support: -> - ⭐ Star our projects on GitHub -> - 🐦 [Tweet about Biconomy](https://twitter.com/biconomy/) -> - 📌 Reference Biconomy in your project's readme -> - 🗣️ Share about Biconomy at meetups or with peers - -## Table of Contents - -- [Contributing to Biconomy Projects 🚀](#contributing-to-biconomy-projects-) - - [Table of Contents](#table-of-contents) - - [Have a Question?](#have-a-question) - - [Ready to Contribute?](#ready-to-contribute) - - [Legal Notice 📜](#legal-notice-) - - [Reporting Bugs 🐛](#reporting-bugs-) - - [Suggesting Enhancements 💡](#suggesting-enhancements-) - - [First Time Contributing? 🌱](#first-time-contributing-) - - [Improving Documentation 📚](#improving-documentation-) - - [Commit Messages 📝](#commit-messages-) - - [Join Biconomy's Team! 🚀](#join-biconomys-team-) - -## Have a Question? - -Before reaching out, please ensure you've gone through our [Documentation](https://docs.biconomy.io/). If you still have questions: - -1. Search for existing [Issues](https://github.com/bcnmy/scw-contracts/issues) that might answer your question. -2. Check out our [Forum](https://forum.biconomy.io/). -3. Join our [Discord](https://discord.com/invite/biconomy) or [Telegram](https://t.me/biconomy) communities. - -If you still need assistance, feel free to open an [Issue](https://github.com/bcnmy/scw-contracts/issues/new) with your question. - -## Ready to Contribute? - -### Legal Notice 📜 -By contributing, you agree that you've authored your contribution and that it can be provided under the project's license. - -### Reporting Bugs 🐛 - -Before submitting a bug report, ensure you're using the latest version and that you've read our [documentation](https://docs.biconomy.io/). If you've identified a bug that hasn't been reported, open a new [Issue](https://github.com/bcnmy/scw-contracts/issues/new) detailing the bug. - -### Suggesting Enhancements 💡 - -Have a feature in mind? First, ensure it aligns with Biconomy's mission and hasn't been suggested before. Then, open an [Issue](https://github.com/bcnmy/scw-contracts/issues/new) to discuss your enhancement. - -### First Time Contributing? 🌱 - -Welcome! We're thrilled to have you. If you're unsure where to start, look for issues labeled `good first issue`. - -### Improving Documentation 📚 - -Good documentation is key! If you spot areas for improvement or errors in our documentation, we'd love your input. If you wish to suggest changes, feel free to raise a PR on our [documentation repository](https://github.com/bcnmy/docs). - -### Commit Messages 📝 - -Ensure your commit messages are clear and descriptive. - -## Join Biconomy's Team! 🚀 - -Interested in joining our mission full-time? Check out our [current job openings](https://jobs.lever.co/biconomy). \ No newline at end of file diff --git a/LICENSE.md b/LICENSE similarity index 97% rename from LICENSE.md rename to LICENSE index cf907e971..84dbcc863 100644 --- a/LICENSE.md +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Biconomy +Copyright (c) 2024 Biconomy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 5409568b0..889c0a096 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,47 @@ -# Biconomy SDK +[![Biconomy](https://img.shields.io/badge/Made_with_%F0%9F%8D%8A_by-Biconomy-ff4e17?style=flat)](https://biconomy.io) [![License MIT](https://img.shields.io/badge/License-MIT-blue?&style=flat)](./LICENSE) [![codecov](https://codecov.io/gh/bcnmy/biconomy-client-sdk/graph/badge.svg?token=DTdIR5aBDA)](https://codecov.io/gh/bcnmy/biconomy-client-sdk) -![Biconomy SDK](https://img.shields.io/badge/Biconomy-SDK-blue.svg) -![TypeScript](https://img.shields.io/badge/-TypeScript-blue) -![Test Coverage](https://img.shields.io/badge/Coverage-79.82%25-green.svg) +# SDK 🚀 -## 👋 Introduction +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bcnmy/biconomy-client-sdk) The Biconomy SDK is your all-in-one toolkit for building decentralized applications (dApps) with **ERC4337 Account Abstraction** and **Smart Accounts**. It is designed for seamless user experiences and offers non-custodial solutions for user onboarding, sending transactions (userOps), gas sponsorship and much more. +## 📚 Table of Contents + +- [SDK 🚀](#sdk-) + + - [📚 Table of Contents](#-table-of-contents) + - [🛠️ Quickstart](#-quickstart) + + - [Prerequisites](#prerequisites) + - [Installation](#installation) + + - [📄 Documentation and Resources](#-documentation-and-resources) + - [💼 Examples](#-examples) + + - [🛠️ Initialise a smartAccount](#-initialise-a-smartAccount) + - [📨 send some eth with sponsorship](#-send-some-eth-with-sponsorship) + - [🔢 send a multi tx and pay gas with a token](#️-send-a-multi-tx-and-pay-gas-with-a-token) + + - [License](#license) + - [Connect with Biconomy 🍊](#connect-with-biconomy-🍊) + ## 🛠️ Quickstart +### Installation + +1. **Add the package and install dependencies:** + +```bash +bun add @biconomy/account viem +``` + +2. **Install dependencies:** + +```bash +bun i +``` + ```typescript import { createSmartAccountClient } from "@biconomy/account"; @@ -23,39 +55,30 @@ const { wait } = await smartAccount.sendTransaction({ to: "0x...", value: 1 }); const { receipt: { transactionHash }, - userOpHash, + success, } = await wait(); ``` -## 🌟 Features +## Documentation and Resources -- **ERC4337 Account Abstraction**: Simplify user operations and gas payments. -- **Smart Accounts**: Enhance user experience with modular smart accounts. -- **Paymaster Service**: Enable third-party gas sponsorship. -- **Bundler Infrastructure**: Ensure efficient and reliable transaction bundling. +For a comprehensive understanding of our project and to contribute effectively, please refer to the following resources: -For a step-by-step guide on integrating **ERC4337 Account Abstraction** and **Smart Accounts** into your dApp using the Biconomy SDK, refer to the [official documentation](https://docs.biconomy.io/docs/overview). You can also start with Quick start [here](https://docs.biconomy.io/quickstart). +- [**Biconomy Documentation**](https://docs.biconomy.io) +- [**Biconomy Dashboard**](https://dashboard.biconomy.io) +- [**API Documentation**](https://bcnmy.github.io/biconomy-client-sdk) +- [**Contributing Guidelines**](./CONTRIBUTING.md): Learn how to contribute to our project, from code contributions to documentation improvements. +- [**Code of Conduct**](./CODE_OF_CONDUCT.md): Our commitment to fostering an open and welcoming environment. +- [**Security Policy**](./SECURITY.md): Guidelines for reporting security vulnerabilities. +- [**Changelog**](./CHANGELOG.md): Stay updated with the changes and versions. -## 📚 Resources +## 💼 Examples -- [Biconomy Documentation](https://docs.biconomy.io/) -- [Biconomy Dashboard](https://dashboard.biconomy.io) -- [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) - -## ⚙️ installation - -```bash -npm i @biconomy/account -``` - -## 💼 Example Usages - -### [Initialise the smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html) +### [Initialise a smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html) | Key | Description | | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | [signer](https://bcnmy.github.io/biconomy-client-sdk/packages/account/docs/interfaces/SmartAccountSigner.html) | This signer will be used for signing userOps for any transactions you build. Will accept ethers.JsonRpcSigner as well as a viemWallet | -| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) | +| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) | | [bundlerUrl](https://dashboard.biconomy.io) | You can pass in a bundlerUrl (retrieved from the biconomy dashboard) for sending transactions | ```typescript @@ -74,7 +97,7 @@ const smartAccount = await createSmartAccountClient({ }); ``` -### [Send some ETH, have gas sponsored](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction) +### [Send some eth with sponsorship](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction) | Key | Description | | --------------------------------------------------------------------------------- | -------------------------------------------------------------- | @@ -91,10 +114,11 @@ const { wait } = await smartAccount.sendTransaction(oneOrManyTx, { const { receipt: { transactionHash }, userOpHash, + success, } = await wait(); ``` -### [Mint two NFTs, pay gas with token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees) +### [Send a multi tx and pay gas with a token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees) | Key | Description | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ | @@ -103,36 +127,40 @@ const { ```typescript import { encodeFunctionData, parseAbi } from "viem"; - -const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address to) public"]), - functionName: "safeMint", - args: ["0x..."], -}); +const preferredToken = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; // USDC const tx = { to: nftAddress, - data: encodedCall, + data: encodeFunctionData({ + abi: parseAbi(["function safeMint(address to) public"]), + functionName: "safeMint", + args: ["0x..."], + }), }; -const oneOrManyTx = [tx, tx]; // Mint twice -const paymasterServiceData = { - mode: PaymasterMode.ERC20, - preferredToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC + +const buildUseropDto = { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken, + }, }; -const buildUseropDto = { paymasterServiceData }; -const { wait } = await smartAccount.sendTransaction(oneOrManyTx, buildUseropDto); +const { wait } = await smartAccount.sendTransaction( + [tx, tx] /* Mint twice */, + buildUseropDto +); const { receipt: { transactionHash }, userOpHash, + success, } = await wait(); ``` -## 🤝 Contributing +## License -Community contributions are welcome! For guidelines on contributing, please read our [contribution guidelines](./CONTRIBUTING.md). +This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details. -## 📜 License +## Connect with Biconomy 🍊 -This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.md) file for details. +[![Website](https://img.shields.io/badge/🍊-Website-ff4e17?style=for-the-badge&logoColor=white)](https://biconomy.io) [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/biconomy) [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/biconomy) [![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/biconomy) [![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/biconomy) [![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UC0CtA-Dw9yg-ENgav_VYjRw) [![GitHub](https://img.shields.io/badge/GitHub-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/bcnmy/) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..937edcaaf --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,57 @@ +# Security Policy + +## Reporting a Vulnerability + +The safety and security of our smart contract platform is our top priority. If you have discovered a security vulnerability, we appreciate your help in disclosing it to us responsibly. + +### Contact Us Directly for Critical or High-Risk Findings + +For critical or high-impact vulnerabilities that could affect our users, **please contact us directly** at: + +- Email: security@biconomy.io + +We'll work with you to assess and understand the scope of the issue. + +### For Other Issues + +For vulnerabilities that are less critical and do not immediately affect our users: + +1. Open an issue in our GitHub repository (`https://github.com/bcnmy/biconomy-client-sdk/issues`). + +2. Provide detailed information about the issue and steps to reproduce. + +If your findings are eligible for a bounty, we will follow up with you on the payment process. + +### Scope + +The bounty program covers code in the `main` branch of our repository. The vulnerability must not have already been addressed or fixed in the `develop` branch. + +### Eligibility + +To be eligible for a bounty, researchers must: + +- Report a security bug that has not been previously reported. + +- Not violate our testing policies (detailed below). + +- Follow responsible disclosure guidelines. + +### Testing Policies + +- Do not conduct testing on the mainnet or public testnets. Local forks should be used for testing. + +- Avoid testing that generates significant traffic or could lead to denial of service. + +- Do not disclose the vulnerability publicly until we have had the chance to address it. + +### Out of Scope + +- Known issues listed in the issue tracker or already fixed in the `develop` branch. + +- Issues in third-party components. + +## Legal Notice + +By submitting a vulnerability report, you agree to comply with our responsible disclosure process. Public disclosure of the vulnerability without consent from us will render the vulnerability ineligible for a bounty. + +Thank you for helping to keep Biconomy 🍊 and the blockchain community safe! diff --git a/assets/readme/biconomy-client-sdk.png b/assets/readme/biconomy-client-sdk.png deleted file mode 100644 index ffe67d367fa6ac89b5e599ae9343b560665710a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61005 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 SSi4jJ0000<MNUMnLSTZYgX~HG diff --git a/assets/readme/biconomy-sdk.png b/assets/readme/biconomy-sdk.png deleted file mode 100644 index 6c1fe2bcfc4bb266d090f8370bc02a1df9d891d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163491 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¨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%0AHAHG6ltxe$JYdV zkRY1|eqL0b0>Hy-;ZINBlK61YzopJFC}8}+=cS&wgq!s~z>VN>dA<cWy`=Rl%2kFx zoVeUWA9FKvnGs|OwVJWUjL$j3&s_BR5I0q4EMFY3o{)OIH5=`^w%oyx4d}J_rGev8 zOs+BS`K+HZS{!=DABKUbs;Rg5i^L4Mr3|<I5_LrDZZ|{RV%(~HF<*%a#fP=Do19V_ z_?ehTDkj`U+#*>M<w3RLgy6&cbqRg|MXwG<t(Jj%=V9sK>0OUDuv~DxOJLKY{l)Sh z$AX0EtI|K60QgQC08c}gLT33TOC;QH@}`S8LZJOiG$GK^??VUf=M-J`tLppPcTf$T zxV|5JD1rfq1;neZB<y1xu>!5WzY8ZO^i8gi7k?Oa-x%SpoG20O{CkTS=#J1M6+bt* z?4>;@)dIDI3(a<xq}y+l`rsM2IQ4Eq2;UaLAprIo#DFS{JKd4amI#iL{6L}L%wdRx zNF;tPcG!L>31<6*IH$gw3MMLk<4cGY<LP@Q4<MV$b20i!JWBNWcDzACoH>j=aBlGO z1>$!Vtjgw`>u@CkejsUif7s6ReNSz-Jh#(bEdjAQoEV;pNu2gJ(RFs2NZ3e95;<Am zyH)1~LpvZJZ4K%qn~}pok=K1mfT5(>q9F`Hf>4wl3UBo`Jbb=MdJstJH=8sA5T>sz zY&0eb+_$jM&bpn=3LLaZJBliCtNrjXOLdE<fsdNEKvILFU~%O;Ai5`F$Kd>KvkM(B z<c@R&8+#ve8r^8NwS_FooP=+<$J0xoxoxc%uNMZ9(#^OgHiQ&8igvDTxMYgY^1#PJ zEMA70f9FNwmD8uTrY3D;n|)%n+DR7;!V`V(?i_0ev7zlX?BbBa%9_LElVf};FFJty zAX1)OEV~HNAW~RvDtt$|EZ0h<y5vpG?9lNR>&=D7IF>A8Ob>Nw=fcd;=iVA_A}Z9Z z4ZfBO(;s~fvFab}DmC7joq5-Frzlw#!LY<~7RK1bCK<=>$B}#y*5e{l)alqh37sdN z&aC9E%1~Kh$f!?a@~-SVnyaDKwwizDk)X^H4t#F3P3w#fpWgZ=Rvsy)-p;BD%wczy zTrx5{`J9Li9~8V7DV(T2itMX^5e0Aits+)Yoij1^IO-c!qQ1xOpWHca6%f7;($zqF zVI!F*1M?_y-alTiyr}j8zFQIJQSLqhE|hR9#-?{Q&RSw3l_^g@pg8Bu<*Rq6$u~}! zfO(J0&IY19-AnX&tpUB?yA-64Gm?%wpcewYtZ3HZE4mzyf*HPa|L0@_22d^)_Qy(8 zO8k~DWH|78%bnmKiD@tgHl$`0IPjF7<csj2g#N0VC@IEubRZT9Y-9$^j>@no5d|ss znpEp_q}VA83AxEa5*9;5k=$3$-UN>Ck-YIL-;2!iWkq3q>p;0P&&plz+gvW=D$iEq z`&E)AHnm_;)bUaoc6$pg4We4Tls$n6ic<u5fTsle(F*r<DnwTpT`r!@+=`U(?`&!3 zy6BgG-7<f0zTViF%|%IZzA-p{nI$BQb+b%YoMY}hrLvTo51`CYopp*Bbn&f(x^9Y# z*wr6e<dqPIeD&k>Lko$A%6)a`*I%g#YMysCc4g%(v!R&4VBd*0a!01E-zG6ddPR51 zEj8qtGTSWB1AouG{=Q-jk`5DRgq3ezNR*kE^qn`;l8l1BNSVwj?dSzG8^IWtXdru| z_F)kTiiZKo?3%_plJ6KQhRCr>c$Zr54#LKw1{*HG@fru<Z;GgNy4MwFoQpeTh*1cV zx~kHKq9kks^`FD}_cG+56O)zdZWSY?nrP~LD;Gv@A2EyKGXbxc9E8sN=tIM1?L5^@ z%mcStq%a*{_YOok5pS3<(}yh!QjZfby)p`x@iR9hdazp=|0=qzrHs>o~cv36zk zrT;2j$3@eks7mxZ3$vn%kfL(z;M6zu^w)2c=yCA5(VBU?a)TiJX5~el7UieNCL;S2 z>Oz*y>7BFf6}HF*N1#OS3I_+DRO&|<01sP`?Oc*5s&C_4`xkFTJ;WtM%~RO31P3^< zpyRrh-^t~qxXNuXOPqr>ziNH7WthGllNKe;xpS(>y|v?139%&tCB&Z7uB2a?@`rU; zGJ7XFvDYnKTbO4!yA5T@?%Ul>EUI=YNeSt{AIaA*Hz#p|5;WC)G0x@lv5BC$a}k`E znz`t?SDH;=tn~V%mT0gzsYqdxq)a2QEJD%>wzLFb{%YDb@udvvTyEqrGimetS<IJF z06@g_JEqIuCIOFX6#6K`F~N}zRkI?4i@YJFb78NCZ`8M`a^BY+_#`)&>-`rElR2Jc zhZTftLv%~K7R?x7tIUX;WP8$n!VfK_CXbA<dyK%F<Dv0Fs0ekMr&!^DG`{`$!}lAp zQ~cXw^57YVpcw$YXYfnNzjc&IDe@sLZLXU<h5g-s4>`3gu%@_&0^x`5wBg<|Du2cY zV6+IUA-gbG5;rsba)^zsuq_s<@imn$GdYPXXQmvWn#*<5Qzol>!86myU=BBSye5*a z&YtJh{zNW8$bjWJnC;xX`KjnkWBXsWk3R5n2kD-QH1nju{?nVXb0DmP7)!h6Y24jS zUXuH(<7dk`4Wf@B%_SEqSZ3&+<>l#6n)bfy!sO+;<@rJVU)QWaw%<2z9--S}#I;vD zP?9B9reHb0_f@WX6PaQ8Zrn=2NO43&eUMkZzL{Z^-uRXI8dtCJ^fzN&231`NgkVy$ zJjUxcr|(h-Gw5j3QVBNp00rL2QdsK71%wiLVNsgeB8Pp+9u0dv=BAoLqDTR$<WLX@ zMZ3u``Bj~WJt3-WqTTCj5(dMH@psf3=y@g<8C_Md5_(Irxj060R}vgvzD6rfDqH&f zCVtK5NCZc5_5mrnneD<xG*ALjpc3bq@7>>Zd~maXH>vMGRCiL}s|2qee`TT0vU5`g zle>_w{L5B-%ofhyB~e<Z8Ca|C|DG)4?!fq4ol#Mc+8GQe5$<l2CwwX(`-_{@@gjo8 zsAmLv8lL~>AMf*@&iiR}e!(gQ*td)&GaKO^-6RM{;DRin@B%pU{gcMezY!YyyMHj7 zM=oz8-Cf?1Sc=<*LX_7@-ZMoC9YsB<97Hdl@##PQi~&3%9{IfFu$E}q99J+t@lRN4 zCJ;ZaD}Xl-aDK26>j@H`MHBHpcoIRrUA!%R>+?FHzg={1+d)tk^8D@NIVDoa48}q$ zmA`qZyBza*PnueX2Tu!!*|e%k9>kEAP!zsI6Bs^Qedu_i{Bm3tj*#N-47^;FmMXCN zFGOc051Ib=%LnJ0O;5CE8ck0JzYqQ-E1jtX-YFM%1xsgn`PFa~>kdzmFrH&^nG7L* z|9nju0}3@WNw(*dI@GAkGoJp+6Wvi*%th!FOD+N8WwZ#l5|CX^P$*pn7lXf|%6IgA zS^<->gu)KMKH~o!W~fpeG_0kG<fveoR9kTj6Q@ygt}eLSmKny&$kk6%Xy(tu#G@x1 z9S9CK^X~gxZZoVSlfrmwrj4@U^TiNsK`@}CvWqw?Us8N(N($V4Fl2HNbp|=VtFHy` z+}F^OEFB8t%70Kw@&Ab{3$}vul5khm=J|FL<ejJ%4+33Ly(i7HO9cniBE=Fp<6RIv z={9mr<ZYz6iWP1rBH%jakCfm(l$BhcsCbAC1{2xnlU-bH#j<rx#O7jYmIC}E28EP` z39`jK4ZYrs{gKq_9-)=niycLkH%PO!T3{>M;)HU~Og)9}=hl53-r(=qxH?3-=0-lq z-BT@ty#}WDmnd(nn1Kc(BFO7s?k^u!XJa+)*J{d|hl%gY7@9b2Uc}^SH%lr=N6NHa z@A}vxkK0=ic{(J8V@XTc3twQB46p26^q0H-<Xs=#6+mLr!o)dK#~5!|*oe+Y&Gk8X zXWKJX&mS4@ME^qodv~a34XRlQDfq*R^`1rE8iK?J=j?i+-}V8|$#H`Q_Z9Cq>lF)I zXDYk=%On0xWx>zq>+_jwRlWTz7JLol&4a(ytMv6FkMH)tN4%7UJMhO(B90%YGd6^Y znjDinmcmXc>R*1)?(bVtT;_O~zIF%TsGvizo|)>qSe;o_on0HsIwF)7C;A&4`RURY zbjJmiF{uP4+naW@Uc8T+%O<g{i0u8p`E`NBd$!jeolEDJF20ccrd?!2@R19dWQ}rb zyG!zn;6Os2984lC-37-r<<Y&Z8kf!Yc&&A2%NbLYtr&@rFHRwP)33*ts;E!1Mdzl+ zBC)pTruSLGJbheg7cnhuQcsrrS*-T!#G0P9Wt*fAshE>FzBS)zIh;!mT;rF_V)vpv zi@%b$ICY?RP|3-mWwh_*q^-FMag?4uRUWhyDihD8T1btSREK-gL5*qF;Y);EszWvU zHVRxQuDTCRc9%#PjNGl$WIo13zDJxJZIaMLOk$a`eGyk#;AhV{_Racd7^e(nIfqRI zVsm7<3$)%zjJoJ&<A<XlG^A+PyhH`wnGK076r*nrT%iau3p~_$eW)M}w*D_Y4?slc z`7zrjE|@@-&G<W7k!=*UWa5c?rZgKlyMppi^Gi$XHIc4rJ>qytUzAJ*imm+6$|=wL z^sP6klbhaz8cJ?|@#Q$rv_RlLz)0f<5;8Lhvcy5X`xpnmrTC)*tzK-mk<(<f!>#P( z-CY<1vUl);7huBCUqqcyCfvQ%`mm@3wN;X_W04Fl<vt8Zca>cHvQ<`uCUJ%{-A1w_ z1o!g8JdyUW?;JBkHCylR*WyMEASSbC-aEP*tq;;26rUT>{m?nfcPQ{nFh$(E*ElOr zWWTdcs)A(PFvcY1f&tKhQ!+PEh&U6GhQ!^<<%sOzr9h~H<#H{!=r_K?N2_u4dwJA_ zCBi(@T*5(<WJCitOZHI9@0jr84Kc&bh((GgE+?fho*@WCB!EWg6R!Dp6Tj2ET<6!r z{uj02Qq7@1#*ut*rhR1bcTZu|TJF_7^~5KM=&TUYUwEq|uJkeP|3f5EED=)kn6;|L zC#ZNq3Gkf*I2=^P8AqlhK4j&+g@wj{f8ey0;hTEP0PVxEh5(lQrs)@)oaF2ZLyZmo zvZTO<?5a};5-34&U05EH?>dC`k=wre`U&^9B<qWt6ke{JB^Wwv{%JxZtho&Nb!9%1 zotJxx1xj!T3^f?P4YKNYQsngD0x!KCSh|8#k8J}7eEjeDMb7WrcJUHsEla31=VJ|D zCnDi|gWiM!0)+!?Q7aDxMF`uvs&NIT#5Z)&&((UH<Tz7sndvEbf<)_W`kjTsRJID! zpnJbk8-{4!Y?IXU(QE<cM`Tg>b~x3lWECS1SNO3$%v#Sy@InK514FMK7KSzhC>BNp z6<$m##Y;x1=$*e0;m&%{QtE0+_oe~@!Xn%IT5OYe1bt69AXxlNh%2M-W00DVu!et> z!Nsv(iSyJa+!V%m{H6*5xe7>}^|b_Eg!TluKh%?^`JNQ>Owohp3%*)7)1eO>nuJ;z z$%hr6{3z({x*_P#>@>7iGvF)^i3%)!G8Ee5ut7uxe|J#U=lt?z%4O;k=7KXln-D1z z@Hnsj5<zFbwe$S6g<x5v3{u@}BGB38@B;HT`t|7H&Bd4EaLn;1-D7Mx4%Ij-95i9! zwx=0zWW!Wvgd1htNhhVoe`za=)|?SVRwb~Mm!!b}K1ik1|9O|$vOLL7Y(ow)3S8b9 z+BBk2^pCYt(0+*DhPEhx-oPzc%$}2Z$wj3>RrZDDGRrQ`3{A<54U@MbD4MQD>*5t5 z`sdzEvBF6Tc@~CZFlY-~jV1^?ye~(vN4XAr2384MjSz2Ac62f)3h;B_v@gFUYS*#G zF^<gT)5sk|9bC8--OIm9tLiac)C_gcsZ8c7E*gz?rsICr)gxCe)4ozjfP8<3j8dz? zr+*Dze1f^|qTI1`3L&McG3RurN85H1;=4p36mt>A$Tb>ysM{B|IY{U)XhhFH|0o-* z3{n4#F>WO0lEcnbBv@*ADF3c#eDVgo5Q2KlyUCni(F@Ke=ftVvXrr+2_(HzOW)Xc8 zLZhql-<C<ta}J2w;e~3Yw14Kg(#kyZf9@j<d=O|{asAMmoRcT8{vd_1?~U)SURIck zAdH%*jTBGT2ZfNhJKL!FPE{*Jfoy`)ebSFLzXI3<xd-dZmW^DAD)!sM1pb&5vQ;q9 z{3#6->ihwo=9Qo<=s1>!wSC$|54XzSd2a2n%pQ6OK&;f}WQLs&w<-^C6JsWn+e-W~ z+=!$2g;@=`NZsqph^)Fv9xkoIEDAPm!m!zQlUm2$Qk27AmQ~ZOh0IcEGgg>Nux2WW z5+TzOPjLxfxE3cby;K_P64=OaL*tlIk4hzSI4=cp$l-I9f?Wvq*>L=^zm&1lTN-2T z6i1Z+oxYQh|0>`fB@ooKUb9mXSP|A2;*VS{BF!9k=9SN5dJU(>?)bbK(nxM7X*Go) zS?y4@xe4&QJEWp_Tvx;dM!&w;Vbc7dqI%g~9>ctqAugQ;RexJaKvoy%nN+4KOq0+Q zuvU$Q!G-(OW(BUz6892YnoE6YGu--lc54=rV*{I|R)3gz#tQo88FO#Wg9odXw+Wb{ zD-4=v)!E6c2iY@SQ7Du&fOtMpR3J>;RYkx_kpE>CFHah)$G&87{yzB9GV+|=_14+` za(|a;T8<?&P+X7l5|N#q{00FH#>J)e*Dy+PGM_zt<5Y8ET<I!4b}b1hWlFucjgrFV zv6~A~kC4MjC4biBq)G<NXnwKb7BhtkN0361tD`RcJhFjn44rXAQjfry%a1~Mn%f^o zi>EZl-!t>z;{hyFS~(?2_ZVhF_WBaxBIe0Hz(a?%s1Te-K_@9Wb|v;r>)%E&8ccnB zR4<%aT-=YyK@@)E5+UpHp+(f}e@{P|mWQ5&>{5fjl*1NHZNLO`AUmLVr}vurw04|b zeRMJyLsc&2NrLINV`5@oNh=7^ciX!YB~RmtDa^zx1Mm{T|MvBUmCUv6|Mk+LgRV5i z;a7{ANtwj4Td|P_SHwEoL{%EJvK$}8fTz6p1<XP7|6;<YQz~u!m-#}fZ|XiPd$9h2 z4waUp=xb%AEJbiZ(V$)ATYnzOFn@V4&Uf-ZJ}L@qeiBHcHO(wf3#D8BNLvqY$~ecn z6hql@t(bvFQ@<@F#9`@O3oQ#F#kd(|D~Q=&tQVHx!7@FYd{O7+G?^6vf%{#p!rDwe zwjNTPxSy3k-Bt=G3Wvs#?I(j@e&^(<rm?DXO!Wzw1*5IZ*>a-ik+mXx0_glOuVenF z@MohhYpxKhL1;cG_Byu-O@7F<WKn*L|GyE0bu$gXTt_Q1xLDClv1pkF3C(0cidUu? z{J;iE=z#l}ajEBC1bV<_di!HvxhQCkPmUei@zn~4`3VJzb6Om2FQOGOLc&So-f8fL z4XOgj7SD0x-qbs2^47F2D7^;d*>aCC9aacJl0-or=jMaK4@a-Q?M~>Qi;wZGc<rZT z>*7?kSHtbmfdy~Q(3g^WrcWeUc$3W#pA57+yP=fYLR(aYMd`;KPU6jeO3vBOm0p4i zmkNH|PRX~D*<!%iN;C;dlueN+?^E4Q*FzNaJ+ICqNOsU$SdhWg<>~dytAP(lls|&$ ztf+9}QsN!{i1)kPN~(YS7xU~vx91J-RnON(GUdYej(_>|7}w9YG)VM(5|o(VfwX*H z!7}(<m#7tWoxLkjj1|LSd$b%~3B!Q}gNPWmU+v<R6n_@;$9}#2V5!L)PMTLZuD9)C z`xr!o<@*yW$rn{@Nwd8A)pyAlzI5dMDmKn!;n0*3gEa`ZmW#oFhS!{BgTtYvEJa(T zsEwlhr_|e|DF_`@XzWhMH7GTE^X)_qZsLF!LI8TrVd*n4-xR1isZ#2CeJWJT{DXrR z8Evk`&`2qV_MwF82qDnxVMkh*rA=(5XztN8JJF-q><RB3{JH?!YqBa{$9|{OA-t57 z8u04cl3+g3YUcN)bny9lh`SVjNO*IT^kyFu6L_-IOj8UvTDuH!BVt_cT%1k!gjdg4 z^v3C^<I#y#<NA~5l34GksKWK5(cgb2r1bRz5Cx1$PzGA4U+H}*g|p|~-U~hF$Nr3l z%eVIh_%N`86dY1|fs!Gybfu5Yz-3m=8y(>Uw{1%-g2^i*f>uij+@@M51l2^iUqLfM zT)#`{`(HiVYYWxH4cd^R2tnJ!iaZ@n<!R#{J$LzYzT8v$*v<p+7k-C<F;ZaqdrJVQ zb!{ELt+h~0jWp9LhxIPBxg>JL>@=qfHJ6jVJ89wxLdax{2|%)II;^%S{^eHfwfwIh z{ZWGyy&cwUc}P>=U`!Pw!@_}9&Jy;vZP;SJ7~@i6qO2qn`Vn9+4UFl+i{0b1wd@$s zkgw~HuV<=6-mm23p00nJKQn134-=bp+#q#{NwbqglMGc)o!@)Hl4On-`ez3333}-n z*8sMPXn~|wf;bRo1$v|FYr1+}%J?GQldW|mxhsuu(*#SQ4mHA|c<WE8i4T@x;;~JD zhw{5mR^0TzB9wONC+Vy+qNYo0P&PI#n$dx_bs%uu-G&6IYWLS*ZI?&f&DyV)q+akU zDkU@2T|yx8SIV=k6u}L=+W_*Fi=+hD@(>~<HOdeXgw#m(&`~~`SKT0=0|`z<Z$D%2 zqw7TJU54^tRV5=-u2J5(>DKxsj0PG^B4@0G;wwhqxlo7t{@&KP^2k62R7TA7(|zzr zuvLU<n4F!$+r-Bf(OXV;ER*vc*ujd7zT6!2uB#o1sKolj%3s+HakdAYrUlT7PbLxf z6G8J8B?O5yGuxtc^2Bf5SaJL7apQ4#@9wmE3<hD~BM2yJ>$aAin9j}Losv%Yb7G$@ zhnyOa`iXZwn+FDR1;A9dcFYpk?cIC+_2*3WY>hqD$B>k=&6`EHm;9h_<Hjk`ywJq} zdNjs9KSy(HQi^|;dID<+(L8Ar%=9q$72Gt;F-BccAzTEJ<wqUrNorwYOY+W$pCmB# z@JAJ^tqg3_kwp*Ue37Y96w07oQZbmL*^{lq;FRY4ar-7ReaGZfP5ms^N}Ukold@{h ztf2bSqx$K!iCP^>KO&@$KuM|N{UK^_o(6!)1+*`Sci2k&MpuWWnoLGHGEZlbW*0QC zr;rQ##bgjyQ;!k=^2hjvw33q9jvrdhy(ltC&TTxWi^U~(>J|Q&sTRXOSz`}d_duSU zPa^^0y((GSz}@}orO>I;><lO5`gHNn*Z)l%l+YU5iSvR$KH$g(avpp;$illaLFN80 zjqYrc($9~;8f3qo8$MFk#VL;5?0f!wMS6PGcd(r9689|s0Vb2f7fbY@7eJP$Fk(WL zv<wc#N(EafgcW=`rMu>t4Rpn1AHc&Ik-5w6|6hml46gPo6U2o3Jaia2O8u350cui$ z`)iK`RegHIkI_S6AFNu0Z}HtyxA9G=l9hS@l*kjBpq+YuA4$`oG8`c57Ar<rpVxp% zqi85z@YoL4Xtx_m_Y$Taib0i?4Q;PO6z~U@8@3TbXMG;VJdGL$BM;VBz~yBXJJ?FH z&P{PAb$*Zj69;ef>rjG8z5Ac@C}=SQs>%u?2}pi}B<S<dw`Hgbqb^jdN#~%?*P%cW zi$^lF*OEn*o<_v=VY!&K<;U6|yuxd_k|?WsL;gN3!Zk_`Gb!?$6Banc*qqL-I4?5W z3Xgcaog`e5;+%~l0hs^8m8+y8k%s)BntjnhnFzR6MH5%_=i@Pw7L$-{Ok;?76(d!J z<h}|nvJ{=M?|4h(+d?*JKE$Z>?eC<w24+T$(0^AV>DfHAL~`Xv2nT>vf)ZMr4a{&o z7|pME7|_30DC1QlQ<BMRcBA~l=US+dBrrX3gFkbD7_ga%N-oI&b=S5RhcJ8+*x4a? zs2N$iNUz1AFpTcQ*Xl(^(ZYaRU1JACTGeT8Hil7Fe(zcgv4Rq3Rq)&you@cwrHs!* z(xQlAev?BRk@fxN&gN;!cLV;2gLc2K530zE>Yb(z=6*m98^C}4lVL;k@aEG;gP9L` z9y>kte(Ys*#1%q0pAIrA{G^5!YL-wm(;gVu;qPoYEnhP+QKYLivi%KKX3>jVF?AUg zCu`%!DRNp=NCn}0yYsNbzi0U9hTpG(auhezl>A#BAr*XHqN`)pl#HX4g`fDv8n{s@ z`VGd^n5_C#&F*83hY5I}wr3=kKPHoqq7Nke@Um8{q&Blp=yALEXJ|gSPjGDCJTdx3 zm$wM_S9MMWI`IAFtxoZUX}2Q!rtewXH@$KxYB0<1e5gK_sKImV19bf2*kf^$-j|!Y z(ckoxs5$Zwyh%TBB+V<_MhEWQ!BAqcOhu8a4*PlP{dZ#(d(P4{1m9qzT|JCPs=in~ zlo<u#v~No)(UL&qsD@wobQ+D|;Z)kdF^^h`A6dOm_|lyEK6TROrx#DF&DmJN1%43a zM{Rt){6NACs2-_rAu~r_ED;wMZr-+ctsgHe-)R8rg~h6IdVDX!k-ryGGF5CJg_oiJ z2E*`1k`akhRj*7$4HC>Aj4?vsm$7a{6w!pdnxc~4V{{|hU;l<{Ml21TE4bB`ai4r> z4n6HZsFo{KF!8c$12AhR>QFRrV)Y~kT4A5@xnQ*kJv7rB$Cos#Mm5%#SN?BLnbfHo zBto`T*eKb1-~hOzD=`w;gy{DZLT;*%vt`IAZ`7TI_F$Ow&4TzQrP6qA+lKIIUd{7X zUKGOS<HM`X<N4oJ&Hf!r5*5{0Qolp)`H_&)BzQMk&k2D?xA`Zr@^Al}XUtrt9Dfxh zgPqN>?!e6YljK^D#-8g;?cWi93=NjqF?{t$@{y^qD({M0zXY|$tzXBq#+?e63V1Uv zk96=zK>Q-4P^HLQHHai_D4Zq^(kk>tlp8%_z78v8tL2h$UD5`5+WoS+5K!I-)`-9H z&2ACj3?_-re6M?6B0fGhZM*zIDz`C&UC^1Sbh9RSyz6`jYj}MFc@F=_kty7>ne=Dt zy@ymPn7VkDHe2O>3(wGBq9#I{R2%Otvgj<9@NVtebAbDVpPCuY`oCkMEewdwWMga_ z>HJQR7c4x_!4P(8*CQ;Y*z;k1dTKCqDHOMK(qH7>QDHzDA%$4!&#B+r{8uJ`I<3<V zVIMRr>Tyh<G{{O6C-xy=WAyEYb5lB#(hz!x+W_k*b}EkN!Se2OY%Ip=!zIu4Qsm!y zQC73|QO$-5=T42b;Sw+@>>xWPu=qSc>x!>>tZPg0^9X$5lxzRhs585_Kn?BaCW{ z25N@~QEY7VT~c{(>N6VDk;q?E6UbLai%s;R_$!%@T6Q>%|4Y)j9(iVEYHaGKIL(Yx zHOKwtvEt>oiw!8Whs58>cj!Q~cUO?}5SH>rhXQAFoHLTHQX7k%8>xEJ6y6X2Z|lyR zULXAE3^Z{3MGet4(Q(2#qRXcBXJsXoR<(fOE$xedta@UQv+@q^&514AvEFo^t%K;t z#l`x_^HP-Fw7u<_sj^VuP}=iSW|eT>{&SbeEZ+j_Mwr9P#j-(@P?qo0>%rRqOrS_0 z{!`U)O+RUviB=PR;>~d74v*(X)x$()l+>xPOV!yfn+|v>y$V>APmr~Y7?6LFuUBYo z@Av}SA=^g|C|eQO*Q)yH28cHe7Xy%*)iMR|er{yFD@kUaw_cM-0?*sU1Bq@epNxfP zTd`jMcKVM<Q>L>wjNKSW7zN9LmT6EKgn^i0cG#d>e8qSjY{ChOnMFGcW4S8EAQeZh zvCqgxm=vF_<=nXP3xW_t^097;^JYq&NZD-iE<(QVVSs1F<|vAFpx0Ol-Nx_>sw-BH zlQ_1}f!O-e9+GFhgCs;>cxg9snr&5PkXBAs!N^O|nRa>PX@(f<VYyy5WVmO)D4+&w zaEnq$=n%A5o5%pm{dr02LnK;X0ccc#2cC{Dr0Vzf>m&Z28~>&GB#y%~)3_tOY08n! z7F}PNwczFtb;E_tp))zR+B0E~Ap(c66XYkao0&DB$G@k9y16euy1K%7p86uFol+(Z z+(FzbGAGOR|6d8@?*#E6YL_M<wF#pG-TVTdA+(occr?Q4e-sY>8V`@7f)7Q>X$ml) z)L=3|R7`9QaK$PsDk!X>*m)jxY>d4W`=WaCdn1QhB|N}P#96vNG#Zqfd|5nrNt%5l zt<i3iJ7YC`m}aBKkod=T(L&;CMJb=>0cWAgS60qSHW^eHMl)mB0ml}dvj%d*4h(IX zVrjmgMk<nSeCY9C6k_D`OX7{(^y$eh2JR5{>qkGXtL$FND)?m!KUxTi^<t$-rW&T= z_Faok0udJ<#Tic<>B2cDJ-wbd?8)RnXGj@5cga^kv{~!50^GgEd{>hO_-}ZF;nps_ z$6JDb)yv<oW5eV;=S3Z(SQ|6|k1AxN^w^dD9xO9i0$)=^ymv>14C=N9#~O&HSGk<y z<_EPTO&1Fxu2N)un;Sutp(AvK8sW~&fSp|`5qe}H37)3oQi_{yWtB9pVH(tY&SIW> z_Q?3G9W;xL+Nhrr&f63k)Ke(eBn46h?ttUc?C`mfrB64kBvMR1-S3$6@X2M=GSQE* z>hxBk@C7xbtdyOomnOY~ad$sb<;Q6x1RKp>h8KlGhQb}&NFterHC4C@L?WDK{@(&v zc9+FBV8E5#%8>z>MTRXra5VY90+`AYiylyDdiob<$jN@_khh=5S&)+m6j?*OIE1-K ziat0|TVg=)rxFP&hKTCAlfxFWS|}RO@DZXX_0rd8w&yg50sAObkD+7q(FwNd=tBqM zHCdwZVb)}P$&{FAcGy{DKMwp=m-|8H&)+j*U+?v*OXwOPiwCuEnq!5Mcq4^F$m%E| z8%JK4P|(VWU-nqN<5z%iZqMZ|%?bl}MrnOTz1W>^Ph_@2(XaeIws-$d^AbdGI=f|W z*E5k6&pZ5d7$14xMQ8!%Qxtt7!t*&7K0=8b1f1?)jJ`f31pmFlYaaJ+bVO&(-{Dj2 zPhVKV$Nw>O<%H1yPbWYf|JO1{@=~beNb4n5Q6_<7WvJNt!NgMK8a|bZf60VE*i?)k zfiu`SLQ*L9!59jkC`Kp}Vxhs&sK>>)6Q9EbL`UkVG<5eLOKdXHw$hQUIZrXXn>{hK z^HOUt(uVOI8~y}xzBP-mP`9i9!uC7J-fg<T3yvQvxK%WX|18V6Io3W-@xWi(q@fww z_YODaNRLe3Y;BB$M!1ba;YqNmp_-)iJ%sux_cDazrfMbov$llzHsb33?MSIK?Q$6b z&D$Q*>;3DV<7|zH@J37b%@uu~zgzBN=>2OK4d7hlwf-S6K&*X1=jX$5Ep5vR!HvoN zs?s_Er(CQGe4h(rB#wnnA-J9h!-<>vPnrE6OfjIWI*r3>k&)dh@t7!@ZPvs`jT^ud z1~7|2M!PS_xp0wt{&T4MOop@6k3_zXya|+Yv>3$wycfB#La?Od&WhfD_9vF*Sx4n> zE2L25A_n{Uhxgv^^VyS4LqUS&G5krdEseu0cf|Bb)qy3aUu<KTDKWGX;wE5segp&R zwX|cGvnNPYXfLs)6<1DcJ8a1AD7XmT_VSJ8bTTKf#*>Rl3EFtcW}brL>~2f?xR#++ zx2Jk;E&uZ@I%~OFPs9+W;GPDWSZ)y!@>iJS+`#S~Q6U7e0awwUx(E0dYGKEE{_8>O zSD77$i88Lb>yz=_yuaR=-r3&&Zl44r>j+5v4^&{F4u>9MgnPc=h<P`BUOec20$r6r zo>DR4Q@x)BrJx_qRtd1P1{(ytmmAu64l+lMUnX~N*TAoL$Aaf0o$ssQ?zE9ScbMcE zOhnWRfmDklGu%A#X|%)m2*h!ibJliu*?y)e!q(Wx1Po{@m}#bJ_93I+X<<S%T1Akw zn<_~6=7oM7d$q(T{sYG>!{bEEMO^}euKDZ`+m(VTCfE&)`SZUfuciX?2htU1#YWR+ zL{P$e%d`j~WMXTuhgfgg+Zykh=t|HCeiD0lM!(g%rFgoxg%NNlUp(+r9UlxBuAveD zBTviW3fUpY(W6DN$9i%Z#__<+t4*>u#~AV00^u>}kfP(E5xT*698zc~`rol&4gM}i zLXXo)0${I42vc32Gfujdz6imTo#0Zl4<y@hDP>?rwzKdDziirR3VS_lPfkIgQJPlk z+~Y<5yp1*T$bsnTLqQTdN9T7ilI#n1sqq70lEy24=t2)y4?K1<Jy^Dz|MLKhO(}VT zVeWE};jdy_neqigU4?0a%6=EH)nXHNME-^xMLEJvMsT-0g?+?D=qO=x=PG%?r{A8~ z6e~$)M%@g{Vd+|ThC!*~iFHPMZXx#l5y8zIrx>=phe6dLgbKzW=hwC$G@aG!Mq?*d z)5(MK&LPv8Aos-9yq^1Zi&Q|R3#W^HHcKXz^S;%tTOcP&H(|xR&x)*sEvIXTh`<8a z$T;!;A?vH6;%tI#ad&6%012*xySqzpNCp|)3GVI=!8HVeySoGl?hpodg3F+n|D5}9 z*Se42L$6i6YgbpV{%Tjn!o!6hyG28zs8JM9DErIzV7%zU(1vB?`-?S5!3hZRFAnT? ztp5^B3NU!r4`q4?;tQtwZe{jPtlwD#N6hhIHJD%0rFpG!;djix$iphF3ok!@!}~%b zyu~drl+MO5JXoZ8JTMrbc;m}YM!StDry<^rc+`T2pviJ3`J<pkvnX?hq0$NHzv3WL zCX-UU)Z>8t2%f6fb3wmiQmS=hYV}5U!R4c<OH>j2{xLb#L;s~(yGQ)A@zUxeqop9P zj?g!B7rM0f8p_hGrIHhcGwdp+s0@MFbDL~2CijVRh4HAgsr_{-75vE3e2Ba!ch5mX ziWSgO(?n7m!Qy8oajjVIiL0}ps+XSzbl%xdDGDBcTu$_8VdQ4R$y+QI+Gz^y=~f%u z{7nTbIm<35{Wjz%>0d=WJ87bkz~3)gs?LCNqCv2AICUIROw-iUVZM#NhS|IxKb-d~ z{}6IJ-Uts3DfUSp${WK29KRh|27jZ=ag^BbARmXtpC@b0gTIXL-U%8!YF9lXYn!kC zdiO)<qvd|)a*;G$Q<MuQrPi!7CO<O#98WH%jI4K}bpu7JlQ9#+WbwuIj?yQBuk9kI zAsd``NPdH#y-V)~;k^b)@7C-cxyZBD%wpgu?^zR7*RZhc(Y;xxtw;f8;}}XWL0kIL zMH0C1#KrAmSs!;>HWWO$TMh;eG(1v^`xpp}wppSwv_@_PTJ!v#o*!FM`8i~~#7Ih~ zMax=TI{&Y`mQ+pt>QVC1ZpeXn{W(F&dEYm4NhgcxJ5T6mw>bLXDF83c=y@XuzPhyn zBIEUuMvq#SmZM~WQZpV^n)!nRi6;gN%{p8WL=1KG1d(k&{KzHV9_kXpub!J0TduiV z{<JQPHiy}W<JgnwM5alUPYjk({QBNB!_v3;SM{Tl1^Iye4zTb$+C0~)xE=W?`9{oT zb@u?EN@oDYdva_OriwprC5;O`Y7juv;g>pY6-8ch1?P`^;m83&*Qv5*7`_70p1y<? zYmmgu{H#B#ScXZ3-AKBmy0ZL%-U&fonk4~oqm_xV1WhRps(($=jWQCXoXq^5z6JBa z(y~0EaZ9B$nG;rk$Zk$FIb0u*Ic%nWYZr2Hhtq%>&b`kGcz*Vbm0h5>=ORPrt7|tX zKl@IJ^?<WB#3mqb7$`Dw8@N_|v;`^-wblx%u+N5p4ZOC=1{wbE4yHt-|KsTZ2w3qR zr3GQJ%2KR^LLp4f|55bv{W!vFTSET(?Z*DS-TUr`hQc=y3S5#Qel+SZsg)7a-5rKz zQ-lzrJ1u7NII-rq@eIc^eY|(B=qw<ueBY!9Z()0pgpNX5&Q~Nq8W1|spU_3E1^B<* z85zx$OkjW5n7D&F`O2~9)?O$nGVG3jc~2PRMpK1;-H2^?R@q+e@U@P?*4RlzYnzD= zI0{lsAMANtSbCXJ;m}GDcL;IG)pgKe2WVHSO%ujw`laRkiTeO_x)HN*WUZ7!0Mj+d zd$1BWlbyaf1FP9+yL8CEJUB_|zZ;gm(4MOG6nj!M*re-m_RCo%rS?B--d+by6OL64 z1aXH=6g4G@@1wT)=`}|nlYO_RYX?g`rNcp}d!Q=*X~RCdv&FuHuug;B5p8_&+s9uf z(wz%zaI)jn^}+vQ%v-SJc3#otH&idPY3NJ}RguZb^%J#1uLok0Y<vEf)*j`>&MtA| zgG+c!^~~sdX$eWn!fTJX)`*NW=$!*s1{qiO0gDyyNvyLocK~Xgm3l8Rm<@$cQ5HM1 z(A0De@1@xqk+wBwj5Fu&rp+^<GYJ?8{WjkY)5x?(nRL?o9~xp?{1qLc`sLj11~<%Z zT`NftaQp-du9kO~xWz2^N|xSH@P?-s04u2Yoxkt?Wm88lUjCf0qULY8Sg>s{z<b(~ zHfilA+dqu4wa?>&Z~9`*&0;eN&OE1prL3ANg81QClF`9pbc2hD&&gfLPum5_GRD(m zL1Kp^i+C@~Of__cJOMy~-tl-Oo&KJ=7~}^LwC|pKYeN?c+{DYbyu7w9!%=_SJzhRf z>h8+&s-q%?Os2mQ7GpToD__J%x@z#?Uy*-roN{ig=x<8b^FI`CH$N3<CPOdM&$FFo zE2WfYU7Y3=W-q;-1ERiBZ~u|mn;RkRa^LF@f4;5E5&5&x?3(>)H+FS@C|bD4h`)g; zU}!35V~Sazm)UxPJkI;;+3tpjMtJOwIpYrY`JX<>32DpJWmN>6iB)U&t?g}s_uipT zI#s0Sh3x^dTu2i;Kj29%Uw}mrFzR3Fayi!Te|n?e#%J`mwYHyW#VBPwXI0pQAD{&K zHiKwy_nT6D@0oBBkpd!2Z&hh;lFB`uP*v}LibnQp$xE!+qqNRSLd+xm9)!7(K(TC| zHvQh&XOmv8xZX2R%u7(9mz!^Ud%tclrjH5g%-!AW^32fz8yE5+o^0C8ol;+nW?Mej zpyq-EQ%{F;vn2M{S0KW=|L%s9#1=`bx*}O@#6WlMD6~)qaS{YvrCx513qs^#MVL{p z{oI?>gqdjB_qA|(E_G6Ej_x@mlJD9}w1OlK&7^c^g!%N3z&Ghv|2*NAe6QO$9$Y#4 zlS-<e<a(xrPRn(}5+<XZo7{3C*x>sc;j^=y2+b#9o9maI7Vr4GJDLQ*-V^wzbN##% zKLC$S5b*0Tm}xe4xZGT<x&Lv~^$JE)Uu2~HELt0N!E`5$+&+heJg&5^<GQ_IEWxTf zA2Tp6E0Wghnc&y%;A2IOYwSIU8FM9K=zC6LwDwOtMTW<^u@--2u1*p{*pZ%3i`Yu> zNL?gXw`Xq(^rw#xYclMzVO=B>4gD(5#=oB17Zr302<fmmvBuvokVb$j`<-wJ;n`-Z zL?`B1(p)M7oh<_;7Ds-fL6xWdz@NY9ec;BFSk(4O%$C~K6_t*jfhzrCk)Ey^Q00s7 zKG$?<ju42hiy9%5fDl1z=!s!l)0F<F7!YuNsxxwiK^eC=2}C@|{eBe!x^#=?rQuCl z0UvnhB`rUCy2wgBj5dOZ7+Z@$Yb1e8Hde0wV4Wz}MFqR~+{>34AnXA*04hSob0Yon zGKSbw1~@r>n6B$xnT-lWFS6<M#o3v;kA2!AzN`K*WKE5c;IZb7Q|`^-KM!7Nx3L~V zpz~Mfh>%1ii=9u5F%xI^F+jbwlZfe)xl<=WU`MCC(fs{|-P_<|b0t9wOaBNv@ddG4 zp~_(c*kNlw(z^d8TY2Nt_itH~mU)wI`?*KA?P6HOUli@w69dY~uCOI(Pv4-wr#`Pv zHNVnHf+ED<PNt}2JK2HTn%z;uf)Xki{R9tAl_`-Yj*vVPXs;~-6%OF^A2v!H%-a`Q z*7`@^uN2y6Bw6l31}&jf|1=VYLuAB$uJ#{icbqLOZ1giJQyzKjQ;8R(++{Bynt3}? z6DW4vyIEfTJD!8G<t+ZY6?|_D3qasKk`yOk$6Gs|kgWMe%ocSx!{2;ci63MaRw73$ z!F6IDK}~*wz{B;MOJ9`yB(&<Sa0!KSNbrkCz{SmCT<7oY*Js-qLwM62nzRdC=8(Hp zlT-tgg~uDVQ%J81spINj2hb&^bcCbW`|x<=Ov7AQDCb;w6g@YN9Ht$mU~N1xIB{d! z*ztQD@-_N~@Vijz9UAzj1RQ{zT5?q)N*qGe^fHYeCDx1F3zJi37Fq!Q<pQ4Jn`bZ5 zH8qgrVMG`u4paEwjM*mDbsaH)8+<{%Rji97!i!R|=ztwu!76+~1PulLM$xOW^)D2{ z22KQ?c@-`aeVO}yF1g;wD{XM%dGP03`xzUF5KctZn)SEDGJAFje{qud9H(%dEhGg- z75P<|#^(XF_Hg8nV*E*;dcrEZRSFAJSH8p~a}4%qCQE~#J9^PQ`W%2i`XSQ3O@oU8 zdK=Q!7-Ltjo0M_y7`?teTz%9<_t+}s;>4pw)QQ;^`a82U#U8))#ur>+5w^`?eOY3O z%f+0OqcI*7)L^ES7)a9wrx5bU;Dm?FoAPOii4NI%<K~-DbuTVI$f?^gI?x1?K0Vze z$bIO>N{G3Y#R15lxg-%5^?g=XklFd$bOaq~1u?z-n&zlZ=#9q%h!rK(6mUMOi#-A# z=m$S5u{?wPz38LG9xBFq#kP~C`6Io7nUMSdvqJ<vPt=6>kB5X<_hdiZ(5s{G+n?$~ z<&lCgIdz)2*3{dmB#VnGKGwNlN`NzESAYK0&BAFIUNC5r9pChFZT`aRQt`#Wx=-ov zXPq=XOQ{d$n;25nj#A)O?`V2+`ebiLbG>aBrgl14(r|u_C(|(59fHl<a%zv%X_C!n zdU9s+76Glz&(eb-K|ui%0kOOA<Q-46)d&xp!N&B9_sHrM!<yiNwB`VMJkegUwxCaC z+b5rfL#9zKrw9e$EF|gD2r!DBjFVYZ(<0e{zPHXIRy>|xFOtW|h~*I(=G4jHw$LiZ zvP-B*@N#Mt<McIu8*c2SbD(GRB#QWYDZ%F*5?k07(v)Qu9m#4oP3-dv>%SfsYZI`k zE{P3O>;(`3$~?NKmz#|IbiT%3Qz>=eq|4lu>aD6rhj^lF5fVi54BDu}_@bmbmK%JH zyXN~gqzuMb<C(9-O1gl39V4`SJ^zbxJvI7X(^zZmwB(gH^+EtZB(ys^v56t!$zvzM zyJSfDWX%lu*(46W!0hJ20T3M+!)25S%x#at)Td*<;-z*k%O-@Ue~or=i`uZr-0m-H zO_hGQ$w!MDPs3fdo-xG6>TaqZh7zv(Om!0krp3JuAhv5;U>X%*gH;vNcqY%Iv!}%& zRVh1v67nHtyXRy0gP=m(@Cr0mLWHoAeeLTJN8l`Gxg~B4Fx24JbaJ>PJVH1<X&Bn6 zA?qjr1+#%(FQ-q5b&}!d$IHSagcFQplsM^kfzDuK#*yA|jLLiKKvc1h>})DbZwbtG zUI9v+dc)y~;;Bhr+!FE`#rtXV79LM8Mnhl3AkWu(hE2e&30+uTa`FS4P$$-Da-QTG zT$4T2DO?)0Nb{^F@*Fml2F+@VD=(TJxy@ecq|TMBTdohHSzOg(`d5x<aRV6P>b%5& zmLDep<b{_@`C@O_Vgf9V<mF<KAY&Lje_@m7$F2R)E8<`8wp^agL_&-bLghpN6XK>g zu@HQKiVAzg@*|)#Rbus)kHs5Et^)l|{_*%VT_s_-$rRB!dgIlomPLy9Xhy!4G`%Gn zKkou`S)@lel$|mfu;*vDVQLgA`|#w`n|R^8y@HN;6(K2QTdh&r{R3!RYI5h_c*L7V zkfycgXfcE+HOH2b#v|0UuWAT>uVZDc7E=5HnNnY_5;7~fIKGcLAw~8u`^x1enI`(@ zCKn@3q>Q&S+Q07kZ-KljuA(c}r1Rs@JJcla&wA$TF`-m3Vm-f@{<Q-OpEEMHuU@x5 z0M+ScK!;E6{UcFUtU#0JwrPfp@{?6t)2#W0cXicIbjc7VUgKhw)l_4Hnhc%}JHDgT zFr-^v1Bi!t)!R@Z+SyvSvvCGRR$)7Bh*y^6&SH4-@<~?lTKhQ}xvk$ZSdbv<u@a8% z&vN{?j+_!Xkepcn5h+&5<))H1d;RGK@uWFP7vXDB;sxkR$JqrM!>4rV8KC5^((lZ7 zzqQ)J*M<C9jzGvu`eR2+?r0aT-#x6>yRC1G!1||;7v$&`$wP#nWbQY!8t?hS!Yk9< zvw6=_ZO5I|%gjntRGN)hWo|9U?!v;Ac<jd{-{ml=?uNy+5yR`%S}J#jx81T7E6xQl z@qa82L;LeTjAtz(LpB@F!K=hF%})a#-e)*ckU3;Xl?l7yRr5d9Z%vUel&HgJQXJqm z@^Pgc3R3vT$EA#tU<yx~-|O<BUY8xHQx2s>I5EJof#vfBy7&&8I9dV*D)Acw`=`wN z6GlG|q3)Z$Jo+m<!y7TF?7y&j-L|On<5cEaO%>eH1aRR4$py7A7Pnqp8yHgNTn{17 zgQLX~1D7eE!X;^sBj85jq0ONQ_+kWrj)Q4h@cAh@+LnQENFL}r?o^$~p@8l(@x(5! zNHF*4n?r&ulSPNAI2g=kKjywf3}ED_)ZkD*6Y}|7Gbe}<_G`_@Pehtf44yy|v0Af0 zb8xx~-tc1#tc(}a;J!dYVxePiFS^^6coG%N9%`*l=zNVX-a2oIrfOD&fT`c9v?xSC z;dHRld3b288XuGXLm?NVxo-`^C>#yG<UUt)igHB)wZhl5ByWdYX?+&=yrjXXYC}3n zRDsV5M5xwyn2fZTNY_Sx<%HCL-b84E;%LXTh;c&V5@v&BGzq!Ym&*%+30~k`v8&|* zI^MT7MyJ>@*jE5War8IiN~TR}?;Q<nEas4&91ge$cTa`SaqBj;`_Zy>jjgnzxpoV$ zrw;fErc{<|%VH_u8`+j$4ifAUn}(sefy5k#GhH(zu?SKZRiYuD&clx!CkVy4Z?_$F z4-l10zsk3x>|i*9G0+>+1qmPsf6yo}30CM$zX&($mUFl8b^ou^j4^nqpT#s<=AIKH zgG`7LV@yX}JMSbdbI1;_lt9Bb$I86CdT&vont!Ir<?AsP|B}5vuM*#A!B}8l4o=*z zkSZ`fF<8)+z-<yqUIOR4y|9N~KM0wKvY1|2_EgvsfgJP%OL_G%JU&SF0)TQmMvzO3 zhL*58R^oXVeT{9fj+?IvSm?g-YesyU((y4ZYrLP)q&-1H0|9;4Y-euE7+dXy;Zwi$ z8n1m0cv13VDxyxT5J4s6mxYfzJ-S(xjPlyaE2g>jw#@Y;(@I=;Z{dK|RTD_@H?H-Z zDqTXxIQeT}U+vs>{Da$U<=x+|)(pp0_zvGrvp3rs!oJ6s_7l0m=%*fow^vN0CZ##N zxVs?Zs?)d<#Ehu~%<2DGR(t1H|82Meb3mNLp>RF1Jh3T;xXG**wGhBYzp0`W-WeD! zPMveVkz6h%6_Gs3j`Mq-_%}Ym>c~ZkwhD)P+F&CaVf>7hDzE71r^dq;bETbD59kk6 z%(=9)gjwt#Y@|jy--eDR=*tN=9P;h<Lk}tmAn2Ivz|QH5Q$6=82zvCd?H~6`H`q^c z6{el>BY)kWBM$g%``Dgj+8cbS1a{rqPg8dcJ?f_W=|v{SF71gP4O$B_N;)3=rHe}? zrI^k5L-8Q>sG!;=I6Rq2`|Yq{TsHcRfFLW@FYf=KRI$@wyf59nat|RnpE%rI-u1EE zF2eep-jx?q1pKnP+M-ImgtM{Mo`o|X3X@VBrC|a!RTC|wW65z5SWsa}X=S733+Z(6 z7-nPDhWAVKxIR>v#s8!&)K|la8=Zn1L&qfZwTAwy8d)s4d(C?N(xZQie%&JcY!4kq zi|d-gam;npZ7#nM3$#ss-?&Zw5N7K(ThoqDq4TU{u{Qok80imaC{c)<=&UMe7@?7{ zc=ZA*aDC5x8-$Jgn9^S|#)Ld?OHRK?ty)uaa57Sy>Y=s$rmig7_@q8P;Q70hpE9%_ zIZUyDWf8<4Mk$S;HY2tfY$D=yoAK~bg;Un>*Wy2e$M)}D*WDSNOKvo#5OdAR)UPOt z7Q#OXdI`Z;a3a&jh54GA{~~1-{%M=)a(lJqN*CW~{|>Gnc*AjYpVagJ=ku-U<t;=m zk=S36CF5g-E3+c1oW4-}yd}*msih`5!meh`UbOvN4AnTADa+&=_o%-3Ch;Agw?<A+ zbbid+=F`KQqYQ|giZBB8_0K8vaIxwG|72Y-E8{=WZ=#R1MG~#GL^*F0Y(a_rr(xz9 zmL6uI1Z?}<3m<f$*B$MeG6Rv+ng;85nl3}6ddeI~?<41MKm>3Y6kk60C=7FB$Kc~E zqts3ZW=nq)?vDqjmKeXhKZ3S;IVhQHcBZpDeC$wIx3x2%Y*V^+rQ+db{daY}WNl|4 zsDH>U1B_N8udixzLq%|~9m!U@n1T+8x9s6N+5Lp#pi#x5Nx)d18da<;FWC98n$!B$ z@xKYo974aO$5l_QveXERz+lPNtf(VP+gS}gSQKf*zV(O(KNDRA{lt@dp^GXie&ttW zY7~pNdi<FjyRAWxpiU+y2L#AD({t(J#Z4D-0q9>!xO$P0Uo`OIju<HC22a;0YLtOj z*Gen{<b&ei;mff0#?1X-8zuCi_GJ78L<ecK8+9Uv;oaU3t;ln+HnolBKheS|@!EqK ztHaWJZpq{7^>TdYdf+Q{-U1NU{uXQCMf1eowT0N+(ufwv=sM0%*~cjFx4flUIIOdX zdZjuDcCTf!^%;&F{g_f)^=w2?6Z0Z_^X*hS(*FfcrK<rG{KB!&7uqliJ|M(2g-dLn zpK_l@C&kV@UEnI}b2>#9&4M>JJ(*V!c>5|70uL73m5ky2SQMP+ckkf&*`?#t00xg4 zHiz23UofxI&&X>|+~AfN>0+^HurDw=$$n6QzWT<Rz@53p;e(ermSk};SY6@qH^*0m z;@4K8c#t<i0<$xDA-(KA?&tU-L+3Er;outt<R0T0b$FN$<#?LRO4c}8N-{x~S~%nc z7K%)Xnw;Kq6V`fQtt>_uLG|e3(XTn&rQ$o`J|y_vCF@m!0<Kq;1|q-Pt4T#Fy9N1M z=($!5)qy>k%w$7<N392Yx)2<5hN0g}VlKmd(DD=3e#=^=gEOOI1N@o6D>ZF6Q&Ge8 zPIN{U&_XQ9!08q#3Kub2z_)=X-ebX2#MjwmSYGC>q3B`FqODq!UWw4GL#09#&M1?} z$_Oj)-@r5R2xTKv9{=xPyP-b?{BxWY+K<06ibzgyUNlM}Vv@(4vWqi(H*o0W3gn+< z`BjHsekM!**bZunMKSKcZI)*$LP_A{5}o0XsvUu+`-LC({EWx38_YSx4-RivkG2so z3r0uMwu#ZC&SCzTnY^BC=Ef#rh#|sHE6oYCwhJ`q#obW`r&GQ0MTPTxjwD#tGq<Ft zZ@qa-0)>i`LU7}PwSV!c$X)wzo9MK793vQ}20IsfT6qI5soKz;Yg_>bWqYi{WMx-S z^8C^Al<kGC@65z(W?IAS<U~wRi-ZZI-Uds=&NhT8W&qDwL+!y$s7Ezf(abL;vf$}& z-jh;?mmwx17`}Qj>wb0AZ`<=xX0X@#y%hg$B3)X|L^Is~TE<Jy-(wy^>ZEY_m$tB( z0g&yto}P`zmgMJ?Yza~v)Sgchz|gn7E8P(%(rS9-M1z6~7JF1{&LE0Uy&Xg@)O{%O zKt<F@^%&fbPFlT$-ugxt#xfw%nO3bT6J8OX7mr99Kq<4bb*)0@j%CQAOiR-Nsh>^w zKY~kwbHa;P72jBc;c;n@_d4SaWtKsM^SF$b$MxW@)yTKGcw6Ob8yP{UjDKDWiQ@#) z(e5&9XUNW?+I5deOM%#aQkjrDu38sFARsP=cxrZDVQaNJpZQOxkBBrYU$+A<wnmqS ziwpm^wVrP-XE>MZTdU9kW@u3O53+w&(+MN_-~I==D5Pb3s?*+<v&}XT6+bfnptHIo zI+Z7d&RX+Q+p+oECn&KaQq@$wHOTOK4Xe=)QgVoZjD*Qm8&LuCrWQ4PfBEf~YO~cs z6fUB+79$i!T(i7Yb5+y3fS=fa)0&fsl+Osk^K%L;Vl`_uir}^bpjF*iaR}7z6F;m* zZ)(}^jAX(4P4jPhTgqrZB9d2+#yd`rmyOpJ=US`Z+o^;*<$dr$-^9GiBc6APT9&vV z(6TC?p^=~HmpS0pmcI%E<J)DK=pLEzYlrKy_N&gu2u7})`K@!htCvnK6Qh6HZ~R7- zG-NPxyOr+*sW6ta&TR8abbN(ARv)lV_HYJF9NdV=s$9~MhVM}Nlt%@AIw`U})tchr zR4yowU>Wqw{`a@LYl+Jd27)SUf9l?uHf6eV`nR}FY)$btZ0TSsK$yH+$ZOSZ+l;E^ zn_9#`0#(GhIu@i$sP9q%U*{Cp*U$f9xRo3$d!X#oQXZBDG}0$6;a%)c?#R|BHoz|P zn}^+z^&rDhU`9{>!IYDV4lwlab}~N-`CSzt2}EJUP)z_kRsF=v(o_gV$YKTW#k!L= zWa=iX&+C0=metO{9h0z;lB3%(&_tV<HORL7Jo7NNaeKpyDdjxI5QiffOZmWub0o_s z9gY2iP(fo7clPH5@?nW$SE`hwIdVyPhN6_b&LEbNcT_68WE#KD6I^+t2`!ED-%ncy zjbZacCAG<yQ)_r@Q~u{e&ZiJNv8U{Rql=56^<zUrLQ1=fO~_U)39v9jA%>D{hPorx zrcfd?AU0cx<V&PQ)|LT~oDx$iqm_<BmmV@(;`TL2lt;%R{J=XEcd9_IUJ<oOG6b48 z#o}U)VC2V4MWSvf#2b&=1RTd^U8<K1c?_b$v8?kA5BrW&JG6$GxO7E|$AO*TYUi7# z6loM7*v7pXL38`v*36S`QzMA#D%gcbcC#>*1Kwg6km_9xYb4zi=tUXEOM`k9t8NlG zo(?%j0&W}o`1-=`;O+IbS+-%E!jR9L7?S|yRP0nmVGxe&-F)_3nuIBHgeudgZWA9b zBpo^aeLV!Z6@ISP9q+oNNe)gicaRC>#cM|ZSFTs+AON_bWWlfb(ah=WW$<9>tG5dt z0KVaZYT06qyP#06=wkTY(qnE2pr_xZDdeXCvaQHd6W~<OR(OKe^Az?Tbar4u=4F|R z4~O~WyHnU+BPjSoIof8gu&d%e0|S_TVCqbn*ZBH;BECZ!4&(@T262VC9E={R<T9Wh zOfsUDwJ>cTRiVowNk*hF{hj^D8H;P_<xqh5o%;9;ewwre8&xEu-9)^+PnVubv(zmz zUeoh}OFUOuK2ym2!t=1xFTISeq);XpLyBm;{|_jTz$;wZUp}Fbt6n1nt}HMbrj+Od z2_~0@Nd>IW#YoiXC+TXjT!dhZAd)elET=YSD4RpLJ`f)#L7&FGZxQn)5D#Vkf&f5= z8%X{KlY0>XEY76g{Cqfn!h~vt$uv6<y5k0g#wZF;eZZf#5|>(+1L1Kmcf;(evnI&G z!(dMTT99yEx4XkR<jLM)oIZ@>pI$zU69ppol7~3BcPvpPzyh<@Ko?P$8P#a4<45G+ z5_BFIAi_(iA5b$GkdTLd6*gy>7J5z3PM;%LMMth#UU_=67}DImw0PSkl9>w>Twm02 zY+Tb@jiN7jk+s5Zrau#*oBd|8WabdeQzV~&nEzyNh5>`QJ8-P#7jSSpx!U(S8i;hN zoU;ujQdX+Ywv=)_a(7KTXD0=h=mexA0Iud#($1SGo!d(&@NKe7{KtOPUSTd&55hyl z^j{{0s4>lA$_x!3cSdS(a55SG^B8K`9Ft@oLgS?w_hsv&#bjqhwTVeBFOFmRtd+69 znMFL%(o8rc)Px@va9D#Xh3uUwa3!LMYWUq(DP=Z_aE}U!623mjHwFMJ5hxc17+0rl z{3uQfnCWE&#tVGBERT_hp*81RH$Fzzg)xyI41XSFD3zeB#1N*onAsUb!2ht6uj)X# zhUu44Z=8U6E!qGVr&Pf36J$$b(4jr|GlrxfigB8wp!%R)w>4(@FGx~EJ)Kod@V4XG zka>gn_~7rKb>Bf~zs?u<w|<_j5LQu~?xT+E6I5k~iDNgd!&T6J)mqmELqCSdM64Tb zuifa~m!?%jHn0Qs*v`zBCs6d%gd|@o_+!2MlsmQ@F^uFxrNTA&Y=C3=PZ)di8@2N0 z$)&Jd37Ho$!hky8sD-Fn?!(7^p#XJdhmpxCxn16KH2XcjpeRkB>|8aM2B+(hAS7jZ z4-dD%usf4CabzbLmq=yZTON`ea%z-<AP8?DQuX?4+Id-B4<x*&=guHvi&^>Wm!$fJ z=9+vIuo2%``luTEjJrb)T3HseUjV8&ZP?=zNPI`}^3_-D*ZRst)cNzBue7dRaPMwW zY*Z&|JH7SDuHW@-KW5PASBNmE|FcD>T&_Rw8hK;=O+;PZ!xt8=Hdd}tG<A#XylI9W z#=k^k`h?N9S6$mfP?rss${1R}Ht+m{Qkv+=Rm6bs+b4<ugK!M)))3Ly^ss((>`U&| zie0ISP|5~Dnt^iPht?b4U5Q=wYaXM`uvPWc5$v|H?tECrv3@Fqaws+)HLDu;pI^{! zveLN!4bgC**i@SnYpcno2<uPzKcj@opG=-zUfT9IvHbk1g=W&(!~hL~`s{XSrqCCk z6|bMZDqW28hqLfo4XrH#rWEW%edd#Yzk`aLJ}w~?(5U9xu{h)tqE}~{ykfm*p-GVz zEkqf;sSPy>qQk_=K)a5f#y6O^nXE@XrgoJ6O7^hJa!nddll&qg8&Pw889qJ#t7Vcw zjMH5+hOMc|K<vuh=HmJf=ceJnJLJj^&)7>?)fE3m*!$PHOLKgW5o&6G$H`y9N32zB zm|le&Up~8!0Ihz^&Zx8;996J_9Y9d<Ox~<O9Uc^i{<uYWx>cJ2W%J6Pk=d={_!dgQ zr|6m}ZZ|@(!F~Nvel}j^%7pcAQX@!FQiv$U&yX-PM<(|*8kiS6I`GLb$>%mL>U1FU zDC0#JnX1?oL)+k)<LeCy7$qSCKO)Q}n&Z$}mz;3a81H-K$Pd*LW914rB_&hQ45m{2 zlh5N+nxFBHLVsV+-Hgi_6$eGr_IlR|noKZ$J&OUQ(0|V%JaM}#YLx{^k<4TYBw@9< zc<ZYoPs^`-k(R0!3zSvF5(jDcpDTrUGnV5S2{21DwC%0dwHo>`FP2o+w+|IG^-Le{ z&S+|Vau-LKb2Eqs3ASdjk|nXG<Xg^ixz8;!t6D&SxGqe+R2o1_FAlt&MmH_T1q$PX zr)Zv2B2#|v;PMm;CRL9@x#y^l3>m-aT6%ZwB!$wa`5->zm}-Z<$XCP}J;IRw9rHcq zUDJ&E2lvvQ!3I?#sq$G?RzIjwMXGA$90Qf)u3MHr^f^360<nb?8QA@}&B<JrQF^0= z2q=0zf{%+63mB+&Y!8_2<Y`81+qnpeJydUs{tI6DK?;l6v>>khLO(*xJB<M8o0m3_ zb5y}nmBPuC`kbpf(CC#+6zuWRvk<j8$Qao(RL|p*w_Fpcb@Trj;Ei^E(1Hwb+I!dy zTh9$-yJA;5DnkTXUVVlKzHYJp24SU8X7UT*6x-q}C5KFAM83B0{>zfN8f;LJcoK8| z2~d{Y@u>EA4%6KizP)x|)1Y`zG1n-YBb-^#5Aw1dZM0tyn5t>k2ljnt)n)RS*}to* zu+Fd}1d<FdFV~^Z@DhxCEN#|bQt_u;3$^)>_DBV05j0+UWAeQG-o*@d21NEFjc;l! zr)*n@2UF8UERgR{Q!D%y?+uP1mz&+T@MbvcQ)ggdmH*k8DdlrIls7M>_JsUQ{7TkC zObD`RJkB~kUb7dx?*87n0zCE2otS9hE7D;9w#cy2z2@s1Z4k3|1~Q^rs~%BHxPs;Y z0_MYwpA4P-<+L$9wjN##Iu(J+quth)N0Hx5HX6JFJ|XJ66vALdL|5n-YT2()Qf=LE zF~=7%?sj$-*_bELfa<AL@UzZQF?m+OzKBu4lEQ%5T#v+dK{?AN{V(tDK9M=foB?jP zo*^z)xmX_~iqI6w_4T~r4BhywvKycYxR{TgGcjs(jD<(3Nt#(s1fx~i6N+g#lH&wk z`vov_%7*Ln)bOrpW7W!gbZL^u0<M+wg$Cshh(#J*&e(jfrYE}{9u(Z-?5s2VE9cH* z)v}j&e`yEh<_*>zsCFKgJw*Hss;PWrZ*H$gzA#ex6h`cn`5F;Jo@}08gXKPzI`k~E zk@uJm*+zx${baKrh$VJy-PKfJRNiy4aE`dv&Lko>VrDANloha^`7Betf1^WWaY$C2 zj0I&$hV0irjIE~a8`;<sNf$T25Ed1tNo|pLE=z9>Vo9m~A<Y)%E>DvYCf|>hRGrqA zLzC;9a~B0_Fi0Shtd!0R1_c2zbm767Zj@>YBkmkw=>X^Oe=9KYzqI6A`)5c4rN!^e z;fsRc-IfJI(s%;3PYA3d3os_d->Vv=Bg1k0pw1dRY^<ylRp<IysCj5F>NYPL3!&Eb zHn4C(82A`o{|IJnobc?>2vlHQ3-c9N2@0_9OtsI{8nRp1r*sQ+iZp8W;t~AGhSt7i zC#Y%II(PWRo`BYFAC5ldM}(fsV$<?rd9Mjiv?QJ6KKP${dzmX231fY5JZ(=}x<1gD zf;>9o<UMHMJW9-?`}Bea{@xjNBCq|93@$j>7ol|<pnf2KQ_CyX*f@IhUrC`Gceh<J zt%)&`ePEM_cX}|airAaA_4F96lzE6G-+c<4GFbV?ibr_1h}OiorBn2!JE<`RcPY!z z`WR)=y|F*R;uxsXre0oJYW9I=u6j{5%OLg<5sSE961|+15$ufag{lZA<{9(v2OWDM zDgGF4CpBQ<j;2Kpn1?P~v?ZBsP4iZ+8Kukkg@$D(y;P+zHQj)wwn#MAHi%D2zHwL+ za3<TJkosJxc>7Hb_-a{Hcg#Y4FN!#z=cb$e$4&9Xps<qHIH#{J%i|(m(h6O^*HM?D zqji=3N8PcoN#&$^gKPL@!Y?y&1}<Y^HY8DA5(vrjLvf0bBm<r<En8n&N-)e1$?wSy znEMPr7a6D(Id?Uy4?SoVndxi_JC*4<vGy{54k^&@4Nu`=PPSU7N31?fRcSn`0lRIm z|MM4w7O+5b^B=$WceMT=em^pDQjraNZ9ew#C;Z*;{Mzcu7ymWj<ZjZH_8TUIr@t5b zdHVk4cfz`>*m7_rf(Rsc*8yi&R6gvS>>&IAsT(&3*=tw!Q}<Q~IOlmKMMCWM#PsM+ zZkz}_;F56`J`jr6ury%2xQf~Efp0xdwu)sm*_?mEWAx{(hjbpoF2bJ2s1p#N;d0~M zk{!4Ia(a7u`_G<hjo6?=?XpLxXloOZO=4`FV>I*!W=6Z9%mG^_JPZo_kW*t=b;(0G zQ<BAcRyLfkBsWfSb=HZts|9DT0b{C#BC&KxqtLx9aBQhe8Au=(!|;_U@|*)Gg%Y-$ z6=dUNPGM%?@hKR8rnkmPUDpXy3s5EF{?W{75hu>&xhDgxT?LQ2<hZ@e*?2ixP=Cq# zdv9H%m5O4^X@nDT2}|wI8!dp?e9|6e&{WZ<ZRtdZJZ}4}<IhOh&!*PDqQkd!XWq{@ zDIs~`yED8_BT2-$3B|qVh<V?zuyET9L1a%|zfp=iiT4~R11(!6C_`m&p5*g=QkLW3 zXm752|2`V#(2fMkW_Ez!wJkcT2H$ofhxsVYPkT|5UmwpLQZc!=F*nH?DtXA`qm8(X zCJjb86do1C$momdFYFdqZ&N5XQp_7E&o+-fUAHLMw%S_gpYY_G1<+PLr9E$r8<u`$ ze3D>hLh+iuTD0-WGTn%N2zV+^safu6JuaEWTT!VBCbQMDm79ykFWn0$a@GjP?07HV zfj?WV*=GNht@2q$m~8NuarZsqKMHUE8mxPpV_F;Ir_;NZwez!)d#s12F2|i_<AnUh z=a(-yGf^*_C!Qo^7BT%HV)<F41w8kkX&+LK>ot$>#@{vTr&EtF7MDWBRKoJ3i!xXV z3iXS4Q)-q~D}c#LNW_6Iui<^f%NE|Nd%a2ZB|p7k^P}hEY*|IaZIuY@-IM9y8(zTD zd|m;4kw&y>o9Ouj1kj@hthh7<x(8@SAzdIv$sWL*niV-;-13ccbB~|zOWa}`Y#20G zTMI}Uqz}kbvJx`J#TgI2xbn~NKfdKdB4WyjnkiaD*NTz0`M$D`t8J@Q7!cR~7dm+V z;{HyfjLayU4t*iHV;}_V;6zZzc1>fCp5f*p!*Xr#Mh@WfQMYW#P#%*e;c5vU7MhXE zZu!4w&Na~vV+V*Yxg2FKZp8MWgD4hmrf=TXkZ4ot>Rq8c3Nv1w8tMZhvK=`Mp;l>) z>3fpx@h_8u`ijcFkjVo5zp##a8&jVQ97AgQ5}G=jX1jM-9lPjg0Wq+a)`_uzGq`r~ zI~yxlg{GsTx$nuCKc+tq0PrUk5AAr##AA*M;2{w<^6u0lvSQ2MpFs=x8>I8QMy{g* z8ME3()7oDw6emlH2&AHiiCf|D<%e9gA{~y6en$?6NFBdX&9rjdE+%(*%NTsh7~E+1 zCejs$uR-1r(}EltNNHAB$x-`5yI)6VQL;NW(Fz!z6fNG5M_hvk$$_`Q)=U3T7#CVm z5XXU+*6O4m13&&nt=swd8%z`}BouP}F|m7IMSs?=<)(==;ULb+gu?3TB>Vm#&pq#I z@U6;_0|En<r(xA+)*;a+EIefn3je@ku4X1}jH1E77>1M1RLUV)QY6+$pvTqhM5$y% zhOPBW+&Hr^QMMjB($M^ykFb_`9TgU6lQyQ!q(x9PO+qq2XdsTDMe<7*j|(F$HcTgj zYgj<~XGtYXQ1cgx7=JXzuUbC^(=EOeU0&W>xi-AK+Owa(2tarNMm-#Vd!f?k2N0Vb z?t+=^t#+sP3Bh8>fNBVNvOeq*<4v$@=b<(pR6{GqAZYmJS*<p1*xsCZMWQ>!v3mV7 z5r|o~tK&k<Q~yTpE$02Ls{;Yp4fE8z)CC8@qZ5;m<Vl4<HYCo_9|pbM=zT5v`bxz_ zziKuK(|%g)K4>#eV6m`^Zj9oEOt}b_J!I==1bfU<W@p^bl;*N^sZKKcA$SJmqZ)G* zI1h>@ea`ruUq3TlYGJJrsYoP_njA~GSNriGQWDlal^^j!T^7!m1jJ}7$B4R1qg5}- z00ZNM`A7l_tY=D_R=g{nzd|6xWP>CH8W;9T7|0UWhXN(%dWiyKF-|@p0`M}ELR0CE zZB~(wlfuwugcfv-4PT0q^zW3C4Nwa)LU-;X*1!{2EoB|aYc?cVOmVFCrC-2>ng%rf zW7D&%1wY*7>Dx<x7B0+cLo?2&cqt}vr_H`AE@k?|8h!$wQV8!-;p9hrKa7j}gv=id zSvy$8<P|k&#R|Jzvj>_z9UYih=F>Qn#T`8j1j=qAQfhDbZ+dy{`j`+E(p-yVYj2rt zPfKSwoJx1G$Uh5D{r=QU_7G(M?XqmwtPwWu2%3M$4}id%JbSK@nG|}GTzr(MZajAk zK%CN{bCsDREI_eoe?rXCfB~;d5XN@=?Pv*NpWftoafA<D{{gIRz0qiB`Phqtn@VJk zu58&VKv_=h+~e$$^Qe#*vSqQ0aR%#)(Sz0A-P8NK;LHsbNTeV{#kuNr9E`I92KLxD zDvP$vpj^gC&TVb|vZipIj&*4gsKl!|`U_Nj+*;Lfs{=0Za9SN$0Wc|RZ4J6FzRbiH zkKhB#0Gi67cCA{PAqsn;O541M@>H$?{L`DyXGigpD2ytM=K3Y2Og2h7VaY|6%y9fV zG%BpxG}A^zVe$*=k!WGD5&QG!Q(kcx?ZZ8H<<_ytf=;5O>ktTp;xyhv4%^JnnPZ)b zoDvJE`0vY0mkIL3#)esq>$DHYG5Kkquv;S^2}U&~mWNQsQ^(JZbK}2jRPTSsK;#8p z7lA8cX0o!jtm3rjIn?Nr<X{e{!46oOG{?jaB~@BTRh;p+23=6Dr+@N2eojh538p8k zIWF$UQLY>G`iVczZSbc-l-Gg7t0~>?F35&-4F3vbSLU4tPe6}->?WUki_q$RmY6b4 z%V%ihGO4V6PEn%51gq=uKFVBTQDkc&S7{e!g|JEU7peM^Pkuca92L%&Rb6M?YR9E$ zXX7@>OBHRW`?Gc4|BWqZ_$}rir-i_EKLTrtnm7o04O%1;4IJKS70b>(dk69)jklDb z0wIe-5d#*eEJ4PfRu0RBF=oJ2teZyfVMBP2Xpp8YlS8y`I{NLO9q<PRY-ZdrpU;Kx z3WYmT$F92z|M4lMhsWs5?(x<OR*rrUDP^p8$I}Jh(dhu$-Yez0Nex_p8^Ci`!s6cF z>MXIy*$oRzE|5n2qff|-RGx9z*b2_BZG$+i%R0lhH7hX|a1}#?f7%Jg=eJPOIzIPW zl+jW|paWbu`ry`MH<bo8_L8&9h;#2v%5ND~#e&OPT0WOW_$5a~z}&Uis5mJ7^}ys) z3GL`bs=9ny!Afb6F8xJ&cSK4rMG=W$QpS_9u&m$IU3n~=*ohBnma7}3W$W-T4_2T8 zk@%l)s6c@CYx$>8-BrN8El~AG>D6Ug&odNS`93+~`Kh68rT+jBha>GnTbDkJ=5BYy zUlJl=t&wJ@u7Md9#f@G?M1cWNV}}^U4UavChY9blpM*wGmoeFAo>E9kIJfqQ39d(c zK7l`^tNwsD>~L^#3`1EJ@f0fQeaHzgra1j~d*@LX0>`)X%XZo-RyKm-cv<N1^bAXu z!iY1t=j3M#-}h+8Tqh06d`<>rQQwnL<WLWikP)E+VrZwAzq$IVpump1o#?b)8v-Ck zzJe$*#63}n)MJJV?P9xt&O%QXP|fn~I<}}$9oWVIpRE|Z3}?P=ez@fYL(J>nx$dkm zbzs5I1_NgCMm2b)&VQZtBa49e2CO@=z2>AXnOGeeJKEJ^v`pD`4%RPibo#GT-#-M@ ztiPF&`XT`hphwGE+<E&aPDY$GX(_{VQxG`EkHZCX*XX(N2mQ>dw@H^Ef4@1R6HdrP ze17xqmbMlDx8{T%v8|OZG2fHjl?+qMse{{W7O6`mvZ>nGA+nnK_0gK1VakycKGPiT z-*aSq@7%M~Y?2uP9I)hdrLEBlPo7q-o859+IU4U6eq!J7J!4s{%P_S{*clP)>_zt4 zGlj<tB`LcCQ#QWQOm8MXpw7E0Y>U?+ZdyN8??^7~9duK`M#vs+(nZAqDi~%Cr8Rc< zRkxRMwL$T5`3w^IKW8dLl4U_2sP%lycsFRKBGrG`BzzOwlyH#RI2+=tCX7d_>m-)B z<FJQso#oX@LYn<J^76cX9QboQP}ewg_TDgXhj8?5=mqQ_W|A46vY7<Dx%2+G-fxf_ z@%4FGwKG?Lv}gp1!p1Rnr&}|{Qah#;v4CimK;}8=FO8a|4E?o<7EEaLsgb|%N*Arm zXElfGtLG$hz5OS~pbZKOOr2=sH!-c6X*f*H+G6vWRgqeyU$uC;*<{3sbPRrk1&Yh2 zN~wH}(F>%{V%E|(uz<DJpbgPUZbK<MI2bOl!v`ImV=sX_YhUkX4lY;tD1JbF{7wXY z23t116!dxR$cUmmsYBN5q10rcf;tc7tOtcN<-%ce-+lFtVJJ(v!E9cP&C7YpeI$G| zdBo!<xw*_0y*5K|j&|JW$hsjF&ko_#;r;|NAO$Kg?P>WEX9X3!yXkbdi>U(D@c)|- z98RAS>S+jjZmP<l8X}p0LL(|L_Do#=Cn^od5HF6Sv^JggGAF}ik&uI26W)v5r9rQV zq?*_-=?_<FD?xnCyg!@~Mdo}db|8P$>@VCWHrhwUL#~G>r|=7A?hpe&lgK;J`wb%j zXh_}F<l-rEh+n(sRa%DLK+|VabG_XKVv_E*%ZUkUW?`;FP@LRki|V%acq@mdV%6{6 z83y_)lHdI|O_g!h+j?j^0P9B@^{DxB_1)tnrqV{dvhVp*W6*##@S!OTQm92q@(04g zLqj4Oq@*I6P&ZBVNNWX`zM&i0Uxfs_6re!hW9tOo5B9O{pH0&2#>8PpX;P$2?W<04 zvg0pbU^}u(Y|1)&3iE&`3aH&)znA9Vz!cj+hlddvBxA2AvG^&7-WN2CCmEz?)2`ua zfg$RKshhdCWw4VRwq@4nLqXWJW0PweCpg({l<UKo@i+N9?CuaM$Pb%;NUC`Jn{@tW z#rO;{zY*zZzQN@Ph`#WS^84|LV|FpnM4j&te-<Qdm@&I@Ex?6FoqSUG_lWy)9wlJZ zqZA^mA#Ih2aSbxM`9P^CbV>b&Q^O$d+i`SS42A{Ry*j>`1n1=&2R{hju{;rv@1HC` zOH@DiBKLiLs0kW2-qpHhpkem?JaVMK79@+#`uAj){uS|I;urU?5m#T-uY$0ZAm79l zcRR~OTUV-)wwSG$yHo1FEgO$+a6s{?DgQpPapD0jUk>$&CpT8+z@;voeSeN}6+p&l z1m_{plr#|8J{A=;|CM5-j;lyfg@viOiA}M=W{iX9LnVlIn}gsZuR%d^wYJwW6cz0B zS{aALls5lyv8fy(v`*PBY_>pR*cuZCfwQV87WREY7cnYACBZC}_|XK6BDDz`BMlHO zZFqMxnufYwRPb%z^66zQZyrTJ{>$&t7R9vb4~YAUpLe(j2@4W+$mnC`wTcnx2sn=u zeRMKurVXPst)2P^h5^G(3UN9ph0X`z;TNeyT6!UtBA<r~Vi$*<fx|UYgV(1?O~bHQ z$jAf$g3#5>DeL3axp!w?d1*G$l@a_h$vcop5j8(7&O`8UI50^Rnw%cLLdm54R1iel zz8ocX<AN;aAbM(fm_-j%PDb=dA*6TepnN=t%1;PF%BWd58T{kSXu*Do(Vq1gtV z5#0Ma>bI)#>GzK13di{LuM>^e74kC&{7IS?`(pxnFAv||>X@Xi+sTm&1H^UltH$$y z&b8BGBe=LI3+%Ii3v=cZ1(!~=sZ#%pe^u9#2|WuhSL3D|kI->i0%3QFcY%H$iYc_L zOg$f32?Ho2lpS&dM<4e@&DFd2^8iw{RTOVI%Cm|}Y-A88s9C`3FhFGt6xz5{Nt{{S zAJk3J^$5M$iijjg)6#ei^(9fIC0oi-CWqA8rkTgjNT**1b5+jIAyj?ec414oR(!<u zRn;ln{$UffeRqkuHcY9o$V)-YJ4g1Kr#ruE5LQ9~7YyBVKR=|>=DCr7&j51t$Kyqt zZCP~3ZAipV;;Qzj{?yv!t7CJy@YQy$p4lAS0rMN@6VOxsaQ@O3k<Mm`<bMgdhUF;` zkT6X5L{-N@Tr5y_K(#Ef&KB#JD8sNK7EpO+d0`Jia&^2#H5UvO4!P|dm7`io)#n`x z!LUko!3HnW_LSxTJ$YNr#ML}dfvQDIBYoo8S4IEr=Bp-qN<z)^-c*9VArt|a9uUCG zw+4L!1K$q>YlW!IxSt?;C5x})C<@RyH@#n)iHmflH`ah!30(qyW9<r{;-Cyu;~~B* zZdz%7I}>M4v`W>i_V+?{&ehLTtkaoe)Bds8D9_S@J`~Y@GqBSny(@$xCRX>bE!w*% zTl2nIbzuSCH7VwW!v(BY>>DKWVl%QKQvs;JJa9oDU18)G1VA8jR%8EnD=oCo#7+be zu_iEoO74mtm|*~_OYjp;DZ6;!9Qi&3&~y?OF+RBVXJVzjfUg6_D#8|ASm6&@kp)6l z8lC<h)hiD>d1m1au3?>VmU~y1IJ@@GmMmR|Pp&Q~SLr8G7Fk)ikB!$6l1-O?1h6GU z)5h$STNZ!huz44UZ1|rSMC_mpEl@^Nj?H9FRa>F1s*WO0gZJL*Ld|W+!Hr|s1<s4t z*HtObmvj--Vm^<qSkrnN*VnJ*JOBl(Fr!_g`+~*-rxuCSWdbW+1w07i`?Q2kE&?or zD-<T-i|GLY!8iKp%^Q#V>;#5|QJFXl!5752tNgp<2Vs@YjhV4QCf0~FLc^lu@JiB( zTC}Qu?GKnrxmjbgexPmb;vbDOUrH?iKMJE*b&hFNj{wYZ<wQk?C+Rr5Mxx#B!Mqr0 z;pXlVpjqoAgK{>Nrp^CulammW)u(}5h66M(2QhlycI@?~0sq?~>a$pSQd=5qoGug= zm=5ppusFJ!LKOVG!#rMs{bq*@;LCV?_Px05L6i8G<M4bW&N{>StW?lf&WY5O>E`(L z^|$qGE4gS(dO?Ye!J_11`N#2~*$?=^^S>pvn-<6FZ7f2iv2Aq>J`jY-Ygud4^rbej zl{AixMYiI|zH7pt+zVOCOS8UHHBd4`)F8Oindvn@5zeIKQ?mRi;3484G}L)hhW-y- zUmX`$vn+@^1ZQw}hY9ZP0TO)BL54tZcXyZIPJ#t@39iB2Ew}{>Zad$-_w9T8+ui=- zOm|nElGEL%dir!%ZRCxQyS?6mJ^d$g<bppIO$!u;ZZ$Z(R^r`*ih9yksn94WuKVk0 z>%4WB7Dhl|^}-PQfcu>Vrn=zB;_IUz;$Xk$zIL6j@_D{~L3CZ6)|~N8e~bh<vjoy4 zcFLj^?|u+|6Z=`J%kY->*RriY8YCOtf?x><`^plEVNrlaJ2Nkp@-3+>1+4`(fd;9s zSPI|w$}RO<xt8K~%V=Q&3}a}L2?|&X?aaq-%&Ws^HIJ-uT372r?Y*y3s@%w2uap8j z>PUub?LR9XIbFWHkGkmOg9TU`x!X^?3q{!m`IkiAi?gdum;)!a8qQ2%e1Z)Rvoyzq z>^a=1p;iS{NI2;->VQBj1K2;`rCnzK;33@C^<gbrz%{`NFD{uLehF|tJ^&=xh>vVI z?`Zq+>@=oYFkUOuMn5O|aN?@IDn*`?Cs=O+jDIM0d~iG_c5!!daQ@28AI*zVo$+92 zD|yvFB+5kCref~7ULw&bMiAAtJenU#YQ-qn7Hru$+Ko~}?f$`*>uT;skFN#*R;PNf zf2^Jw%|G{j95AjNX(n2^p0ED#-qSBJE#ct$&s+O%n?j95d(hp=JpSV$LY(;@YrJ=D zyq5`GRg{@0;W-IS{zf1)zrfe6c$21%`xW$vm+HB2^bWCHtHF}s^0K;!ndus`%R&qy zM}O_dX;eqaIL5GxKUA?hzO-sOK%d3&mwrd^-?kW>(FBOeFb}J<&pyw-Q0GnD)h>V0 zi;K4nQVOH+AcP=aaKx5X&FmKZ%5&lI$`ivnnsa}q4KzCGa+x+*<Vl0<E-2!zF4<4Q zx9@p$f4nE_D&Cg(%8SGeU+;^a1Y_d4Iy4jTLkIY393&Gw#zi;HK;g0q4RBq=Z(!7M z5o7_PoaEj4`8lY9T5gClltqi02x4q+WtB>i^J)Kf1TWfe{saENWwB$2KdhhJIv?+9 z6YkI;?@)NzdKl%tZUS6)({eBpMGoMs1go8ltFIY6gzRm$={^-12Cf%~`$9?{2@8Xm z-Aqd|`^Y(8mD~tY0CE-E2iX`3BFQWB?0(D0dT2fCrnX`{yr*|g?sw&u;;K7I#z3(_ z3Z?Ak{Ns0HXuf<(XMl%UPo}-QLXcQ;gNe3VuPSobR8849F&Iqb@7=>w6@QR%x$((2 z*4s%6zl_LYGpe)5Q9Wa$O!|TZYery$e_J`mRkPW@6Ws}hG}e`8+W(=jxypiL+JS<R zkrOop@tGP~ZF^AfcZ*_JE-)QYh8Af~OcnHXdF*C=Da=ePr3uL{myWSDReJjUG}rJp zzp;^qIEk>cWd@;xbN8)!XRn3s$fD|T9)#ZGZeWv~vvh$dXks7jq^nNOrfg`yoa9JD zo@GM1n{lBFtC+#KvCL}uz|-={`)o6hU~NM`W2NE*-Nk@q8y0g5I;FX&C*;diFEnj> z8`Deii=v$doOETMLw<Zy0}j8$vx73D!JzQy?XjjD1Sjh4?$*5;yl7aiFfztkFv2Cw z{OLLZn%+)f{nO-IE=0tW&#kc5r?7UO>$Rb2BtS)=^0#DjkTQk{g8&)+hv>pxa-7Qq zd60wSuhAOnm(s?##o%&D!gC14w~mPJa!sZl<r-OMzw*|@6xm<0)GcTQOQl8J-I3}_ zavdtP6qx8PbI?GcEX8ESaO8d!r6QPCOaInvgYq$Mu;X<eO^liZnc+?kU*4MR+&CbQ z-Ij$P+L|v`YK@&>jN3mkj->uvS|eh2!Z{ra=O%K76uvr(Z_ZgSU{xRq1Bv~TIQfBD zN1!32GNnIZIOVINXmC@07lCJ+v>WMEy!K@ov#}Z3JFzXe=ESY+bz%om1!N7>7-{)B z?ib0$2=5-xmx~eyvY!NfC9;VLXc)LcaQn&M9q_Hg<JAaum2jMxklxU!qZ(*uOH+c- zM`Uq&6=7ZAPvv#C;RF<bqhgc1tD6-oCBIzc!>`|7|B5hX4}Pm^$m@;lHxw!Oeq%h7 zH6P>ZB+=ANBI?N(cZVrJO;X85M>Wm0>d!YoT(=}1nK8b#NP?^a_8T)(C<u1kw5&>f z$jBKA?vKOE8xVWqp2*puyF=#gE4A^&3jN?~OYP3^cvO`<dPwZT?&`TA_hu+ABuGTm zGEi^-yqNTyrqB8_#Z-5i%C2s^89ENMH49RtMqL1%G0BAA$?2)$hPmd+*<F}PXX5oS z1zeX9-7r29vwV{-o7LRONGPLF!r~h#zz7Yq7TUvAV!@O<H>vT)<O{dX2qSwXp%0be zG<N7dye!K$%{$0AJ6F}DUSJcJW%gta*=Lrk;>;gm3jIz%M87B@!&R&(7=o_tFia?I zWJWzAn8Hj|HZ%?ShFiuWtVEE&E@vIZy)D<)Sy+qvMgUXD{WLuyx$dh?zs$AK1tV@_ z${hShh<nw4U*-5M#o%k~rD^5bK#iS8m|77SBkwESE!AY@nAt;Q)_p)L_`_@oDtIEE z%~TIpn#alyZka9Kxm4;@x=`}wZO!P73ojPx4%CCylgHQpEHXM3fQLoFRT235vKcuz zGn6;5J!ygowhujRSCyW&)2Ez*sadoRSQT9vex*}+&Sq{C{rBsH#F5iu@mAWpSL<{6 zx##|^ck*KiBAKjJNCj<TTw!8BF}C$5rwh}s#|jD>5wkew7_@A>Q5WBEhFMehSx97Z z)MbjW<osiM)u?~DP|fED9B0dSMC7vvqhI-w_<2kgPIp?nuQl;mtMBO3J~ezepAq}n zF1a}^K*dUeM=hYV<FOgRd1;~kSzK?ry9^erPIp0i5INwGceaBeM#Ufbl5MJ@ZP^Ob z-W1(q;5<6{g0a(AzcvD(bEJn?OCoEL)AS}zIj#<gY(5n2GVD57bsns(T;9>u5_`x2 zI@#PUc*z!J$TP;!JDi+}j64fiai~uqv>`j|yDhn%Qyd}iSCTe*i`k=;$AcRZV-1Dk z&N?3inlvbfAbCv;vE4y~2XqS^N71#y{y`<NYYj~YAUcxh*Uq1cod)r@CA@Bw6gc#^ z;r!p(U+(X{*cTK<=UM(`YxHAVh}d=>J#vZ9Rlj|*Dy55`feb4n%77EDsELF#ZKyw$ z{&E;5Xj7O6VTF@}9GJuPk6oA$%pL#cl&Ac5l2;h_L_zta>PdpeoRX;uv?KR_?r}MP zzNpXI)z~R&pCx{Zr@&@`M!(@ROO}hH(4Qq<==;z#hSiS6!pxFB3w{0nR;DMJdwr0c zPu~+BKNBi=G{%cneR{>@i6ggHiEnvFG2?iu;Y+q!xU*DwB<FV@j`8YFxvqy7+nmDK zP@PXo$nQq+lz|8gmgE^pYSAhTl*Vp7n6UD84$EJCM`@c#eYo>Q2w|RNnSKZG#eC;p z%(_^Ne-bdnP_i2xD6{h%U8~pyxH}};ad<`O;x0*SZ%7pF4RAYOqtdyIP)|OQFP^w9 zkVTnnNi1>sS`>e8Fc56_^r%sRa~E{<SV!<AG8uFC`G#ISn2D@pu7>(aQ*WRoa&RHX zus5Z$@5{_ld==iY5Agjhn0BE<?iM2!07}rIFai{tcG&l)Ndqx%`LTaCQWNd2y8me1 zS)wK$;)}DJakTX}qBVYbg(V)2=UbF1${@hZ>zNezOi~p!AO;_)w{aCUxUk-C5CTh< z<n4Ezrpn_5{f>1j_l0b=Ivz~gkhpqHQv2EWG3~^~uIjznPbbM&TerMUcLkE=dy7}1 zqK)Co6{29MgD;J%2EG?;Yl3%eXD9NNa%<@2H>qlkQ_}R|kDtQRQBpwxzR+2dw{ola z&j}^L)AIJ;*?6BYp;L|z7g}B}W>7Z=KR~VdpKUxxbr~;(78H4}UgZ6ah=~ku@;|!_ zX8igLrK~*l?w@Y<3H{v+ig9jCin<2fw)rr6Bh0^^oqm@XD>1_c@GR>al<Flt9;TVG z0V|0P^TLS!g5>;H7H?y}6vOtUt2u1e>@h+1ZOLZem(ux=<TOb{%1E3)O5|ly_=!xR zzl#w6v2GnYm6Xg60-p+!3XUO>R_HBa70ST!+^VPDJ=LhLO@WQPP`twFufmvgB$iK; z*`de$)sP>NgWu8)qK~?43b_rix}JxBCfSgrK<2(q{dZ%-X&T4w{yw`F;oYcMpp5k> zM*6mYoKm5oanW#jQlBZaV|-g>DH{bqA+>N#kbD-r=RCd_50^t0jZmR3;|bqFL4)O_ zzzEvHLvWf7o-wkO?5VgNL54uxcQ9i2G;<S^=TtS3&()T=pF#I>xcC~R+VUBeDb9@i zFt%EM#mJ7=74ql4Vke(wO6^+4iFJB4%&(o8j)edtJiKhyzS&%nyYqj+?kM}qqB6xK zPQjPwKi2s5!(c^e9$ndi{59NM#FiqCmxK$<<7P^=Yv7>0iurT>ll$J&*UIU1&dFo~ zl^n9;?`nJqZ4yO_DwBfNJ9>;iyY@CO#=k#M=f+;ujv}WxcO(u5V(Tw4#op2Tg3U)d z8#Kgyn2~v(<e20?8bvdIPhwl!_iEyW7(OIjvK%ui9zRTXbmH?+(S75QkV0*JzDgwu zZZady@P2NbSvsqSpAqzj96<xNT;zS=Yh*mcsP@-*MLr<S>TSKK%Y3WfUqOBc^fJu9 zOlz5!czPL^0PnpXY+i~?d5prxy0+6kWIbfuTMzZN<;Xn<xbiR$=S#!E$xqmveN1b0 z37YWa^!W-0XW2PCZFY;_(?f??9n&`_9Y}&7s43LAAqeyL?<cP^beZ#ySHxlFDS%kX z{lCD)l`Hz4hbs${{&?D%m?Hby_zbkhhpG>knc?=<zx=!S=%1G3yYdR@2PTEe7B(UD zZ+W+0Bq!tnVj_0?hRMYBFTZb$FE}~hHStBE-}!634k|gnDh{`jPA^Hcw7KH6;lx^~ z<#4U7HAr5_H5_H%3p7bgNM{n}{+2D89{9-Vb4>manHDOWo_{-lzz}zZ59SJzEg$jz zJ3%-T=$iljTW$k73k^Z2+y}``yjI}&&8Od*l;AY$s`q<Yn>FZt1R+YOJXa>uij}rT z*b<3FcbRo_dQ|7dQdvSd%WTDs*Cb8{PF6hf`Lp>6B}RbZjuH&Sq|mh|GIe~yAdjYa zIm4IO%%`^o?^vX_XTO*A0fx&z@S|Oy@})T`f7;=uQPe!^y{vWJwxNRBCa=yHAV1t) zJ~EPj4dnMhN6fWNi4P2$ks_^*Oqo$)p>5=rA_h+}lP{Gm0V;nq@ThCEeCr(`u}IN^ z_M1ot(gx>mAse(b>=sio;?CBEbSxpj&G?k+>3cUuMyGg(85#-gVtvm9eONf%4`|W7 zxYR*1bh3j~frx0<vZZM8LTiEY1=t!ezbWb>5EU33`q<tw8%lX4n&g7#DGiEDWnXV5 zg0POYGtRp{r%VOLPi=;1zLdZ2a4udI-51FQA_<rM#U}MXyyv@w4yL%vld@!vslyA> zlIFo`Az**KMTU~Xi04i973Djd2Xm3?Y6%i+)vt;b&eV$NHcpj4xVihO*(-UJqD0m* zRa9q%m~?6TD(5A0R2oc!zLmnu9fFd0<igBrDu*v5g46tg$^d!<w7Jp%Gq^??qS0b% z<hsx}G7Dn81Fi2p=qGGSkr81LR~WG{FlSVFA&_ZQbeW8CmYc;+oY><vImNllFTdL* zz~n_)LPs@o&1y?XXq(BgS3BD*|CX;K>QOPt%MUpFK_fz{5cX<$Q9?Q>O(IBy1)(x@ z77+#|AA?z<6eCtEWS0)ERYmzgL$6yjLZJsKy<0CO^{Vka{XR1kKO9Tdf_#&q6CJp~ z-By-t>G1e#ver77DhBdQ0%c};{ZJ2jh#36O;C_yk;>l;iBaD$%RZ1po9ks|U!lAZ) zk5Hg(-av@UrcmZw*$p7aM@(2xwqmGXU>Oc&=Ydn*yJ~cbl^Z`eT*merYK}aIi*=0| zH6R_>V}G;G=N9CaH88e+vFX^(GkSPJ{vR4bTfnuYl(GX?^ELX4UQty1k^L!yt1GdK z;Q_Dn+egNF#PDa`E03dlw~O_;k+z{&1JzD(*X<X7a!AMeaG;#4TyBA+pNK7kf36MY zq&t$UiGsz-=YlU)jp+*2Be)8hnfSy!qs+!hbJs;-$0hT^!4$vYZ%=nz|1IQA3@PUZ ze;5&E^K)0=;HqZ+WfMW*VAHrt4cMxh?XdD}Kgdvv*2ii}>s(%pf-hTqGWB{7dY<Rq z;joYt6Nuq9;F=Ko>~GMagW{g@KP^?wNm@qP$$MzI@#t1ryU^S|L+1WxtI}R)VEDVN z+=AP)ZV`@9vzLoc*8O?l;L7>i<dZPb6StlDXhl?_9}&bBuolMwSuOlJXMDmtLIU;d zI{bTo$#{3@bLLKU&i0@3MAo!@$Fr5@{+v*9A74ejYOO*9hQr#f_#$zEai5nFu>4Zl z{ZL$;S+<}SU)$6Dk)dNOlJ`&3ubHT%dqaI%yW$iJS0f%qlo3>u=p_ue%y_**=;{Hm zR7|#}rvIfxyf(3_c}!9(noi}b#>=>qFGbeL(as*<hPZ3k`y=0>rmu+J@i`}{ltZ(@ zb%{m;!y0zGTR&7cD{gJ}&g1Oy-cH-mNw|oB|47uzOCa7<&9>yZ|Ec;^w1|>*d%NVP zMb9fZ9NP2yw%nfcC^_Blf7V;MIT1DFwdV64=;~e~`<)JFBxjZT#oUdr#gm)Md2Dt( z0R6c>3*SE?gTHJCPYb)phy&J!VF@F$MH+*xG2D1!d$hGHOX9wcPK$fGxsy#p@TAf< z1qj)YUNYu%dnAkd>$*$Sj){T`d*>`jL}2poOeEMSeU8oV%A8-EoJG7olcJ*{{g6E; zJGJV$S#}n+Gbi#+K|=l<vu5BD<_+yH{@MpYUI#6d!ecK>8v}l)pbIelnnz;>v7lcK zI*<=TDt}sh)Nra3)?IQa16`k#j03$8=T8tHr;FrTe2$RbC0Mu|s>oO@*%|xk)?!Oy zFgity(O!?hSnTPZ+`X=AwGIK-U)G?!qYH_mHb&Q?XOAVHSMEi9G2-e%zog<^&Ugs6 zAQucD{S=nM)Ya$^eC$AMEPA?{q4Ozc(=Q|YO3~*ZJFETvrst=w_~8XiKOm%N4T#p) zNF1P+l|lS|rNj-~_bcvzVozj+=0=?OZjntj%RQ}IOAa>8!OjF{AdUDY-6DWh%+dCs zJ1vU7Yv;9a;BH#CFn;hFGHMj`hf}~s{y6!9sPEGzXDS@OjTK1oSLH99O_r}VS+xEQ z`>hWL_o{D;)kBTUzs0-pcY}2@rWc-G;X%0aR_cfT?^h@CC#$%An4}A@yR4OyT~?a4 zHVIzI+vH}MKS-}?$Pi=l^arl#1S|jMBEgOs93wEh6EAP!Wo~AX_o>jW`V#j%oq518 zdQMv<3;yw$D;d6p4yy>Z2QmgKFd-QqZAnTpNTu!6Vq4^se}#-Y^NMXe?f>nBjNYR) zI_)s3<vlFn+5lPV5YqZhfmDFljA$_-<|D%|ns!=o_u93fRkDYo_misJ2`9)4O?K;D z`JJv$u8#WWMmFbb*2d=xAB#Ug<3>An_1)_Qj&A>3#CcLo&Ax=#lz-GQ#vh&h59c)p zRqr1L?k;~c7jA3}K~b?4?nBYe6N}?6N4yryN7Ezub``&WIpi`qD3Zy+2TiB9!tujU zb0j;FJN5I6_@6lKekk#<3mbY;-Ep7bXY6v170-#XT)$s9*MH+^&S3DBdV+ikK8{t3 zz~qSRgGg|Z@ai!AI%!nVr?9=cw_lHE6$$zK03Ii>6BFO?H+@9Fvaf8hVw@ks1>uHI z2bcgURH7q2p$GY>2-M8%gp+mGA3i@$9N`sL@8u~zJxz&`H2>1UrHGXqP$fd-h@{l~ z`VJ6lwaE8$a}fEE#++i_0Baa9`kO)i8Dihx0O2yk*@1($ax_v1VXXYLnb1TtL<V!C z8j&M9tKrf*It+#NHM!!XT%44kh0aewN6e$BHelKV_e;I8|Nbx|iEFP8_f}ntB9ZY0 z{w@LWjl^eu=!0P=!PW;_a$Hp<UlO*kZCFHZqVkfA8T{HI{7<`!6n|x1xwy=E9fb^i zeppt7tJFE9^>WYytzujnpH4y8()goyK7S%3QgQ64P^tfzkUZ$^p!i%pt;^29B+&ff z>TI!;t_SjLd2Xwn74e%%Oigj0MtXRNW(0_8Eya_JpQ_FrwWSThccq?*ZSM>=;J1@q z!%u@X?hd_25DTi{zz?BmImS!>G~_ioei45JY)#Il^eet=D4ET8dfQB1_4)BGyuwz} zVp`^*FjAys9!|ba-4#_3JjH%Q+o+cR?o(fz*p^!unkw3Ce&8s&K*>&A@dmDywL zPQJ$B?Tx<X&$t7~Zr@ii^;4i}m^-o(Kk@JEs&K9B+3^s5E$PzL;vvbR5OxJs{e-C@ zedinQ^_xA%iRmS*YYY;bJ~~Ls(+f{iK3P-#7hB2qy6Nrkl=|4WwL-VGFse#*ioCV) z1L>i)!*H898UTnU5Di|13i4Ojfy};$MOVf_uEQaJOXP#<;NXn*w2tuc!V#r=+E^nq zkz~;<yR=@2U}+^vc?U@&!JIY`S_5U9Iw8&{Pu9<jr;x26`E>?SEE2n=yHK%(L9ws# z`OF8Fx7@L5LxHBf`L%pxY6jS0qo%qcG1z<5v@)W)8+&5fS<^#P{pqs>j5plQU%sMC zgSHG?xx5lJ0Imw)mK}{C*v*fR0ap&lC7;qQc+|YAFFeMJ)C}K|sKHukE~m%+ft#I{ zPWI^L66DF#U!Jm4Z&vhwxywweE{)%=R>Qy>_=oRACW3`0L#y*Rovmbdwl9WNUYr9R zI$;=N79H6NPj|kl?e@nKv7S2Q;K36THXH7_FEbA&>b=Opb^>6qRv_&095mJ(=2Gdw z5TE~8z9axx7u)tjY>+5xkpHq+?M2ETJTN*;wmr+j_y&C4$dp)Tc)7XShn|s#a(5%E z>Ugt_%RP>hllA^3jrf)Pc#hHkhd1g~s(4zESJDJI<`w7KG*xoG>HJgw$7X|OdPw?R zUL))=-w_5$h$Og=ct=@aOZ9l}?b%9WD!?7>OZSV-e*<;4^kPt4k8jT)>E3rM*sfVF zNSM%vy&Yp^_f?0(PP4?Q)p8vS#HC=Gf@H^QG%H$7QDKmfP5{nFY39mS?}SKD?}~QV zeg2!`&QBemS6J6$H>B9X(`NcbiUbAUP$7R;sir0XaQKG~(tt&{kn2fM*yXXhLv)*} zP%x6|)RMy>Vb{ic*Ao}zph0uyS+^sc|4nhZqI(wox4|Wq>oL*eQf*+-$zU6jf0;qC z0WJ`$d06OTj9OWGB#%39<j=ZI$k<5q`tnERZ`|VZYw*a`r=IUzj+6W@j{Uu6p5X<8 zB;mz_CBf|XkDt;J(lQklNEkkAF(g%}oPE)wT%u@sl&CeHM@9=4@|o42%zJkCKPRMi zu65tc*lJ$oGCk=F5>qF~zkzkHseG5>{eE5MeK=Q%K`<z3WV*zgj+V^#bN`~x(x;`M z7_ogxO44E9A7>}D@o~!aDjU8YN<5SG;avs^@$97`>`dK%5*Lx5jlKkmE#N+;)85r) zoATHSO<|1p4x@%@kSxR=UriU&WpoF+(tNlhi_1?ukpFVAcEkb{Y_2>V%+BrHocC~e z)TQ+B_d<iefB$`CXBN3`<WH0eh4IF253b6Vit*W=5+CzhZj45$PT=t$3DJc=y9H+Q z(!Sl%LY+pp>*P$|nrXR~DQ<pe#RfCy`M(NGJzQSb0|Sh~na>RayUt1sZ;nYb{H=b| zChl#W%R|5zG3_BSLI8s)3Ik`?r-Hl9GQp2_{XW8itp$!yPZ8hav$K5`kvmD@uhV^$ z`*u};4|eHm32`!firaMG{J;OaCd3c(qEmm#fzh8TMP)y{l{kw2JO_(cgxF}mSb%6s z>0G3ycL)|e1wUxKOOiJy42uq(R$`0UJq}vqYKaZyE|+u_G||^ekkJ=2PbBog(;5#{ z45-Sr)|9}ToMtYJG)PtP>7!#RM1A!^>?=lOU`gMhOHEd}pcCEvaIHdgz{MQF5a^L) zo-Dzqx8<~_f+sS&uZXLvR2T_P$A>>sdAi#B#jXjca%mN*=ejuHRS7bY4W%}&G7}07 z6wiau5QVJ>L0>YRAZz?ER>H8)t;~dSPnKq;pS}s6P0kNZ$ryIVdyeXHr|1Eg8>xVf z9GgK=VIxwZ1u-@pIdtJ{sV~0a*h#V*<ie!C=pfiqJn+Ft)Wo5Z!PrTN03gZ;6LiQX zuyyB4D#)2mQH7YpB4JAL{Mtu~rT7OgNHRDfrZ-=5m|kNpt>FB8)z@dP?Bj>2O>$^X zr=;0_1zPcCF%rQYh(b;Jv#4hXf^BE<Y<7;JpB+}n<ikvNL=ytc+JE1{R|y#kk_yud zQYH!_4TUADcjWFWXmMYy%<9S8j=#Jsr4ka<X+0~#8u94N0f|~pcpmIcbdO<Jcdp(% zJqR3RJEy-H0Uuv{-t3H^QMRug#g+sgP`e5xQMPrUyx{|*k*MKAp%-%$hiNMFeCQ<v z1D1m%1Op#>NuchQ4NeHWdgCC;Yk?#<^SFbL653USRGt-titVCkQgNBp>0lE*!n(Zq zkrIic==^BN(ZXpi$z;BByqDogW5togQ71oQoTjOPsDM3^P;w@GLKv7!z%DC!WQ#3P zAL2*He~ekJ9QE^*!Qp(FDaD9H&$%UzlKGC3iGO5v*pd>lT*bq^Gowbt;#>sK)H3UT zU$?3?u8I@x=t)~uV|K_o95>1lhP%90IIBh^Jzzo9*D1;Z9Em&mF)+OOhVKY#B}7%V z7CgJmeV4v;m;Nw_5{(|sE!Icc*BSJDWFPY@?gXWTl|G4thKo~sR71ykwwpM9b?73G zjnY-C?gnx90UDsg$3QB3RUV9gB**PH(>-KRINablLy!Ub(a!NbzR98Pc%d)DKDW1L zhDLe#+VP~j*mBl4Y1%2(jWE_MlqQQou7v;aFIu*dp#<o|wDsZw)fI9{a&pc_;j9hU z5y){5kQV$K_@U=0T5Fm>k6qGyc94am^a5Ar6L&vHSe#9)Be_=09LwOXOUa_-03d51 z9T8u8fMA=Tc!wvOqc<uM>PO^WYd{MOI#$WsrcmyU4y4h=5ay@{Bx+!U4@9_dpSDOv zO^4uvot(IvgsOVuMj>g27`4$j<Qf>{I$s0~O}Je^ZGaj2+m@;M8ZUbK=d8jX4n)_? zyLwhNQ}cpRW0L)XYiP>Yk)OH5SWCVRcd%`FmEkG(@8IgDmQnMR^%T$P>`W9E$TZCA z_q*sv$4nLX21lf;*(8p|*;MV2EYq0v6A-IW5~rQH*a}t3I`ML>bDTA3U__o*0026e zG-dIKISVwFP%&WDvK&=4=p=D`;{{_*&MJv@OrYYcl;E*e1(=yzau=g94gUPejrLEG z3@6RK4R9-J*~rSbQx{GBh{iIhj`0+$@%LuPLuBs3Zt?tJC);`Ajpxm0^`Go@;Mj<` z<((7?we;?pGIdD8#&x1Q0d?Q*x(&4OdQFcbH6cy6OY!iiN5PcVs?bU_-4H!M({)Wm zl=dy9LiielLhZY=?Em!ho-Se_t51tg+`|=>_D#-imw)nIxHNND%fqYuk!F)rP;2Mc z@L#ITxa_;gY1Kl>6%{Y9e+nLJ#2cbtas=b?sYQ1mM}uEF4oTbH;)C8}BbeNOnXwmC z1q|zCnN^gr6ROnq21T6V=b9`@kD+$t@?V}`8{;6#TI882D6Ax;tsD9U<M+xW;Fj~( zu$ZKtSq=>EK%<4hWRa|zlG3T$ncx%1{FQhL)G~cQoP6Ce{6NH%EHIQ?_H^_MLUAr# z*gDGhGw57qmdeN0euyjMTMn4rmTlB{ZzMXLlag&TUKB|L3-GJPVZ409C(F6ba5l+C zj>k%1i-Bfi!g3LR*s#gTvBgC-n!-M;aanEaGI-Cb!{_hsH^WI7B5ZLo0!+2O__>!A zlY2nY07w%?JUluKYd;Ie6_Vy;T49v7$9cWA+-LDnYZXvh(t#c;C)&99(}l~KuC+T} z`90z@Sv_Ks8{94+aCJ`b<{?6^RM3&6dp3M@(&KiwOUz(T__Q-tEDA|bu9~@}8)8Y~ z5DDLM#tRH{yjM2?!CO+Y0>AFXx5j#2WH4dxyzi{G{qfHA;kzca8B<B9S)42d`K~l1 z`$lsfj$?{s<_ip6!1&tWr$%+D@q##Wy-qaD%W;4z{ATTy7!YG@`I>@6$~6|nrJ>t4 z-G+PLT<@!RkxTtrK8&qI4<eTGdnWZ3Rv#yVUzob9*`td*z(!By=pR+=pQD-&@1{^x zJLVnV#TKo`ctc8A_DFP_56-1_6i6$prgS^EGMJ5K+Sl4BHgY~l1s~}RoO9kvgHQfk zdASfXc(xq$)Uo-8frKq8jwEvhBmZ*1FvnbX>>b@-sCn4`w%WY?v(7Vqmnn9+JyGXF z$BxmExn@@x6sFOTTB*r0pBcahYYR`uG5}Lv9)wD!(TdufqaWSW=+VSBdUZatk!m+{ zhhODHQ1z~$Kp~OCZ;HN>jAn1HV2&0)4S#Jz1oReYq4(87uT%QbF_t?nBn9i08W?j- zJAjz>a(XtreGJ!ujtQ7|_X!=midyGc_=1lTe8E}#-he7(Jp_B(B!T<8MB8wv>pO=5 z0_H0e5qPImMu#k-PP+NCAI`x#*^^>tDY`MYZ<YuAM*m7B4gPBLj+<#C`EfMzg5Mt| zH^qR^rIImmabQ@74+X_HZ!#>Nl)j7C(#?waYV5ay?LBC^p=4FqlFXJhWBO&rU983Q zJtYYFTBc|OP9;e&Hzbp-B@%6lu3m)(7`ZG^@Q6DD-h4@DIO!V7QDC%qbGoNn`L?aD zH1BQ*b-taS`?zRt{l;@Tul)8Z)g@kf+vuGXPnj&9u<vM1sAHCqO_{b-oC<GEp~E8! zg7i`=;_4=xjtN?OIS%3nZ;I(-Q0R0k#t&!Pz59~bM4cmm8rmP7cwsii$Ry|H$4!%F zW*(Fva1@Z-L_OW&v9IPGlf3U8lOEGCo84f6TNjPj-anw&jvs6_p?Gb!rCLG4^+iXS z8@NgUQ(QLgx#I**T0A>e!&pDpOt;XoF{?9_Y`rp!V=(wK(Zvj&EjEHZbaCel`=ec% zABoCdP6A_iYH4-|tJ?cLY6^j4#_JA-K|%k0D&GzZKWvf_?u=re;&n@cOUH7*8%SY= zkGl9IY@o3LT4y_B14$xCljg?HWP3H_K30s9RE2PVh2SnZUYa?~5U>xP%5W=ydZQBs z@M*<0FlrUR+;hv`Kgv{Q9<$BpjL&Pacj^?bMHi;bE=1*iw<&PnQ;-_Rd|soFo@p6M zaPhF?#%CUEY3WbkXyWeBVD%^pI@*8lA$M{HrwTXxU0<JJ1!&!jvz8<zgO|?n!x=W2 zP-Vso3${p6y-!r%c5x-dJVWGDw}uukkQtaz1x9HxE8h81J{ij@jhFSet?@V7G{VmB zV&^QEL4{^}9NJh0G*vSy%mf9{j;bXjNquIe5+Lz7&On}EhTvZT=toe9hx%26-zkqq z$M18DZ}f?`fQs2*@%vNE&Al1bQQ?zN)c}1|qF_SqZ%XM8Mi>-nPiQpWw&i9GSl%is z*6jHT68gi!{pLbCqP@Fr`_9Dja@iqSAbZdvZypF5k=$XIp;=@TfcM8snX$F)A<8aj zjI)MqEo1Gs4+mogWck{?<6mj8;;?`8pL9ah?iK-0g@K@fKf?XFCe{0`h}vO(>NMo; zl%JJRb(=J;09JBP0451Q(y=?|{<nPN?x?MbbMVwRZ{ugZ&OB^FKP9G!1>Mbm0KQ{T zgxZ{NBFwGL4u}M<G&~CUUq3C&wO|q$7#Jke*K^`rtR!tjYB`8R<P?lq2vQ0PCY7ZW zyi^Dh_Rc?b0^U~jzXdQ5Oij~U-u2S8?G6b5h?U(aOpIKNJq9MsN~<t1X-M6=eSs?5 z<ui*5%=MFEPtP^WoFq>jE<OhiGU5(7hsYb-Arsn-vQnWDhh3<)Lw^r$f*<)!=O-t1 z7{+OCD?-!gUXT)hB?S35EBMYlGYnSzWU+p;KSt9s+3KK-c@*8p@RvKdQB)pBD=$Rn zAX!i>e>3Y~rqihpvK4lldBX(UxXuUn>@0fp<}J7EW(Bt%u)bo*<533DSRZG1zx|z* zCk%X;qA|qjk+8(ZIlyX_PXtq3T1oY$bl^r}J__#&N9K3M$xz55Y`9I)G}FL2XKHsD z0=cZ4>3!w=4@3mg`KsVveWDB$$~iO?r46?@)n~xZ68^qox~{69bZ`QD+KMA~HKL1Q zUX^Cpqd?c>FY8yb^yE74Ud`ueq{WK54rnlta*yi8X5k-g@&aLB*Y4Q?b*`_<lDXeu zUZWHg^%v>Yb#haOfr!4}HDsz}i00@KkQV4S105y(4MCwva{lmD`J7w`$7VR+(Peju z0f&>kfQN`zEQ~?6tx0<;k{)ar>FAh4&Kd<fAb^RcBgpJ(t2$sB8*o@n_tOx_$JL!z z9GNWV-!Y^#BW2P(MO38YiaIyoty05La+1_#)ix)q*!RlmI*lgfFTX}%Y=ROPNP`|6 z_!>h%=P%WU2c<Jllk^+)S@fklxa+_hBkzL3;4kt9Gb-j`OLk*_KHU`yTTsAfUSzNM z=c(9hS!w=Gsy!duw$i(!&rxe%HBi*0&9?^S$F*@=ASl&RO8PmXVtgPX`gP9CtB&Jh zTKX^Zu46vaC|LWFDLV7tbhZnVjXd&j^Obg`XtWd!On{tlJLIk-!99oUT;F%c+q~3P z3R#;70nxbD4GLRrgy=DY2z}#!A9jkZIs@?l3uwRU>rZ&PKzxAO#-1snSo1*B#d+<3 zX&oPKzk2tf7MxxQe2KC;{NX6yaHdv!j%*4dV_iq?mAhZ;a--?o#sO~rUE)MYMFVR7 zV>xP1x)d>a-+I!c$DVXMyAOI=KInLNfG#Pt#ru%uC*8Fl9h0LQba#E&@vY@WvOPu} z$2NC|W$ohC<VJ_w*DK;&e5^)uD1?PX<v5&*X++)I4&GB<W>082C)$w2==}Mc+XH!< zDz4zfkQ*IMrBvBhYktV;FZUcLLIUs7d@-e5Z2+~-it6N0<m~S0AN{Rj9SpNsToL>U zrffGl*zrBphiH<b8zdN0_>Ya|cMD(hFnywdzzm>}s7L0*;?qJT=!1~dWAb5BQAi}X zjf0Tz|AF3D<CV%x!9?Kz^Km8NnFfXbpV&c2|0k*ET6aFyDmY1ejt~eZiQ*bWAK!lp z!U-ppO!Sk}$DQbLPC|AkM<7{j)cU?uZ0IBHwRDhMswM(%XAO}IIgymN+Lg!ipQoP+ zqGNQ&eSezYg<$Rc<qV$6q8@)i#@`V*qxmk%Ab9bzpr22Ym002=l2|gUn_MyqQb_Pn z8%`#64gultK(1V572*;QsJ$RCn&U(vfRO%OW>S*9c<nJ}&+;MO%uh)rbA-SAr<vF! z%v>JFsGJMvN`?@qM5=y;9}X(1jXEBQV@jEq5ck8$)V6#Mk)a*5;I2a3VbKHC&5Cf; z0*=H6O1tT_W736V6W%^zw0{He^wY?&$qi<IjW*Q<Wkpd}=S!jva5-_`^L`0!>9#hF zj~syfdAkKr??#>jPVSasGVGZKU8T7_Kt;PQz#%CRG^7yK2LfrAHW?ImeK0qTOD0jU z^wg2U3Ybe*oL+3U={-gh(4oC)QLMQALHB(-8Il27i=i;fn;SopHLNBZfe75$sWeBk z!Ljt<Ee5tbVubYY9Bi??LVf=QihzevQQ2q*5$1Z}EU-n_$x8~VTN_EX+nP0MZ*~<I zN8iqGHPVoa7U=)+=RqEYS_zP=&5I%~(oqRs|3J1I{9LZ!x^qb$Q<zsPz!Eo_yRHRv zsX8!R17IuwG}a?H-mq1nL|w|ZFAz%mYG8QAtJY9>f}FU8DAM%0hCH~rIR5;_8eqz~ zF$NZv&0++prTqX1_ctnd#}I+{2THZiYxO{qtvikn*yGXLRe;4Bp(<0!lAPU!Klz5A zx77F#ff6%zxOeG&X4ooj+BMJ4s<|$?NsJaWNYnv<0CS8aMubIh0-2ohH3nlV6+&S_ zzXEnnbV7vm6kWDV2Hx}WuDQ0bYT+zd(um`T+6mO~$3+YKZcsz@F2r;!nB7+$;EK#{ z^&(H&t(!Gi`Gy$rI{|ZGiLr`+RbdId)c{HAz}V~<3VXU9;HsM?qdDgmtlA-@T~UuA z@V1>tTLH%t>thz=GvdDjfJ{t>U;?pE>=4E>hgb50_@UYZ^n-1Y>~LpwXYpH~?dQV- z$)Mg3z@VTYF@x<*gW%UXaJU>yhy*sm#|IRnBqmf^2bpgCb+_@6vg=<=XW%v8ymh-~ z%BQ<c-#pRw`UeP%{q=MJZUJmR3MLZ{iA2oQ|0s;%lVH;T0|1nmx~FReI51o&2$ES* zhg}T<2m}{>RieSqkqZB9?4dS)%4dgQs={rv<fQF&e`?7$k76OC0|L|R>o#sED@7Gi zNOO;pDXDs@t>nYS84Qg*_x3jGHrqMi(CAptZ4eyoJejTEo_;R3<8A15GZDhi;*D-U z$A@kY;4j7Y$UCyd+feudOFbi{kSndg%0h=}4+LoL`$|di7=-iNH3efY_9bIXOeLU6 zBY8|8S}Rmah42}o4t!HOb`GnM0L8kHrJ*T$&L#+<e5D)8+;6F&!!R{-!7<zY6r)d7 zOx<EOkWZb#&Q$f>0SIc5;a=Q4dVEItg^5$NW##}1{VZe|7g-k_HSNR=tP0#N7n`WP zWc0wr4vwKJ!{=COz$$2QnFS=tjnzu-^a?VN=qNf8(Dk>7ZMU=lM0Q<f6(<MOoiSds z86l4ATh~JV;fy(icy6~o1g4kgm}1rUIJqv1)UJT5rLAjy&H!ic6jQ5etEEEEQ*u<| zCS;fIQeRQWTD_6!ng}{|XV(xoN&HpAnUv;T{+zS)!*I+u=(NanH*)Shd}se6L}PB% z^2;LpyZkx!qA-S{u`}N9Oq|7IXNZ@9axD4)6;ve5sKn<qz-<Fy6qb8~K580<gIx~G z?4Cf1Ayhd!u;n>Q)tQ@*1<782r}w)s&7f8bR%D>Ft+q28JP3N8)n6<+k(+y%EczwB z=U~at3t=6fgMM&$AfkJomV-miX%nAgp}|w_GlC-&Nth046LOIZBi<5;Rba*8H8C;g z*xU4X%ypzkH7*<B;w8lvNJZ!6?qX8ZBc(qsve$y!G#vqHBan8yM8vn(2UfAV$sag= z!!d)YYKcX%Zxftq0CaNhLM6mrq(^5WK1BI#c8J|MJ+*25Gh?siv)@FV?oE%}4m<~q z+(4!n&(Qs!;j$#NQzf;XHo2H|9DM396NMPSpANvtosf&Kf6?XW2Kg)uOg9&XH18{Z zIBj_>jr=#bB3od-3<QQ-3SJ31OLhLwWc38$pAzlAL3||Y|BR3VSo+B-;_D_%c#U)} zli^^TVf`3|8ry3s#tH0v$sx97p=NPa|CXWl(E%~-L{(469)1x7*~{&{M4zdI=Yqu4 zR9CBClq7n3cg6qT5?&*8gTdWz(mRz-`S-iB1U|Ax^Sc%fiwVt;4|c(?Dt<0GUYuK2 zi2P`l#X+MeYyBo_Wm~Ga9#j>~l0RQ4*z^blu{QiL7@G9J7l8>oS~1PSxl2^lNa8s` z#DWQpFBEHXcLmLQvppYl*26EsS!kVgh93u(csX#-gMIO>pQhGtiEU74dn}za@2G1H z(J6jqHoQ|j8;o?XW;pqKlk*y5@YC#(DXC|E*UDBY9qILe0N#Ca<<I()8!Ofy%=LEm z<IoP~VXGdU@w9femvPuud4G5DX@5kWi>x4FDK|7r9S7y%SA<i{dtk-EkF>z|wUS0i ze?D}dSrZs$zvqx755t`t4p$0bx{TLw07?1S(rRHeRYXQd_vnykA+EBhpcZZEfn-w% zY*G8pR!XQ9ylt(CzSOMabEPHR#;`ACS!LI}gV#&GrT(^Vda(<3hSy;;r3{N_x29BS zFMFza`l76`6i!N>71SPR<#QvpglnXEyPf3rWPM`LCj51?1*^kjCyruD)awYwSF50> z9PV%VMJau2Mc<nv{i}xy`>V<y;bvGzM7*R9nHuC<sczU{6DoO}E4;OQN>Fh6E8bC{ zVLb&E73@!}tpwfd#B9=l9t7be8*QmS2&b?;rwIEjQev>2!RWemXi0eR)B~*uODz<D z=gSgIk7^T6`tEWQE^N)0fS+)#V+!w1G4@%oQ4bNm;(o=@rei}ql_aaLgQu441_k-g zfs=6?3{4oh9#j&2Sg|AhOlm$&2R4i<{DluLi%N)3bYVRdV`@QagGdZJurlpo<s@pt zQ6*i*(CN?-(wMXo1U<7zu2>Lp3ErWta3F9|qk{0U6L{5#^%-?)(r_huc7-Q?RShTE zRjwJr7E$AFA+T`_iwTI}>gG8*NG)8&EI$ZF@FqFKqv+;d?pPB@&>xDWSU*vn1@R{* zH@ss{>mDw9Qa=_W`~C->7V)%dGkmHc&6le9k92C&JLGj_8HV$|KLjXc{4J`h;c|C@ zjPgnftKph=u>QX5;T)z=Po<*?4eun*e({v*C_Z)5r;i+gw6$MJV}Jbk@%Hh-9$05r z?%C>KrC*u$M`iRTSa`NDR~Flfsxk1BD+2Rc>o1f#=yu1px`fowv2k(y#y}C>VJB$p zO4)>!uja{Yzgi!r(uWiYX;s@3zuUWkG?KjVHNO_o%MRV7b<{6I*P?>B>JX}eLt{9f zBMAW9&tz<Rzg6!-b*6tOwhO5-)~__C?hP{yxcGj;RKgmOb|7a1r4AAh)0Aq4o+$PV zkDK&6N^qqNb5j9eTUgMEg3?O}uUpVi!uUp9+R(7M52Rny9F}o>=fHh?VKzg;8a<^d zC0{_+uQw)SXC{!u(-SqFx8fn}DX<)(Z{5(TyMD>2NPBv}XJHPz4ZA(v;#bg_*YLw+ z@*44e>T8j2E8!e8#7m;%m_qUB-Xw5QZezGzFLKy(`omuug2f~mZQPOX*NT~?GWvvN zi-@@6b9w#Yg9TP4;qR$&&VkYQIb0lL<ieFQLhe+_46D}YI()e!){9!FE`2n=tl4|j zs(1gsbMv~xs!DgHM@w_k&vY>Z>E7q40Xf_<gK@@Lg~_ootbYG`UzM1Hg(jz@#>;W$ zVzo2VQz{4u4vo%PXi?%jS`s8A=H)e{ZgJtluZnO?RAd2!634vUBliF}daX4iYkkd_ zKqer|Hf?krr4~4E+XinHK~Z_iJiuZ567DwI%7>q!CkL4|ik4hn!hk%%E#Bi=8#_d4 zKc{>{&6W1(J;ssg>A{)S0OL&=wZFQ}@l+HiPG-EbgIpLhG%38QY3Mi|k=Q@`>LTx7 z-s=}9U7wLn3uCg6>x`Lep2azJF3p?I%t*b;6;YLJ=iCN_qIAqox2u8s8fm-vK^JQL z=9=wfyNp(X=X!K$*A{U(6r~F(P#iHOIHC=Q#{Oq4BEN%aa%Lrt#OoZs5@Mo1jst9( z_9sTg>NJ1V>QN#DcY=mwk8rP#Oj`Dv{^W?&%w}ZUJL~@r>Yq<i*kJ;&1(9<zmPqz2 zIe6lrfP?^C*@L1ShLUDtZu-d5cYr!fBE-IGag?y^4?0toLtBomDv`qvZqB`;3vjrL zQZ)D&>tGLlfK%tAY1;}qABY8zHG9uw=+x<A=Mvx3JJ3UgBeA7PfFQ&TAmZDHM+U3y z`Lqpzjut6(umMET*v^EKGDkF^e7s;*6u2}u5_}B89?>dE$_pp4b#P)wKtxpl>Epy` zshB<4RGyj?1>VnBA5)rFuhblvw`HFXr1CZ)5gi;=hXyhYKRpud1@pQtc&rvVZ_lQX zV6ejqw^&pH%-^ORB9w5GUL6=ckq{JBNuloF@8)S=z8F{By|@@IDpS_qz5HF8Fg-!I zPp`yNFq?wu1puicC4<K&$Vp(a;UuveC~+eFdOhfl!;YJ55<W8i%Q8#BN8tR+Os5+| zBqE@TPoV#4)@gw)z-Q8Uox4WMu1UM*)h=EjG()i}*b3>kT*Pq83Js*Pl`XvNsSDy% zB%zm*F&Qp6fAe@-t`Fxncy88kk5eGeAnvqKws~Bw<0N626&@kPOdk1bStr|P?!~xV zXv&kZq0$6Nchib;p#JO7b4O9tA3}uB;EP>Ff;XT@mg!-cL?axT#;8~WQNWX(u}&*q zO;31Qt#HOoYU0Rsp<}ex(s}$~(hqe$r8<+@hJQCCeI@>WD9J2tpoSLEm)2W+Mi#x= z;~@SX<72WQ;U^bnDWy#$c!GT#zuh{YHmP_Y_s}@c8<VS$U<_gvv8#E4<Esjw;-nQz zyx1OIIvZux6!Qn{2rkdP34%5bew{<!cbzew+0xc^g(ITkpaSPk0aHyj62DZ%JnADv zmAIW_{>4TK!*I6bxOCt`BS?0JB582KV&=Uo;*XOEhIggt(ouy~o(Rd&Ka?5Bb!YVG z#(MzN*06(LOid6HT?hbvya2tRo+P7d*zSDSn;Dq}*H=G7_!-wCXEsp_Lq@KiVqu@} zc-1E>kT~WfBd()8O%4*#I4bdv$?{bhU?Hv=4lJaFPzGmQXAD&)0OU74;2})$U2zqc z&YbHemYi6!-~uX_C0f`IbVAIBN4$e!osNt&UErbMR57VBOet4lyeeS;Rxa?B<ehnL z?k-pwrqTeYZOleeV41sN12d2sN9P;R_DRwGdHg-91TUNrR@{PXakV%qQ}xN%3EFB; zcWPYFwg5mLYfv3_u)ilE8mWY}rmehtDHoUtxs^hbD^<{+sEvH<o#So;I>!W4pOnMF z6JdgOY`XL9W4QU!!SJe?liZ9wrJiR9`isHmp%e$YlgBfGJ;y7E7>_*$Mq8UTG_HFL z)ZBPP<f4iz+jJV>AR<ksR~M-y28Jhw9JeD8W)+{{wr-gW7mT^xMLPB#^@UKE_ps7= zKz|31na6~`43)x*v#I5(->U~rxO5gbLKrKNi*!U3Rrhs2gJ+a=X5E&>gELj$mV~o* z8w#jUx(b!1**>M1z(@4b$6$-2SC{^93S!gUMd?iXkO;pgrWl|pA}a9F4-s|pZ}V_` zYD0!~vk@|K)*9!t5o1U(0`xOK9k(tJMG=({Q%b??Vz2W5uB?GzC*iU|KmGTcOjFU( zL$RqNdkQ5Ll%N19++gT-fD|YogboQxj2Q|*QN(}}(+rY@?u-CH@B0szuh1;re=!^m zP1uRY4Jd5KvKN?nA%|thC;B9dbASnl#zbSaY2WXI%Wb?p$*2zG;LY0tUmeu5Mx=j$ z!`;pUnTbWFS4X5z3LQ@}3go@ezWO)?KF}RKp!tjSJkXhmUGAg*o@69S|6pg=`8bj{ zDVB8qaMAo4Nqu0>d6ZXw^!5*7tGM^9P%MEwoXdUb;*Gz-zdvRn%C@E>$@=q#NxQWY zBMlUvAr3$;vGIf5Fm~*lxh{T;YnbEXdkVuRVn)TRN~(*nmFFKe;^FIk#^I)!ZNiB9 z@e-n3E=v&WoW-%Ox_HskER%@3q7@ji-oVxjNn3UimP*X9U+k_&=NDb$5N-bs(OFPC zO;Rt8r)jYU>lmOTf$uj=FjTlc^8@A^gSI0gFy&5GZ-Qt@!D*Bj?MIzy9O8gR${0Qd zz^xb|PRuh}kB37rH?ZgM^eR|GJVSK|xo9&^6sKVniI(3jLv__<`@6Rv*R$$@l^TXP zAeAVFeZ?ZUma7LQvFCdea!1!ugo(Ktm(#jvSiH@JWqVfd&@>i>cdK1AcFOSQ{PuA- zETj)^;C0_$o~&MzIT6`@D`Tt*r*_}lXCa+9KMUu<#yYibMp8>|c)HU*6|z_JMMf2D z3mLi98-YEu>zb2k)s*O3z$i7D-o(8O)su(18#un7x_go-hR$3bP8%F+4Q55BNt-kY zL&x*q_o(XhZ~AZ=ls7j1?mHMRf0JEtE!(fBd3VjeCcF?$&1Rh=X$D1uq|x{{S_>|x z{x7!PI;yRujT<c#DDJK$cyS0V?(RhjEfTCqp|}=zch_LW9a@~=?v&yh+}#5==bU%l z@7}dO{>UObYd<>ko7sCF38k}4oi}oJ9oi5?dVPeCDH}=<MbJ0J0sn`&^{8mO(rEOL z*L%`-P}k%O;kP-(EmF*nuE&O1&O{hZ$U|^rm%V3yN4iqv#0S!K?GkV8MGI+rNE3CV zN&Il^7~mk8WN;(O_@*_4G^*l}59zf`ukDwW0Hgr_TW${n;EyJ&hLP0)_*d7Vd!wi; zFYqd6h&b0IhriLfx3Ue_s*6cj-AKeBEonMhNXEqKz{T|t$CN8_gVH#7EZbn<@Db+Y zBE0TYVj+Zz5+Q$cOCUA=#<XacHIQ*4pa?{yKKHIfS_3<PQEFC#ftklyhKG<v!i<yw zU%l{EJi5#<HAg9-uL5&IPqFI7XjmBQbbY1|M4lQb(n>#9^{&6F``3s~%f<15P%M2v z2a6NkCbHCMLY7J^T+hwGj|MEHIr1-S3&CZ0UGS5x9)cmt3A(_K5s-aUyjFVmS%n=W zx@itNd<T=ODtt_eDb{S#4uf<ehg4_$(#)b#PS?&`0QQ}@*Bw{_jrJA;w3@*mnlEwk z=3fM<v7{gGu<Af^6#E}K&^dGf*KYlnasEXRcjGDfEE-Uzh0n#7&wr=^hF`H$n^2iK zdO4#UlnePEY=mF_Lg+xbh&TQZT4XnuZKiMyA;Z@bV7tfjbHVCM!D<ZR=p`SowiErA z8zisRtH<5Bu_l(gsDCi+pU?jb7|{ecUI&AIABz4DvHI0q$C*BSXGVpprBF{`V366> zL`NA8I$^TK#k~tE%kq;U77-^gxIz_>ZWNJ8R(d~=T?s+JYI?D8^RbfZDFKas$nh|> znepx34fK>@xwfJMmvB3qP2wWuSq$b*dAf2|NwZw{QJGDX^7B}t22AprP3{TN7({E7 zI-SIo`G$*)AkM!1MKIghoA(X3mlv0eq2n7@w1l)?CAl;_XbS%wk1U=VAL)Rmsu{Ih znS>=49ljYI0G|s$kf{;BlPi%O!^DiAkIG*u`&LqghZ+BCqtNl^XvVz3Fqba_zN`jD z(-kT$<{wD<gE*t!@0(=VrdQE_?A>1~w=PWUo}A;y;tX}mi0Gx;Y?!#_o(`~dVPKY= z=@U|!k;&f4q&>W{V~L7X-KAj0WHhKzyA1YctW|w8M=0C7Eu8b5-hDQ;zxS7T%R(!N zJ!(XCDbR^?qVLVF7m=vY?kWgG%5C6kYb$~G)YLQse|@mpeUg6U<lgLdD=~9tVwC|X zXFnobSPd8y0%#~_0C4mME!tu?wry#iiq1#!t;FqLurI7`$&Pd%wKaQj@qh~3k4QJ+ z$1N=Rr^FvkC&P%9Hm@+Jn?bCE@Y7%=oa~%<=UP=xJ6AylRbD{l43T6@$qcIrK2zOl ztb05vMvr)lZn2cI&YvnSFAam2BCg;1#&@@F8<oKu{xc0NPn0u!i#)2Svwg%N?fG1` zY9tQiGAF)LEnW#69bBXM7=cBRf(FHhhdYkOxWylXi2Frm2DCD}Etdkg4A{|Me_9~+ zj?zjsbPUe>yEGE)&)PqpT&yH2<VNV>da}=M;5ojJn`PVB34IDN)k=#t{x*!MtTIFx zst-u;3mXE`ZBE!ft0tn#oXNjc_-GbVpo6HHm#U&p->cwJM2Z&;fJTLlZu}Vno_{op z0{o$WZ(uo%q=GK{r*KKey?BPL(^=(9VWf*-o@)L6W;V5o9wAEDT_t)?jR5%G#yBlA zTh+?=OckVUum{Yn`WWdv*6h5$)p%7KMx+p~;6($)2#lCK*wj;h6uohAYM&|O`f|+; z*gR)N(SbL!<C1NgVgH2L(UMOwJ!{@~x4CS}XPm^?&Y#+GUAs4zjm`U;E6E<qF*@We z>I*A8Gi<`)L`FL>MDSurpqbKnaxj+`RdOOuqF~p{NsY(yN$vk!;CH+8m~>B&FkSyY z*C<uzER*(~Ph`-fWKpmraDRkgl8fvvG;><rtAhpNgRm*cfJhR1WIUEvS!aFCJ*Iq? z!lDAZ=nR--|L+gkw<pOxUCqUTp4*?%0%cL6owgz+aUX^O8n5M0qE|1ER0qQoH|PTU z7X*5E2RM(ZxN}$_WNMyYbk-O+&QJO+^!V)IQ&sF{XqM6pk6f6?GRt_MO3!_vWrXAT zA@|qK!SCmYUWV1}yB|d%Djb3RuWC-kydD}nUP^+x;AF|r3)HaMf0PJ$-uGH7Z{nXi zE?3Rg#KTPxRK|LT|3Y!TQnj>ntF{?@Gg_PNX*ag~$5%v?ieFKG(;#N4ZRYy=(4lqz z=0+haoF>P0gXS3~nHuK?99RES`ILN+Ih9kjR?30H1ecX#0IH8g(JWiAOPS@ADd$3W z@k!PW+G^0)cna=~ys(_wJHT{@?G6yR%PRd}h%d+Y6zvV(>=WjsjlQ0Jo1rRhS+?;~ z$P$*x5*D><N_Z|#uS^ti_aU-SCrp~zWIY@xov3aW0O-m}Bkaz_D`MusBE^%*!nSG= z=L0Zu19XZ;a#1t3@QRBqrxgk(?Q~|zOoc1kXJp)F{R`updRr+Q@3*_<7rHwS(8Ex_ zOK1gY%^}G+KZ=@v_z;FPAHZmXVWJaNG8=(sKjw4dpqlw<{~Odf^6MKNIKueyXPxlZ zvP(C4XMnihW=ArFRW<U?zFqioS2^;Sd#^-1vQzX>?xsl?PRr+p<D*%~EWU*xV?vnT zp~ok~IAVeca9fXGVJhpQlo@rLB1AhmmBd|$(F$B}T_HSAi7er^L~5HU_>S$lxZ>@% zf1z%sIvuP!<LsbnVbj8x#&O`>HpU@fki@PBxjreY)WMmp$4_-ng}#R@56lxMedq0n zJ!cQQ;STm@lf<)>xNpU4$aMq3eoXTJgRRP!*HfahpQ3o#2YZMD4^3%ZG7MaKT1<>+ zpfg1E`;x`?&QnD2X-GuJG%_xv&+Vf)2QA9t>k!ZZRej9tts>1RI&>}Wk`^<Rt2t)H z@i|5Z4jf|2T)dLOJc92MJ_nvl*htWSRxw)AVF{~{eQQ#Q1F*(T7Y$O6Ehh`x;tn%A z<PNI<D!Vh|SMox*E$@D!La(wSa%b?M4L)!86~%i^T4eWtDs%5XzBMU@huaz|>U{KO zlL$Zm=6qcs`r9>Jscpm|6LeteGk#keO6*-BgV8N2t2g<SAGY!bU~LnkQ$dR3RA+K` z6tTh0ZmIl_s$n2*-FUOHYi_CO<fSE@D88^H)j$RPmMipZ+X%wqTfX<PVp)GHX2>8W zMlE48=x0m9{&(3QkH=Fct${6@4G+6zGTtLbE~A#C=MoeKw^ws=|B2DahFR#nq3L6B zTSMWV&%k^!U}Ft2!F;?<u1A5Fsz1DQBv2fPYgHXrr}T7($vP{z;Cd9cyi)sjDq_Q` z6005OhK!h3edBRZss5SXc_m+(I3Vv1G&hSL8vmWy>u<1{+g<pBPQm(PZx}EM$$;b7 z<aX?OG&IUC4lkvB6zmS+ZUP*EA(J>qOG)P!fW-c|cnRocX=00Y=8SQHKsIseKLb8h zLTV4;ra6PBj6%)z&8~jgA}tMc_WaIv?)dnT>AXA3mc+|bsikEaVsls>``?H<b@qn+ zShj6x_r|w?_QkS51=ye)UCr5EfP1d{@l~Qjd92q{v+{wBy0kash|Kni)Fip$-N+HR zWAEYVe}iw-)eF~O=Y~(8{`Tr)5eq*K3U;~Ss#r(0p?)*;@HHp<++3Jm)B;|{=_v-q zTMysL{aK{*qwpoK*jFFJ0I&XrbJ+s9+w<d&8pNHAJ+ZzlOG=5Z?tmfNoAa#jwDbqq z<>t@2`J|XNo0vtVWR#occXAKrnMe<6S_k(U+mQJVrf-7J>C|Fkg6Z7fE!WBC3|!7y z5^v|6^3NeAsz4umIjJkoYI3+T`{NsJcPP{<ijs!~H&|vy)#{-SEOAH=D9O9lC8x*M zMBl;v&QH7|KB_=-WeRdX4-z&$a}o^i*0ggFoKj3KuGHk}TC!-GpPZMWSKz1NF>Jp0 zzjDVEgPn$X)cY1Ze?Is*BlG>az2Ta=u~Hron}P1iG4U2*eP3PH8|9}N4e!Sz>?v<V z_Rjvs)O*II--P3A==Iuah%iIJdSLfk;_cJxR*Pc_d27&cl1$4&l60YZz1Gi0wGWEu z69gj~Ns2zRAN*7+y|K0rQlFc&OqfQrcK%)^D<j7{U$-h6JXQo~6&fFFvJl|^WMDjo z=<V*#^-iSmbCB?kqdVn0AR$vJS6<S3>25XSobL90h>IDB3I3Z>ZS+y#@9Ate6S-Ca z-XGUjztLE<;Cl&8P@$7aC34rF6HQ5K6r$g3UilI~U6mEki5UZF0nsVC`5VrM<$x|O zl$xNgZY2VIIcaq-wwYj>?9nuCQ;jr&XgX%3+ZTl=!A3Bos-549pL4Ys&nmbDT=3DD zb({ECji))Cn<Wg7j~pNU2OS0Jr@gZ1={WkludCf$R_sVMPK++qc5&aQZemp(SAP9G zXraG!1M0ek5BgW;{;k6*o7R!}B*F66eqTi;W^jaRD+uPc^h8EauC@y=uQAZ0CIq7z zHR*qe5}0bT;wiBg3rGux$*SWJE5lW{-%DcnRYbXXVKv9#I&o22TH;?(tHc&Ny7(c4 z==a|anZEE*d0k0<Q$(IF2G{lu3G-mbvb?6?a`Aj3%pPf?LiKqUWt8UX2>qYVD_^B6 zHZCzGb_7j_zw#Krti1O{QHq;56}+EwD4l|mQ~x;Ead4v|tmx%oCL^lg%m*BHnkzWO zw@P#c>mmWpQ!3;D=a+ibCIAN}b}Ke~dU8`da*v0glpy4h+QB|F0HmPR@@U__i(?0t z)#`&Kiy@ayvX)zVs91301bkmY2{JalMe+1Rat&W6G_TP)u}rXJ1E-WB>fT992~oGq zeHaW1I(GwNCdpW{KMdvK6Mg>`(2&2J?{aLdt^o>`{pw+EU8X1S{bfZIEDQ_AFr{ke z+N5Qs#!TIullcTBM#GOjzwe`amyJ8HSq!hh5FV5}(|Q<$2MrR9^<0eX4b4U%51llw zS%W6w(JeMiuD`<&Wbz<x%YL4!->UJ8*bU7m@gV;5c=fqvdOzC&2OFcw-GSNh!$jcf zkB>+*<}^Wo+XxbWsk*00xshFD8tMd5Pr_y6A2-e(dpk$(aGT#T+iNg8zAS752tQN7 z&7%ei$?>85@r6)lq^9++|6o(=^yCcmq=n+Rs<!xbJlkH?c4Tew>GIZoKnODW{BzCY zz8JQ#!I{T7R^eMkKA!0>%zt94tCLqKjwoIksAd@p&FhUbVPNf|_?@hSTTv|sq;4Nj z1e}6@hvZZJuu<r2dJvK_NX$>R^kxJ++2G05&35y-mRf^m5e!7W!p-J;e^tcq8Xrp1 z&mR-b8Kt>7pZyW_3pJL6XGPA7G^G;uu4P#Kpf(<kgaSQMWjCIw#}`Tr5!jI-Fh&GR z*jv#p7;s3p!jPZyOc@p>lKqkS;;vXOYOX1y)DW@g`Hp(N-RE{@MW#>N%n#(lk^lM$ zaCfqOxNcS_zUhM}ANJJ8L)c6av5cWwgen+WSKKwEZ-6Y~lkQ;8BQyCq%K&9zSUZhQ zc#Ii$C}6xLm0`o}^czt`*m|qZG7iMk>g?ALn1+#jWY;(*4h3MUR$V_iqw`TsY`ps< zB7!Y3N^XVd{7Qz}{RiG@m8WOC3FO%%*0@OQ))#5!AB#e*ng3=Gz8hGQgnXd<*f`IS zWc*?N(K(2LTr6C&1|j~h@?=ct$u$;FYL_z>;rDp2N}7=QaN8PM(|1YvGKZMI<B*_N zd|H>k9_nT-nT{Y!ySL#e(Hxi*0RVU{C*hdrs;ZBap6b2O`AcoCkY_K-%kX~O0Ta3q z3g=A+Hp1|}+RZLBy8iaNu-dQ~QUIZcFn+jahDi=~tF?DUYd)Rq56zknopP=FlNB)2 zBplE9^H;u1gyGm{sZ$6!J$mHjxket`KU(TA(K$Zl$y?U9wW5Ac$vb$rn9y1f@KxD` z$ZBzDm*lOFk6|wpx!7r;=`M*_w!2by0QhVOaFE!PXe$Z{=;aCphuvUs)#03_&<b*P z_&dvBy)XPFU;PWpmq2JBnUpEpMEBGLkvh3RNM!zVbZQyrKXdxl-QBtS8B}fev;luZ zxj3x%OJzJLyBs7zm)BD75`izvwfm*s&mnpWw=@K>$ZT?sGzLex)~5}#$w<vj-KPu@ znXMpxS5vMwFAwN`FI2b9s+>UDXQHNF`0M;VJ6%5up!n9~&GGxw+Dily_e+b=?AFT> zRn<;mva5-FBib8Q!bvyH)3hPGiO5?g;J4T8caLj=v>Ugs>dWE@6t|xxls@O(-|R^P zOD-KTUiN~>7We;|8tHF~QMb*1lxcjylc4&dkcB8)gGA2AW2vvrhZkj?jH0>VB0$mb z6R1vbvvz#>0yCSupVNDBc-8;iF#nPU>*{~7Y)pkU_41XbJ$Pji>$Yzcj>~6U>0nI7 z1`vGB_JoPxxI#r|Vey6PdWQLV`k>d*2sm!QEKz6pvT*<4rvBIP_1>3}M!(uN2_<E! z_w>x)U)^mXhonEa0GFW|$~^}<nm22emzS-o=E{_v<KIOQQ*HGSF7XXt_;#eB{chQm zY%%m9kfRT~eelW#QQ8zC{#<OBn}V){{<y}aq=L?8Mv_C*eNu05yn}?{#rf|&9z<vN zZKS%`gHyHu&zxH(hmk?y;Q}LdZ8%ZTWZd~V&UOMCvmxY|N5b!p16p9Ec_)vh#(fG6 z0VFHg#a#{A1I;BG{k{&{SPezWua5^(;FO9#zbIK`2F7kxuTR}R$D+0R`7rJe@0kdX zh0B_XcfFmO&;5K#K$w!}YK<q{W*#g3de1!U+yKQQ%7Z9ecH`~Toh`a!LU_ET$Zw3l zjL10E3v^SjT0CM#zB46$*rBT=Q|FNf{`LfhfkwjVw%?L;I|YT#9mQL|T3NpIt1vhj zb{8qe<wo{cfKxJ#LeU;!4>GH)<mpAAHmv7--mi53J5)KN?7_dsV$Ma};2dXZGZ|-q zvv)y@k%W;D2qy(AV4<KV{}4-aAxcTd>$3A@xeL_omVI*E8jz~Q1gi2$Y!k4rSl{6D ze93)yxpq4RJKNDbaXzWKZZFwW!yt{ZXf4kE)X`WO_v$%u;+MQl>_cyb-S5<H#*02U zkfQd)|LhW#{x}${j^uc@b2&*@3`>Relp7Qu?PTZsC;iMLZ^W-$yD1gXoQO&=;{5z_ z)2MnyhV}gi3pD*|#%cljh%Z82X3nyTKqK}d>TjXoGMifQ_+#qu@Uq3%;O0&XqA<~Z zt3(F=UAs>d{j&OnXZIHOi<H?o&dSF&#mbfgrN7q(Op7_Cu%|q|IN!^n;QnAeCbK;e z*MS;pkV*AH8RzFYNvS2?U)7wztezaL6MHv5{=eLz2PX*eatY(1S*ihOwwa)Zv-`2z z=2lcI=x?MNn8{NLX8cEkYlg!PA7{!|bC(tFnESay+6jKhM6`6s=w0@oa9{VoPq~xs zqfexHwmkg&Vz`u9G_LmcKF}3Ho-1U^tk^iL&?NUA5lO`$%5LLDiM%XVLf9*dhtx50 z>~S1U)CI&s1o=(8I(*vCmplEE(7K<X$!XTE>HSH%EpjEM{8l#c$?5m<Cyrma_NuVR ztzJ&YbD<sb{ko5j!E6hcArocg9cC+YBqaTlrl{zjbV=VI1@osQVTrq<(gvBKIyh2} z^tgVpG*da=iaHPDH|I7bd_6%b8)F(rBQ{7X`@12@wJpun@uX^zmR`zjJK!g8O6H+x zCNa4lwuI6eU6)>s(;g;fg<$8=I~>;&^0T{I<Rf)|yWiSq^@l%D(lchSiSEon-w`wr z%vPuork#!A@o6)^iOVw=$(rDT`~z`_^p*Gw<e7qH$-e~Ro{d#qPy+PGSG0NDxChCf zW1CuU0$TsdH8`(rC$x^I*kVOL;^Q7Y+HAgd|4*@0V%eLn?zqi)^G}p|w1wtzl78+% zN2}2JC0$G0kX)b<YIjr@loUq-)xo5H-HNG)KcxnKL6@PWeBV*Pl%98);VWi}tE5F= zRM!l4<CU(ZzVcb!&t3XEBpd0;_-*WO@swp`a_eio<Y=20gg!wMQNs8^{KL2=4nC+X zr1TcJJ<&n9OcI0Lm5HouD#(GkKaWM0`{WW(Q&b(N3=S!lXZvwgeML<u?82AsejUJ5 z4Nh$w$>AUs!4@4NL(*AS&KA~oSQl#4<<Nv$yyxG9Q~N|`sZyCBo85GZhbN;}R;Ebi z`>QzSt60=_KctP+_V+P<VI_XU!gz`4v7YmMvY?1vZwW-cHAci1^o2ow`$Fx@H<uQJ zft^^=rJJyGuVCZiPe+=QO$V<ylhw$dUytQtY#MMZ;H#2nJ}QOlbV1oYGbD^vmOID@ zRcS5RqTK*LzggcemVEt88QXY-Mqa~+i5xBW1n_}0!k%q6+f%?8J1qP2`<!L?<L+&6 zv5HQs?|tSMe0=Xr*HFnrKm6W5AU6k&3%Bz<X{sEqh36u{=_~|L{te0_!(zq-ru0Xu zh7rtaOh~~}+H?@8?H1~t5kK88f-fW{_oxE;)5)-+ajF%Qh51&H&)i3HauGgx_`-&0 zb5P0Kr6x<(`G}5rSYhP|6KMatHC&=Ve6k4#m7K`y$JOta<!{9q#65ia{KBhsOqPDy zsN`;F5(NQn$mua{3jPr-x~u1Ksy_*8hG*<Y`H`q|E#P;yDLy5nc|J0nwx@BxnRYzp za^nMEeL|9eR-3D1h3@P+M3zK`Mf5<~A5Q}NnIv8t$>0L<XR%tP6(<aq104X&aBim^ za)G%BHH`nzQ=%Xobe8Ae{QB<j9o$T7uqYG}@>kXYxgWbyVI*{=GoVfIKjb_E;2nu{ z>NDTt2E{YHP^!x}8&UWx;|6c3qoE=HAu0JI72EzZR8(q~q|;7)C|3QCj<_W1lr_>Y z!)fQwh((NppSC2wH}qycA2qln++Ub(sXg?M_VOlP*NqraB2KV(n?E8P;aN8t5u7`| zYTXpdIaCMGSjLlw{n4v=Q?<ZjT)&u$4dBC(F5?KhV}Jb~`d!;-KyU6f(`N}X85>+Q zExh@|UdKr009AA^`vmK}#6kOX=caEQKLm4y4P1%hGd8VY_P_e5(@cJ6>-$X+YCcBa zbqZg4?0hY7D0DDgUva5O9FWK3K^FK%?Zh36TsCN1@X?w5jRtOnmU^${z4Xl_vk=Nw zt+d*V$5Gl@gL%`QSuEfyA-8((8$5=cZ+)oZz3S3Q5yn$QQfN9xR)p@uGr1nqHEw(p zEx2mdlZarx4D2vx@vR1o^9n5ev(MF^m)mPxcZaG5XQ=r*W#ScYOY14xRUa+q&c~_% z8iA1U6P7=Zs;!s+tTU5xjJy)pi7bQoet6KZrMy~ZQgQ3LRlS2op|Hp+HP66T-Luw$ z5yjm4L;(F{>K}r%`b6C`$tR_ko@kEElK!;CtKs_3m+m@G+rpGo5%%v3uhM<D+H8Pc z$`W!^+x>4f;tZ(|CD74PsEcxE4Dbq^5CKeP)b%J9F*ZOmbVR&8*6FR<_aC|6#_oTL zvSm=|dpoQer_TL$ffX<oBHM&c%JK6kZO<z5%2~6NbTSJ!hZs2rRcFHr2cr$Y3ekPl zab2Sw4i~~)8V%}&F<6JSIw8+vyy{4RjX&ksVY-u%3ppy`T89m&S0-Q8niCWevSbBI zkJ9HA9?tfp&l~dG$z>vD(L>71^cB*vQ{PF39HP-~{!vg9TR7dn+0hKlWXOSn??`Es z9TtJ7LAO06e>hoicadsiX|Pzlcbq1C4fi*$BLlAk|2_+U;<Q{N)#%l_AWaUyRBCP| z#N&%K=2=b+Fe}*5C2BF5^k9=gue0GRFzJ)uuxd*HZd}BicFy2BQK?aUTi_O_*X|RK z7b+!14k31rK?y(d%pUBEH#1Ca78VlI8yuIQuBn}$h~@Z)@95m_A%?ep_3pz%n-NK1 z*C1Kbl)Si}kE*(n(5!0C@c1J<IX<u2l^6*w=i}&Z3djIN8FrXlBx+X%kCeDTu?60+ zOV~yR#~)=cbM#jpkG6@O^pqgC9nCyt)lGPb-cKAx5;nPBA3GIv8F4ux*#Z;ffJb*q z9DelXi{WoJHr+n?=)Yq*M#{>+XZQ-f7rrQ0f#wEgtD06>gXgA<wx|bAS3BB*b&&g| zP(G0RrWF`dEXCq37Fm%)2FmL%@+i~e<lHNJ<V4{&Kb@C1eQlbGc^Mn4G&lWe@q$-@ zIqaFe?A8FfIH`<9TehUPD`O;h*fFwAXd<l|9|V~sch#b+h!!64f`xpL4N$0F^eX!? zR35uNZx{zsM0>`FUy*^IeG4|YUO4YAFTFr(V$k!cq462J$GKR2qM^aTSTh#?06NgY zIR?0Hq7D1y+LYYuC9C^+8;cCIW!FevwfczhrMUxAciC0%1){k`dO5O)JU@Wh2}7J7 zqlEqC{xe`w#|rKYA>FJAzTx{-&T9gth>G`%Uh)eThM_NM*dUxnG5x(h5}YMf)5_~- z>gNK2oC1f5a~|p*RP@k*P@WTZU!R=Q!$;1xd9AVceFSG?jamLAz826>2DHzh2j~KD zLjb0AHY1-U?V}7Q8mP8nNogaNbl!7k>J<-Z#!a(shvX(7KC%kY2#?%ebE}=5yZ2{$ z8Pb?yP*2@0S!RYjVQy5zxVH<1G@~>upv7nmj9+ApNmYmw6|A_U6%!Sdl^J2%^apYU z)9&2VGH8eH*WSaTm*ifHvQYI$-u%8eb@v6UilN&98oRGsG!6wHjf4UA1+}|V;Z|u& z%k0xF{9*MAcMjcR)de4)tobpjyX^(g<#dd-G7N(YMy4Dc_{hfd?_{PStx9mZNRThp zb0F;gMo@IW|4k}d50PJco7azvfFHhXJj~EHo;ssTEm%QV2oXS1<4tS@$~JL_BmQ&T zx8istGP}fklX;#(&PV!Y2ePUL7-yWgGSB|60&thL<KE^D`nv1+bF3)pVQXe5WtsKG zfVxlH=VLmygf2)|vKca#eU`CK1&L2le@~Wl@`F-du|d*&TXp+#sc1eehwDVd*~^+| zjUtV?%L;_^)3W3x$kvC=>_^3201OH1?e2H)?R<2xA|(sbVQD?*f%T%`-AhF%sLj_k z(>?P0z-^B)#Pr<92qU`q6Ux|}%y25}88N|$aQ(WIP!2pcOGP6EO;IbURKAF|AYhP< zfF)0oCiX6Bvg}HV`!U5g=jE>F+nt4>C9uAF{Z8Vom(S%^hwO_@o^kCq>dEt6$A7dB zkXus@@tcecteC)lb1}OwkT-U31<<Zd<(rhR5*fepV=0t?oK&wMR(&E~5etn^mtN(P z1@W*ZlPC00bx}y6L)gtJ6(KofNfJsBYFKmlyIy2Iu+`ghz@R4b=v;I;#|<a!3a1m{ zO~jQV;0*`kW{Mu7>(FsdllrgN@S{}e7%F9HA+(4qqZi?(dX8mApVL=ATId}$923rg zxK;xCqLdsoVMj^QXB&e4IjbyKbAiPJ9;j|4FOF<>;hy)0uEL>uKfAItz{P3aBVrSc z?||eBB=dLqUOoz@p9*}t2BmRGa_-zImp-!~<pHS4G0*v3H~qhFs-59#VTZV1b@KM3 z(+>8Ccn9Fj4axGzHfC|(e8TnMG4=BB<fHU?T$!zg7;fL)f8~`W86h>|e?y`g57rMf zcy_CLJ^3<IZ#y-3hsb|?L4I`cvhjcmgk3t(L=a{kfPJx_QLys{5eOF`q^HDkn@@yK zSV(hneXp73Qr9Q0O<qZls~Sje-CZiwGK}}->M;XbUNiHwtorAmoF*>MNRVKXoHh8~ z3!Ghj?6a3pi&X-=Q3<v76<!VQnGNl^M!=r?X=j@)tlXR_=5fE}lPD?NNCjaA#wqRb zdHf$od9S*AmG1`nR7^pPu13Q@;tiY;ybj8BU_m;Th<BvCoZ|l-8j>3hVg@cpO5lXN z#T{_&7l)FLk_sN@Ivn9D2(k0X&hUp6XH(~JuiGc{qTsT8jZ)~d7fI&sphEQ0lRuO1 ze`Qs?wLfAFG<EL8K@wT_3xBgHijdKccb4u;>MXGu4Dci{a(9DwdO1?Q!Hb8XoqfJN zn+yfCb|Mgv5TN;m`2rCEZ`6A;vtBVF(>zJ$ZTONV3m^OO;6)sz2*YUi@_T0GLNLyO z@Adm<4F1e`PR<CyA2vryj?){XbDG&#V|LFR1)hG3s{J$WL)2Jc?rWs6!LkI8gzyaa z55cn0&&UPv7_6tGMQic^LAgW?)I~konCslIOKD1sDrL$*+7gfc`N~9Y_>hn?YuvJ8 zJ4X5$#VrXX71g)wXMXcobpz*}icKi+3Q$1zQYs0R3B^zmYTe_Z@CjcS<)Im*h16L! zb-WD2TAMwVV4hpB2N;Ft4m1EKweT|iIkKh-yma2yM#rif)$;ydDKo&8J1?G^mcUw? zya)c5+x*EAxP!Djp0#^I+g|W@!LeDszplLRhB;MGyfa~emTO{dLU)`Er{FHNH3a>3 zo0lUV13eTWva9qJy;ME3ovtT@49BJOthC;479wf7tze;R4ADQ!JqYo_7ZJkGqJ2lz znX!imGrmNIeht`9YVv$9jV!>7`P3%S@m(F@+4BO!AUhk|?|-pu{u-z+CzkFm8oPGV z^9A|X{W(q7Qj!N>CaZ{k7+<!obn|mBLpZ7eiGF|Z^F!3I`~etBmIw}ifr*;?W(#Y# z-H6`i<)%INd(<w9!v1vyZB^{0N1p%f>6q_9FEKeWF&N(_?|hU9i*v2*8`)55;>nKX zKxpq<hIgA9W{U3^c;7+e9McuZH6%-Rk~iU9*D}tTl?x*@I1-!{F`3PMy`Q4QYU6$i zpt_6pTzweDsDRBrndVLP`h*=qy$mglVD+qlUvzbCh-~sc`qwsMF7A{$8zbgGe?yVs zp-J?mQKZ@r5(=_1@2=c<BJc7ijg)c89ZH$!V&fzBfV3<g(lqrD4pHp#-#f3;@h$-U zS09EWi;lqotmG<3PRcafDtZ1_6RU!?^CrtaZsjyDEeLnDrspZf7}4lasd{#v<2_nJ z6MCzda}y8cR5T(*1nC-#^=yeOYNhh<h?po17Sk~_#f2wkXr2)s^kFwGpQU*CNp#?- zI#NyGj?nzN&u8$GbY_j7lf2Ovz1p&{p~^ev5c&jbo9ukFXbf+h|Fn!5+Ee{b%*Eti zuEUZAT)%Abx>F;CcQ@LpXb4c<lZ7>Bg@Zbes>5Ri7CXM>45U4ycucjy`XqZ4dYY=d z4JTuHGEf!C5``HQ@%smpLImW(Lr_O<Qk{S~r{EQ>F_TP(pOF!IdX{ZM^O6OKrW0dp z^rEB3ZZv-l^?ha%a3c3j(bw7;H#CLCBNjk7YrDFSIa^Z7zJYC)%RcIsg~s|zqMUoh zK};;P$~<^Z8F72{LAQm&fbKf}k3lR$bzz#r7&j!rD2os`b;~IDa0uUIHPAx(J?ZXN z6Wp(vDA9iJYu8M3>xk7KYW<hpBVsv*iSHh_9>Qq&%Tf&P_JPR$<2S*wX+bU$9uiU- z@Rl+XrDhK@gxur`iU1jfVLBd7KyqmzfEHyZ0_88nt;Vx_<!~#pZ|qp-ft%~j`+m9B zeWWH>7Qv{CV~)@1<bscsZ%0c{wD)gj)xba+?D~wGw!Ben-}He3Dsy>5f)SlI0dM-O zcf**#9M4D(NJ>ajQJ`nh=E>$siBGZ!`u3$vTI1_crsV6>wIy(YF$NY!q#D{kyMy`9 z9O~-_FR@DwLL)UN&EN0mD;D^Wn@1@tyLd;RGu-`uoqo<S{)Y|prbmFByV&LUGQcP4 zV~1{qib8^eq}E^|>gRrWS(ZE?zHt(ZDhua4SnnBSA8a7k)7@<{0^cQ|M~ywi2&91N z?Js@d^+0!Kf*MeI;NxkxkUC*l)lu2kwCybx0tVJxIJD(Pz$&(F(!Im?6#6%u9k`14 z&_#LkcgWL^9r%uG{I+w{VksS&bj9l%qyW5l$)fMnh7@Iy26H(lY*72DwXIYjw$9ta zTqw!COJ?I6wXjCWxpTamB>Q3qP72x@xOi5$pZ7^7#E53R5fJU*7i)~VJ~dEA`4!yH z6uW+4%RfNl%Cq+mvmD)k<qGxnv{JW7-5jyTT~ls`2~G(Z8+erK(HcrON%#|Wh=;tN ztw1u~rgpW|=ret=D4UpOE(~t8B6kU(nXF{`R9HxqtngQ$D(bd0y`r0+hJ<N6OEPyA zXaG;QrraNfO9RT93wf!W5!18OwGr@XTPjn_KKijPKH>k^;9+n^x5~j^1Bs2`SMS}I zz^ncPd^;Ts=$Px#oAw9zn8q7u6>6TWaWDhz@zy?f&Ddh$d5sD+4Pv-2M%}yLmv(LA zPdq4zwVv?g9_ny*Pjnx+)oEUy(SvJ5iy)#o{x_vb5o9`!vd*z3>Y5jylN1Gg6^hA< zk=}M6*+r1tBa@LUFw#*w5Gg4p*}f<f&@yP%nH43ONtf`WC))RS1sGr*DS3H07*gcS z?ys5VZLBkeyqVx2>F2fx#@*_|-P!~g9^(?~r$6Tbs$#FIV-lCKQ(UvO1M+aR^TI*} zhulEjGaMPN!pk#Q0kG3GY^-Ol;E?c{@1Y~-cuWY+6aC_JP5iI)CcxB)A7Uq3Wy&oA z^TWja0Yb$_^|1CxC7OsM$#{{Pp_hF;!gRkpvMhvnCFY9_=QlPNzTAk0R9V*%s)CSL zfllr}Fl7+A)}i%PEI`Nj+Sel98p8ID4yZEY-u(K8wY~*)#T)k8?muWEuDI2t;#azI zkF2B%eYwvgJ+ssLQkC^T)IQ1F@h8yQVU}9b%z&6U!~C1`CBhSuM(=<HS#e3YIe71g z81TSd><VP&zEWPRcx2-gf}B7N)vpbED)iScQH2`u9(j5A!={WL{LsD?z07%%qL)`Y zZ^sWMp&g%Il=C(=nfeRI!>78&t7<VM)dgZ;*qigDz1$GO0Bp_}V^s8r;E*?g?J=g* z!~;gCjz*M+T@BFK$tZu%7T!|40Y-O9r}!x2P0~S9aij@S`zFPl5CDUk6y5;lTxAt| z2jt#||LOWLbIC4r&704Mr%T6!T;<H0t;?;`F6$Vv5&OnZ4n?k$&VnxPnPUQec85$& z=GWzjf&kcjqrT<-3T1?f5-~Ol6mY;s>fT8gNU$E?Maw@j;SYvQEr=2d_yK5g6B*&~ z4Tg6mknlxT3)~Q7!y>tA2*sH*_GpUnAAIYV!-13fI`ps*sK4_!9BmatSos%k==)BZ zYtVq`c;u!GtTdOG2oDdPm_b_In^~{Idq{F9Ofd}+ElFVf@G<r0NDO__K}bkMIdgs< zAZtAKE8FQSW3=Q1vnjSA=2X12f~ig)X-vPDQM{zN6tTYtAg&+pVy-z3;SJKD^9aNP ze)8I=0RUJiKe2u~KT5uw!j_ak%<)@?Q4m8679u_AL#TZJU?|3qmV5h+9O`7@X!EF* zdNkZFURg*I_o%)12g>Jsa0k_MVK(sL`<-4Q(u-$wL!epIG*J@=|N5=qD+3ylS2BVk zPp{r>LZVPt#q<j$UUCn{R05y#a&A7*2b4efV8ovTqINOph;E?zh9tM|J3%y%81F2S z$k7j#UUS)#amwW$uXo(5PuKXBMLsTw7Q%uh3;bcEvjg{!G$)7GoTQZkF&nfcOOi;j z)LpZh0E0Fm)?nQ$w;%Awh@1w^V&5kD$du*nTScE?a6s$E_nxS!Hh3}yx)7Q37-?%H zL;NVB{OTqx1TROd3jDIU<#GgV8=81al_7;Xq0xez#!#wT`Omh9?j<-)bo|Bs#iH`O z{_r1k3h6n$$W}YKz@U6s*ktb^CjXiyK%R4Xh9^1Ua!u>h{^Ru%$w0L!&2AroUUbGB z>ICy64LunBhFl&{`{j`aUbXExlFK`4E=24vIefk2DS@wd1Or@<&llTXPy#HG&pjN4 z=SA>c%7MzPviJlzCEnXX+=*fx!tX=%$j@m+9ApQV8Ugm16e9V8<Rm?F)1$`}eRNBp zOana?`+E%H+Hd<l4}a7fXzXeA>9BeNjYvYv#}7LjpBV4pE#z(2`rX|R3+->0^t{rw z<Fl~NKv`}7*q#wNLk?b8!KrY=xZ6x!4EvGdl*TlMY4{jJp}Uxt_JM`1k%pLj>_{%n z7x(!z_SYjx)bEF<Zxe5HmR3YZ=$_PkF(KessJfWd(|gJo(BF>i#9D*9*!KDbm6fnf zeo4n8<ZgNcBpV5;P8wr8mXFev<-)H_97y&>BOh@+5ImE=(?bHZud(8ACHIMuX|EMp z;Ku+|zFb`vn4z)wOJ>ih6sTfjYrGa57CVdPA@G>^c(P*0{Jl`p(=PU~a~1c2T~`cN zFwt$7E~)Sstd!OBbnE<C)E5Ud$U|0_9mfQ3mqO+{0K2+j*|z+ut}Z5L$To<hMy-}* zgy!Owux^xJ3q6;!N8@mRieApNTj`jAICq~;F*gOQY|<pJ7fr5>ouMnbWokTW$r^h= zz^4yiyPztw(zGpz)M9&7?px<*%b#j5KA)qtD&NdAc>Yx*9-mJimlcc74u;svVz`}5 zwEG3}l2<^A&89>_jEaBl1RYmpBm3xeU-vo{otR|&CxQjFum?gcBwR?SL2bqfb}yJ^ z{o%ffW|#Cub%$8deXQ`2hhEI~LPM<T=N(zJ=?LNQl~B;ebJ|srkbllk(f5to6<(jb zhOy&KbyC)L>pplV7O(2NZcPDnDYR~~{9X%GK*T2Uy;-a+qe&w7orTk%r5VYqcwHEw zNN)(D4PwPSL1KM=0m~~L-d<>qRm(~guAqF*-ysj#YZyNkHwmH%(~XCTQ<{Yo52rMr zPR^SvO}6VdRfoq}FS*Hby;Ca$R2j*0=pfM~(EGvbtfVQY@rPDb;^RwAlzVVLG(q?_ zAiUq5`+|v}lfX0k$m=Qnjhc>lC3J>rao~eCbQsc*Ibi<^-GW@IzSm{?Uw%_{NJjU4 zdvo?gfokiG?>>pLR<+f;;k#FHjwIF!C&-<yy3>2k)b6UtUG&lkHxK?y-8>ci+%S<E zE)MIjI~p-{qg=*3XgxhmbQ@0h1U|38?&|S)qhCFjE-$f&dS$v-ZOT91+|5@fH>v7* z<s(SzphW+bL03~tEVk4;QQx{JXj<tVw&<7RaqRb{yVZO$V2ZrC_nZ~`Qga9|EPQWW z4TX55iH$G~+aAN`Fb7AKaJU+9n&c>Ajsdr`WqSJ#r44#1LBR?pb2B^RL*ob9Zq*a| z&JE>zKc8F|TL7QuAMffv*cIQktC<V^KE+T58s19>MwW~JtNurHl5Vm1O{Gnfs|SL+ znOCe}Dw?j!&h@lr|3|CmszjN`r<FrBCh~fz7%_0nz|!fT)_O7c;MGP-hY^Xub^7d; zA1^qiTVzA)j$e@ZXca*c40VE9EOo<mve@cJ-ooz@JQ<t*Pc5NY8fBpT{qhaY+F=mu z?Zb_yn|6-|ilBXFbNdasaKsSx*g~my=$q0tu|YF%+E!z0VeijGe(T69NHn0G&BwV4 z8>Q^K@is5i?#x;2$%P$U{Gb1COMHc=?u4!;zQ0&Lg!pbX--l7h4K!r_VpM)~OdL>r zQHr}*G7$Q8+MN04%xUROt*ut#hz)T5_+Y|BwXuB8Php}7RY1F*u7(jUoQi!RBl7St z(oF9l+tHB>_t%PIMv~Aq4s{0U9FZk}aZyg0Ba!i!D=bisQG~@RpKN#NCYzfv+x#N> zV7hRvSVFKkDcX6xy7O(en={Ll=)T|yN7>G_G-7<n3WK-v+%E|LRtxJw$0t4H`2JQU z3_2C$7S=P8MU|F0G+4{}MUt~~v2WVnq08FlA9FR@UF6HRz<j}Y;to`5my5}iGP^#C z7f+Z$6O>tB*%QlG>DG<v=x$(L^wW#;iShG-lgb;9C?B79D47Gjahku3s0jqeaIi0Q z*($L_4Y*<ze!b5Oc*mM0e1)ADkc2}mZ}lOC0P9<V4fqdlnKHG~@7OWZ{&GU6Z-|<> zLPsS-H{5ix4DkVopNf01DXdsxoJHRI!!!H`JTMtOhs7>*O?u@Qzi~|;g&`;xmb8`_ zxgkGCV;^%cPUDkuKdcn`P)wVF1v{0Ddi_?CZ9whpH7m)us3t#61Kh4yaq+IputkYe zJ}UG#f6obw_}p3OFpK2yyNbbRx{6VyiXAxvD4xa6#ZXd|<`?#-dK{Nv>PVkH&@7j+ zl6CUK*Lux7g6J!GYaMo6D@y=R{7I)g?}|&m>l_~eeNii6VJo3YfNTqj<G`Z)%!(eA zod;@09r@OOL(x>AW~TVZRU-Do(&Z{F_apZ2aGf71R$rvMG|xhX!@7(2ZjbMJvMU1~ z=#HhDp|Eb-4;gpE(&)E4)=vg+gr2#ZVrRv&J=1(|+N!EYOtpn$`4)s-v1HA!X8MY9 zM_8%S3b$%`lqC)_go{=t&2;mezf<?fVWMquJNNSU$VG`<=zgyj{`)Ha_Ybb=?_Ry? z#%}G3ok-GOc$6zzwOr@9-_c+Mt_uHoHyBoH;P#7*z{`)*pA_Ez8$$wdh72Kxh((7x zu}r;NS=thi&q&lS-Q>r(J6Xs^%Q*d>QCWq48A)GIAe51$Dcs(t@B|*!|Cl?34D6yC z`&6l@gF+M@#N&~FFFd%`?O2J}8Qs<SO!M_y@BF7)=xKMf|L|GQlg0D+W0qQy%X3vA z)eGtJnjP2^=W-&)`eC3L17;M~x?6j3!Z=OL*iFm=&#cFbO$eAbgTyMNb4zGWzGMuP zNEf#Hp}lwAphH>Rg$zW-=-lpc)MjW9c-ibMN<EoR(naJ<;TDXQZz@x-Ig>CC9eX0% zHwce^hZjkDniWF6kb+rs3~-n!fY+5KwEsS~V!J+>+Jj^dz~dsLVxHr6DBHu0Eh`)# z=O@<E7v0SOo<4r7nfmE)inC$KfHgf#xe@5HErL%j#GLoZ-nY+VNj0W!YR#nvN)z~K zM2shv`}UUW<>-FsboHTg=2NYV>jxGGZ(5c$C4F`Cw(H-zhO6J0BF_8lFO;9F9DB?K zzEJP}M!(B@evJ%ANVjaZnA2&y+Nx&Vgz<s<NSgIxh|1F#n4t<_J%60i)RACIt*FmB z-5oBw`L~5Dcpy?(Zr?i@M=PaZ+rhTnkLJMlr}1_@v?_7vd~I0-sC_{q*4d-P#P`#= zZaRdaO7gIIY5Vm=s>X3Jh*fV^Nvz2kApN4Czq-W9HfI>+`+3_9mE;!suRtmO$rE8S zDzg`QkbDOfPAjIT=Bo2CQH<);lM%Fupl03nj<ZJz0)lE#L8e6CI&J@>!+<px$HeDq zdzYGcf*P7e?M|HQ4_FmmuFEcnIcpC@(bg?DjxDC=uP1c-bdGC<wswIXN#7<o*X){7 z9;Uo=F<j9Q+jlv>1jaLqv+7e7{?BhxF!tB~+Qx6U(MJaA;(h1nl>fl(CA<Pp@)Q>f zscrH25|DMMsWqe99^z~2P5b<$!8>w}h>YmrWiwz9Gt<Ic@vlftG!ShBu|I3Tnu`U8 zIW(U!J6J?NAM9SvPz)66C_2LYyMuEMahm|Ein9U)`o@r01tDeWm;r@7#|cBaXS-xo z8~#(O5%d46)Q|o2YG7BgoHt07_f9(S5aUpeeU;IWFu(P94>3wIZ5@qPjpl#q922jH zK4hYN5*0cTM40%8f1q8q@FnZIzJS(?fcBcAzCK8~3xCTwIDn`9nqz!>%OkiEg@uwm z)=3ZfN!@p(bJ$|QfXO}kA9I4AhI94df5@q1zSdlZo9Rys69KqP&KKW;%LAjcYG6&3 zh(2i$?cbPv@I|xFfN9gC5;VmRwzPL}aM;!xX;<Cblm}MN=&Lph&X0!QY{LC+{9N?? z*C|}TPs=WVoH;m`%WxE(6Ya-Kfgk6UAXXxA{0}S%7X*dZjEt}xqr&Y<*DLm6&u`Z1 zCoFOQ8-#myA|hnE_oGdRLBfsKtmJc7l)f#hQukIMiPl5oc`6P&9I6{$TkxOBcShi+ z9Mqer*{;8r+Q*n_KzK#<pMmUl!G>6AZDpN>*ec^!@6z%l5}l~hv<_U*xIg|t1X@WX zGKOhLnJN#zm2X$FoQ{JdP*?*tz#xQ?gq$lrgFMPPHoPIgl>{>(!Y#E*GLezo%KN)p zx-oeyu`IroZ7di$fZ1-@>NQl=pOPik@t01AHW3ya9{zvBEJIa{^lYZD@NM#tsSUaY zcOow%@;;)ngbnrUg+LVv5d<{}y(rR2X$fUT8|uIz^+}?%fEwe_F;hN9G5}qFN)I-% z)wBVLvYRoZav@owlG(gM6scO*2bKJj2USBKJt31Y8@FRTtD;svi=}r=BA$(JUq$O- zJrOh=XeBTfF)*rNT28lB26nDdXw;b$d0;D_NDv-QZe0+kWo4QZW%#|aY|ItYYn)R^ ztV33Qm(6;nrV`3%(I{d$-65aRP#t78d$q)CnQt0z8z`Upqw(Fe0iUJD*Oo(a*_I*c zhn(<+U^g8n1GjX^CVG5>R|=TE(j?sl;G_@FUM-rWF-daGju!LLLZ-17zYabZ&ooy! zhn1yL6%=Uy=%U!A%8yvwCygHF^I$=-BkiKd{-oXc6gy^MLGTjWUOuEk8Q#sH)c;wU zbUKnh7a>DD(afKakk9f@=BhLuF&n=mu@ho1@^JZTjFwJ~toLiBPeUfrHlGh3mG48p zT@EWV;Nl}*^KA^Q-CdUJ^mtAb>HpGK-}R_D*KmDGT-RGsaj0lfp$r6s2qS%#r1WeG z1{}j*32ov^s>7bK|2b^p2;%>Q8_-gR`-fO6F3y$h?Zw;P+MGC7!=wF+XkpV%{=c}> zF>S5A4VM>D{wF!{+>7anU(US@)Rco5?yN%dl7Fe?aDPK4D|n}JrjF!4fu$a4<)SW| ztfZ~J_J>t`3qNA-+KJi3??HvIIS9b;R)Zb>S`1scHR!nf4{|&YE{m0Tp#w`;mVz_~ zk`j49abDO*eBtln@eviRR{<vpp5zKGN*s=i&N@HoubmCvm;y1syI|zy9oi5;46~ut z9kbGgb&#xTEFajz#RW{MeM+XUj_vhlObZmxvI5z*jb#&YZnyBNc_)EY`(&HRvI19y zA_!=;pW;5_IAB||%d=+8U@*oPv2E5{g0fs}H<I=xVpuYcbl_VZzj>I0GOEOMl<}XR z4iy|EEZL{DG1_2)fyqxRzdZXVf1h1lwjQ$TF+IbR>nX|wi}cMhk#Mr<PdN&6&sO)y z1abDzQZUwh1ibV|ZszJo<4}3NmvCPEf^@tx?C|~N?DT7vq(mRmTrqrgJGA6Z5F5BA zBkhn(duGNW^gMN0DO8wi-+4E+?<GUIrn}(3ie?d^^CWaGlC5?*s$M_zLlVmQ<Ux13 zc_r(&6+2N@2>Xje!ikLS^vG)uJDI)zdn_iWqcbU50+EBO>;7dO)coSTa2}g&=YsR_ z`13AtSLmfmn;5EEd@TtJq*y7-J(IjjP|pc=R(4mUAl?zY^!2bv=O`&H)@hlM@Jbgg z@^6CZgXc%GyuTFrx@pP?tzXn5AH9Bvny0XXnykh@G^RCv9T0O|)o5&dM+xlAf+jXi z#z`3rt3Pp{i?ADHD#i}5Fy1Q(7wmw|gg+NuzORx!JFlN2SGoIs6+Ur1Qy1!@xmpQZ zl(Je8t(rJqgOioau|1@5q7`~}xU4*p@P!ciUI^b+ZoOdzV)u$72RBNpfuhTJz2fGA z2$^<=G@yYuS8F=WskYsArE0v7n1SIu8{e8ETzj{h<LhzuoE~qxmzu&rHm6`CxQ#zv ze(UB4?&)uuxeww0lCAoNg*l7#hr(dY1a7K{Yan>5ZDe5IN;ZEucMf&8ak@A?p^B;7 z?P~+?)u(Y$kz%-nBz90l9|hO5Sk`~2l})Pi+b9cVJ79b*slgy8fcwv6@8=9YSCe%C zc4)AI$~dQEy}-dj5<Kyu@z3pLqmbdMes1<hYV9U(g~w*mMqjnIXbg8>rWYf)pVD=L zL%NL%NG9g4lPB=V*8=nZA@{Wr^I#syZ~xe%&DwImZWS#-XY~I2bznwL&I~!*q5fLF zPG_o+Eoj>39}5z|<;ywRqIn13F8?c@{picr*}e${$jeoI&;QfYTR^qdJpaSE6!$=( z!L?X%3tCEwQ;HRLx8e{eP^`EWcM7ynyg-5CT8g_%DDF-I$(ugE_xsPe=S0r#?9A-U zXZPmr%uKv`@}xY{l)jgi5Z6}V%>Pd9*`*C<J$g{<$o=<gm(h(&&c;g4#KX?cl24|z zj0xRUUrVqge;2JPOYE7oK<eBz3YI&8YXi)Q7H~)b^*smPlSc}aGyQ4j7N#U-nARXp zC8?{*4(q8b&iLql<4)iSTJLEd_BR^|))A|ZT~Qr#tI@nt62SrBIjVmjT(s(3bu+RT zmMck4D4R1E1-w1Mt&mM@-X9fpB&o8c_|DY8?<6}v-|`6GJdPNG*FG}ENRKn+gQFEq zUaK8sRlj0(4oKMdM?V`!p&!f6+oB@(vpdNX>pO{mf<~<!G@p)U>_y?98?VK<5pQty zOo;rsXSm83zIS?VSg-YL6kXwQXC^xi7Jh%b=#@lCcUdm~{^m{`qLz=_FzGde8!_M_ z^Wz^6V*hxc=@@#mfMAP}Uhmib@M{9TZ809ZGVvvNTWMyH__=WH(cP;*l?sZRm>ct6 z7go~yA#rcFs3^rvugfWJNNZToq*Hx8F|Vg46LZ()fgFZxdOtb}rME7MWU~$5TnXol zJu7#n2>dEt<Ph<TR-IQEqF_Ixq**v&pP>V<zj+UdN9n#}=TkfG(}&@5EO?QfRhYVS z<g<Zi@y@Rwhsp`MWeHGLl=**F6p4mViV79#=RthG%THeAYx#YeV7FD2Q&2vok=3Os zN(2Vf9*Yk9VQADau>5+%2qrk1b)UPp=(b++3{KvmX1D)d6ZciNj)(d<IERX^#Njef z$G*0cV<vaJQ+8}?chTAPI_JHqeXdP}vZL8taCMCb{I*ZZFP>yEm0%f|T^4)neiu^~ zfpfDUiz{`sSoS~m{vQ}|@TR?TdZ9P%#g$7JP$}~5P7RO@AC5JaWu9q19_qzf*50su zEfB*AC$Znl()frUA3cb0w})wOz~!4ddmHs8pivD?dQr#U*QB~nhh-^j(?x$V%Ia7R zoo1`+<2G-obCf)RH$0zF*2|G$^2$ThX`VMZ4IG@~s^aPk|DQ(lmOD8*b|U@Pe1%6N zY%-n(_IqPG<MgqXIR&`Nt#n;2=-uGM>`-7tcIo)U69pW8xi!Kak4JHnfeOZ(CaHX; z!3es_q5RoveFOFm*6R7T{uk#k>Jc7H4wGme7PkhqcJ}D#{Li0s|E^xAL{$A<#g^ec zt<HB9sJ$DVrf&Kg|5aVUN9M>f<JXcfVQqNbD~18wqXOF2gjmRH<^%2JScUqfb+Cqn zH$-GU^rVUxFS2eQ>sb-#JZA9OjLj!;fX*lNWfIOW-BZNQjsZ8YM9j$KotyxMUr!MB zr8hRmyD-$lY_o@yg%Nr;smL}92ERe*DS`h9!#_iD^A_X#y1K9xs~r*{?!z=7=zurX zCtl{l#B9cHnlIQCZ55Am)hKNh?Q!%spZX<T#)Y}rXInz~(mHLW4n|~)(20lY&Uq<a zPMd1@apf;@tLV=kcA8|vOIB9HGXuQWF=Wo~10Fg5uEo~{CoRKq@M^V6Zx}!6&cEzf z!5n{AA}a?!?W}4pUph>mhur)v!cjU2Re>U?y>^Kxe<BDGz|%FeB9WQXQ#s8bSF@_v zM%lx|V+v`LR^%&E3EWjSKbXX-H~aY&@6{EMg}@Jn9spC`tHyQkm08J0ZRQ31){M-B z`kJgP)!JL=4a^lB?3cVkx!Bn68x2~MV`S76*BK&bE?o{H?gi;0^NE&JH?}W}6+PsN zhhp(=@Z(j}yR3~s%cM97R#C1>G+3!as;V@uX~}%mHug4GuPe&_r{9o=p3&aMRU(Se z3mW{+BnD*ky<WzkAQP4hG}dBxD-#g*Ob*X+)eH<Zco%IY8E3@?2s;`3D1L*ag;p_I zd0EhhcX#lP0xanRKX^Dl)$BdtR@5xOr!9G#Bv`t7ZMavRk|}8JYl4>i)WMg^Kbzn6 zqG3?Uz|~b<lJN1E;sN`zQMmh^dmP>!iP3H$PwQKAIK#qj@!K$FYEp-2=C1R<)b=M? z*HMf*IK(Z}p(^^65|}2FDKWZjL_deH&n)%BnKKHxolVeZdG<<|7&tMACa3kgQg|k( z<&?siZ5B-I6ntkbeBZWSoYecAd5sT+HT}fsw^afIBw`yUx;%<D8|;phGW$9qT2hw% zI5eF-$=^b$<#tA<az%J&bggxx>72widAxUBd3>;;zXTL9lUTJl?_lpR`yLDu^Z zdl~Lc;vd@WUd=dtg&4wrcHkVXO95L|X^3@)pV5;CYgdFY9xn^Id2cp5UDA~B^$7w9 zD+LnrMxX}A#F2#|bXwa_y7xTL!(<*l(Tzu2DGZ<@q`xEy77mHhD#lq&Oe525m{%hk z+dhiVrCY}xx2m2svSGpJ`bT7bkvqg2emNI8sqP$Lh?Es$_xsK>4tVE9qod{Lc2)nS znJ748KQi|EWxJ-*nqb_~pcjh_rnhGhX*PQqWval%W2x?WBs;t9_Q&A8jUhY!z8e>M zvOm5fCX?nr`&(bugdOVqA3S2hZ$}#>6@80BijZs%#ac*#rDi)*UWyv`J$swW1mvOx z;5I3&XSk@`<^x#m<4`Kb*yIoAls#b?dyP#5YtCK@i^?+#(oSN1!a-*0cyDC+g#8U! zZ(K+kHQl{O1S%@+<}}CbxyUH*Sxvm4uiIEe--zEHgZ961UYYWKD?4LK(xtluM{R=D zON-n;?a>AVq^R5(nLHfPZuqzV%5Iw+vVB|3zqr2KWo6}k+P$MtB0D>I<l#7Ko4yGB z13O>MmMvcNvMNem%J@-mc({UShRRIJnp(G}DRnr!YHGd;qVFtEhDL?%6}&7$Y&N=u z{M#0Q&<wsLZ)ufHXlePqyQ*JrCE}(f>tfpU5RHN!WH;};55|2=`jYLH<z5;8$wK{A zV)$u#he);v2h92GBkXvwB2l!^<n{5$()cxzD{}cfVIlaSzk|@3Ls*f5L~+`?E^5)X zvrD!`3+cYpENiMRUwuZVbzc-Lsx5AFhTnE3dKs@+rN@Svx)a44Jc;ICAn*W^R=KMA zJ|oou>G1(JdS7+_5vOV*QyBQ2YYB_xzx5vXrW5}(_V_j^)o<a7QxqCPAXJ>GTy}Vm zjld_kCMkymZqEXUA`(B8PHA~Z_Ixcax1pfiJ0aZ(2oA&y;n<}yV$Vp&KAQdeFb5;1 zP#d@RE_tUMk;yFFkiRp%;|0q6llo(B2jZ0Q$)d3Z64Py5u#Ak9=Ckii6f7cRPo^cR zqakvMlL5lf*~3D@6do}h*Aad{=3;tq<vXWon^A@WE*{)9>)YY^!0L-p8WzyRK4<B> z$VM?@e)XKSpCV=RMzSHXSr)SyNpx>yeu7b>h5WG8%whWIRqQ_DN4I+>WZEX;FNQkS z&k<?bier0%fpCY);Y$FYPhV=vfJxOP5QRT;*LBuybqoUp<EDsGisM;1*Nr{l3pu%< zW+bnFYih_@+cHw4osRIE`%vb?GWh&-X$0_ZOTEQ4q%TCd;Qq<!PHzC03D}yk9p-#q zX_IvR?w~CTvIxPM$62CHKSbSFpmvnVvIkEZWYTRjlEMG2JtsXkI|CZ(J(n}UqeTPh z<s#pAX}_r!Aau%?S}<|FJ$R)ns*cN)eA1a^SI+~FQ|fGm8~g4K4J{8|hd#OuE=%2U zNTb2m<MpkCDG^quj-I)Z-4#?^KWMaPY^ODpg<hvNfg9v3G0C$jYR$XJ3_L&lM60rm z?V}>y!f__Gj5qKAuCR(+zyJM8QA#BHbW|<mAzL2~9~gH{8Ccs|EHQ1TBpkq0Y@P%A zdX%05*Pv_+?$*mAAqeWmq*XKflPgKfnH%^$|JSc(<+42KcN~4QL*IaVVj;JGLY~nV zG@H&KpG%w7#-a}8KfI!)yL2Tzc&ie*v3%<aKS8ZbM^~M{qDc0}<U@lImrpC!ceJ$! zkfP%iMZtwYoZGPwAfTWe_)vk&^2@gu01!r=az1_P#vjMZ>*jX*ZlvTqfa?bd?$$_i zqge>*|337Q>~BcgyVKL#yqxnH%BwT8psz@OKhUf2bJ>j@a3FG9SpYyn`sK#$(Fzq9 zkdt#G=lA}Q1DH4$3i#*&N*Fgof)KIqbGNxb@`yqG#Dfs({P9V1zr>^d8!WBIjiWd5 zF(1QNb$vpgu=s%mBn(&;$fyQt<CRcVkr-bLWVbL=y!u!TR)|r<2xb0F#uQFTE>EXR z(F#!*&}ii(6X7&@GW~^~O#GE1&T<XuZ-JSYwx~$4hsMkd?q`YK#RGJ&_oFDt_M%)u ziF?ZAI{oPJM<dkbnJWjc7ouRd=j-29lc844M}x~Vm9T<{0^Y<~!N}Mo6Jf>`s|xHq z+rGkOv93XTGOk2H%LywQUh*k<N$UkJSzhY#Wv^fMa~@v?ZCS`uB{*2(-E`6l>vGL{ zVGozISfxgb++fosL7nTMC#r`fLoG(j%pUoQmve7FG1s0-vb~)77M3=yWi46bk_^t` z@JR|#QmzGs{P<{`UWvzSB3~*LcO`<uRY9MuvvmAUk940bt9n5_<LN#v*?tVgzBjfi zmg&#^Z|R1*qkw?Gd5OR`g%Tn6mG*k0yKhA1o6oO<OsO1Y=CRL>6^-|EjQ+xWP$|i0 z(}NfPT5oGU2Hu^ncLW6^eJ5x*G=Ej1=C=wFj;)U4MYw4|%Jo74_^vpSim{%Xfq<?E z+eYBy=LjeHkBRYGeGGz68VmpCUepQFI!r>X^b_!ot+<k_9W+~+Jr{l|C9_fOrwdu? zW{8WP0)0ezzOA}2^Y-&Rp1sMS5OMyH$TW3HIUSMQR8IfRG_>y}NHi$i0TfnS{bKfl zp*SF2&h=9*G#>Ax3N@{o|D4kvb%TNe|4@zZJ?b}3!y1;}=AVY4L!1Rm#{>j;+U?(1 zDk0oF?A6irzVT+_%uia$m5fX%ld5LOwR2R$eU+s4bxcatm6@g-bND!>yeak>{u+{5 zmh$`Fvrj#l#(ra<meI<$AuIXZRw_!Ps${+XUP%AtlT5ocJJ7o)FTDt_mj^Kh2agam zh1hJB-qs_wJhg=*K~KhrnYj&T1s)8UpFV0Q7Y{`o^9vd!(F)FtMTde!mo5gv=z*$7 z<X3{e3(1Vdxnzn4$$B{|Gy+Fhozq|3`vh$HiQJguLAK2`98>+)QK-+%W6|i$uXzP` zY5X0V`FZ8GZ==t*tr{GiW(cJ;uh!x-lv$mdqg1R~DYxmFiQ0tA01jNv717+J8lgI` zNMq98$hiv1y(L<-&BXiu1VFxD(s&98jV}(-;+5i=w|BE{#_{D`PCff4S#Xndbzn40 zEMYUFH~&cm&d<TG5a*U5T2Bq@S3tg>kGvOePN&4rWfR=Z-TI_2Z%2J&zYW*QV5~i6 z3!Po@U;csru~V&q(_E6|&%*`Oz;NNq(qO^?ND(3CB}0!bMD6{Q30z+1#d!NTsz&?A zO|gw^XaFuQ|JH9md(NjL#La7~ODKE&{9gl2VL-4VkY_Un2O3)9%&&@;Vdh*QsxN4s z?_c1L0;h+8%l<88fOTxY0t#aYZJbst;91(QA@h7At8(i?|Hk-70y?<`HF3=UW%S$> z4@IeH#m}#eg{~S--^j5c`2QN&HoOR0lyR+D=r@-ZNc$cUHL4kVlGNf1{2!fs=wAis z$?WlQN!w1cxxh2J-{ww>n>!j!9JfznGnoE~eyJ3`DP_v*bC#=#Z6ht6w$vT(q<UGW zo!z_jN9a^&oPsFww&k&LVe7BK9Y#M&ef=3zK_>2Ps;wU0iwmtCb|}H_o%g+wmihki zN5hp;zl5N($9E6cRsttvwE<4eO15@848m0ZwDS;m`yV{db1Hr%!-0+6-4As39{>2y zKJ!WP{vr4J!pUUP@z&eCR9}u&7gWF@=u&#p`~kPc|7Nd0R=-(n>%pC7Qw^(&R|``q z?TveWb_F`~q_z@st3*#KBhhR9t6LE+8@najnnrI7Q_}xNb@t~bpyMOws_$CdQ393K zb~zBc$a}$OkTOTnZ;;THc7b&Xf6r~kN#+VInmQBD^j`dL)AaN0{GWeQ8%mALmJEqh z`vbSLcvGtM@vHU=qBuQcoM3h>Wk_y?WH|%C-+9g#ipe6;GZB>3d>3C$l6Ld~rAuU4 z=B00puvpZ~30QdZyuJ^4nMfw{37GJxWDGq4$7HHxtWGVzSjczeu<;czUO$xG$-2!d z;0=LiGD;5o`B69$&TDU|LMl%{R}$FQZ$w7zC2yofNUd}SNC5Ogj+U<L2$hTpek(48 zsU-K1{TxskudvuP(I|J?Ddj1idZ{eACJ0~dCpL}cwJnWC?PpWNas4vwDcOW=4NVlI zxua1jbd*w<3*@4|aec&lIY4z4CO&TU&e}xYs`?v&5i66DE$55xg*0jx%%LFz<UOC? zW{~bW;zKHpUpC??ONLuZFu&Ya&VH@`Lr19<wFK<9(vdoFn>f79iHY=fG_l%TeVP9* z@IULQTALS4c?MM7PYC^0iI)79syH#89!OD|2>v}d5oVp32zKmaREkUlaFT})F#>zN zB$7|mX_T`mX_Hx$(J6?;OaS{MkYv%zxLsdg-_h_4T*5O+73)?VZW9H=OswC^Vc6OL zc`$&7G+B#ORYxgb`CnqXO=fhi6me$xux|;`UP_dVYI}?fMG&1S3C&uFm%2hdyYdf0 z+BhV@@K>jm8nN$;xt1))YWR(yPM=6G{-zb?DvK6cz(UceDT7^~mhSt~($OT*K*=fG z=;znlThlJBWZ(knc}>?QX0N0@FSf=-f=8?1mv1Z|g$3HVKFl9oV3?vm-GpzjpTNDg zY*k4`f^dV@r<*n9Z6fFvK-Yse_{ET4MD3>!Sr>{+`VoW!A#qiD;qU@UJ>(lN<nrHs z3&a!|@`PUt9*o>`0g|S5;x$8DF^T;99%5vhNOU!_Wi7aoDyO3c--!3~Om&afFQNpy z9xUL0V$~4ndZKE{a5}(&HumoTv)UTGHK39pdiB8Ya@6SxzkIVM>G3j)(;bB9iY+8? zX^?_wAS9vc*&4D>8wRwHuq-$zLKG)#@ORz1DK?Tck$uF*XU5u!zF)4vxEHrU)Ux}o zf(RQzpcIoJKb9e2)-y4co}mq0LiPyp<Q@$8&&|Mc@R=H8{PKrf5v(?g+TSNdkduxy z^kYT*W=NUs0?1MM1dO<8O5~u6Lq0Y9j&m#PU5Y4=ypr|!&<U{3?36pkN4ooCOD}@t z?>J_z{q7I-yAKK^LwwkLZK+q=p?OQopelyXSJV~1@W0&H<84vMQtrueirXs_e{g}_ z+M73f+5O~jT}Q~!DK2qD-)!b+1qu^F!HD2GH=LjNy;`K#Wm9JLC)}}0-|P3#1F)!{ z2T=Dh1*Cpbo%=ZVq68dnG6)bRc`J^Xv3P*ibib|u9ot8@l|Q|lFW_lJ7|+2P`e2qe z2Lxd<cr{2h;FvrjK{*(4$LVLx6hbZ80dt{WzkU>`Apy65Fp2v~GX{dspL%$m3kEYL zlt4FkH=k0ktQA2M`YhVRK=mcbU&ax0G{pWv!6Rkq52O3jqlH@?`vY;;G{hrSvXwe! z#>ud)&xg1J8Hch7-Ph+PWIS22rbxjMJ*JSB5;9_0juQFnWPgngkTz*9rZH(*lvJyK zNVp8a4JBjFi!(z$GU(yq`y<>}383b}@f8smMoWNezHG6kW?nRI;nU~uA2%IG%tES_ zA$2dVu|I%%(yxIZ#0yGE`9I5o2zSQ67j#A+dnHEp1`4-;Sg&DN@{DLEqz||rUYjI& z=6hSy5oMpHmhSi2d;dsu%wBtlx$wPRzql<(pt(LzZA_L`gajNYNn@?vbza+H&lSv8 z@K?)0EY#^4+ENcf{E9%L;H+z*UkGTzz`=dnT^CdEf%RDvbktc7_ypVu3a5%4pxpA= z`%2+~BrL(76c~SXDtrT-SqUtdOw^;GC7MLz&nb`JbqJ7ZR<JtIGd}+eeL+|3u?D9Y zTy>QaA=ab%*QTb!C{Xm-dP~LGu2?^nn*?78lhN+Ps~`gtYhfkK+_-^zk#w*1I~OFS zPk-lPTfkab5vS41i$Qb4I-0>I%M@J?7n11WCx%oEt!baoneK3_sv?Nf@5mVSf{AqM zUkKPJk<l6`e$i+*PN4vDXmKgKga>U&o~}aI+TR0D+h2WD8eO;P0NKy9T&kRPHiM)@ z+yK||B?Am{FT~yh{5GW=_g#qA;Q==%$LxN-7cD<Tk*WLEjb!W@>#{XZJCV>`b0K4s z$FuqU+w#=S$V|2QIWfG(aOu<RJn3<(hK$`rDcfpNtcJF)mCO0G1dDHd*Mq7~#^P3f zJig0B20PAGc+5}A2Av<wKK8y7x1GU_r}IUNS!izB$=UaJQ@vXozTX@!p*0-~o+0q# za$$<b)fig~Cepu<&59d<#*PX+i!ZB$A_W0K{<X9nL9~RyRR;ycQR@k!ea)Nhtvc(B zqe5@q(+_$v^m@#$I<%CP6rPZa>KaF|F(wMzZW=C&w&CVI%|pTpwMzzmEYvy9wAiq2 zEp7dEcXt?V8$I3t<^xexaz`2(^tg~-!ohFQX-bB7r|v?wGV91X2&=v3P7@<v6;RrW z31jVr@|=4@o|=9>s60NA(8JzCCGy?vEHG>)num32A1=Ed8I*nD!}dS4P6!bC!oe>) zTN=v|W`N6&&f$U|6}>#{e6_6urfyeyn}XMF9LXwpUcVB&o{kq>&LB2HH4rQF&{3G& z)IG8~3gg2dclv^JNC5qC?eKLRc2oro%cxA3EY(a&0`bln7NmNs6zFDO?|Y<Pi$IgE zB@8P|YYG;t#uIa@#$y$yIMUf6pI`UD9t^A?ru20n7MBK))QIui{21XJP5-m~)Ys#T zxbbp)D;QVX9aIm!ml=bz?tXK{57U$VIo^JnL^zkw7!7DAopeQXH`TryN#`cOqjYUX z-Si1}{oZ4|ES;$iM6s8*1>e*@oH3t%_>-#-!egSVr^}w20FzkaQn0a3!1jX@?@jke z8?P<ik1Z=A0+@w-zoW2?_a@o7;P%~UV?EAXdl+kx<EKRyG$3Z@f*=|d8IT3_EVv%@ z!zu~1C}>b%kd$;*7kw>KPks2tc8~gM^p<a`Jf#-I>%ziFCUv+>eRrSG4J#HmhrBT9 z->hVH)dr^E#k)jZiM+|XE}8-qP~w|>_3DCU*J;35!JYvDusdD(wG#&ZfX{N=>aZ|z zONe8uO2HAJG*Q$~jb`8JXhX=FXZcW+S0NW(_%~TE-w^Ax&`$AC8tieDqSTC*^{agx zTpXUS8mgRPPwDP^s~CI6bn4Eyvi_G<x!x`bgi3sC`0@E^El4I&{>kLgH`WcdVfijt zefuaZDE(t$ia2F$;A$6h>Cf>{pL|coq}Q04d_(WPHmcDaUf!sJ<9=ZslBL^1^4iB? z#j~$D;!(9Esf*0=`53?{WsI3^5&>a`?oaQwA0|EC(&tlNh5${@EG((!FQ6k^cOk^j zbO$!<w2^<^gT0an2Jsz+9;Zdxd)$qx+`_)ceZUL#Z*2XZlZSk6a<>rd=4~+n<AG;# zfpCJqCpxGC!?FGU&dzRq$UpteTanghcwUzV`NMse`BP=;{cCEk308;=P^f>f%WANY zc{1Vr6%Z3~WYrY_gkL6DSS}0d1rfqFtV;R+_{u+NeA}R(&Tjqp_2K+6AQuZ|jfhqT zOe9v?c^VH9q(b-t$4Shu$Mu<KVMBfQsX-%&f06K$L6Oy+L~k#mK?aAGR(<I+E%JR; z@-vJ<F_qlc<Qp;T`jq$<mO<*P>ArE}THwO<G*)$jc2W!Lx(+#CLo-D&g92W#K!PDT z2^TfYc+T#Q_^<&Ie+4F&4rNXTsrwofK%Lki7Ftug`_v!ynNbsO0OXE8f5{XQ$DKk1 z$>f_W$7O?Pf8<E|cui{q(Q%N+fJYX*5n8}O9BsEquI2GvhUCYs>-NKACsY64$!_Ip zV~5YHK8{C;D^=i(QBFOle{sgEoJDhDzu=1TSpD`v(Y3gFFP!tzwmbA<V_*k}OLPaA zqoI!cxM3v<kG(V4WHJOeBP{wZHmwXoh}I2*@q*&0eYQi>q_?av?iyLq`Kgr<7($f! zym+9U1`w+}F%5VdS1K}~NQE2U&w%u*d$21uHw>gpC(KRs>?QexS8`$<2#f&{P>iu? z{SEWVxCVdewi-lpd;P`Gj1jgYox=F>HO-?L(Q$To<W4FGtN^nPw}X%!rlK_T=93c4 zhgGAq|Kbx*Q2MJv`mK~S#k8n`4ZH3)aTrOjq_@(qJ?0Kzq?T({rQ=nlB;&?4iHgz* z>Q`VMvXOzc51rgw9oRv^!4D*7dqG)9ctwvs?Z#lnhy~JeH^?*xr&pY>cs3kslr7t0 zWu{dm+~^^K;CrSjeedTizZ<PuTpNK3r6LwFYywHT^KXoVMx_%uaLn9QJwWu)3@S(g zZP(>Veh`cuveeh79&cEF%Hg&q?bfmAv?k_qvzoe*F&~5G_xN21LE;wUQ7dN^O7f=g zLCsBUE%;dN5Dg^CXdXUeT9_aw4j{OO#nz4Cw=%EXt;(LMl%F8*`=E@@#oJ#3SCw)T zEgv<=6VGXZ&nUX?Zg7M^eIY>$?(~-<(Dzq+xhzL~ndcTzJLvmEROT7^lF%ss_;EL7 z!80ImE7J`2g41S%wns`d%%#KIX&tAvY)IZ6&Uu5h@V@lvDNqm!+cnd~Qh3w~e2Cgz zrpBmc`QyA{tN3^<J+^y-2@l)o3e~ES1rR;?!a+-SZEbH>Q8;-9IZi*&MJ~fgJ0BO% zh=^R?z`kp*u}@vISAak3F{M-G?37*Y1g`DaYAHk6-7bScRA`zymn8l<y~*YvGiD&W zWmS2nnQl2u?@%gW>v;vj>=5~3GJ4OPs>+hTRK82A*LJ>ct|<GLeu{ril=`v&nmzXr z&SF|e>lg)wFkOLPj`syOXZ74b4#ya;1fB1n5?V<zf}KlmP)}5}U-AFZraruy#J4%5 z-DsA1Y}MaVn11^<*~Y|yfbKx$6-H~^z!&y9B5M%~>?->ruLx^_YQKXqR1B|u(1jq~ z?0z<b`n#M(BGW0klJjfcC0vfbU-XFHLf<>G&?`eTq3OOFt|I-_kYNb?bKT^R`Oz#8 zNNKNx;`fc5)=W#Vui4#^IaeC*&bj~{o#BK=l0eC!j`lDh<@wY4DitlBCzLP44CZp@ zFcqRE1!DXeMd}EB+Pq-D!S5})>4Pn@`TtN==rbBP92zVh6U7hw>URuq`QFs@*)+$r za(2!!#u0;?^T!XOc$^(}m3TFfy2$VNVNaGHUiY3Qgv*{Kby#D)5qa4AzwMP4i7kC3 z@^#ZnrHAT`)2Lo1jB-1F{;T98F<56DE3bvq;G7ok=}g1)G@jyl#8f3-^Onb3i_pos z*RgfzqRthQh0YR~xkTg5Pt5h(8E!h(Y696fqbC8=LW{-E^kbFJm9=>fzU2<v4sN|v zycv40;@K7=K)05*^JjA^BKha$PhTDumea^xjn9!Zkp=OYYgN_nMM26|g303VZ0x3g zn9N=sRrdGy?|ZqN2k=6C<`?xri5g2#+>%W&biZFYILKk=VtQb^e|Q{9k^1#K<~&xj z#`Jo`e&gZ9LJ9!Z(|Ygt!gYJwm{=5}a;Ml(kXVDaqiWmp!c#A1WYKy~U_1A>57QCJ zCG1U!{Jx2DfxZzXd?EDH=w(t~Wap&$68h{{MDsQJA;N`<cuOOeGwAeC+eFctwm0q@ z_e)-uuLlNYek_%7HUqi>bZ>O@^u0Z+c9c?<AK_2qH<QzodwPayB`%$97J~HX1o{8S z2<0i4OxOqyalxL(dyUwaQrw!WkB{luRo+fH#m4@4NlFb7qBAB)nd}Nurnx^a*T1}< zvF4T)%o^8}!%~Ji-aGnF!H<cC?A@_I^*~u*AL`7hx+<Ns-dpIWCvCb+#2pHw>_qY+ zo*qfM>Q)7Ii}JJPZQ^|%Or}VK|6B@LaBa}f-kU&{>XF-5ln)%W*9!Q6evwi1L(V~@ zikeaZC0|}9j#$#9)+gl=d&>BhwAn(@7h*3Ah3Qs@nkE?^k-{YwYh1s0h;nFb|7874 z{+Y@n#N#_*-{MfcynAXVJeHrQ!QnG&Iy?2FX|h72An#g??pky1?oo&is`~dl=$WYI zNa}s8xv(v090e7__68JzYSvPO>TK_`Z5!hvi`b%~C(TpGBaGGPbR)jz3bLui7z)rC zf~Rn1<(qo5R5Isfm4)ciOl_)c_&&X?@Wx96iTVJyv_*}51So$~3w14qu=L=#ZBgs3 zzyow&HB7`;e@pRF)Mo{M+ND%X?J`}NK-G~pC!r(M5h#&|-3riQ2R78AdGE(d*mZDa z>90xWyyN`dZXmcTcUxH7>RKR6M<h1g;FL5{!R|QA-Cm5YDk3PAQ_-VyDM)v72Z_gN zN0+SA)llE&(4qJ`{@3$cZh`&t?iZVO!b_JZ(ORP&z{&>HQJFTjhE_PVIC{}htjUJd zkxHaWV9Nf_&tHSfVug|gYC?{%6pOA{OVXj~T<EU#R#bi;$*n$s&Yp2o@JRuvKl{AY zqo(0Z7-*V4b{WrK50L@Ib=xyy?7lobjPepD1UYMDRC|c>=j>4}z3t}44jk->z`h*K z^L1t5`D4EjRK*eWGk-z)Ix!cuuj3|VEU|chgcbZP1oxrNn)T0NqB6_fDG3hp;*l-- zTs}6TCa~PZ^X!CU+LH1D;DN&kKS@PvLr8TZ+nS`DsgSf-?-tCPv&L$FL4uL+yIP4Z zmk`&2_sfy%j!(<Qb9zU^3_nZ_urgu%F7s-L>FfjIUL)<LH=NgSZG=sWEl?HZFEO_t z&pm)2mV^0NC+usxLqh1gWrITS&4Wr`4(<wee0|+to1OLgZ!{IdSKSv)i1}b-8>~E0 zgY(@Ott<S!##GqG4gS&jp<{R77dbttl299=fJ?R;gOEHlQ)nx#>2gGsp79{D8IG0k z+SvQ(+9>=FtI{;gD9rz2haOmDko?5W)?kuz*z@BMjxrRj3bop-&yC~dy8~P>A!kk0 zXemsLhocH;Rl!tA{N8TB&9w+W?rZ+M^ANwM(US%=Nul<n1vQs-TBwOr(hTXWKmZTz zg^ftmGz=%X1n8Iw)`@qkdmr^aUcJ06(O3Xd0dNChBt<97!>$A9{GM^)s}nKdn7Aa* z-19wITc=m?PwA(|?EA_oq&pQKt2M-vU**+GE$tqZBF*0oYTO7AW9{{I2m5ja5<iPv zT8wcD5}2;mP%0{cs<DVqS71UCZvy`aALQqCu@;>`ezpMlGRD<dPDZeqX&#GGLBe!0 zC(NQHs_3P{W2+iIFxeGj-Uo?MRg8;@6Dwv(d;;HP=mHEncDFu`n=;|Y$@n-d6B0Zk z<p)|hMCL&n=CjD7djyya_x|Xd)8G+YEL$`&Mh*-F)zu1~lUMP^`S^U+GmW^lDE=NX z`+30LqLN*2jM#5QqF1t~wXG^Y$^>UD)-6+LEbAO@`Pukz!i-RpkU*VKx~(d?fgpo1 zc3#lmCv*&i$u@-btHx?XhMk(SSB_i0Y@t(&@1|%$mLaD?pAgk*vQO@jpp^W|lIceC zh2R^^D@c|GjU^IC$fanrH8QqHz}T~l*P>-x?VVr$20Q=f!ro7zYAdcK7LP0TwQ9Y} znACoI>xD66YR?-j<4iVq-!%9bR%K6+N56YTSgIcb5XkPK#29&NMS%Y1#n&Y@!WI|4 zY`?=F9NF97o$%9KxNtC>E$0uvkWR3r66T1z#HrCa>j-zSB{hESVRil#k-3kaszRv5 z`@6B`PoqeZgS4?rQHfeOzO`gmmL7@zce-k4r2BUl-L~^pw!M4k@-6Y-$zv1LJ#c63 z_+335QDAlnv^c}0TQKTklRPI`IRo0GqBA;cr~NK%#5ybcBq`s&&GUI^z_O*u2Y7$4 zveIWc0AvFEeBSEdlVghV$Xgv6^r@wJKUeC1Hec76u1^SYW>7_zVtqX{h*6vA{W9jo zXwz!Cx#_4(qHj<`T|C@KrMT`Y{Cv!(WRmx6IX-f>$TTNj&&bEop#>v7hTVsqn}#!% z_JU9-t-*%Ykl7(ZE%%Qiev;aY8Ixb!qjl{0&N^Ur)wB<P2HDYHaJ^Aw<z`DIeSF)? zPLRtg^jj;%SYo>R_x8)L(9M+8kLvWQrQfc4h4M6pgfnNV^xzB@zQdi;1Iw`!HN<NU z(g8;Jh$!TR_2n?x8uGBFz@aOmrE~9T%W3G|VT~nH%#9e~KOn}`Ibi9)Frd?{DUC3! zceBh)eVycN881>t@yc+pHb$x=!Eox+riP*5>-Sgnsl(oX=zks2+q7J9r$;)4s`s3a zBv^-~T9bSSY$=D^(23I3T5hOS4m@C+3eK>rjxt9Jz485#ThPY5CMNy6noqIwe1i;L z!*OPDCgiqZ*%=HU9womIkvMAR0E({DUm<Fz0V_6gDuf*ofMvTvL?`TK=a(n{IUIsB z<~9kK^P;xN$qRUB=wpsH>=C6Sadlrn%KFck$V9{s3{O0teqmVo?y<k=xN}ETNpgR1 z&Z!d@fsLQu-qud~tNrnAe{?y#u(oPF=wdtX2zfAVduhR)GfH#+DBBtQ=)+xO)`@t2 ziyX-jJ1xK18Qm$#U9SQ^54Z3?qBLTX3Y4xjI6DiA`f1NR*}U}Q{l)osis3l_6w>PP zMD@@0@%~uMy5?cQ{z+g_NSat_YOph;ZBk&Nd*RnY6Asci&J@)4=tVAe`eU*X`N&_u zesPSb?7j^_T*D8+K}c9o3z9_EWlasbJlOqEuesX9)8M=;I``g(Z}jsfj7aK`Op40( zPrrzilyM`(=k@1F+5uTrTbWK3Wa4$3ed^@<-M-WEtan$4k#V$6mb@#g!ylW9GEvhf z*!!j9hMNCll@H;sjHHOC=q#99SHSCNt#+$X;dopKa3Sr(PVH;RH!DRB!s0j0plg!n zaEG?US`uZBf5hVDNomx`#{+_sHDEuz)z|Akq;?oM*97PN>n-Ub939IZV~65~<8h^R z4xdm<;*4^?6!^}~cwWG`_b<SGhiNTI1D1Qunt%PkoOkv9a4C#&><`LO7$D#%rwlQ^ z|G3=3mM4W5#p8JR&}A_4WwM%)V$}g%z@&C%9+(-^KhXMAI3QyIx%~KH3nZv98>X@3 zH?Zi%792KHyry=mrj^4PgJTCeOmA&~;{I#nQd3~rrnM`Zr*y_s;QxC5Pk?yYo=ym+ z=RAt1x@%DY4uT6Tx&M9+8Z>tq>oqn0-6>yg!;d-GIu>2(!lUb&k{w4Bzhr_USuGbW zM?8P3uZw-mo<iz{uG^L}G)35XOHDxA4u;1*{o+{i258sn4bYlq2;RNo?L;Y0;?RTm zvP(S3XR*YVMmG`P`wyrc>u0&4pfeZPlYyYj+Q{WXUym@bnr8r*sb;isp6OI<+FTKM z|CS3Ur4n%c#UwWC_NlccjedF$tD}C?-GTa{W$Fw?bRBq!x;SQ8G}6A_k;OSBI`ra6 z7M2S%7Hrf^EIM2ZPEdCQ+AV2YOSb(Uv|Zw{rjVE};+{U(Y&9xU6C-+IX!7-iiG10+ za-QYRPky9lO-^_6lKTy_&>%C0_c_!VjK+g0p)s54->ep_6&T*6qrM0E_a~{@Hdv~# zf7Kma8equT_cHGna4%!|`zchN-MW=t#5ifcuGdD5mTz>8?YUkgZ_-RMK;;mH{f8?9 z>>yE(KDh|>Fz@F$LBp)3xR!-gs@6Iz6jpC5)aqNwF*Wj3*oy$e^L(P<emT~h?P4%z zj@s`=CL1FQ@|gp*`2^<a1ZSNJHOA?B@Zmp$rSXYknXL;Y|Hu&;-~(pktmc@hTaj%^ z`02^;?&l|}64+DkDxJByTF!(wgBZ>_U!$BH%g*b=h2qs`c$7J90(#uzO$E6fT;}|s zbtNoECkvBNNj5ZSt4{-%x7iDOS<F{+KAdz@JfmO1@|uh6C=4{8it48FLa<kaASw`b z6k_ssP&mz}N2?9QV#u6q62~nGqH7!B--eC@<a>#1FG5Tzhu_iciPG7BQV_%{C0~~L zk{@D@G1ejQ*wq)V_>Euda~&A?5}VSotsV3M-A)II=2j81R&Y(??H+(c6UbVUmEO^k zqk6nddxWy5!lTxot%U?2<&X^s2lEcx|Lj|mtT%?<E^tRY4zH&)6=WyF{|^@aIif8^ zUzP()Sc~~Z4?CWvtdR<-U8E>o-^(|YO#kz<r7I48m?(KR&A*<%h7`jXZ%Xd5JZxRl z_W880n7_lapLz45eA6I=<{nG_=+!0By4V6b;L!z$@?xvQ{WfN%Xw|<1j%)wF-#la! zoQdx(i=&+1Y+S!`Hk$#Ddd~_){N1Vq{DCR&%KtE1o)impotH33DWj8OVG0~D(R=RU zn6A827FJ;*|D^g$O!w+1cL*=4UNhQfe6HjDopXhGZ<Bd%NMjVNJ+JwfX*G6h^&#pi zk+DYm@KV9rn2&5@H}|6#t?<r*85-Lwdm;Nj0)v=JX2w?lVWTz8-5VM?8T?&+nAC+l iPCWh&AsPo01h@S5+2EkQ3j_`I0>9Kys#Y)$`~LuZ&3MEB diff --git a/biome.json b/biome.json new file mode 100644 index 000000000..20f2a72ce --- /dev/null +++ b/biome.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "files": { + "ignore": [ + "node_modules", + "**/node_modules", + "cache", + "coverage", + "tsconfig.json", + "tsconfig.*.json", + "_cjs", + "_esm", + "_types", + "bun.lockb", + "docs" + ] + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "warn" + }, + "style": { + "noUnusedTemplateLiteral": "warn" + } + } + }, + "formatter": { + "enabled": true, + "formatWithErrors": true, + "lineWidth": 80, + "indentWidth": 2, + "indentStyle": "space" + }, + "javascript": { + "formatter": { + "semicolons": "asNeeded", + "trailingComma": "none" + } + } +} diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..b5ff986bce2335154fdd941cc3017a64ea05c78c GIT binary patch literal 262560 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�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 K)ck+??|%XI3z#ba literal 0 HcmV?d00001 diff --git a/jest.config.e2e.ts b/jest.config.e2e.ts deleted file mode 100644 index 2fff1ca6d..000000000 --- a/jest.config.e2e.ts +++ /dev/null @@ -1,6 +0,0 @@ -import config from "./jest.config"; -const e2eConfig = { ...config }; -e2eConfig.testMatch = ["**/*.e2e.spec.ts"]; -e2eConfig.setupFilesAfterEnv = ["<rootDir>/tests/setup-e2e-tests.ts"]; - -export default e2eConfig; diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index 844398aba..000000000 --- a/jest.config.ts +++ /dev/null @@ -1,198 +0,0 @@ -/** - * For a detailed explanation regarding each configuration property, visit: - * https://jestjs.io/docs/configuration - */ - -import type { Config } from "jest"; - -const config: Config = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/_y/33lkcttj3w3fd6v6xvg7f33m0000gn/T/jest_dx", - - // Automatically clear mock calls, instances, contexts and results before every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: ["packages/**/*.{js,ts}", "!packages/**/node_modules/**", "!packages/**/dist/**"], - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - workerThreads: true, - // This is experimental feature. Keep in mind that the worker threads use structured clone instead of JSON.stringify() to serialize messages. - // This means that built-in JavaScript objects as BigInt, Map or Set will get serialized properly. - // However extra properties set on Error, Map or Set will not be passed on through the serialization step. - // For more details see the article on structured clone. - - // An array of file extensions your modules use - moduleFileExtensions: ["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - moduleNameMapper: { - '^(?!bn\.js$|hash\.js$)(.+)\\.js$': '$1' - }, - - extensionsToTreatAsEsm: ['.ts'], - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - preset: "ts-jest", - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state before every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state and implementation before every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - roots: ["<rootDir>/packages/"], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: ["<rootDir>/tests/setup-unit-tests.ts"], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: ["**/*.spec.ts", "!**/*.e2e.spec.ts"], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // A map from regular expressions to paths to transformers - transform: { - "^.+\\.tsx?$": ["ts-jest", { useESM: true }], - }, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - verbose: true, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, - - globals: { - testDataPerChain: [], - } -}; - -export default config; \ No newline at end of file diff --git a/lerna.json b/lerna.json deleted file mode 100644 index be069a470..000000000 --- a/lerna.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "packages": ["packages/*"], - "npmClient": "yarn", - "version": "independent", - "command": { - "publish": { - "conventionalCommits": true - } - }, - "ignoreChanges": ["**/CHANGELOG.md", "**/node_modules/**", "**/*.md", "**/perf/**"] -} diff --git a/link.sh b/link.sh deleted file mode 100755 index beaca34a1..000000000 --- a/link.sh +++ /dev/null @@ -1,5 +0,0 @@ -!/bin/sh -npm run unbuild -npm run build -npm link - diff --git a/linkAll.sh b/linkAll.sh deleted file mode 100755 index 3597ec1c0..000000000 --- a/linkAll.sh +++ /dev/null @@ -1,3 +0,0 @@ -!/bin/sh -for dir in ./packages/*; do (cd "$dir" && yarn link); done -cd ./packages/account && yarn link '@biconomy/bundler' '@biconomy/modules' '@biconomy/paymaster' '@biconomy/common' \ No newline at end of file diff --git a/package.json b/package.json index 72746e0a2..f8649f58c 100644 --- a/package.json +++ b/package.json @@ -1,86 +1,113 @@ { - "name": "biconomy-sdk", - "version": "1.0.0", + "type": "module", + "main": "./dist/_cjs/index.js", + "module": "./dist/_esm/index.js", + "types": "./dist/_types/index.d.ts", + "typings": "./dist/_types/index.d.ts", + "homepage": "https://biconomy.io", + "sideEffects": false, + "name": "@biconomy/account", + "author": "Biconomy", + "version": "4.1.2", "description": "SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.", "keywords": [ - "biconomy", - "sdk", - "blockchain", - "integration", + "erc-7579", + "modular smart account", "account abstraction", - "smart accounts", - "erc-4337", - "crosschain", - "cross-chain", - "metatransactions" + "biconomy", + "sdk" ], "license": "MIT", - "homepage": "https://biconomy.io/docs", - "bugs": { - "url": "https://github.com/bcnmy/biconomy-client-sdk/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/bcnmy/biconomy-client-sdk" + "repository": "github:bcnmy/biconomy-client-sdk", + "exports": { + ".": { + "types": "./dist/_types/index.d.ts", + "import": "./dist/_esm/index.js", + "default": "./dist/_cjs/index.js" + }, + "./account": { + "types": "./_types/account/index.d.ts", + "import": "./_esm/account/index.js", + "default": "./_cjs/account/index.js" + }, + "./bundler": { + "types": "./_types/bundler/index.d.ts", + "import": "./_esm/bundler/index.js", + "default": "./_cjs/bundler/index.js" + }, + "./paymaster": { + "types": "./_types/paymaster/index.d.ts", + "import": "./_esm/paymaster/index.js", + "default": "./_cjs/paymaster/index.js" + }, + "./modules": { + "types": "./_types/modules/index.d.ts", + "import": "./_esm/modules/index.js", + "default": "./_cjs/modules/index.js" + } }, - "author": "Biconomy (https://biconomy.io)", - "private": true, + "files": ["dist/*", "README.md"], "scripts": { - "dev": "yarn rebuild && yarn install && lerna run build && yarn link:all", - "rebuild": "./rebuild.sh", - "link:all": "./linkAll.sh", - "build": "yarn rebuild && yarn install && lerna run build", - "clean": "lerna clean && lerna run unbuild", - "format": "lerna run format --npm-client=yarn", - "prettier": "npx prettier --write .", - "lint": "eslint -c .eslintrc.js 'packages/*/src/**/*.{ts,tsx}'", - "lint:fix": "eslint -c .eslintrc.js 'packages/*/src/**/*.{ts,tsx}' --fix", - "test:run": "yarn jest --runInBand", - "test": "concurrently -k --success first 'yarn start:ganache' 'yarn test:run' && exit 0", - "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'", - "test:ci": "FORCE_COLOR=1 lerna run test:ci --stream --npm-client=yarn", - "test:coverage": "concurrently -k --success first 'yarn start:ganache' 'yarn jest --runInBand --coverage'", - "test:e2e": "yarn test:run --config=jest.config.e2e.ts", - "diff": "lerna diff", - "release": "lerna version patch --no-git-tag-version --no-push --conventional-commits --yes" + "format": "biome format . --write", + "lint": "biome check .", + "lint:fix": "bun run lint --apply", + "dev": "concurrently \"bun run esm:watch\" \"bun run cjs:watch\" \"bun run esm:watch:aliases\" \"bun run cjs:watch:aliases\"", + "build": "bun run clean && bun run build:cjs && bun run build:esm && bun run build:types", + "clean": "rimraf ./dist/_esm ./dist/_cjs ./dist/_types ./dist/tsconfig", + "test": "vitest dev -c ./tests/vitest.config.ts", + "test:readOnly": "bun run test read", + "test:watch": "bun run test --watch", + "test:watch:readOnly": "bun run test:readOnly --watch", + "test:coverage": "CI=true vitest -c ./tests/vitest.config.ts --coverage", + "test:ci": "CI=true vitest -c ./tests/vitest.config.ts", + "size": "size-limit", + "docs": "typedoc --tsconfig ./tsconfig/tsconfig.esm.json", + "docs:deploy": "bun run docs && gh-pages -d docs", + "changeset": "changeset", + "changeset:release": "bun run build && changeset publish", + "changeset:version": "changeset version && bun install --lockfile-only", + "esm:watch": "tsc --project ./tsconfig/tsconfig.esm.json --watch", + "cjs:watch": "tsc --project ./tsconfig/tsconfig.cjs.json --watch", + "esm:watch:aliases": "tsc-alias -p ./tsconfig/tsconfig.esm.json --watch", + "cjs:watch:aliases": "tsc-alias -p ./tsconfig/tsconfig.cjs.json --watch", + "build:cjs": "tsc --project ./tsconfig/tsconfig.cjs.json && tsc-alias -p ./tsconfig/tsconfig.cjs.json && echo > ./dist/_cjs/package.json '{\"type\":\"commonjs\"}'", + "build:esm": "tsc --project ./tsconfig/tsconfig.esm.json && tsc-alias -p ./tsconfig/tsconfig.esm.json && echo > ./dist/_esm/package.json '{\"type\": \"module\",\"sideEffects\":false}'", + "build:types": "tsc --project ./tsconfig/tsconfig.types.json && tsc-alias -p ./tsconfig/tsconfig.types.json" }, - "changelog": { - "labels": { - "feature": "New Feature", - "bug": "Bug Fix" - } + "devDependencies": { + "@biomejs/biome": "1.6.0", + "@changesets/cli": "^2.27.1", + "@commitlint/cli": "^19.0.3", + "@commitlint/config-conventional": "^19.0.3", + "@ethersproject/abi": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/wallet": "^5.7.0", + "@size-limit/esbuild-why": "^11", + "@size-limit/preset-small-lib": "^11", + "@types/bun": "latest", + "@vitest/coverage-v8": "^1.3.1", + "concurrently": "^8.2.2", + "gh-pages": "^6.1.1", + "rimraf": "^5.0.5", + "simple-git-hooks": "^2.9.0", + "size-limit": "^11", + "tsc-alias": "^1.8.8", + "tslib": "^2.6.2", + "typedoc": "^0.25.9", + "vitest": "^1.3.1" }, - "workspaces": { - "packages": [ - "packages/*" - ] + "peerDependencies": { + "typescript": "^5", + "viem": "^2" }, - "dependencies": { - "node-gyp": "^9.4.0", - "typescript": "^5.3.3" + "commitlint": { + "extends": ["@commitlint/config-conventional"] }, - "devDependencies": { - "@types/debug": "^4.1.9", - "@types/jest": "^29.5.4", - "@typescript-eslint/eslint-plugin": "^6.7.0", - "@typescript-eslint/parser": "^6.6.0", - "concurrently": "^8.2.2", - "eslint": "^8.48.0", - "eslint-config-airbnb-base": "15.0.0", - "eslint-config-airbnb-typescript": "17.1.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-security": "^1.7.1", - "ganache": "^7.9.2", - "hardhat": "^2.17.3", - "jest": "^29.7.0", - "lerna": "^7.2.0", - "lerna-changelog": "^2.2.0", - "nx": "^16.8.1", - "prettier": "^3.0.3", - "rimraf": "^5.0.1", - "ts-jest": "^29.1.1", - "ts-node": "^10.9.1" + "simple-git-hooks": { + "pre-commit": "bun run format && bun run lint:fix", + "commit-msg": "npx --no -- commitlint --edit ${1}" + }, + "dependencies": { + "merkletreejs": "^0.3.11" } } diff --git a/packages/account/.esbuild.js b/packages/account/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/account/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/account/CHANGELOG.md b/packages/account/CHANGELOG.md deleted file mode 100644 index 59678fcca..000000000 --- a/packages/account/CHANGELOG.md +++ /dev/null @@ -1,166 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -- Added missing extensions ([fdbec6](https://github.com/bcnmy/biconomy-client-sdk/pull/451/commits/fdbec68625f4d7f436dc39d4c1779cdbb7c53e6d)) -- Fixed issue reporting format ([815e9440](https://github.com/bcnmy/biconomy-client-sdk/pull/450/commits/815e9440db03ebae98bb24edfcb3bbcabf9b2a61)) - - -## 4.1.0 (2023-04-03) - -Features: - -- Added Speed optimisation, removing redundant gasEstimate call to bundler ([2371b2](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2371b230cd5806ec4c7c95ba604d6f924b4be768)) -- Added smartAccount.getBalances() method ([4b8bae](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/4b8bae412577b846e700b168976cefa6b0803ff6)) -- Added smartAccount.getSupportedTokens() method ([6d2fb27](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/6d2fb27d6f9b424e440e45990ea06820a9d16d4b)) -- Added smartAccount.deploy() method ([be9dc4](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/be9dc4d74a3e5a22e69416983436997cf2ea417c)) -- Increased checking of the chainId from the bundler, paymaster and the provider ([5d2f3](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5d2f34d8f0fb4f9ff7c7ddc00336471e57efdcfd)) -- Added entity name to Logger calls ([9278ec](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/9278ecc21e060ef75ab29a0d054d95d69cd4ae27)) -- Export a 'getChain' by id helper, which returns a viem chain ([ab2ba](https://github.com/bcnmy/biconomy-client-sdk/pull/449/commits/ab2ba2c518ce867c52bf90b9018dfc1b4ec3b4d4)) -- Add "stateOverride" optional param ([20fd54](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/20fd54c817d2dcbc6b7d9a247d890d91b19a9c2f)) - -Fixes: - -- Fix for encodeAbiParameters inside batched session module ([b27061](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/b27061e2eec7bafb0620e88e6d94e56e9a13cb76)) -- added flag to skip calldata approval patch ([75698](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/75698c827015533e32acb1f535bdf6b738876217)) -- Fixed the particle auth build - -Chores: - -- Added tests for ecdsa module ([1a8f29](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/1a8f296c26c9fedd57023f8f6423d7662a3adfee)) -- Increased test coverage ([329003](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/329003cebb6b4034496e41651985804cdec0d311)) -- Improved issue reporting guidelines ([8b9fb5d](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/8b9fb5de9556870611307c12e57df333619d9252)) -- Added e2e tests for optimism, ran from GH actions ([5051ba](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5051ba5ff14220ad616f1ec3bc93a3f42d6f8887)) -- Added ABI SVM test ([49c96](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/49c968220e2db0aeee5cc6419f45df2b98f9792c)) -- Added tests for batched session router testing ([2eb9765](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2eb9765d066fcb7b35d08223257aeb9b38c7a78b)) - -## 4.0.3 (2023-28-02) - -VERSION Bump Only. - -## 4.0.2 (2023-26-02) - -### Bug Fixes - -Particle Auth Fix - -## 4.0.1 (2023-02-22) - -### Bug Fixes - -- Fix for RPC endpoints (Quiknode, Blast Sepolia etc) failing to respond because of custom headers being set - -## 4.0.0 (2023-02-06) - -### Features - -- Export bundler / paymaster instances + helpers from master package ([1d1f9d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/1d1f9dafddf11bde0e1a75383bc935b22448bedd)) -- Export modules aliases from master package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00)) -- Added sendTransaction abstraction for buildUserOp + sendUserOp ([335c6e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/335c6e7bfc5ca1ad240e7cbfd678d905c7f16812)) -- Reduced bundle size ([765a3e3](https://github.com/bcnmy/biconomy-client-sdk/commit/765a3e337fb9ad8f1f8dc92b5edcb1ed0940f94d)) -- Added bundler abstraction during SmartAccount init ([591bbb4](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/591bbb4e37774b16cbe801d583d31b3a14608bc1)) -- Added e2e tests that speak with prod bundler / paymasters ([4b4a53a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4b4a53aabdf9e22485599872332b3d63e8ddd87a)) -- Added support for simultaneous ethers + viem signers ([8e4b2c8](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8e4b2c86b871130befbf3b733cf503d24f7226a5)) -- E2E tests for multichain modules ([ecc86e2](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/ecc86e2c7146046a981c3b6fd4bb29e4828b278b)) -- E2E tests for session validation modules ([4ad7ea7](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4ad7ea7f8eb6a28854dcce83834b2b7ff9ad3287)) -- Added [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) ([638dae](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/638daee0ed6924f67c5151a2d0e5a02d32e4bf23)) -- Make txs more typesafe and default with valueOrData ([b1e5b5e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b1e5b5e02ab3a7fb99faa1d45b55e3cbe8d6bc93)) -- Added createSmartAccountClient alias ([232472](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/232472c788bed0619cf6295ade076b6ec3a9e0f8)) -- Improve dx of using paymster to build userOps ([bb54888](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/bb548884e76a94a20329e49b18994503de9e3888)) -- Add ethers v6 signer support ([9727fd](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/9727fd51e47d62904399d17d48f5c9d6b9e591e5)) -- Improved dx of using gas payments with erc20 ([741806](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/741806da68457eba262e1a49be77fcc24360ba36)) - -### Chores - -- Removed SmartAccount Base class in favour of Alchemy's ([be82732](https://github.com/bcnmy/biconomy-client-sdk/commit/be827327fafa858b1551ade0c8389293034cacbb)) -- Migrate to viem v2 ([8ce04a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8ce04a56f6dcdfd1f44d9534f43e3c6eb8b3885d)) -- Remove common + core-types dependencies ([673514](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/6735141fbd21a855aadf69011bc06c69e20f811b)) -- Reincluded simulation flags ([25d2be](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/25d2bee339afd9d8c143fe6dad1898e28034be17)) - -### Bug Fixes - -- Make silently failing paymaster calls throw an error instead ([693bf0](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/693bf08591427c03e317d64d0491e23b1c96ea30)) -- Added string as a supported Transaction value type ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11)) -- Removed skipBundlerGasEstimation option ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11)) -- Ingest rpcUrl from SupportedSigners (ethers + viem) ([f56b4d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/f56b4da08f47af577c01a641b81a3ef9e354cf97)) - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -### Features - -- Make entryPointAddress optional in config([cf35c4a](https://github.com/bcnmy/biconomy-client-sdk/pull/336/commits/cf35c4a8266d27648035d8c9d63f1b9157553128)) - -### Bug Fixes - -- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3)) -- change receipt status type from boolean to string to be compatible with bundler response. ([317f986](https://github.com/bcnmy/biconomy-client-sdk/pull/342/commits/317f986b7e8f08d3ccf1e68f12a0696f1116de6b)) - -## 3.1.1 (2023-11-09) - -### Bug Fixes - -- optimistic implementation for getNonce() and cache for isAccountDeployed ([5b1d4bf](https://github.com/bcnmy/biconomy-client-sdk/commit/5b1d4bfd7b5062d05bbb97286b833d879cd972b0)) - -### Reverts - -- update paymaster check in estimateUserOpGas ([2eb0237](https://github.com/bcnmy/biconomy-client-sdk/commit/2eb0237b37425da3558801bbe9d0ce5d6fd696c9)) - -## 3.1.0 (2023-09-20) - -Modular Account Abstraction is here. Contains BiconomySmartAccountV2 - an API for modular smart account. - -### Bug Fixes - -- add 10sec timeout limit for a test ([5d12fe7](https://github.com/bcnmy/biconomy-client-sdk/commit/5d12fe7d4b32e5c4628b971d22f6fc9cfcc6b414)) -- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b)) -- BiconomySmartAccountV2 API Specs ([69a580e](https://github.com/bcnmy/biconomy-client-sdk/commit/69a580ea9e309141b500274aa95e20e24365b522)) -- build errors ([9fb0475](https://github.com/bcnmy/biconomy-client-sdk/commit/9fb047534935b0600bd08a4de7e68fd91a8a089a)) -- comments [#296](https://github.com/bcnmy/biconomy-client-sdk/issues/296) ([55b7376](https://github.com/bcnmy/biconomy-client-sdk/commit/55b7376336886226967b5bec5f11ba3ab750c5b6)) -- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388)) -- gitInitCode cache issue ([4df3502](https://github.com/bcnmy/biconomy-client-sdk/commit/4df3502204e3c6c0c6faa90ba2c8aa0d6e826e48)) -- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) -- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7)) - -### Features - -- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7)) -- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4)) -- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206)) - -## 3.0.0 (2023-08-28) - -VERSION Bump Only. - -Modular SDK - consists stable version of below updates done in Alphas. - -## 3.1.1-alpha.0 (2023-08-02) - -### Bug Fixes - -VERSION Bump Only. - -# 3.1.0-alpha.0 (2023-07-24) - -### Bug Fixes - -- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b)) - -## 3.0.0-alpha.0 (2023-07-12) - -### Bug Fixes - -- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388)) -- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7)) - -### Features - -- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7)) -- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4)) -- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206)) diff --git a/packages/account/Readme.md b/packages/account/Readme.md deleted file mode 100644 index dedd3e2e6..000000000 --- a/packages/account/Readme.md +++ /dev/null @@ -1,138 +0,0 @@ -# Biconomy SDK - -![Biconomy SDK](https://img.shields.io/badge/Biconomy-SDK-blue.svg) -![TypeScript](https://img.shields.io/badge/-TypeScript-blue) -![Test Coverage](https://img.shields.io/badge/Coverage-79.82%25-green.svg) - -## 👋 Introduction - -The Biconomy SDK is your all-in-one toolkit for building decentralized applications (dApps) with **ERC4337 Account Abstraction** and **Smart Accounts**. It is designed for seamless user experiences and offers non-custodial solutions for user onboarding, sending transactions (userOps), gas sponsorship and much more. - -## ⚙️ installation - -```bash -npm i @biconomy/account -``` - -## 🛠️ Quickstart - -```typescript -import { createSmartAccountClient } from "@biconomy/account"; - -const smartAccount = await createSmartAccountClient({ - signer: viemWalletOrEthersSigner, - bundlerUrl: "", // From dashboard.biconomy.io - paymasterUrl: "", // From dashboard.biconomy.io -}); - -const { wait } = await smartAccount.sendTransaction({ to: "0x...", value: 1 }); - -const { - receipt: { transactionHash }, - userOpHash, -} = await wait(); -``` - -## 🌟 Features - -- **ERC4337 Account Abstraction**: Simplify user operations and gas payments. -- **Smart Accounts**: Enhance user experience with modular smart accounts. -- **Paymaster Service**: Enable third-party gas sponsorship. -- **Bundler Infrastructure**: Ensure efficient and reliable transaction bundling. - -For a step-by-step guide on integrating **ERC4337 Account Abstraction** and **Smart Accounts** into your dApp using the Biconomy SDK, refer to the [official documentation](https://docs.biconomy.io/docs/overview). You can also start with Quick start [here](https://docs.biconomy.io/quickstart). - -## 📚 Resources - -- [Biconomy Documentation](https://docs.biconomy.io/) -- [Biconomy Dashboard](https://dashboard.biconomy.io) -- [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) - -## 💼 Example Usages - -### [Initialise the smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html) - -| Key | Description | -| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| [signer](https://bcnmy.github.io/biconomy-client-sdk/packages/account/docs/interfaces/SmartAccountSigner.html) | This signer will be used for signing userOps for any transactions you build. Will accept ethers.JsonRpcSigner as well as a viemWallet | -| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) | -| [bundlerUrl](https://dashboard.biconomy.io) | You can pass in a bundlerUrl (retrieved from the biconomy dashboard) for sending transactions | - -```typescript -import { createSmartAccountClient } from "@biconomy/account"; -import { createWalletClient, http, createPublicClient } from "viem"; -import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; -import { mainnet as chain } from "viem/chains"; - -const account = privateKeyToAccount(generatePrivateKey()); -const signer = createWalletClient({ account, chain, transport: http() }); - -const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - paymasterUrl, -}); -``` - -### [Send some ETH, have gas sponsored](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction) - -| Key | Description | -| --------------------------------------------------------------------------------- | -------------------------------------------------------------- | -| [oneOrManyTx](https://bcnmy.github.io/biconomy-client-sdk/types/Transaction.html) | Submit multiple or one transactions | -| [userOpReceipt](https://bcnmy.github.io/biconomy-client-sdk/types/UserOpReceipt) | Returned information about your tx, receipts, userOpHashes etc | - -```typescript -const oneOrManyTx = { to: "0x...", value: 1 }; - -const { wait } = await smartAccount.sendTransaction(oneOrManyTx, { - mode: PaymasterMode.SPONSORED, -}); - -const { - receipt: { transactionHash }, - userOpHash, -} = await wait(); -``` - -### [Mint two NFTs, pay gas with token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees) - -| Key | Description | -| -------------------------------------------------------------------------------------------------------- | ------------------------------------------ | -| [buildUseropDto](https://bcnmy.github.io/biconomy-client-sdk/types/BuildUserOpOptions.html) | Options for building a userOp | -| [paymasterServiceData](https://bcnmy.github.io/biconomy-client-sdk/types/PaymasterUserOperationDto.html) | PaymasterOptions set in the buildUseropDto | - -```typescript -import { encodeFunctionData, parseAbi } from "viem"; - -const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address to) public"]), - functionName: "safeMint", - args: ["0x..."], -}); - -const tx = { - to: nftAddress, - data: encodedCall, -}; -const oneOrManyTx = [tx, tx]; // Mint twice -const paymasterServiceData = { - mode: PaymasterMode.ERC20, - preferredToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC -}; -const buildUseropDto = { paymasterServiceData }; - -const { wait } = await smartAccount.sendTransaction(oneOrManyTx, buildUseropDto); - -const { - receipt: { transactionHash }, - userOpHash, -} = await wait(); -``` - -## 🤝 Contributing - -Community contributions are welcome! For guidelines on contributing, please read our [contribution guidelines](./CONTRIBUTING.md). - -## 📜 License - -This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.md) file for details. diff --git a/packages/account/package.json b/packages/account/package.json deleted file mode 100644 index 408ff4cef..000000000 --- a/packages/account/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "@biconomy/account", - "version": "4.1.1", - "description": "This package provides apis for ERC-4337 based smart account implementations", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "Ethereum", - "Smart Account", - "ERC-4337", - "Account Abstraction", - "Smart Contract Wallets", - "Biconomy", - "SDK" - ], - "scripts": { - "docs": "typedoc", - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "test:concurrently": "concurrently -k --success first 'yarn start:ganache' 'yarn test'", - "test:cov": "jest --coverage", - "test": "jest tests/**/*.spec.ts --runInBand", - "test:run": "yarn test:concurrently", - "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json", - "docs:deploy": "yarn docs && gh-pages -d docs" - }, - "author": "Biconomy", - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "devDependencies": { - "@ethersproject/providers": "^5.7.2", - "@ethersproject/wallet": "^5.7.0", - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "gh-pages": "^6.1.1", - "lru-cache": "^10.0.1", - "nock": "^13.2.9", - "npm-dts": "^1.3.12", - "typedoc": "^0.25.7" - }, - "dependencies": { - "@alchemy/aa-core": "^3.1.1", - "@biconomy/bundler": "^4.1.1", - "@biconomy/common": "^4.1.1", - "@biconomy/modules": "^4.1.1", - "@biconomy/paymaster": "^4.1.1", - "viem": "^2.7.12" - } -} diff --git a/packages/account/src/index.ts b/packages/account/src/index.ts deleted file mode 100644 index f46953a67..000000000 --- a/packages/account/src/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { BiconomySmartAccountV2 } from "./BiconomySmartAccountV2.js"; -import { type BiconomySmartAccountV2Config } from "./utils/Types.js"; - -export * from "./utils/Types.js"; -export * from "./utils/Constants.js"; -export * from "./utils/Utils.js"; -export * from "./BiconomySmartAccountV2.js"; - -export { WalletClientSigner, LocalAccountSigner, type SmartAccountSigner } from "@alchemy/aa-core"; -export { - BiconomyPaymaster as Paymaster, - type IPaymaster, - PaymasterMode, - type IHybridPaymaster, - type PaymasterFeeQuote, - type SponsorUserOperationDto, - type FeeQuotesOrDataResponse, - createPaymaster, -} from "@biconomy/paymaster"; -export { EthersSigner, convertSigner, type LightSigner, type SupportedSigner } from "@biconomy/common"; -export { - Bundler, - type IBundler, - extractChainIdFromBundlerUrl, - type UserOpResponse, - type UserOpStatus, - type UserOpReceipt, - createBundler, -} from "@biconomy/bundler"; -export { - createECDSAOwnershipValidationModule, - createERC20SessionValidationModule, - createBatchedSessionRouterModule, - createSessionKeyManagerModule, - createMultiChainValidationModule, - DEFAULT_ECDSA_OWNERSHIP_MODULE, - DEFAULT_SESSION_KEY_MANAGER_MODULE, - DEFAULT_MULTICHAIN_MODULE, - DEFAULT_BATCHED_SESSION_ROUTER_MODULE, - type ECDSAOwnershipValidationModuleConfig, - type BatchedSessionRouterModuleConfig, - type SessionKeyManagerModuleConfig, - type MultiChainValidationModuleConfig, - type SessionValidationModuleConfig, -} from "@biconomy/modules"; - -export const createSmartAccountClient = BiconomySmartAccountV2.create; - -export type SmartWalletConfig = BiconomySmartAccountV2Config; diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts deleted file mode 100644 index be406b4cb..000000000 --- a/packages/account/src/utils/Types.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { BigNumberish, SmartAccountSigner, UserOperationStruct } from "@alchemy/aa-core"; -import { IBundler } from "@biconomy/bundler"; -import { - type FeeQuotesOrDataDto, - type IPaymaster, - type PaymasterFeeQuote, - PaymasterMode, - type SmartAccountData, - type SponsorUserOperationDto, -} from "@biconomy/paymaster"; -import { BaseValidationModule, ModuleInfo } from "@biconomy/modules"; -import { Chain, Hex, WalletClient } from "viem"; -import { SupportedSigner, StateOverrideSet } from "@biconomy/common"; - -export type EntryPointAddresses = Record<string, string>; -export type BiconomyFactories = Record<string, string>; -export type BiconomyImplementations = Record<string, string>; -export type EntryPointAddressesByVersion = Record<string, string>; -export type BiconomyFactoriesByVersion = Record<string, string>; -export type BiconomyImplementationsByVersion = Record<string, string>; - -export type SmartAccountConfig = { - /** entryPointAddress: address of the entry point */ - entryPointAddress: string; - /** factoryAddress: address of the smart account factory */ - bundler?: IBundler; -}; - -export interface BalancePayload { - /** address: The address of the account */ - address: string; - /** chainId: The chainId of the network */ - chainId: number; - /** amount: The amount of the balance */ - amount: bigint; - /** decimals: The number of decimals */ - decimals: number; - /** formattedAmount: The amount of the balance formatted */ - formattedAmount: string; -} - -export interface WithdrawalRequest { - /** The address of the asset */ - address: Hex; - /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ - amount?: bigint; - /** The destination address of the funds. The second argument from the `withdraw(...)` function will be used as the default if left unset. */ - recipient?: Hex; -} - -export interface GasOverheads { - /** fixed: fixed gas overhead */ - fixed: number; - /** perUserOp: per user operation gas overhead */ - perUserOp: number; - /** perUserOpWord: per user operation word gas overhead */ - perUserOpWord: number; - /** zeroByte: per byte gas overhead */ - zeroByte: number; - /** nonZeroByte: per non zero byte gas overhead */ - nonZeroByte: number; - /** bundleSize: per signature bundleSize */ - bundleSize: number; - /** sigSize: sigSize gas overhead */ - sigSize: number; -} - -export type BaseSmartAccountConfig = { - /** index: helps to not conflict with other smart account instances */ - index?: number; - /** provider: WalletClientSigner from viem */ - provider?: WalletClient; - /** entryPointAddress: address of the smart account entry point */ - entryPointAddress?: string; - /** accountAddress: address of the smart account, potentially counterfactual */ - accountAddress?: string; - /** overheads: {@link GasOverheads} */ - overheads?: Partial<GasOverheads>; - /** paymaster: {@link IPaymaster} interface */ - paymaster?: IPaymaster; - /** chainId: chainId of the network */ - chainId?: number; -}; - -export type BiconomyTokenPaymasterRequest = { - /** feeQuote: {@link PaymasterFeeQuote} */ - feeQuote: PaymasterFeeQuote; - /** spender: The address of the spender who is paying for the transaction, this can usually be set to feeQuotesResponse.tokenPaymasterAddress */ - spender: Hex; - /** maxApproval: If set to true, the paymaster will approve the maximum amount of tokens required for the transaction. Not recommended */ - maxApproval?: boolean; - /* skip option to patch callData if approval is already given to the paymaster */ - skipPatchCallData?: boolean; -}; - -export type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & - { - [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>; - }[Keys]; - -export type ConditionalBundlerProps = RequireAtLeastOne< - { - bundler: IBundler; - bundlerUrl: string; - }, - "bundler" | "bundlerUrl" ->; -export type ResolvedBundlerProps = { - bundler: IBundler; -}; -export type ConditionalValidationProps = RequireAtLeastOne< - { - defaultValidationModule: BaseValidationModule; - signer: SupportedSigner; - }, - "defaultValidationModule" | "signer" ->; - -export type ResolvedValidationProps = { - /** defaultValidationModule: {@link BaseValidationModule} */ - defaultValidationModule: BaseValidationModule; - /** activeValidationModule: {@link BaseValidationModule}. The active validation module. Will default to the defaultValidationModule */ - activeValidationModule: BaseValidationModule; - /** signer: ethers Wallet, viemWallet or alchemys SmartAccountSigner */ - signer: SmartAccountSigner; - /** chainId: chainId of the network */ - chainId: number; -}; - -export type BiconomySmartAccountV2ConfigBaseProps = { - /** Factory address of biconomy factory contract or some other contract you have deployed on chain */ - factoryAddress?: Hex; - /** Sender address: If you want to override the Signer address with some other address and get counterfactual address can use this to pass the EOA and get SA address */ - senderAddress?: Hex; - /** implementation of smart contract address or some other contract you have deployed and want to override */ - implementationAddress?: Hex; - /** defaultFallbackHandler: override the default fallback contract address */ - defaultFallbackHandler?: Hex; - /** rpcUrl: Rpc url, optional, we set default rpc url if not passed. */ - rpcUrl?: string; // as good as Provider - /** paymasterUrl: The Paymaster URL retrieved from the Biconomy dashboard */ - paymasterUrl?: string; - /** biconomyPaymasterApiKey: The API key retrieved from the Biconomy dashboard */ - biconomyPaymasterApiKey?: string; - /** activeValidationModule: The active validation module. Will default to the defaultValidationModule */ - activeValidationModule?: BaseValidationModule; - /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */ - scanForUpgradedAccountsFromV1?: boolean; - /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */ - maxIndexForScan?: number; - /** Can be used to optionally override the chain with a custom chain if it doesn't already exist in viems list of supported chains */ - viemChain?: Chain; -}; -export type BiconomySmartAccountV2Config = BiconomySmartAccountV2ConfigBaseProps & - BaseSmartAccountConfig & - ConditionalBundlerProps & - ConditionalValidationProps; - -export type BiconomySmartAccountV2ConfigConstructorProps = BiconomySmartAccountV2ConfigBaseProps & - BaseSmartAccountConfig & - ResolvedBundlerProps & - ResolvedValidationProps; - -export type BuildUserOpOptions = { - /** overrides: Explicitly set gas values */ - // overrides?: Overrides; - /** Not currently in use */ - // skipBundlerGasEstimation?: boolean; - /** params relevant to the module, mostly relevant to sessions */ - params?: ModuleInfo; - /** nonceOptions: For overriding the nonce */ - nonceOptions?: NonceOptions; - /** forceEncodeForBatch: For encoding the user operation for batch */ - forceEncodeForBatch?: boolean; - /** paymasterServiceData: Options specific to transactions that involve a paymaster */ - paymasterServiceData?: PaymasterUserOperationDto; - /** simulationType: Determine which parts of the tx a bundler will simulate: "validation" | "validation_and_execution". */ - simulationType?: SimulationType; - /** stateOverrideSet: For overriding the state */ - stateOverrideSet?: StateOverrideSet; - /** set to true if the tx is being used *only* to deploy the smartContract, so "0x" is set as the userOp.callData */ - useEmptyDeployCallData?: boolean; -}; - -export type NonceOptions = { - /** nonceKey: The key to use for nonce */ - nonceKey?: number; - /** nonceOverride: The nonce to use for the transaction */ - nonceOverride?: number; -}; - -export type SimulationType = "validation" | "validation_and_execution"; - -export type Overrides = { - /* Value used by inner account execution */ - callGasLimit?: Hex; - /* Actual gas used by the validation of this UserOperation */ - verificationGasLimit?: Hex; - /* Gas overhead of this UserOperation */ - preVerificationGas?: Hex; - /* Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) */ - maxFeePerGas?: Hex; - /* Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) */ - maxPriorityFeePerGas?: Hex; - /* Address of paymaster sponsoring the transaction, followed by extra data to send to the paymaster ("0x" for self-sponsored transaction) */ - paymasterData?: Hex; - /* Data passed into the account along with the nonce during the verification step */ - signature?: Hex; -}; - -export type InitilizationData = { - accountIndex?: number; - signerAddress?: string; -}; - -export type PaymasterUserOperationDto = SponsorUserOperationDto & - FeeQuotesOrDataDto & { - /** mode: sponsored or erc20 */ - mode: PaymasterMode; - /** Always recommended, especially when using token paymaster */ - calculateGasLimits?: boolean; - /** Expiry duration in seconds */ - expiryDuration?: number; - /** Webhooks to be fired after user op is sent */ - webhookData?: Record<string, any>; - /** Smart account meta data */ - smartAccountInfo?: SmartAccountData; - /** the fee-paying token address */ - feeTokenAddress?: string; - /** The fee quote */ - feeQuote?: PaymasterFeeQuote; - /** The address of the spender. This is usually set to FeeQuotesOrDataResponse.tokenPaymasterAddress */ - spender?: Hex; - /** Not recommended */ - maxApproval?: boolean; - /* skip option to patch callData if approval is already given to the paymaster */ - skipPatchCallData?: boolean; - }; - -export type InitializeV2Data = { - accountIndex?: number; -}; - -export type EstimateUserOpGasParams = { - userOp: Partial<UserOperationStruct>; - // overrides?: Overrides; - /** Currrently has no effect */ - // skipBundlerGasEstimation?: boolean; - /** paymasterServiceData: Options specific to transactions that involve a paymaster */ - paymasterServiceData?: SponsorUserOperationDto; -}; - -export interface TransactionDetailsForUserOp { - /** target: The address of the contract to call */ - target: string; - /** data: The data to send to the contract */ - data: string; - /** value: The value to send to the contract */ - value?: BigNumberish; - /** gasLimit: The gas limit to use for the transaction */ - gasLimit?: BigNumberish; - /** maxFeePerGas: The maximum fee per gas to use for the transaction */ - maxFeePerGas?: BigNumberish; - /** maxPriorityFeePerGas: The maximum priority fee per gas to use for the transaction */ - maxPriorityFeePerGas?: BigNumberish; - /** nonce: The nonce to use for the transaction */ - nonce?: BigNumberish; -} - -export type CounterFactualAddressParam = { - index?: number; - validationModule?: BaseValidationModule; - /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */ - scanForUpgradedAccountsFromV1?: boolean; - /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */ - maxIndexForScan?: number; -}; - -export type QueryParamsForAddressResolver = { - eoaAddress: Hex; - index: number; - moduleAddress: Hex; - moduleSetupData: Hex; - maxIndexForScan?: number; -}; - -export type SmartAccountInfo = { - /** accountAddress: The address of the smart account */ - accountAddress: Hex; - /** factoryAddress: The address of the smart account factory */ - factoryAddress: Hex; - /** currentImplementation: The address of the current implementation */ - currentImplementation: string; - /** currentVersion: The version of the smart account */ - currentVersion: string; - /** factoryVersion: The version of the factory */ - factoryVersion: string; - /** deploymentIndex: The index of the deployment */ - deploymentIndex: BigNumberish; -}; - -export type ValueOrData = RequireAtLeastOne< - { - value: BigNumberish | string; - data: string; - }, - "value" | "data" ->; -export type Transaction = { - to: string; -} & ValueOrData; - -export type SupportedToken = Omit<PaymasterFeeQuote, "maxGasFeeUSD" | "usdPayment" | "maxGasFee" | "validUntil">; diff --git a/packages/account/src/utils/Utils.ts b/packages/account/src/utils/Utils.ts deleted file mode 100644 index 6041a2fb9..000000000 --- a/packages/account/src/utils/Utils.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { encodeAbiParameters, parseAbiParameters, keccak256, Hex, Chain } from "viem"; -import type { UserOperationStruct } from "@alchemy/aa-core"; -import { SupportedSigner, convertSigner } from "@biconomy/common"; -import { extractChainIdFromBundlerUrl } from "@biconomy/bundler"; -import { BiconomySmartAccountV2Config } from "./Types.js"; -import { extractChainIdFromPaymasterUrl } from "@biconomy/bundler"; -import * as chains from "viem/chains"; -import { ERROR_MESSAGES } from "./Constants.js"; - -/** - * pack the userOperation - * @param op - * @param forSignature "true" if the hash is needed to calculate the getUserOpHash() - * "false" to pack entire UserOp, for calculating the calldata cost of putting it on-chain. - */ -export function packUserOp(op: Partial<UserOperationStruct>, forSignature = true): string { - if (!op.initCode || !op.callData || !op.paymasterAndData) throw new Error("Missing userOp properties"); - if (forSignature) { - return encodeAbiParameters(parseAbiParameters("address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32"), [ - op.sender as Hex, - BigInt(op.nonce as Hex), - keccak256(op.initCode as Hex), - keccak256(op.callData as Hex), - BigInt(op.callGasLimit as Hex), - BigInt(op.verificationGasLimit as Hex), - BigInt(op.preVerificationGas as Hex), - BigInt(op.maxFeePerGas as Hex), - BigInt(op.maxPriorityFeePerGas as Hex), - keccak256(op.paymasterAndData as Hex), - ]); - } else { - // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) - return encodeAbiParameters(parseAbiParameters("address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes"), [ - op.sender as Hex, - BigInt(op.nonce as Hex), - op.initCode as Hex, - op.callData as Hex, - BigInt(op.callGasLimit as Hex), - BigInt(op.verificationGasLimit as Hex), - BigInt(op.preVerificationGas as Hex), - BigInt(op.maxFeePerGas as Hex), - BigInt(op.maxPriorityFeePerGas as Hex), - op.paymasterAndData as Hex, - op.signature as Hex, - ]); - } -} - -export const addressEquals = (a?: string, b?: string): boolean => !!a && !!b && a?.toLowerCase() === b.toLowerCase(); - -export const isNullOrUndefined = (value: any): value is undefined => { - return value === null || value === undefined; -}; - -export const compareChainIds = async ( - signer: SupportedSigner, - biconomySmartAccountConfig: BiconomySmartAccountV2Config, - skipChainIdCalls: boolean, -): Promise<Error | void> => { - const signerResult = await convertSigner(signer, skipChainIdCalls); - - const chainIdFromBundler = biconomySmartAccountConfig.bundlerUrl - ? extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundlerUrl) - : biconomySmartAccountConfig.bundler - ? extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundler.getBundlerUrl()) - : undefined; - - const chainIdFromPaymasterUrl = biconomySmartAccountConfig.paymasterUrl - ? extractChainIdFromPaymasterUrl(biconomySmartAccountConfig.paymasterUrl) - : undefined; - - if (!isNullOrUndefined(signerResult.chainId)) { - if (chainIdFromBundler !== undefined && signerResult.chainId !== chainIdFromBundler) { - throw new Error(`Chain IDs from signer (${signerResult.chainId}) and bundler (${chainIdFromBundler}) do not match.`); - } - if (chainIdFromPaymasterUrl !== undefined && signerResult.chainId !== chainIdFromPaymasterUrl) { - throw new Error(`Chain IDs from signer (${signerResult.chainId}) and paymaster (${chainIdFromPaymasterUrl}) do not match.`); - } - } else { - if (chainIdFromBundler !== undefined && chainIdFromPaymasterUrl !== undefined && chainIdFromBundler !== chainIdFromPaymasterUrl) { - throw new Error(`Chain IDs from bundler (${chainIdFromBundler}) and paymaster (${chainIdFromPaymasterUrl}) do not match.`); - } - } -}; - -export const isValidRpcUrl = (url: string): boolean => { - const regex = /^(https:\/\/|wss:\/\/).*/; - return regex.test(url); -}; - -/** - * Utility method for converting a chainId to a {@link Chain} object - * - * @param chainId - * @returns a {@link Chain} object for the given chainId - * @throws if the chainId is not found - */ -export const getChain = (chainId: number): Chain => { - for (const chain of Object.values(chains)) { - if (chain.id === chainId) { - return chain; - } - } - throw new Error(ERROR_MESSAGES.CHAIN_NOT_FOUND); -}; diff --git a/packages/account/src/utils/index.ts b/packages/account/src/utils/index.ts deleted file mode 100644 index bc65ec9be..000000000 --- a/packages/account/src/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./Types.js"; -export * from "./Utils.js"; -export * from "./Constants.js"; diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts deleted file mode 100644 index 1b4dcc586..000000000 --- a/packages/account/tests/account.e2e.spec.ts +++ /dev/null @@ -1,995 +0,0 @@ -import { TestData } from "../../../tests"; -import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, IHybridPaymaster, NATIVE_TOKEN_ALIAS, PaymasterMode } from "../src/index"; -import { Hex, createWalletClient, encodeAbiParameters, encodeFunctionData, getContract, hashMessage, http, parseAbi, parseAbiParameters } from "viem"; -import { UserOperationStruct } from "@alchemy/aa-core"; -import { checkBalance, entryPointABI } from "../../../tests/utils"; -import { ERC20_ABI } from "@biconomy/modules"; -import { privateKeyToAccount, generatePrivateKey, signMessage } from "viem/accounts"; -import { BiconomyAccountAbi } from "../src/abi/SmartAccount"; - -describe("Account Tests", () => { - let baseSepolia: TestData; - let optimism: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [baseSepolia, optimism] = testDataPerChain; - }); - - it("should have addresses", async () => { - const { - whale: { viemWallet: signer, publicAddress: sender }, - minnow: { viemWallet: recipientSigner, publicAddress: recipient }, - bundlerUrl, - } = baseSepolia; - - const { - whale: { viemWallet: signerBase, publicAddress: senderBase }, - minnow: { viemWallet: recipientSignerBase, publicAddress: recipientBase }, - bundlerUrl: bundlerUrlBase, - } = baseSepolia; - - const { - whale: { viemWallet: signerOp, publicAddress: senderOp }, - minnow: { viemWallet: recipientSignerOp, publicAddress: recipientOp }, - bundlerUrl: bundlerUrlOp, - } = optimism; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const recipientSmartAccount = await createSmartAccountClient({ - signer: recipientSigner, - bundlerUrl, - }); - - const smartAccountBase = await createSmartAccountClient({ - signer: signerBase, - bundlerUrl: bundlerUrlBase, - }); - - const recipientSmartAccountBase = await createSmartAccountClient({ - signer: recipientSignerBase, - bundlerUrl: bundlerUrlBase, - }); - - const smartAccountOp = await createSmartAccountClient({ - signer: signerOp, - bundlerUrl: bundlerUrlOp, - }); - - const reciepientSmartAccountOp = await createSmartAccountClient({ - signer: recipientSignerOp, - bundlerUrl: bundlerUrlOp, - }); - - const addresses = await Promise.all([ - sender, - smartAccount.getAddress(), - recipient, - recipientSmartAccount.getAddress(), - senderBase, - smartAccountBase.getAddress(), - recipientBase, - recipientSmartAccountBase.getAddress(), - senderOp, - smartAccountOp.getAddress(), - recipientOp, - reciepientSmartAccountOp.getAddress(), - ]); - expect(addresses.every(Boolean)).toBeTruthy(); - }); - - it("should send some native token to a recipient", async () => { - const { - whale: { viemWallet: signer }, - minnow: { publicAddress: recipient }, - bundlerUrl, - publicClient, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const balance = (await checkBalance(publicClient, recipient)) as bigint; - const { wait } = await smartAccount.sendTransaction( - { - to: recipient, - value: 1, - }, - { - simulationType: "validation_and_execution", - }, - ); - - const result = await wait(); - const newBalance = (await checkBalance(publicClient, recipient)) as bigint; - - expect(result?.receipt?.transactionHash).toBeTruthy(); - expect(newBalance - balance).toBe(1n); - }, 50000); - - it("Create a smart account with paymaster with an api key", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - paymasterUrl, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - paymasterUrl, - bundlerUrl, - }); - - const paymaster = smartAccount.paymaster; - expect(paymaster).not.toBeNull(); - expect(paymaster).not.toBeUndefined(); - }); - - it("Should gaslessly mint an NFT on baseSepolia", async () => { - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - publicClient, - paymasterUrl, - nftAddress, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - paymasterUrl, - }); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address to) public"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - - const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress()); - - const response = await smartAccount.sendTransaction(transaction, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - simulationType: "validation", - }); - - const userOpReceipt = await response.wait(3); - expect(userOpReceipt.userOpHash).toBeTruthy(); - expect(userOpReceipt.success).toBe("true"); - - const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress()); - - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - - expect(newBalance - balance).toBe(1n); - }, 60000); - - // TODO(Remove when Yash fixes approvals issue) - it.skip("Should mint an NFT on baseSepolia and pay with ERC20 - with preferredToken", async () => { - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - nftAddress, - publicClient, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey: "7K_k68BFN.ed274da8-69a1-496d-a897-508fc2653666", - }); - - const accountAddress = await smartAccount.getAddress(); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address _to)"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - const maticBalanceBefore = await checkBalance(publicClient, accountAddress); - const usdcBalanceBefore = await checkBalance(publicClient, accountAddress, "0xda5289fcaaf71d52a80a254da614a192b693e977"); - - const { wait } = await smartAccount.sendTransaction([transaction], { - paymasterServiceData: { - mode: PaymasterMode.ERC20, - preferredToken: "0xda5289fcaaf71d52a80a254da614a192b693e977", - }, - }); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(transactionHash).toBeTruthy(); - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - - const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress()); - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - const usdcBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress(), "0xda5289fcaaf71d52a80a254da614a192b693e977"); - expect(usdcBalanceAfter).toBeLessThan(usdcBalanceBefore); - - const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - expect(newBalance - balance).toBe(1n); - }, 60000); - - it("Should expect several feeQuotes in resonse to empty tokenInfo fields", async () => { - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - biconomyPaymasterApiKey, - nftAddress, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address _to)"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const feeQuotesResponse = await smartAccount.getTokenFees(transaction, { paymasterServiceData: { mode: PaymasterMode.ERC20 } }); - expect(feeQuotesResponse.feeQuotes?.length).toBeGreaterThan(1); - }); - - // TODO(Remove when Yash fixes approvals issue) - it.skip("Should mint an NFT on baseSepolia and pay with ERC20 - with token selection and no maxApproval", async () => { - const preferredToken: Hex = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - paymasterUrl, - publicClient, - nftAddress, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - paymasterUrl, - }); - - const smartAccountAddress = await smartAccount.getAddress(); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address _to)"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const feeQuotesResponse = await smartAccount.getTokenFees(transaction, { - paymasterServiceData: { - mode: PaymasterMode.ERC20, - preferredToken, - }, - }); - - const selectedFeeQuote = feeQuotesResponse.feeQuotes?.[0]; - const spender = feeQuotesResponse.tokenPaymasterAddress!; - - const contract = getContract({ - address: preferredToken, - abi: parseAbi(ERC20_ABI), - client: publicClient, - }); - - const allowanceBefore = (await contract.read.allowance([smartAccountAddress, spender])) as bigint; - - if (allowanceBefore > 0) { - const decreaseAllowanceData = encodeFunctionData({ - abi: parseAbi(["function decreaseAllowance(address spender, uint256 subtractedValue)"]), - functionName: "decreaseAllowance", - args: [spender, allowanceBefore], - }); - - const decreaseAllowanceTx = { - to: "0xda5289fcaaf71d52a80a254da614a192b693e977", - data: decreaseAllowanceData, - }; - - const { wait } = await smartAccount.sendTransaction(decreaseAllowanceTx, { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); - const { success } = await wait(); - - expect(success).toBe("true"); - const allowanceAfter = (await contract.read.allowance([smartAccountAddress, spender])) as bigint; - expect(allowanceAfter).toBe(0n); - } - - const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - const maticBalanceBefore = await checkBalance(publicClient, smartAccountAddress); - const usdcBalanceBefore = await checkBalance(publicClient, smartAccountAddress, preferredToken); - - const { wait } = await smartAccount.sendTransaction(transaction, { - paymasterServiceData: { - mode: PaymasterMode.ERC20, - feeQuote: selectedFeeQuote, - spender: feeQuotesResponse.tokenPaymasterAddress, - }, - }); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - expect(transactionHash).toBeTruthy(); - - const maticBalanceAfter = await checkBalance(publicClient, smartAccountAddress); - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - const usdcBalanceAfter = await checkBalance(publicClient, smartAccountAddress, preferredToken); - expect(usdcBalanceAfter).toBeLessThan(usdcBalanceBefore); - - const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - expect(newBalance - balance).toBe(1n); - }, 60000); - - it("Should throw and error if missing field for ERC20 Paymaster user op", async () => { - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - biconomyPaymasterApiKey, - nftAddress, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address _to)"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const feeQuotesResponse: FeeQuotesOrDataResponse = await smartAccount.getTokenFees(transaction, { - paymasterServiceData: { - mode: PaymasterMode.ERC20, - preferredToken: "0xda5289fcaaf71d52a80a254da614a192b693e977", - }, - }); - - expect(async () => - smartAccount.sendTransaction(transaction, { - paymasterServiceData: { - mode: PaymasterMode.ERC20, - feeQuote: feeQuotesResponse.feeQuotes?.[0], - }, - simulationType: "validation", - }), - ).rejects.toThrow(ERROR_MESSAGES.SPENDER_REQUIRED); - }, 60000); - - it("#getUserOpHash should match entryPoint.getUserOpHash", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - entryPointAddress, - publicClient, - paymasterUrl, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - paymasterUrl, - bundlerUrl, - }); - - const userOp: UserOperationStruct = { - sender: "0x".padEnd(42, "1") as string, - nonce: 2, - initCode: "0x3333", - callData: "0x4444", - callGasLimit: 5, - verificationGasLimit: 6, - preVerificationGas: 7, - maxFeePerGas: 8, - maxPriorityFeePerGas: 9, - paymasterAndData: "0xaaaaaa", - signature: "0xbbbb", - }; - - const epHash = await publicClient.readContract({ - address: entryPointAddress as Hex, - abi: entryPointABI, - functionName: "getUserOpHash", - // @ts-ignore - args: [userOp], - }); - - const hash = await smartAccount.getUserOpHash(userOp); - expect(hash).toBe(epHash); - }, 30000); - - it("should be deployed to counterfactual address", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - publicClient, - paymasterUrl, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - paymasterUrl, - bundlerUrl, - }); - - const accountAddress = await smartAccount.getAccountAddress(); - const byteCode = await publicClient.getBytecode({ address: accountAddress as Hex }); - - expect(byteCode?.length).toBeGreaterThan(2); - }, 10000); // on github runner it takes more time than 5000ms - - it("should check if ecdsaOwnershipModule is enabled", async () => { - const ecdsaOwnershipModule = "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e"; - - const { - whale: { viemWallet: signer }, - bundlerUrl, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - expect(ecdsaOwnershipModule).toBe(smartAccount.activeValidationModule.getAddress()); - }); - - it("Should throw, chain id from signer and bundlerUrl do not match", async () => { - const { - whale: { viemWallet: signer }, - } = baseSepolia; - - const createAccount = createSmartAccountClient({ - signer, - bundlerUrl: "https://bundler.biconomy.io/api/v2/1/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44", // mock - }); - - await expect(createAccount).rejects.toThrow(); - }); - - it("Should throw, chain id from paymasterUrl and bundlerUrl do not match", async () => { - const { - whale: { viemWallet: signer }, - } = baseSepolia; - - const createAccount = createSmartAccountClient({ - signer, - paymasterUrl: "https://paymaster.biconomy.io/api/v1/1/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71", - bundlerUrl: "https://bundler.biconomy.io/api/v2/80001/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44", // mock - }); - - await expect(createAccount).rejects.toThrow(); - }); - it("should deploy a smart account with native token balance", async () => { - const { - bundlerUrl, - biconomyPaymasterApiKey, - viemChain, - publicClient, - whale: { viemWallet: signer, account }, - deploymentCost, - } = baseSepolia; - - const newPrivateKey = generatePrivateKey(); - const newAccount = privateKeyToAccount(newPrivateKey); - - const newViemWallet = createWalletClient({ - account: newAccount, - chain: viemChain, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - - const smartAccount = await createSmartAccountClient({ - signer: newViemWallet, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAccountAddress(); - - // Setup: - const hash = await signer.sendTransaction({ to: smartAccountAddress, value: BigInt(deploymentCost), account, chain: viemChain }); // Send enough native token to counterfactual address to deploy the smart account - const transaction = await publicClient.waitForTransactionReceipt({ hash }); - expect(transaction).toBeTruthy(); - - // Test: - const { wait } = await smartAccount.deploy(); - const { success } = await wait(); - - const byteCode = await publicClient.getBytecode({ address: smartAccountAddress }); - expect(success).toBe("true"); - expect(byteCode).toBeTruthy(); - }, 60000); - - it("should deploy a smart account with sponsorship", async () => { - const { bundlerUrl, biconomyPaymasterApiKey, viemChain, publicClient } = baseSepolia; - - const newPrivateKey = generatePrivateKey(); - const newAccount = privateKeyToAccount(newPrivateKey); - - const newViemWallet = createWalletClient({ - account: newAccount, - chain: viemChain, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - - const smartAccount = await createSmartAccountClient({ - signer: newViemWallet, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAccountAddress(); - const balance = await publicClient.getBalance({ address: smartAccountAddress }); - expect(balance).toBe(0n); - - const { wait } = await smartAccount.deploy({ - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - }); - const { success } = await wait(); - - const byteCode = await publicClient.getBytecode({ address: smartAccountAddress }); - expect(success).toBe("true"); - expect(byteCode).toBeTruthy(); - }, 60000); - - it("should fail to deploy a smart account if no native token balance or paymaster", async () => { - const { bundlerUrl, biconomyPaymasterApiKey, viemChain } = baseSepolia; - - const newPrivateKey = generatePrivateKey(); - const newAccount = privateKeyToAccount(newPrivateKey); - - const newViemWallet = createWalletClient({ - account: newAccount, - chain: viemChain, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - - const smartAccount = await createSmartAccountClient({ - signer: newViemWallet, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - expect(async () => smartAccount.deploy()).rejects.toThrow(ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY); - }); - - it("should get supported tokens from the paymaster", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - bundlerUrl, - signer, - biconomyPaymasterApiKey, - }); - - const tokens = await smartAccount.getSupportedTokens(); - - expect(tokens.length).toBeGreaterThan(0); - expect(tokens[0]).toHaveProperty("tokenAddress"); - expect(tokens[0]).toHaveProperty("symbol"); - expect(tokens[0]).toHaveProperty("decimal"); - expect(tokens[0]).toHaveProperty("premiumPercentage"); - expect(tokens[0]).toHaveProperty("logoUrl"); - }); - - it("should fetch balances for smartAccount", async () => { - const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - const { - whale: { viemWallet: signer }, - bundlerUrl, - publicClient, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const usdcBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress(), usdt); - const [usdtBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); - - expect(usdcBalanceBefore).toBe(usdtBalanceFromSmartAccount.amount); - }); - - it("should check native token balance for smartAccount", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - chainId, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const [ethBalanceFromSmartAccount] = await smartAccount.getBalances(); - - expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n); - expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS); - expect(ethBalanceFromSmartAccount.chainId).toBe(chainId); - expect(ethBalanceFromSmartAccount.decimals).toBe(18); - }, 60000); - - it("should fail to deploy a smart account if already deployed", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - expect(async () => smartAccount.deploy()).rejects.toThrow(ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED); - }, 60000); - - it("should fetch balances for smartAccount", async () => { - const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - chainId, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const [usdtBalanceFromSmartAccount, ethBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); // last result is always eth balance - - expect(usdtBalanceFromSmartAccount.amount).toBeGreaterThan(0n); - expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n); - expect(usdtBalanceFromSmartAccount.address).toBe(usdt); - expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS); - expect(usdtBalanceFromSmartAccount.chainId).toBe(chainId); - expect(ethBalanceFromSmartAccount.chainId).toBe(chainId); - expect(usdtBalanceFromSmartAccount.decimals).toBe(6); - expect(ethBalanceFromSmartAccount.decimals).toBe(18); - expect(usdtBalanceFromSmartAccount.formattedAmount).toBeTruthy(); - expect(ethBalanceFromSmartAccount.formattedAmount).toBeTruthy(); - }); - - it("should withdraw erc20 balances", async () => { - const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner, account }, - bundlerUrl, - publicClient, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAddress(); - const usdtBalanceOfSABefore = await checkBalance(publicClient, smartAccountAddress, usdt); - const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); - - const { wait } = await smartAccount.withdraw([{ address: usdt, amount: BigInt(1), recipient: smartAccountOwner }]); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - expect(transactionHash).toBeTruthy(); - - const usdtBalanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress, usdt)) as bigint; - const usdtBalanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner, usdt)) as bigint; - - expect(usdtBalanceOfSAAfter - usdtBalanceOfSABefore).toBe(-1n); - expect(usdtBalanceOfRecipientAfter - usdtBalanceOfRecipientBefore).toBe(1n); - }, 15000); - - it("should gaslessly withdraw nativeToken", async () => { - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner }, - bundlerUrl, - publicClient, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAddress(); - const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - - const { wait } = await smartAccount.withdraw([{ address: NATIVE_TOKEN_ALIAS, amount: BigInt(1), recipient: smartAccountAddress }], null, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - }); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - expect(transactionHash).toBeTruthy(); - - const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - - expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n); - expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n); - }, 12000); - - it("should withdraw nativeToken and an erc20 token", async () => { - const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner }, - bundlerUrl, - publicClient, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAddress(); - const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - const usdtBalanceOfSABefore = await checkBalance(publicClient, smartAccountAddress, usdt); - const usdtBalanceOfRecipientBefore = await checkBalance(publicClient, smartAccountOwner, usdt); - - const { wait } = await smartAccount.withdraw( - [ - { address: usdt, amount: BigInt(1) }, - { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }, - ], - smartAccountOwner, - { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - }, - ); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - expect(transactionHash).toBeTruthy(); - - const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - const usdtBalanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress, usdt)) as bigint; - const usdtBalanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner, usdt)) as bigint; - - expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n); - expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n); - expect(usdtBalanceOfSAAfter - usdtBalanceOfSABefore).toBe(-1n); - expect(usdtBalanceOfRecipientAfter - usdtBalanceOfRecipientBefore).toBe(1n); - }, 60000); - - it("should withdraw all native token", async () => { - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner, account }, - bundlerUrl, - viemChain, - publicClient, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const smartAccountAddress = await smartAccount.getAddress(); - const balanceOfSABefore = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientBefore = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - - const { wait } = await smartAccount.withdraw([] /* null or undefined or [] */, smartAccountOwner, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, // Will leave no dust - }); - - const { - receipt: { transactionHash }, - userOpHash, - success, - } = await wait(); - - expect(userOpHash).toBeTruthy(); - expect(success).toBe("true"); - expect(transactionHash).toBeTruthy(); - - const balanceOfSAAfter = (await checkBalance(publicClient, smartAccountAddress)) as bigint; - const balanceOfRecipientAfter = (await checkBalance(publicClient, smartAccountOwner)) as bigint; - - expect(balanceOfSAAfter).toBe(0n); - expect(balanceOfRecipientAfter).toBe(balanceOfSABefore + balanceOfRecipientBefore); - - // Teardown: send back the native token to the smart account - const teardownHash = await signer.sendTransaction({ to: smartAccountAddress, value: balanceOfSABefore, account, chain: viemChain }); - expect(teardownHash).toBeTruthy(); - }, 60000); - - it("should error if no recipient exists", async () => { - const usdt: Hex = "0xda5289fcaaf71d52a80a254da614a192b693e977"; - - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner }, - bundlerUrl, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const txs = [ - { address: usdt, amount: BigInt(1), recipient: smartAccountOwner }, - { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }, - ]; - - expect(async () => smartAccount.withdraw(txs)).rejects.toThrow(ERROR_MESSAGES.NO_RECIPIENT); - }); - - it("should error when withdraw all of native token is attempted without an amount explicitly set", async () => { - const { - whale: { viemWallet: signer, publicAddress: smartAccountOwner }, - bundlerUrl, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - expect(async () => smartAccount.withdraw(null, smartAccountOwner)).rejects.toThrow(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); - }, 6000); - - it("should verify a correct signature through isValidSignature", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - publicClient, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const eip1271MagicValue = "0x1626ba7e"; - const message = "Some message from dApp"; - const messageHash = hashMessage(message); - const signature = await smartAccount.signMessage(messageHash); - - const response = await publicClient.readContract({ - address: await smartAccount.getAccountAddress(), - abi: BiconomyAccountAbi, - functionName: "isValidSignature", - args: [messageHash, signature], - }); - - expect(response).toBe(eip1271MagicValue); - }); - - it("should confirm that signature is not valid", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - publicClient, - } = baseSepolia; - - const randomPrivKey = generatePrivateKey(); - const randomWallet = privateKeyToAccount(randomPrivKey); - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const eip1271MagicValue = "0xffffffff"; - const message = "Some message from dApp"; - const messageHash = hashMessage(message); - const signature = await randomWallet.signMessage({ message: messageHash }); - const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters("bytes, address"), [ - signature, - smartAccount.defaultValidationModule.getAddress(), - ]); - - const response = await publicClient.readContract({ - address: await smartAccount.getAccountAddress(), - abi: BiconomyAccountAbi, - functionName: "isValidSignature", - args: [messageHash, signatureWithModuleAddress], - }); - - expect(response).toBe(eip1271MagicValue); - }); -}); diff --git a/packages/account/tests/account.optimism.e2e.spec.ts b/packages/account/tests/account.optimism.e2e.spec.ts deleted file mode 100644 index d558ba4ed..000000000 --- a/packages/account/tests/account.optimism.e2e.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { TestData } from "../../../tests"; -import { createSmartAccountClient, PaymasterMode } from "../src/index"; -import { encodeFunctionData, parseAbi } from "viem"; -import { checkBalance } from "../../../tests/utils"; - -const maybe = process.env.WITH_MAINNET_TESTS === "true" ? describe : describe.skip; - -maybe("Account Tests", () => { - let optimism: TestData; - let _: TestData; - let __: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [_, __, optimism] = testDataPerChain; - }); - - it("should send some native token to a recipient on optimism", async () => { - const { - whale: { viemWallet: signer, publicAddress: sender }, - minnow: { publicAddress: recipient }, - bundlerUrl, - publicClient, - } = optimism; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const accountAddress = await smartAccount.getAddress(); - - const balanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint; - const smartAccountBalance = (await checkBalance(publicClient, accountAddress)) as bigint; - const { wait } = await smartAccount.sendTransaction( - { - to: recipient, - value: BigInt(1), - }, - { - simulationType: "validation_and_execution", - }, - ); - - const result = await wait(); - const newBalanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint; - - expect(result?.receipt?.transactionHash).toBeTruthy(); - expect(result.success).toBe("true"); - expect(newBalanceOfRecipient).toBeGreaterThan(balanceOfRecipient); - }, 50000); - - it("Create a smart account with paymaster with an api key on optimism", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = optimism; - - const smartAccount = await createSmartAccountClient({ - signer, - biconomyPaymasterApiKey, - bundlerUrl, - }); - - const paymaster = smartAccount.paymaster; - expect(paymaster).not.toBeNull(); - expect(paymaster).not.toBeUndefined(); - }); - - it("Should gaslessly mint an NFT on optimism", async () => { - const { - whale: { viemWallet: signer, publicAddress: recipient }, - bundlerUrl, - biconomyPaymasterApiKey, - publicClient, - nftAddress, - } = optimism; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address to) public"]), - functionName: "safeMint", - args: [recipient], - }); - - const transaction = { - to: nftAddress, // NFT address - data: encodedCall, - }; - - const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - - const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress()); - - const response = await smartAccount.sendTransaction(transaction, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - simulationType: "validation_and_execution", - }); - - const userOpReceipt = await response.wait(3); - expect(userOpReceipt.userOpHash).toBeTruthy(); - expect(userOpReceipt.success).toBe("true"); - - const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress()); - - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint; - - expect(newBalance - balance).toBe(1n); - }, 50000); -}); diff --git a/packages/account/tests/account.read.e2e.spec.ts b/packages/account/tests/account.read.e2e.spec.ts deleted file mode 100644 index 32af9dc26..000000000 --- a/packages/account/tests/account.read.e2e.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { TestData } from "../../../tests"; -import { createSmartAccountClient } from "../src/index"; -import { DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules"; - -describe("Account Tests", () => { - let baseSepolia: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [baseSepolia] = testDataPerChain; - }); - - it("should check if module is enabled on the smart account", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - } = baseSepolia; - - const smartWallet = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const isEnabled = await smartWallet.isModuleEnabled(DEFAULT_ECDSA_OWNERSHIP_MODULE); - expect(isEnabled).toBeTruthy(); - }, 30000); - - it("should get all modules", async () => { - const { - whale: { - viemWallet: signer, - account: { address: accountAddress }, - }, - bundlerUrl, - biconomyPaymasterApiKey, - } = baseSepolia; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const modules = await smartAccount.getAllModules(); - - expect(modules).toContain(DEFAULT_SESSION_KEY_MANAGER_MODULE); // session manager module - expect(modules).toContain(DEFAULT_ECDSA_OWNERSHIP_MODULE); // ecdsa ownership module - }, 30000); - - it("should get disabled module data", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - } = baseSepolia; - - const smartWallet = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const disableModuleData = await smartWallet.getDisableModuleData(DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_ECDSA_OWNERSHIP_MODULE); - expect(disableModuleData).toBeTruthy(); - }, 30000); - - it("should get setup and enable module data", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - } = baseSepolia; - - const smartWallet = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const module = await createECDSAOwnershipValidationModule({ signer }); - const initData = await module.getInitData(); - const setupAndEnableModuleData = await smartWallet.getSetupAndEnableModuleData(DEFAULT_ECDSA_OWNERSHIP_MODULE, initData); - expect(setupAndEnableModuleData).toBeTruthy(); - }, 30000); - - it("should read estimated user op gas values", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - } = baseSepolia; - - const smartWallet = await createSmartAccountClient({ - signer, - bundlerUrl, - }); - - const tx = { - to: "0x000000D50C68705bd6897B2d17c7de32FB519fDA", - data: "0x", - }; - - const userOp = await smartWallet.buildUserOp([tx]); - - const estimatedGas = await smartWallet.estimateUserOpGas(userOp); - expect(estimatedGas.maxFeePerGas).toBeTruthy(); - expect(estimatedGas.maxPriorityFeePerGas).toBeTruthy(); - expect(estimatedGas.verificationGasLimit).toBeTruthy(); - expect(estimatedGas.callGasLimit).toBeTruthy(); - expect(estimatedGas.preVerificationGas).toBeTruthy(); - expect(estimatedGas).toHaveProperty("paymasterAndData", "0x"); - }, 35000); -}); diff --git a/packages/account/tests/account.spec.ts b/packages/account/tests/account.spec.ts deleted file mode 100644 index 9e76f2f89..000000000 --- a/packages/account/tests/account.spec.ts +++ /dev/null @@ -1,283 +0,0 @@ -import { Paymaster, createBundler, createSmartAccountClient } from "../src"; -import { Chain, createWalletClient, http } from "viem"; -import { localhost } from "viem/chains"; -import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; -import { TestData } from "../../../tests"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { Wallet } from "@ethersproject/wallet"; -import { getMockBundlerUrl } from "../../../tests/utils"; - -describe("Account Tests", () => { - let ganache: TestData; - const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1337/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f14"; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [ganache] = testDataPerChain; - }); - - it("should create a smartAccountClient from an ethers signer", async () => { - const { - minnow: { ethersSigner: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - }); - - it("should create a whale smartAccountClient from an ethers signer", async () => { - const { - whale: { ethersSigner: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - }); - - it("should create a smartAccountClient from a walletClient", async () => { - const { - whale: { viemWallet: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - }); - - it("should pickup the rpcUrl when a custom chain is used", async () => { - const customBlastChain = { - id: 81_457, - name: "Blast", - // network: "blast", - nativeCurrency: { - decimals: 18, - name: "Ethereum", - symbol: "ETH", - }, - rpcUrls: { - public: { http: ["https://rpc.blast.io"] }, - default: { http: ["https://rpc.blast.io"] }, - }, - blockExplorers: { - etherscan: { name: "Blastscan", url: "https://blastscan.io/" }, - default: { name: "Blastscan", url: "https://blastscan.io/" }, - }, - contracts: { - multicall3: { - address: "0xca11bde05977b3631167028862be2a173976ca11", - blockCreated: 88_189, - }, - }, - } as const satisfies Chain; - - const { - whale: { privateKey }, - } = ganache; - - const accountOne = privateKeyToAccount(privateKey); - - const walletClientWithCustomChain = createWalletClient({ - account: accountOne, - chain: customBlastChain, - transport: http(customBlastChain.rpcUrls.default.http[0]), - }); - - const blastBundler = await createBundler({ - bundlerUrl: getMockBundlerUrl(customBlastChain.id), - viemChain: customBlastChain, - }); - const smartAccountFromViemWithCustomChain = await createSmartAccountClient({ - viemChain: customBlastChain, - signer: walletClientWithCustomChain, - bundler: blastBundler, - rpcUrl: customBlastChain.rpcUrls.default.http[0], - }); - - expect(smartAccountFromViemWithCustomChain.rpcProvider.transport.url).toBe("https://rpc.blast.io"); - expect(blastBundler.getBundlerUrl()).toBe(getMockBundlerUrl(customBlastChain.id)); - }); - - it("should pickup the rpcUrl from viem wallet and ethers", async () => { - const { - chainId, - viemChain, - whale: { privateKey, viemWallet: originalViemSigner, ethersSigner: originalEthersSigner }, - } = ganache; - - const newRpcUrl = "http://localhost:8545"; - const defaultRpcUrl = viemChain.rpcUrls.default.http[0]; //http://127.0.0.1:8545" - - const ethersProvider = new JsonRpcProvider(newRpcUrl); - const ethersSignerWithNewRpcUrl = new Wallet(privateKey, ethersProvider); - - const accountOne = privateKeyToAccount(privateKey); - const walletClientWithNewRpcUrl = createWalletClient({ - account: accountOne, - chain: viemChain, - transport: http(newRpcUrl), - }); - - const [smartAccountFromEthersWithNewRpc, smartAccountFromViemWithNewRpc, smartAccountFromEthersWithOldRpc, smartAccountFromViemWithOldRpc] = - await Promise.all([ - createSmartAccountClient({ - chainId, - signer: ethersSignerWithNewRpcUrl, - bundlerUrl: mockBundlerUrl, - rpcUrl: newRpcUrl, - }), - createSmartAccountClient({ - chainId, - signer: walletClientWithNewRpcUrl, - bundlerUrl: mockBundlerUrl, - rpcUrl: newRpcUrl, - }), - createSmartAccountClient({ - chainId, - signer: originalEthersSigner, - bundlerUrl: mockBundlerUrl, - rpcUrl: viemChain.rpcUrls.default.http[0], - }), - createSmartAccountClient({ - chainId, - signer: originalViemSigner, - bundlerUrl: mockBundlerUrl, - rpcUrl: viemChain.rpcUrls.default.http[0], - }), - ]); - - const [ - smartAccountFromEthersWithNewRpcAddress, - smartAccountFromViemWithNewRpcAddress, - smartAccountFromEthersWithOldRpcAddress, - smartAccountFromViemWithOldRpcAddress, - ] = await Promise.all([ - smartAccountFromEthersWithNewRpc.getAccountAddress(), - smartAccountFromViemWithNewRpc.getAccountAddress(), - smartAccountFromEthersWithOldRpc.getAccountAddress(), - smartAccountFromViemWithOldRpc.getAccountAddress(), - ]); - - expect( - [ - smartAccountFromEthersWithNewRpcAddress, - smartAccountFromViemWithNewRpcAddress, - smartAccountFromEthersWithOldRpcAddress, - smartAccountFromViemWithOldRpcAddress, - ].every(Boolean), - ).toBeTruthy(); - - expect(smartAccountFromEthersWithNewRpc.rpcProvider.transport.url).toBe(newRpcUrl); - expect(smartAccountFromViemWithNewRpc.rpcProvider.transport.url).toBe(newRpcUrl); - expect(smartAccountFromEthersWithOldRpc.rpcProvider.transport.url).toBe(defaultRpcUrl); - expect(smartAccountFromViemWithOldRpc.rpcProvider.transport.url).toBe(defaultRpcUrl); - }); - - it("should create a smartAccountClient from a signer and chainId", async () => { - const { - chainId, - whale: { alchemyWalletClientSigner: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - chainId, - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - }); - - it("should provide an account address", async () => { - const { - whale: { viemWallet: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - }); - - it("should have an active validation module", async () => { - const { - whale: { viemWallet: signer }, - } = ganache; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - - const module = smartAccount.activeValidationModule; - expect(module).toBeTruthy(); - }); - - it("Create a smart account with paymaster by creating instance", async () => { - const { - whale: { viemWallet: signer }, - paymasterUrl, - } = ganache; - - const paymaster = new Paymaster({ paymasterUrl }); - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl: mockBundlerUrl, - paymaster, - rpcUrl: localhost.rpcUrls.default.http[0], - }); - expect(smartAccount.paymaster).not.toBeNull(); - expect(smartAccount.paymaster).not.toBeUndefined(); - }, 10000); - - it("should fail to create a smartAccountClient from a walletClient without a chainId", async () => { - const account = privateKeyToAccount(generatePrivateKey()); - const viemWalletClientNoChainId = createWalletClient({ - account, - transport: http(localhost.rpcUrls.default.http[0]), - }); - - expect( - await expect( - createSmartAccountClient({ - signer: viemWalletClientNoChainId, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }), - ).rejects.toThrow("Cannot consume a viem wallet without a chainId"), - ); - }); - - it("should fail to create a smartAccountClient from a walletClient without an account", async () => { - const viemWalletNoAccount = createWalletClient({ - transport: http(localhost.rpcUrls.default.http[0]), - }); - - expect(async () => - createSmartAccountClient({ - signer: viemWalletNoAccount, - bundlerUrl: mockBundlerUrl, - rpcUrl: localhost.rpcUrls.default.http[0], - }), - ).rejects.toThrow("Cannot consume a viem wallet without an account"); - }); -}); diff --git a/packages/account/tests/utils.spec.ts b/packages/account/tests/utils.spec.ts deleted file mode 100644 index d8dfc2a79..000000000 --- a/packages/account/tests/utils.spec.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { BiconomySmartAccountV2Config, ERROR_MESSAGES, createECDSAOwnershipValidationModule } from "../src"; -import { TestData } from "../../../tests"; -import { compareChainIds, getChain } from "../src/utils"; -import { createWalletClient, http } from "viem"; -import { bsc } from "viem/chains"; - -describe("Utils tests", () => { - let ganache: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [ganache] = testDataPerChain; - }); - - it("Should not throw and error, chain ids match", async () => { - const { - minnow: { viemWallet: walletClient }, - } = ganache; - - const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1337/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44"; - const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/1337/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71"; - - const config: BiconomySmartAccountV2Config = { - signer: walletClient, - bundlerUrl: mockBundlerUrl, - paymasterUrl: mockPaymasterUrl, - }; - - await expect(compareChainIds(walletClient, config, false)).resolves.not.toThrow(); - }); - - it("Should throw and error, bundlerUrl chain id and signer chain id does not match", async () => { - const { - minnow: { viemWallet: walletClient }, - paymasterUrl, - } = ganache; - - const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44"; - - const config: BiconomySmartAccountV2Config = { - signer: walletClient, - bundlerUrl: mockBundlerUrl, - paymasterUrl, - }; - - await expect(compareChainIds(walletClient, config, false)).rejects.toThrow(); - }); - - it("Should throw and error, bundlerUrl chain id and paymaster url chain id does not match", async () => { - const { - bundlerUrl, - minnow: { viemWallet: walletClient }, - } = ganache; - - const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71"; - - const config: BiconomySmartAccountV2Config = { - signer: walletClient, - bundlerUrl, - paymasterUrl: mockPaymasterUrl, - }; - - await expect(compareChainIds(walletClient, config, false)).rejects.toThrow(); - }); - - it("Should throw and error, bundlerUrl chain id and paymaster url chain id does not match", async () => { - const { - bundlerUrl, - minnow: { viemWallet: walletClient }, - } = ganache; - - const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71"; - - const ecdsaModule = await createECDSAOwnershipValidationModule({ - signer: walletClient, - }); - - const config: BiconomySmartAccountV2Config = { - defaultValidationModule: ecdsaModule, - activeValidationModule: ecdsaModule, - bundlerUrl, - paymasterUrl: mockPaymasterUrl, - }; - - await expect(compareChainIds(walletClient, config, false)).rejects.toThrow(); - }); - - it("Should throw and error, signer has chain id (56) and paymasterUrl has chain id (80001)", async () => { - const { bundlerUrl, whale } = ganache; - - const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71"; - - const walletClient = createWalletClient({ - account: whale.viemWallet.account, - chain: bsc, - transport: http(bsc.rpcUrls.default.http[0]), - }); - - const config: BiconomySmartAccountV2Config = { - signer: walletClient, - bundlerUrl, - paymasterUrl: mockPaymasterUrl, - }; - - await expect(compareChainIds(walletClient, config, false)).rejects.toThrow(); - }); - - // test chains - it("Should return chain object for chain id 1", () => { - const chainId = 1; - const chain = getChain(chainId); - expect(chain.id).toBe(chainId); - }); - - // should have correct fields - it("Should have correct fields", () => { - const chainId = 1; - const chain = getChain(chainId); - - ["blockExplorers", "contracts", "fees", "formatters", "id", "name", "nativeCurrency", "rpcUrls", "serializers"].every((field) => { - expect(chain).toHaveProperty(field); - }); - }); - - // Should throw an error, chain id not found - it("Should throw an error, chain id not found", () => { - const chainId = 0; - expect(() => getChain(chainId)).toThrow(ERROR_MESSAGES.CHAIN_NOT_FOUND); - }); -}); diff --git a/packages/account/tsconfig.build.json b/packages/account/tsconfig.build.json deleted file mode 100644 index 42d88a236..000000000 --- a/packages/account/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests", "tests/**/*"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json deleted file mode 100644 index 53677da37..000000000 --- a/packages/account/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node"] - }, - "include": ["src", "src/**/*.json"], -} diff --git a/packages/bundler/.esbuild.js b/packages/bundler/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/bundler/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/bundler/CHANGELOG.md b/packages/bundler/CHANGELOG.md deleted file mode 100644 index 7730bad6b..000000000 --- a/packages/bundler/CHANGELOG.md +++ /dev/null @@ -1,94 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -VERSION Bump Only. - -## 4.1.0 (2023-04-03) - -VERSION Bump Only. - -## 4.0.3 (2023-28-02) - -VERSION Bump Only. - -## 4.0.2 (2023-26-02) - -VERSION Bump Only. - -## 4.0.1 (2023-02-22) - -VERSION Bump Only. - -## 4.0.0 (2023-07-02) - -Export createBundler alias for static Bundler.create call - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -### Features - -- Make entrypoint address optional in bundler config ([547724a](https://github.com/bcnmy/biconomy-client-sdk/pull/337/commits/547724a15366ee1e63aee80fdee0edc128a84c41)) - -### Bug Fixes - -- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3)) - -## 3.1.1 (2023-11-09) - -### Bug Fixes - -- resolve comments ([34fd6a3](https://github.com/bcnmy/biconomy-client-sdk/commit/34fd6a308805061d9faf408f1ce6da9cac0ee819)) - -### Features - -- add linea mainnet ([c3d1283](https://github.com/bcnmy/biconomy-client-sdk/commit/c3d12832002c18e187f910b5f7dac5ef5b797abf)) -- chain integration ([ddc5d91](https://github.com/bcnmy/biconomy-client-sdk/commit/ddc5d91d5df10a10266f4500644d24e0bc1ea684)) -- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360)) - -## 3.1.0 (2023-09-20) - -Modular Account Abstraction is here. - -### Bug Fixes - -- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) -- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526)) -- more lint issues ([10df908](https://github.com/bcnmy/biconomy-client-sdk/commit/10df90821b473fd668907cf3e447dfe3825317fc)) - -### Features - -- base mainnet integration ([c17f5d6](https://github.com/bcnmy/biconomy-client-sdk/commit/c17f5d6c2fe34b106e6d9755f54fab2493db6fbe)) -- chain integration ([ddc5d91](https://github.com/bcnmy/biconomy-client-sdk/commit/ddc5d91d5df10a10266f4500644d24e0bc1ea684)) -- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360)) - -## 3.0.0 (2023-08-28) - -Modular SDK - consists stable version of below updates done in Alphas. - -### Features - -- base mainnet integration ([c17f5d6](https://github.com/bcnmy/biconomy-client-sdk/commit/c17f5d6c2fe34b106e6d9755f54fab2493db6fbe)) - -## 3.0.0-alpha.0 (2023-08-02) - -VERSION Bump Only. - -# 3.1.0-alpha.0 (2023-07-24) - -### Features - -- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360)) - -## 3.0.0-alpha.0 (2023-07-12) - -### Bug Fixes - -- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526)) diff --git a/packages/bundler/Readme.md b/packages/bundler/Readme.md deleted file mode 100644 index 06e0c4af6..000000000 --- a/packages/bundler/Readme.md +++ /dev/null @@ -1,99 +0,0 @@ -### Bundler - -In the context of (ERC4337), A bundler plays a main role in the infrastructure. This concept is integral to the operation of account abstraction across any network that utilizes the Ethereum Virtual Machine (EVM). - -## Installation - -Using `npm` package manager - -```bash -npm i @biconomy/bundler -``` - -OR - -Using `yarn` package manager - -```bash -yarn add @biconomy/bundler -``` - -## configuration - -| Key | Description | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| bundlerUrl | Represent ERC4337 spec implemented bundler url. you can get one from biconomy dashboard. Alternatively you can supply any of your preferred | -| chainId | This represents the network your smart wallet transactions will be conducted on. Take a look following Link for supported chain id's | -| entryPointAddress | Since entrypoint can have different addresses you can call getSupportedEntryPoints() on bundler instance for supported addresses list | - -```typescript -// This is how you create bundler instance in your dapp's -import { IBundler, createBundler } from "@biconomy/bundler"; - -// Make use of core-types package -import { ChainId } from "@biconomy/core-types"; - -const bundler: IBundler = await createBundler({ bundlerUrl: "" }); // you can get this value from biconomy dashboard. https://dashboard.biconomy.io -``` - -Following are the methods that can be call on bundler instance - -```typescript -export interface IBundler { - estimateUserOpGas(userOp: Partial<UserOperation>): Promise<UserOpGasResponse>; - sendUserOp(userOp: UserOperation): Promise<UserOpResponse>; - getUserOpReceipt(userOpHash: string): Promise<UserOpReceipt>; - getUserOpByHash(userOpHash: string): Promise<UserOpByHashResponse>; -} -``` - -**[estimateUserOpGas](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#estimateUserOpGas)** -Estimate the gas values for a UserOperation. Given UserOperation optionally without gas limits and gas prices, return the needed gas limits. The signature field is ignored by the wallet, so that the operation will not require user's approval. Still, it might require putting a "semi-valid" signature (e.g. a signature in the right length) - -**Return Values** - -**preVerificationGas** gas overhead of this UserOperation -**verificationGasLimit** actual gas used by the validation of this UserOperation -**callGasLimit** limit used to execute userop.callData called from EntryPoint to the Smart Account - - -------------------------------- - -**[sendUserOp](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#sendUserOp)** -it submits a User Operation object to the User Operation pool of the client. The client MUST validate the UserOperation, and return a result accordingly. - -The result SHOULD be set to the userOpHash if and only if the request passed simulation and was accepted in the client's User Operation pool. If the validation, simulation, or User Operation pool inclusion fails, result SHOULD NOT be returned. Rather, the client SHOULD return the failure reason. - -**Return Values** -If the UserOperation is valid, the client MUST return the calculated userOpHash for it - - -------------------------------- - -**[getUserOpByHash](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#getUserOpByHash)** -Return a UserOperation based on a hash (userOpHash) returned by sendUserOp (eth_sendUserOperation) - -**Return Values** - -null in case the UserOperation is not yet included in a block, or a full UserOperation, with the addition of entryPoint, blockNumber, blockHash and transactionHash - - -------------------------------- - -**[getUserOpReceipt](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#getUserOpReceipt)** - -Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation - -**Return Values** -null in case the UserOperation is not yet included in a block, or: - -**userOpHash** the request hash -**entryPoint** -**sender** -**nonce** -**paymaster** the paymaster used for this userOp (or empty) -**actualGasCost** - actual amount paid (by account or paymaster) for this UserOperation -**actualGasUsed** - total gas used by this UserOperation (including preVerification, creation, validation and execution) -**success** boolean - did this execution completed without revert -**reason** in case of revert, this is the revert reason -**logs** the logs generated by this UserOperation (not including logs of other UserOperations in the same bundle) -**receipt** the TransactionReceipt object. Note that the returned TransactionReceipt is for the entire bundle, not only for this UserOperation. - - -------------------------------- diff --git a/packages/bundler/package.json b/packages/bundler/package.json deleted file mode 100644 index a41dde75f..000000000 --- a/packages/bundler/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "@biconomy/bundler", - "version": "4.1.1", - "description": "Biconomy Bundler package to interact with any bundler node as per ERC4337 standard", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "Ethereum", - "Bundler", - "Relayer", - "ERC4337", - "Gasless Transaction", - "Biconomy", - "SDK" - ], - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "test:file": "jest --config=../../jest.config.js --runInBand", - "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'", - "test:run": "jest tests/**/*.spec.ts --runInBand", - "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json" - }, - "author": "Biconomy", - "repository": { - "type": "git", - "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git" - }, - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@alchemy/aa-core": "^3.1.1", - "@biconomy/common": "^4.1.1", - "viem": "^2.7.12" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12" - } -} diff --git a/packages/bundler/src/index.ts b/packages/bundler/src/index.ts deleted file mode 100644 index 7a779f5d5..000000000 --- a/packages/bundler/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Bundler } from "./Bundler.js"; - -export * from "./interfaces/IBundler.js"; -export * from "./Bundler.js"; -export * from "./utils/Types.js"; -export * from "./utils/Utils.js"; - -export const createBundler = Bundler.create; diff --git a/packages/bundler/src/interfaces/IBundler.ts b/packages/bundler/src/interfaces/IBundler.ts deleted file mode 100644 index 75077e141..000000000 --- a/packages/bundler/src/interfaces/IBundler.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { StateOverrideSet } from "@biconomy/common"; -import { - UserOpResponse, - UserOpGasResponse, - UserOpReceipt, - UserOpByHashResponse, - UserOpStatus, - SimulationType, - GasFeeValues, -} from "../utils/Types.js"; -import { UserOperationStruct } from "@alchemy/aa-core"; - -export interface IBundler { - estimateUserOpGas(_userOp: Partial<UserOperationStruct>, stateOverrideSet?: StateOverrideSet): Promise<UserOpGasResponse>; - sendUserOp(_userOp: UserOperationStruct, _simulationType?: SimulationType): Promise<UserOpResponse>; - getUserOpReceipt(_userOpHash: string): Promise<UserOpReceipt>; - getUserOpByHash(_userOpHash: string): Promise<UserOpByHashResponse>; - getGasFeeValues(): Promise<GasFeeValues>; - getUserOpStatus(_userOpHash: string): Promise<UserOpStatus>; - getBundlerUrl(): string; -} diff --git a/packages/bundler/src/utils/Utils.ts b/packages/bundler/src/utils/Utils.ts deleted file mode 100644 index 692cf1bdd..000000000 --- a/packages/bundler/src/utils/Utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const extractChainIdFromBundlerUrl = (url: string): number => { - try { - const regex = /\/api\/v2\/(\d+)\/[a-zA-Z0-9.-]+$/; - const match = regex.exec(url)!; - return parseInt(match[1]); - } catch (error) { - throw new Error("Invalid chain id"); - } -}; - -export const extractChainIdFromPaymasterUrl = (url: string): number => { - try { - const regex = /\/api\/v\d+\/(\d+)\//; - const match = regex.exec(url); - if (!match) { - throw new Error("Invalid URL format"); - } - return parseInt(match[1]); - } catch (error) { - throw new Error("Invalid chain id"); - } -}; diff --git a/packages/bundler/tests/bundler.e2e.spec.ts b/packages/bundler/tests/bundler.e2e.spec.ts deleted file mode 100644 index 7b9211dd0..000000000 --- a/packages/bundler/tests/bundler.e2e.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TestData } from "../../../tests"; - -describe("Bundler Unit Tests", () => { - let mumbai: TestData; - let baseSepolia: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai, baseSepolia] = testDataPerChain; - }); - - it("should have chain data for mumbai", () => { - expect(mumbai).toHaveProperty("chainId"); - }); - - it("should also have chain data for base", () => { - expect(baseSepolia).toHaveProperty("chainId"); - }); -}); diff --git a/packages/bundler/tests/bundler.spec.ts b/packages/bundler/tests/bundler.spec.ts deleted file mode 100644 index e663dafb4..000000000 --- a/packages/bundler/tests/bundler.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TestData } from "../../../tests"; - -describe("Bundler Unit Tests", () => { - let ganache: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [ganache] = testDataPerChain; - }); - - it("should have chain data for ganache", () => { - expect(ganache).toHaveProperty("chainId"); - }); -}); diff --git a/packages/bundler/tsconfig.build.json b/packages/bundler/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/bundler/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/bundler/tsconfig.json b/packages/bundler/tsconfig.json deleted file mode 100644 index d9b305a9a..000000000 --- a/packages/bundler/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node"] - }, - "include": ["src", "src/**/*.json"] -} diff --git a/packages/common/.esbuild.js b/packages/common/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/common/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/common/README.md b/packages/common/README.md deleted file mode 100644 index db4c4a8c7..000000000 --- a/packages/common/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# `@biconomy/common` - -common utils - -common methods for other biconomy packages - -## Usage - -``` -no direct usage of this package -``` diff --git a/packages/common/package.json b/packages/common/package.json deleted file mode 100644 index 22010587c..000000000 --- a/packages/common/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "@biconomy/common", - "version": "4.1.1", - "description": "common utils to be used for aa transactions", - "keywords": [ - "utils" - ], - "author": "livingrockrises <chirag@biconomy.io>", - "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme", - "license": "MIT", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "files": [ - "dist/*", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git" - }, - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "test:file": "jest --config=../../jest.config.js --runInBand", - "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'", - "test:run": "jest tests/**/*.spec.ts --runInBand", - "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json" - }, - "bugs": { - "url": "https://github.com/bcnmy/biconomy-client-sdk/issues" - }, - "dependencies": { - "@alchemy/aa-core": "^3.1.1", - "@ethersproject/abstract-signer": "^5.7.0", - "viem": "^2.7.12" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12" - } -} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts deleted file mode 100644 index cca231168..000000000 --- a/packages/common/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./utils/Helpers/convertSigner.js"; -export * from "./utils/Types.js"; -export * from "./utils/Constants.js"; -export * from "./utils/Logger.js"; -export * from "./utils/HttpRequests.js"; -export { EthersSigner } from "./utils/EthersSigner.js"; diff --git a/packages/common/src/utils/Constants.ts b/packages/common/src/utils/Constants.ts deleted file mode 100644 index 4e3292cb5..000000000 --- a/packages/common/src/utils/Constants.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SupportedSignerName } from "./Types.js"; - -export const UNIQUE_PROPERTIES_PER_SIGNER: Record<SupportedSignerName, string> = { - alchemy: "signerType", - ethers: "provider", - viem: "transport", -}; diff --git a/packages/common/src/utils/EthersSigner.ts b/packages/common/src/utils/EthersSigner.ts deleted file mode 100644 index d77e0eab1..000000000 --- a/packages/common/src/utils/EthersSigner.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { Hex, SignableMessage } from "viem"; -import { Signer } from "@ethersproject/abstract-signer"; - -export class EthersSigner<T extends Signer> implements SmartAccountSigner<T> { - signerType: string = "ethers"; - - inner: T; - - constructor(inner: T, signerType: string) { - this.inner = inner; - this.signerType = signerType; - } - - async getAddress() { - return (await this.inner.getAddress()) as Hex; - } - - async signMessage(_message: SignableMessage): Promise<Hex> { - const message = typeof _message === "string" ? _message : _message.raw; - const signature = await this.inner?.signMessage(message); - return this.#correctSignature(signature as Hex); - } - - async signTypedData(_notUsed: any): Promise<Hex> { - throw new Error("signTypedData is not supported for Ethers Signer"); - } - - #correctSignature = (signature: Hex): Hex => { - const potentiallyIncorrectV = parseInt(signature.slice(-2), 16); - if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - signature = signature.slice(0, -2) + correctV.toString(16); - } - return signature; - }; -} - -export default EthersSigner; diff --git a/packages/common/src/utils/Helpers/convertSigner.ts b/packages/common/src/utils/Helpers/convertSigner.ts deleted file mode 100644 index 5aadb0803..000000000 --- a/packages/common/src/utils/Helpers/convertSigner.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { EthersSigner } from "../EthersSigner.js"; -import { SupportedSigner } from "../Types.js"; -import { WalletClient } from "viem"; -import { WalletClientSigner, SmartAccountSigner } from "@alchemy/aa-core"; -import { UNIQUE_PROPERTIES_PER_SIGNER } from "../Constants.js"; -import { Signer } from "@ethersproject/abstract-signer"; - -interface SmartAccountResult { - signer: SmartAccountSigner; - chainId: number | null; - rpcUrl: string | null; -} - -export const convertSigner = async (signer: SupportedSigner, skipChainIdCalls: boolean = false): Promise<SmartAccountResult> => { - let resolvedSmartAccountSigner: SmartAccountSigner; - let rpcUrl: string | null = null; - let chainId: number | null = null; - const isAnAlchemySigner = UNIQUE_PROPERTIES_PER_SIGNER.alchemy in signer; - const isAnEthersSigner = UNIQUE_PROPERTIES_PER_SIGNER.ethers in signer; - const isAViemSigner = UNIQUE_PROPERTIES_PER_SIGNER.viem in signer; - - if (!isAnAlchemySigner) { - if (isAnEthersSigner) { - const ethersSigner = signer as Signer; - if (!skipChainIdCalls) { - // If chainId not provided, get it from walletClient - if (!ethersSigner.provider) { - throw new Error("Cannot consume an ethers Wallet without a provider"); - } - const chainIdFromProvider = await ethersSigner.provider.getNetwork(); - if (!chainIdFromProvider?.chainId) { - throw new Error("Cannot consume an ethers Wallet without a chainId"); - } - chainId = Number(chainIdFromProvider.chainId); - } - // convert ethers Wallet to alchemy's SmartAccountSigner under the hood - resolvedSmartAccountSigner = new EthersSigner(ethersSigner, "ethers"); - // @ts-ignore - rpcUrl = ethersSigner.provider?.connection?.url ?? null; - } else if (isAViemSigner) { - const walletClient = signer as WalletClient; - if (!walletClient.account) { - throw new Error("Cannot consume a viem wallet without an account"); - } - if (!skipChainIdCalls) { - // If chainId not provided, get it from walletClient - if (!walletClient.chain) { - throw new Error("Cannot consume a viem wallet without a chainId"); - } - chainId = walletClient.chain.id; - } - // convert viems walletClient to alchemy's SmartAccountSigner under the hood - resolvedSmartAccountSigner = new WalletClientSigner(walletClient, "viem"); - rpcUrl = walletClient?.transport?.url ?? null; - } else { - throw new Error("Unsupported signer"); - } - } else { - resolvedSmartAccountSigner = signer as SmartAccountSigner; - } - return { signer: resolvedSmartAccountSigner, rpcUrl, chainId }; -}; diff --git a/packages/common/src/utils/Helpers/index.ts b/packages/common/src/utils/Helpers/index.ts deleted file mode 100644 index 235336dc3..000000000 --- a/packages/common/src/utils/Helpers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./convertSigner.js"; diff --git a/packages/common/src/utils/HttpRequests.ts b/packages/common/src/utils/HttpRequests.ts deleted file mode 100644 index 192a33e4e..000000000 --- a/packages/common/src/utils/HttpRequests.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Logger } from "./Logger.js"; -import { Service } from "./Types.js"; - -export enum HttpMethod { - Get = "get", - Post = "post", - Delete = "delete", -} - -/* eslint-disable @typescript-eslint/no-explicit-any */ -export interface HttpRequest { - url: string; - method: HttpMethod; - body?: Record<string, any>; -} - -export async function sendRequest<T>({ url, method, body }: HttpRequest, service: Service): Promise<T> { - const response = await fetch(url, { - method, - headers: { - Accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); - - let jsonResponse; - try { - jsonResponse = await response.json(); - Logger.log(`${service} RPC Response`, jsonResponse); - } catch (error) { - if (!response.ok) { - throw new Error(response.statusText); - } - } - - if (response.ok) { - return jsonResponse as T; - } - if (jsonResponse.error) { - throw new Error(`Error coming from ${service}: ${jsonResponse.error.message}`); - } - if (jsonResponse.message) { - throw new Error(jsonResponse.message); - } - if (jsonResponse.msg) { - throw new Error(jsonResponse.msg); - } - if (jsonResponse.data) { - throw new Error(jsonResponse.data); - } - if (jsonResponse.detail) { - throw new Error(jsonResponse.detail); - } - if (jsonResponse.message) { - throw new Error(jsonResponse.message); - } - if (jsonResponse.nonFieldErrors) { - throw new Error(jsonResponse.nonFieldErrors); - } - if (jsonResponse.delegate) { - throw new Error(jsonResponse.delegate); - } - throw new Error(response.statusText); -} diff --git a/packages/common/src/utils/Types.ts b/packages/common/src/utils/Types.ts deleted file mode 100644 index 52eac0216..000000000 --- a/packages/common/src/utils/Types.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { WalletClient } from "viem"; -import { Signer } from "@ethersproject/abstract-signer"; -import { SmartAccountSigner } from "@alchemy/aa-core"; - -export type SupportedSignerName = "alchemy" | "ethers" | "viem"; -export type SupportedSigner = SmartAccountSigner | WalletClient | Signer | LightSigner; - -export type Service = "Bundler" | "Paymaster"; - -export interface LightSigner { - getAddress(): Promise<string>; - signMessage(message: string | Uint8Array): Promise<string>; -} - -export type StateOverrideSet = { - [key: string]: { - balance?: string; - nonce?: string; - code?: string; - state?: object; - stateDiff?: object; - }; -}; diff --git a/packages/common/tsconfig.build.json b/packages/common/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/common/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json deleted file mode 100644 index d9b305a9a..000000000 --- a/packages/common/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node"] - }, - "include": ["src", "src/**/*.json"] -} diff --git a/packages/modules/.esbuild.js b/packages/modules/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/modules/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/modules/CHANGELOG.md b/packages/modules/CHANGELOG.md deleted file mode 100644 index 7c3d40af8..000000000 --- a/packages/modules/CHANGELOG.md +++ /dev/null @@ -1,64 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -VERSION Bump Only. - -## 4.1.0 (2023-04-03) - -VERSION Bump Only. - -## 4.0.3 (2023-28-02) - -VERSION Bump Only. - -## 4.0.2 (2023-26-02) - -VERSION Bump Only. - -## 4.0.1 (2023-02-22) - -VERSION Bump Only. - -## 4.0.0 (2024-02-12) - -### Features - -- Export module create aliases from modules package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00)) - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -### Bug Fixes - -- Update import paths for consistency and fixing build issues ([ec5c3a3](https://github.com/bcnmy/biconomy-client-sdk/pull/332/commits/ec5c3a352e8caab6e94234264f4cd5cb32e5af3f)) - -## 3.1.1 (2023-11-09) - -### Bug Fixes - -- Fix update batched session router address and signing logic ([107b881](https://github.com/bcnmy/biconomy-client-sdk/commit/107b881da4b1a6da1f9db22ac54eda62f8c05b59)) - -## 3.1.0 (2023-09-20) - -Modular Account Abstraction is here. - -### Bug Fixes - -- incorrect data merkleRoot length ([2e9d2dd](https://github.com/bcnmy/biconomy-client-sdk/commit/2e9d2dd5876a4de61af390d6595e1ab2cf8c137c)) -- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) -- more lint issues ([10df908](https://github.com/bcnmy/biconomy-client-sdk/commit/10df90821b473fd668907cf3e447dfe3825317fc)) -- signing issue ([f67e339](https://github.com/bcnmy/biconomy-client-sdk/commit/f67e339bcff8d9712df8406b4d123affcd4d4aa4)) -- sorting leaves always ([1fb908c](https://github.com/bcnmy/biconomy-client-sdk/commit/1fb908cb3b90abe4588c3a162ecf45c8afc80d81)) -- use hexZeroPad in leaf ([b3da05f](https://github.com/bcnmy/biconomy-client-sdk/commit/b3da05f2e9c56973e96d0a7a3bc065aef23f9c18)) -- use proof instead of root ([3a40a9d](https://github.com/bcnmy/biconomy-client-sdk/commit/3a40a9d8b9fb1fba8f660e5eab1fae1369f9f289)) - -### Features - -- add session key manager ([af41480](https://github.com/bcnmy/biconomy-client-sdk/commit/af41480ff1c88e2a4d0ee8605f2f01b3a958a1d9)) diff --git a/packages/modules/README.md b/packages/modules/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/modules/package.json b/packages/modules/package.json deleted file mode 100644 index 7d73de383..000000000 --- a/packages/modules/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "@biconomy/modules", - "version": "4.1.1", - "description": "This package provides different validation modules/plugins for ERC4337 compatible modular account", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "Smart Account", - "ERC-4337", - "Account Abstraction", - "Smart Contract Wallets", - "Biconomy", - "Modules", - "Plugins" - ], - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "test:file": "TS_NODE_PROJECT=../../tsconfig.json mocha -r ts-node/register --timeout 30000", - "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'", - "test:cov": "jest --coverage", - "test:run": "yarn test:file tests/**/*.spec.ts", - "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json" - }, - "author": "Biconomy", - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@alchemy/aa-core": "^3.1.1", - "@biconomy/common": "^4.1.1", - "@ethersproject/abi": "^5.7.0", - "merkletreejs": "^0.3.11", - "viem": "^2.7.12" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12", - "@biconomy/paymaster": "^4.1.1", - "@biconomy/modules": "^4.1.1" - } -} diff --git a/packages/modules/src/BaseValidationModule.ts b/packages/modules/src/BaseValidationModule.ts deleted file mode 100644 index 4f739f782..000000000 --- a/packages/modules/src/BaseValidationModule.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Hex } from "viem"; -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { BaseValidationModuleConfig, ModuleInfo } from "./utils/Types.js"; -import { DEFAULT_ENTRYPOINT_ADDRESS } from "./utils/Constants.js"; -import { IValidationModule } from "./interfaces/IValidationModule.js"; - -export abstract class BaseValidationModule implements IValidationModule { - entryPointAddress: Hex; - - constructor(moduleConfig: BaseValidationModuleConfig) { - const { entryPointAddress } = moduleConfig; - - this.entryPointAddress = entryPointAddress || DEFAULT_ENTRYPOINT_ADDRESS; - } - - abstract getAddress(): Hex; - - setEntryPointAddress(entryPointAddress: Hex): void { - this.entryPointAddress = entryPointAddress; - } - - abstract getInitData(): Promise<Hex>; - - // Anything required to get dummy signature can be passed as params - abstract getDummySignature(_params?: ModuleInfo): Promise<Hex>; - - abstract getSigner(): Promise<SmartAccountSigner>; - - // Signer specific or any other additional information can be passed as params - abstract signUserOpHash(_userOpHash: string, _params?: ModuleInfo): Promise<Hex>; - - abstract signMessage(_message: Uint8Array | string): Promise<string>; - - async signMessageSmartAccountSigner(_message: string | Uint8Array, signer: SmartAccountSigner): Promise<string> { - const message = typeof _message === "string" ? _message : { raw: _message }; - let signature: `0x${string}` = await signer.signMessage(message); - - const potentiallyIncorrectV = parseInt(signature.slice(-2), 16); - if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - signature = `0x${signature.slice(0, -2) + correctV.toString(16)}`; - } - - return signature; - } -} diff --git a/packages/modules/src/BatchedSessionRouterModule.ts b/packages/modules/src/BatchedSessionRouterModule.ts deleted file mode 100644 index cec1cddd4..000000000 --- a/packages/modules/src/BatchedSessionRouterModule.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { ModuleVersion, CreateSessionDataParams, BatchedSessionRouterModuleConfig, ModuleInfo, CreateSessionDataResponse } from "./utils/Types.js"; -import { - BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION, - DEFAULT_SESSION_KEY_MANAGER_MODULE, - DEFAULT_BATCHED_SESSION_ROUTER_MODULE, -} from "./utils/Constants.js"; -import { BaseValidationModule } from "./BaseValidationModule.js"; -import { SessionKeyManagerModule } from "./SessionKeyManagerModule.js"; -import { SessionSearchParam, SessionStatus } from "./interfaces/ISessionStorage.js"; -import { Hex, concat, encodeAbiParameters, keccak256, pad, parseAbiParameters, toBytes, toHex } from "viem"; -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { convertSigner } from "@biconomy/common"; -import { defaultAbiCoder } from "@ethersproject/abi"; - -export class BatchedSessionRouterModule extends BaseValidationModule { - version: ModuleVersion = "V1_0_0"; - - moduleAddress!: Hex; - - sessionManagerModuleAddress!: Hex; - - sessionKeyManagerModule!: SessionKeyManagerModule; - - readonly mockEcdsaSessionKeySig: Hex = - "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b"; - - /** - * This constructor is private. Use the static create method to instantiate SessionKeyManagerModule - * @param moduleConfig The configuration for the module - * @returns An instance of SessionKeyManagerModule - */ - private constructor(moduleConfig: BatchedSessionRouterModuleConfig) { - super(moduleConfig); - } - - /** - * Asynchronously creates and initializes an instance of SessionKeyManagerModule - * @param moduleConfig The configuration for the module - * @returns A Promise that resolves to an instance of SessionKeyManagerModule - */ - public static async create(moduleConfig: BatchedSessionRouterModuleConfig): Promise<BatchedSessionRouterModule> { - const instance = new BatchedSessionRouterModule(moduleConfig); - - if (moduleConfig.moduleAddress) { - instance.moduleAddress = moduleConfig.moduleAddress; - } else if (moduleConfig.version) { - const moduleAddr = BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex; - if (!moduleAddr) { - throw new Error(`Invalid version ${moduleConfig.version}`); - } - instance.moduleAddress = moduleAddr; - instance.version = moduleConfig.version as ModuleVersion; - } else { - instance.moduleAddress = DEFAULT_BATCHED_SESSION_ROUTER_MODULE; - // Note: in this case Version remains the default one - } - - instance.sessionManagerModuleAddress = moduleConfig.sessionManagerModuleAddress ?? DEFAULT_SESSION_KEY_MANAGER_MODULE; - - if (!moduleConfig.sessionKeyManagerModule) { - // generate sessionModule - const sessionModule = await SessionKeyManagerModule.create({ - moduleAddress: instance.sessionManagerModuleAddress, - smartAccountAddress: moduleConfig.smartAccountAddress, - storageType: moduleConfig.storageType, - }); - - instance.sessionKeyManagerModule = sessionModule; - } else { - instance.sessionKeyManagerModule = moduleConfig.sessionKeyManagerModule; - instance.sessionManagerModuleAddress = moduleConfig.sessionKeyManagerModule.getAddress(); - } - - return instance; - } - - /** - * Method to create session data for any module. The session data is used to create a leaf in the merkle tree - * @param leavesData The data of one or more leaves to be used to create session data - * @returns The session data - */ - createSessionData = async (leavesData: CreateSessionDataParams[]): Promise<CreateSessionDataResponse> => { - return this.sessionKeyManagerModule.createSessionData(leavesData); - }; - - /** - * This method is used to sign the user operation using the session signer - * @param userOp The user operation to be signed - * @param sessionParams Information about all the sessions to be used to sign the user operation which has a batch execution - * @returns The signature of the user operation - */ - async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise<Hex> { - const sessionParams = params?.batchSessionParams; - if (!sessionParams || sessionParams.length === 0) { - throw new Error("Session parameters are not provided"); - } - - const sessionDataTupleArray = []; - - // signer must be the same for all the sessions - const { signer: sessionSigner } = await convertSigner(sessionParams[0].sessionSigner, false); - - const signature = await sessionSigner.signMessage({ raw: toBytes(userOpHash) }); - - for (const sessionParam of sessionParams) { - if (!sessionParam.sessionSigner) { - throw new Error("Session signer is not provided."); - } - - const sessionDataTuple = []; - - let sessionSignerData; - - if (sessionParam.sessionID) { - sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({ - sessionID: sessionParam.sessionID, - }); - } else if (sessionParam.sessionValidationModule) { - sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({ - sessionValidationModule: sessionParam.sessionValidationModule, - sessionPublicKey: await sessionSigner.getAddress(), - }); - } else { - throw new Error("sessionID or sessionValidationModule should be provided."); - } - - sessionDataTuple.push(sessionSignerData.validUntil); - sessionDataTuple.push(sessionSignerData.validAfter); - sessionDataTuple.push(sessionSignerData.sessionValidationModule); - sessionDataTuple.push(sessionSignerData.sessionKeyData); - - const leafDataHex = concat([ - pad(toHex(sessionSignerData.validUntil), { size: 6 }), - pad(toHex(sessionSignerData.validAfter), { size: 6 }), - pad(sessionSignerData.sessionValidationModule, { size: 20 }), - sessionSignerData.sessionKeyData, - ]); - - const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(keccak256(leafDataHex)); - - sessionDataTuple.push(proof); - sessionDataTuple.push(sessionParam.additionalSessionData ?? "0x"); - - sessionDataTupleArray.push(sessionDataTuple); - } - - // Generate the padded signature - - const paddedSignature = defaultAbiCoder.encode( - ["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"], - [this.getSessionKeyManagerAddress(), sessionDataTupleArray, signature], - ); - - return paddedSignature as Hex; - } - - /** - * Update the session data pending state to active - * @param param The search param to find the session data - * @param status The status to be updated - * @returns - */ - async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise<void> { - this.sessionKeyManagerModule.sessionStorageClient.updateSessionStatus(param, status); - } - - /** - * @remarks This method is used to clear all the pending sessions - * @returns - */ - async clearPendingSessions(): Promise<void> { - this.sessionKeyManagerModule.sessionStorageClient.clearPendingSessions(); - } - - /** - * @returns SessionKeyManagerModule address - */ - getAddress(): Hex { - return this.moduleAddress; - } - - /** - * @returns SessionKeyManagerModule address - */ - getSessionKeyManagerAddress(): Hex { - return this.sessionManagerModuleAddress; - } - - /** - * @remarks This is the version of the module contract - */ - async getSigner(): Promise<SmartAccountSigner> { - throw new Error("Method not implemented."); - } - - /** - * @remarks This is the dummy signature for the module, used in buildUserOp for bundler estimation - * @returns Dummy signature - */ - async getDummySignature(params?: ModuleInfo): Promise<Hex> { - const sessionParams = params?.batchSessionParams; - if (!sessionParams || sessionParams.length === 0) { - throw new Error("Session parameters are not provided"); - } - - const sessionDataTupleArray = []; - - // if needed we could do mock signature over userOpHashAndModuleAddress - - // signer must be the same for all the sessions - const { signer: sessionSigner } = await convertSigner(sessionParams[0].sessionSigner, false); - - for (const sessionParam of sessionParams) { - if (!sessionParam.sessionSigner) { - throw new Error("Session signer is not provided."); - } - - const sessionDataTuple = []; - - let sessionSignerData; - - if (sessionParam.sessionID) { - sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({ - sessionID: sessionParam.sessionID, - }); - } else if (sessionParam.sessionValidationModule) { - sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({ - sessionValidationModule: sessionParam.sessionValidationModule, - sessionPublicKey: await sessionSigner.getAddress(), - }); - } else { - throw new Error("sessionID or sessionValidationModule should be provided."); - } - - sessionDataTuple.push(BigInt(sessionSignerData.validUntil)); - sessionDataTuple.push(BigInt(sessionSignerData.validAfter)); - sessionDataTuple.push(sessionSignerData.sessionValidationModule); - sessionDataTuple.push(sessionSignerData.sessionKeyData); - - const leafDataHex = concat([ - pad(toHex(sessionSignerData.validUntil), { size: 6 }), - pad(toHex(sessionSignerData.validAfter), { size: 6 }), - pad(sessionSignerData.sessionValidationModule, { size: 20 }), - sessionSignerData.sessionKeyData, - ]); - - const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(keccak256(leafDataHex)); - - sessionDataTuple.push(proof); - sessionDataTuple.push(sessionParam.additionalSessionData ?? "0x"); - - sessionDataTupleArray.push(sessionDataTuple); - } - - // Generate the padded signature - const paddedSignature = defaultAbiCoder.encode( - ["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"], - [this.getSessionKeyManagerAddress(), sessionDataTupleArray, this.mockEcdsaSessionKeySig], - ); - - const dummySig = encodeAbiParameters(parseAbiParameters("bytes, address"), [paddedSignature as Hex, this.getAddress()]); - return dummySig; - } - - /** - * @remarks Other modules may need additional attributes to build init data - */ - async getInitData(): Promise<Hex> { - throw new Error("Method not implemented."); - } - - /** - * @remarks This Module dont have knowledge of signer. So, this method is not implemented - */ - async signMessage(_message: Uint8Array | string): Promise<string> { - throw new Error("Method not implemented."); - } -} diff --git a/packages/modules/src/MultichainValidationModule.ts b/packages/modules/src/MultichainValidationModule.ts deleted file mode 100644 index 0846b0f83..000000000 --- a/packages/modules/src/MultichainValidationModule.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Hex, concat, encodeAbiParameters, encodeFunctionData, getAddress, keccak256, pad, parseAbi, parseAbiParameters, toBytes, toHex } from "viem"; -import { UserOperationStruct, SmartAccountSigner } from "@alchemy/aa-core"; -import { MerkleTree } from "merkletreejs"; -import { DEFAULT_MULTICHAIN_MODULE, MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION } from "./utils/Constants.js"; -import { - ModuleVersion, - MultiChainUserOpDto, - MultiChainValidationModuleConfig, - MultiChainValidationModuleConfigConstructorProps, -} from "./utils/Types.js"; -import { BaseValidationModule } from "./BaseValidationModule.js"; -import { getUserOpHash } from "./utils/Helper.js"; -import { convertSigner, Logger } from "@biconomy/common"; - -export class MultiChainValidationModule extends BaseValidationModule { - signer: SmartAccountSigner; - - moduleAddress!: Hex; - - version: ModuleVersion = "V1_0_0"; - - private constructor(moduleConfig: MultiChainValidationModuleConfigConstructorProps) { - super(moduleConfig); - this.signer = moduleConfig.signer; - } - - public static async create(moduleConfig: MultiChainValidationModuleConfig): Promise<MultiChainValidationModule> { - // Signer needs to be initialised here before defaultValidationModule is set - const { signer } = await convertSigner(moduleConfig.signer, false); - const configForConstructor: MultiChainValidationModuleConfigConstructorProps = { ...moduleConfig, signer }; - - // TODO: (Joe) stop doing things in a 'create' call after the instance has been created - const instance = new MultiChainValidationModule(configForConstructor); - if (moduleConfig.moduleAddress) { - instance.moduleAddress = moduleConfig.moduleAddress; - } else if (moduleConfig.version) { - const moduleAddr = MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex; - if (!moduleAddr) { - throw new Error(`Invalid version ${moduleConfig.version}`); - } - instance.moduleAddress = moduleAddr; - instance.version = moduleConfig.version as ModuleVersion; - } else { - instance.moduleAddress = DEFAULT_MULTICHAIN_MODULE; - // Note: in this case Version remains the default one - } - return instance; - } - - getAddress(): Hex { - return this.moduleAddress; - } - - async getSigner(): Promise<SmartAccountSigner> { - return Promise.resolve(this.signer); - } - - async getDummySignature(): Promise<Hex> { - const moduleAddress = getAddress(this.getAddress()); - const dynamicPart = moduleAddress.substring(2).padEnd(40, "0"); - return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000`; - } - - // Note: other modules may need additional attributes to build init data - async getInitData(): Promise<Hex> { - const ecdsaOwnerAddress = await this.signer.getAddress(); - const moduleRegistryParsedAbi = parseAbi(["function initForSmartAccount(address owner)"]); - const ecdsaOwnershipInitData = encodeFunctionData({ - abi: moduleRegistryParsedAbi, - functionName: "initForSmartAccount", - args: [ecdsaOwnerAddress], - }); - return ecdsaOwnershipInitData; - } - - async signUserOpHash(userOpHash: string): Promise<Hex> { - const sig = await this.signer.signMessage({ raw: toBytes(userOpHash) }); - return sig; - } - - /** - * Signs a message using the appropriate method based on the type of signer. - * - * @param {Uint8Array | string} message - The message to be signed. - * @returns {Promise<string>} A promise resolving to the signature or error message. - * @throws {Error} If the signer type is invalid or unsupported. - */ - async signMessage(_message: Uint8Array | string): Promise<string> { - const message = typeof _message === "string" ? _message : { raw: _message }; - let signature = await this.signer.signMessage(message); - - const potentiallyIncorrectV = parseInt(signature.slice(-2), 16); - if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - signature = signature.slice(0, -2) + correctV.toString(16); - } - return signature; - } - - async signUserOps(multiChainUserOps: MultiChainUserOpDto[]): Promise<UserOperationStruct[]> { - try { - const leaves: string[] = []; - - // Iterate over each userOp and process them - for (const multiChainOp of multiChainUserOps) { - const validUntil = multiChainOp.validUntil ?? 0; - const validAfter = multiChainOp.validAfter ?? 0; - const leaf = concat([ - pad(toHex(validUntil), { size: 6 }), - pad(toHex(validAfter), { size: 6 }), - pad(getUserOpHash(multiChainOp.userOp, this.entryPointAddress, multiChainOp.chainId), { size: 32 }), - ]); - - leaves.push(keccak256(leaf)); - } - - // Create a new Merkle tree using the leaves array - const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }); - - let multichainSignature = await this.signer.signMessage({ raw: toBytes(merkleTree.getHexRoot()) }); - - const potentiallyIncorrectV = parseInt(multichainSignature.slice(-2), 16); - if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - multichainSignature = multichainSignature.slice(0, -2) + correctV.toString(16); - } - - // Create an array to store updated userOps - const updatedUserOps: UserOperationStruct[] = []; - - for (let i = 0; i < leaves.length; i++) { - const merkleProof = merkleTree.getHexProof(leaves[i]); - - const validUntil = multiChainUserOps[i].validUntil ?? 0; - const validAfter = multiChainUserOps[i].validAfter ?? 0; - - // Create the moduleSignature - const moduleSignature = encodeAbiParameters(parseAbiParameters(["uint48, uint48, bytes32, bytes32[], bytes"]), [ - validUntil, - validAfter, - merkleTree.getHexRoot() as Hex, - merkleProof as Hex[], - multichainSignature as Hex, - ]); - - // Note: Because accountV2 does not directly call this method. hence we need to add validation module address to the signature - const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters(["bytes, address"]), [moduleSignature, this.getAddress()]); - - // Update userOp with the final signature - const updatedUserOp: UserOperationStruct = { - ...(multiChainUserOps[i].userOp as UserOperationStruct), - signature: signatureWithModuleAddress as `0x${string}`, - }; - - updatedUserOps.push(updatedUserOp); - } - return updatedUserOps; - } catch (error) { - Logger.error("Error in signing multi chain userops"); - throw new Error(JSON.stringify(error)); - } - } -} diff --git a/packages/modules/src/index.ts b/packages/modules/src/index.ts deleted file mode 100644 index ca954778b..000000000 --- a/packages/modules/src/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -export * from "./utils/Types.js"; -export * from "./utils/Constants.js"; -export * from "./interfaces/IValidationModule.js"; -export * from "./interfaces/ISessionValidationModule.js"; -export * from "./BaseValidationModule.js"; -export * from "./ECDSAOwnershipValidationModule.js"; -export * from "./MultichainValidationModule.js"; -export * from "./SessionKeyManagerModule.js"; -export * from "./BatchedSessionRouterModule.js"; -export * from "./session-validation-modules/ERC20SessionValidationModule.js"; - -import { - BatchedSessionRouterModule, - ECDSAOwnershipValidationModule, - MultiChainValidationModule, - SessionKeyManagerModule, - ERC20SessionValidationModule, -} from "./index.js"; - -export const createBatchedSessionRouterModule = BatchedSessionRouterModule.create; -export const createMultiChainValidationModule = MultiChainValidationModule.create; -export const createECDSAOwnershipValidationModule = ECDSAOwnershipValidationModule.create; -export const createSessionKeyManagerModule = SessionKeyManagerModule.create; -export const createERC20SessionValidationModule = ERC20SessionValidationModule.create; - -// export * from './PasskeyValidationModule' diff --git a/packages/modules/src/interfaces/IValidationModule.ts b/packages/modules/src/interfaces/IValidationModule.ts deleted file mode 100644 index ee3da28a9..000000000 --- a/packages/modules/src/interfaces/IValidationModule.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { Hex } from "viem"; - -export interface IValidationModule { - getAddress(): Hex; - getInitData(): Promise<Hex>; - getSigner(): Promise<SmartAccountSigner>; - signUserOpHash(_userOpHash: string): Promise<Hex>; - signMessage(_message: string | Uint8Array): Promise<string>; - getDummySignature(): Promise<Hex>; -} diff --git a/packages/modules/src/session-storage/SessionLocalStorage.ts b/packages/modules/src/session-storage/SessionLocalStorage.ts deleted file mode 100644 index 97a1d6953..000000000 --- a/packages/modules/src/session-storage/SessionLocalStorage.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { Hex, createWalletClient, http, toHex } from "viem"; -import { SmartAccountSigner, WalletClientSigner } from "@alchemy/aa-core"; -import { ISessionStorage, SessionLeafNode, SessionSearchParam, SessionStatus } from "../interfaces/ISessionStorage.js"; -import { mainnet } from "viem/chains"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; -import { SignerData } from "../utils/Types.js"; - -export class SessionLocalStorage implements ISessionStorage { - private smartAccountAddress: string; - - constructor(smartAccountAddress: string) { - this.smartAccountAddress = smartAccountAddress.toLowerCase(); - } - - private validateSearchParam(param: SessionSearchParam): void { - if (param.sessionID) { - return; - } else if (!param.sessionID && param.sessionPublicKey && param.sessionValidationModule) { - return; - } else { - throw new Error("Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address."); - } - } - - private getSessionStore(): any { - // @ts-ignore: LocalStorage is not available in node - const data = localStorage.getItem(this.getStorageKey("sessions")); - return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] }; - } - - private getSignerStore(): any { - // @ts-ignore: LocalStorage is not available in node - const data = localStorage.getItem(this.getStorageKey("signers")); - return data ? JSON.parse(data) : {}; - } - - private getStorageKey(type: "sessions" | "signers"): string { - return `${this.smartAccountAddress}_${type}`; - } - - private toLowercaseAddress(address: string): string { - return address.toLowerCase(); - } - - async addSessionData(leaf: SessionLeafNode): Promise<void> { - const data = this.getSessionStore(); - leaf.sessionValidationModule = this.toLowercaseAddress(leaf.sessionValidationModule) as Hex; - leaf.sessionPublicKey = this.toLowercaseAddress(leaf.sessionPublicKey) as Hex; - data.leafNodes.push(leaf); - // @ts-ignore: LocalStorage is not available in node - localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)); - } - - async getSessionData(param: SessionSearchParam): Promise<SessionLeafNode> { - this.validateSearchParam(param); - - const sessions = this.getSessionStore().leafNodes; - const session = sessions.find((s: SessionLeafNode) => { - if (param.sessionID) { - return s.sessionID === param.sessionID && (!param.status || s.status === param.status); - } else if (param.sessionPublicKey && param.sessionValidationModule) { - return ( - s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) && - s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) && - (!param.status || s.status === param.status) - ); - } else { - return undefined; - } - }); - - if (!session) { - throw new Error("Session not found."); - } - return session; - } - - async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise<void> { - this.validateSearchParam(param); - - const data = this.getSessionStore(); - const session = data.leafNodes.find((s: SessionLeafNode) => { - if (param.sessionID) { - return s.sessionID === param.sessionID; - } else if (param.sessionPublicKey && param.sessionValidationModule) { - return ( - s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) && - s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) - ); - } else { - return undefined; - } - }); - - if (!session) { - throw new Error("Session not found."); - } - - session.status = status; - // @ts-ignore: LocalStorage is not available in node - localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)); - } - - async clearPendingSessions(): Promise<void> { - const data = this.getSessionStore(); - data.leafNodes = data.leafNodes.filter((s: SessionLeafNode) => s.status !== "PENDING"); - // @ts-ignore: LocalStorage is not available in node - localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)); - } - - async addSigner(signerData: SignerData): Promise<SmartAccountSigner> { - const signers = this.getSignerStore(); - let signer: SignerData; - if (!signerData) { - const pkey = generatePrivateKey(); - signer = { - pvKey: pkey, - pbKey: privateKeyToAccount(pkey).publicKey, - }; - } else { - signer = signerData; - } - const accountSigner = privateKeyToAccount(toHex(signer.pvKey)); - const client = createWalletClient({ - account: accountSigner, - chain: signerData.chainId, - transport: http(), - }); - const walletClientSigner = new WalletClientSigner( - client, - "json-rpc", // signerType - ); - signers[this.toLowercaseAddress(accountSigner.address)] = signerData; - // @ts-ignore: LocalStorage is not available in node - localStorage.setItem(this.getStorageKey("signers"), JSON.stringify(signers)); - return walletClientSigner; - } - - async getSignerByKey(sessionPublicKey: string): Promise<SmartAccountSigner> { - const signers = this.getSignerStore(); - const signerData = signers[this.toLowercaseAddress(sessionPublicKey)]; - if (!signerData) { - throw new Error("Signer not found."); - } - const account = privateKeyToAccount(signerData.privateKey); - const client = createWalletClient({ - account, - chain: mainnet, - transport: http(), - }); - const signer = new WalletClientSigner(client, "viem"); - return signer; - } - - async getSignerBySession(param: SessionSearchParam): Promise<SmartAccountSigner> { - const session = await this.getSessionData(param); - return this.getSignerByKey(session.sessionPublicKey); - } - - async getAllSessionData(param?: SessionSearchParam): Promise<SessionLeafNode[]> { - const sessions = this.getSessionStore().leafNodes; - if (!param || !param.status) { - return sessions; - } - return sessions.filter((s: SessionLeafNode) => s.status === param.status); - } - - async getMerkleRoot(): Promise<string> { - return this.getSessionStore().merkleRoot; - } - - setMerkleRoot(merkleRoot: string): Promise<void> { - const data = this.getSessionStore(); - data.merkleRoot = merkleRoot; - // @ts-ignore: LocalStorage is not available in node - localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)); - return Promise.resolve(); - } -} diff --git a/packages/modules/src/utils/Constants.ts b/packages/modules/src/utils/Constants.ts deleted file mode 100644 index 7a2a308fa..000000000 --- a/packages/modules/src/utils/Constants.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ModuleVersion } from "./Types.js"; - -export const DEFAULT_MODULE_VERSION: ModuleVersion = "V1_0_0"; - -export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789"; -export const ENTRYPOINT_ADDRESSES = { - "0x27a4db290b89ae3373ce4313cbeae72112ae7da9": "V0_0_5", - "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789": "V0_0_6", -}; - -export const ENTRYPOINT_ADDRESSES_BY_VERSION = { - V0_0_5: "0x27a4db290b89ae3373ce4313cbeae72112ae7da9", - V0_0_6: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", -}; - -// Note: we could append these defaults with ADDRESS suffix -export const DEFAULT_ECDSA_OWNERSHIP_MODULE = "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e"; - -export const ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION = { - V1_0_0: "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", -}; - -export const DEFAULT_SESSION_KEY_MANAGER_MODULE = "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489"; - -export const SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION = { - V1_0_0: "0x000000456b395c4e107e0302553B90D1eF4a32e9", - V1_0_1: "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489", -}; - -export const DEFAULT_BATCHED_SESSION_ROUTER_MODULE = "0x00000D09967410f8C76752A104c9848b57ebba55"; - -export const BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION = { - V1_0_0: "0x00000D09967410f8C76752A104c9848b57ebba55", -}; - -export const DEFAULT_ERC20_MODULE = "0x000000D50C68705bd6897B2d17c7de32FB519fDA"; - -export const DEFAULT_MULTICHAIN_MODULE = "0x000000824dc138db84FD9109fc154bdad332Aa8E"; - -export const MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION = { - V1_0_0: "0x000000824dc138db84FD9109fc154bdad332Aa8E", -}; - -// similarly others here or in module / signer classes -// Mapping / Reverse mapping of version -> module address can be kept here - -export const ERC20_ABI = [ - "function transfer(address to, uint256 value) external returns (bool)", - "function transferFrom(address from, address to, uint256 value) external returns (bool)", - "function approve(address spender, uint256 value) external returns (bool)", - "function allowance(address owner, address spender) external view returns (uint256)", - "function balanceOf(address owner) external view returns (uint256)", -]; diff --git a/packages/modules/src/utils/Helper.ts b/packages/modules/src/utils/Helper.ts deleted file mode 100644 index b0b6fc43d..000000000 --- a/packages/modules/src/utils/Helper.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { UserOperationStruct } from "@alchemy/aa-core"; -import { Hex, encodeAbiParameters, keccak256, parseAbiParameters, concat, pad, toHex } from "viem"; - -export interface Rule { - offset: number; - condition: number; - referenceValue: `0x${string}`; -} - -export interface Permission { - destContract: `0x${string}`; - functionSelector: `0x${string}`; - valueLimit: bigint; - rules: Rule[]; -} - -function packUserOp(op: Partial<UserOperationStruct>, forSignature = true): string { - if (!op.initCode || !op.callData || !op.paymasterAndData) throw new Error("Missing userOp properties"); - if (forSignature) { - return encodeAbiParameters(parseAbiParameters("address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32"), [ - op.sender as Hex, - BigInt(op.nonce as Hex), - keccak256(op.initCode as Hex), - keccak256(op.callData as Hex), - BigInt(op.callGasLimit as Hex), - BigInt(op.verificationGasLimit as Hex), - BigInt(op.preVerificationGas as Hex), - BigInt(op.maxFeePerGas as Hex), - BigInt(op.maxPriorityFeePerGas as Hex), - keccak256(op.paymasterAndData as Hex), - ]); - } else { - // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) - return encodeAbiParameters(parseAbiParameters("address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes"), [ - op.sender as Hex, - BigInt(op.nonce as Hex), - op.initCode as Hex, - op.callData as Hex, - BigInt(op.callGasLimit as Hex), - BigInt(op.verificationGasLimit as Hex), - BigInt(op.preVerificationGas as Hex), - BigInt(op.maxFeePerGas as Hex), - BigInt(op.maxPriorityFeePerGas as Hex), - op.paymasterAndData as Hex, - op.signature as Hex, - ]); - } -} - -export const getUserOpHash = (userOp: Partial<UserOperationStruct>, entryPointAddress: Hex, chainId: number): Hex => { - const userOpHash = keccak256(packUserOp(userOp, true) as Hex); - const enc = encodeAbiParameters(parseAbiParameters("bytes32, address, uint256"), [userOpHash, entryPointAddress, BigInt(chainId)]); - return keccak256(enc); -}; - -export async function getABISVMSessionKeyData(sessionKey: `0x${string}` | Uint8Array, permission: Permission): Promise<`0x${string}` | Uint8Array> { - let sessionKeyData = concat([ - sessionKey, - permission.destContract, - permission.functionSelector, - pad(toHex(permission.valueLimit), { size: 16 }), - pad(toHex(permission.rules.length), { size: 2 }), // this can't be more 2**11 (see below), so uint16 (2 bytes) is enough - ]) as `0x${string}`; - - for (let i = 0; i < permission.rules.length; i++) { - sessionKeyData = concat([ - sessionKeyData, - pad(toHex(permission.rules[i].offset), { size: 2 }), // offset is uint16, so there can't be more than 2**16/32 args = 2**11 - pad(toHex(permission.rules[i].condition), { size: 1 }), // uint8 - permission.rules[i].referenceValue, - ]); - } - return sessionKeyData; -} diff --git a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts b/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts deleted file mode 100644 index 53b1c4027..000000000 --- a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { - DEFAULT_BATCHED_SESSION_ROUTER_MODULE, - DEFAULT_SESSION_KEY_MANAGER_MODULE, - createBatchedSessionRouterModule, - createSessionKeyManagerModule, -} from "@biconomy/modules"; -import { SessionFileStorage } from "./utils/customSession"; -import { WalletClientSigner, createSmartAccountClient } from "../../account/src/index"; -import { encodeAbiParameters, encodeFunctionData, parseAbi, parseUnits } from "viem"; -import { TestData } from "../../../tests"; -import { checkBalance } from "../../../tests/utils"; -import { PaymasterMode } from "@biconomy/paymaster"; -import { Logger } from "@biconomy/common"; - -describe("Batched Session Router Tests", () => { - let mumbai: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai] = testDataPerChain; - }); - - // TODO(Gabi): Fix Batched Session Router Module tests - it.skip("Should send a user op using Batched Session Validation Module", async () => { - let sessionSigner: WalletClientSigner; - - const { - whale: { - account: { address: sessionKeyEOA }, - privateKey: pvKey, - viemWallet, - }, - minnow: { publicAddress: recipient }, - publicClient, - bundlerUrl, - biconomyPaymasterApiKey, - chainId, - viemChain, - } = mumbai; - - // Create smart account - let smartAccount = await createSmartAccountClient({ - signer: viemWallet, - bundlerUrl, - biconomyPaymasterApiKey, - index: 3, // Increasing index to not conflict with other test cases and use a new smart account - }); - - const smartAccountAddress = await smartAccount.getAddress(); - - const sessionFileStorage: SessionFileStorage = new SessionFileStorage(smartAccountAddress); - - try { - sessionSigner = await sessionFileStorage.getSignerByKey(sessionKeyEOA); - } catch (error) { - sessionSigner = await sessionFileStorage.addSigner({ pbKey: sessionKeyEOA, pvKey, chainId: viemChain }); - } - - expect(sessionSigner).toBeTruthy(); - - const smartAccountAddress = await smartAccount.getAddress(); - Logger.log("Smart Account Address: ", smartAccountAddress); - - // First we need to check if smart account is deployed - // if not deployed, send an empty transaction to deploy it - const isDeployed = await smartAccount.isAccountDeployed(); - - if (!isDeployed) { - const { wait } = await smartAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); - const { success } = await wait(); - expect(success).toBe("true"); - } - - // Create session module - const sessionModule = await createSessionKeyManagerModule({ - moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE, - smartAccountAddress, - sessionStorageClient: sessionFileStorage, - }); - - // Create batched session module - const batchedSessionModule = await createBatchedSessionRouterModule({ - moduleAddress: DEFAULT_BATCHED_SESSION_ROUTER_MODULE, - smartAccountAddress, - sessionKeyManagerModule: sessionModule, - }); - - // Set enabled call on session, only allows calling USDC contract transfer with <= 10 USDC - const sessionKeyData = encodeAbiParameters( - [{ type: "address" }, { type: "address" }, { type: "address" }, { type: "uint256" }], - [ - sessionKeyEOA, - "0xdA5289fCAAF71d52a80A254da614a192b693e977", // erc20 token address - recipient, // receiver address - parseUnits("10", 6), - ], - ); - - // only requires that the caller is the session key - // can call anything using the mock session module - const sessionKeyData2 = encodeAbiParameters([{ type: "address" }], [sessionKeyEOA]); - - const erc20ModuleAddr = "0x000000D50C68705bd6897B2d17c7de32FB519fDA"; - const mockSessionModuleAddr = "0x7Ba4a7338D7A90dfA465cF975Cc6691812C3772E"; - - const sessionTxData = await batchedSessionModule.createSessionData([ - { - validUntil: 0, - validAfter: 0, - sessionValidationModule: erc20ModuleAddr, - sessionPublicKey: sessionKeyEOA, - sessionKeyData: sessionKeyData, - }, - { - validUntil: 0, - validAfter: 0, - sessionValidationModule: mockSessionModuleAddr, - sessionPublicKey: sessionKeyEOA, - sessionKeyData: sessionKeyData2, - }, - ]); - - const setSessionAllowedTrx = { - to: DEFAULT_SESSION_KEY_MANAGER_MODULE, - data: sessionTxData.data, - }; - - const txArray: any = []; - - // Check if session module is enabled - const isEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE); - if (!isEnabled) { - const enableModuleTrx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE); - txArray.push(enableModuleTrx); - } - - // Check if batched session module is enabled - const isBRMenabled = await smartAccount.isModuleEnabled(DEFAULT_BATCHED_SESSION_ROUTER_MODULE); - if (!isBRMenabled) { - // -----> enableModule batched session router module - const tx2 = await smartAccount.getEnableModuleData(DEFAULT_BATCHED_SESSION_ROUTER_MODULE); - txArray.push(tx2); - } - - txArray.push(setSessionAllowedTrx); - - const userOpResponse1 = await smartAccount.sendTransaction(txArray, { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); // this user op will enable the modules and setup session allowed calls - const transactionDetails = await userOpResponse1.wait(); - expect(transactionDetails.success).toBe("true"); - Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash); - - const usdcBalance = await checkBalance(publicClient, smartAccountAddress, "0xdA5289fCAAF71d52a80A254da614a192b693e977"); - expect(usdcBalance).toBeGreaterThan(0); - - smartAccount = smartAccount.setActiveValidationModule(batchedSessionModule); - - // WARNING* If the smart account does not have enough USDC, user op execution will FAIL - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function transfer(address _to, uint256 _value)"]), - functionName: "transfer", - args: [recipient, parseUnits("0.001", 6)], - }); - - const encodedCall2 = encodeFunctionData({ - abi: parseAbi(["function transfer(address _to, uint256 _value)"]), - functionName: "transfer", - args: ["0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", parseUnits("0.001", 6)], - }); - - const transferTx = { - to: "0xdA5289fCAAF71d52a80A254da614a192b693e977", - data: encodedCall, - }; - - const transferTx2 = { - to: "0xdA5289fCAAF71d52a80A254da614a192b693e977", - data: encodedCall2, - }; - - const activeModule = smartAccount.activeValidationModule; - expect(activeModule).toEqual(batchedSessionModule); - - const maticBalanceBefore = await checkBalance(publicClient, smartAccountAddress); - - // failing with dummyTx because of invalid sessionKeyData - const userOpResponse2 = await smartAccount.sendTransaction([transferTx, transferTx2], { - params: { - batchSessionParams: [ - { - sessionSigner: sessionSigner, - sessionValidationModule: erc20ModuleAddr, - }, - { - sessionSigner: sessionSigner, - sessionValidationModule: mockSessionModuleAddr, - }, - ], - }, - paymasterServiceData: { - mode: PaymasterMode.SPONSORED, - }, - }); - - const receipt = await userOpResponse2.wait(); - console.log(receipt.userOpHash, "Batched user op hash"); - expect(receipt.success).toBe("true"); - - expect(userOpResponse2.userOpHash).toBeTruthy(); - expect(userOpResponse2.userOpHash).not.toBeNull(); - - const maticBalanceAfter = await checkBalance(publicClient, smartAccountAddress); - - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); - }, 60000); -}); diff --git a/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts b/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts deleted file mode 100644 index 84b3f627e..000000000 --- a/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { PaymasterMode } from "@biconomy/paymaster"; -import { TestData } from "../../../tests"; -import { createSmartAccountClient } from "../../account/src/index"; -import { Hex, encodeFunctionData, parseAbi } from "viem"; -import { DEFAULT_MULTICHAIN_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules"; - -describe("Account with ECDSAOwnershipValidationModule Module Tests", () => { - let mumbai: TestData; - let baseSepolia: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai, baseSepolia] = testDataPerChain; - }); - - it("should create a ECDSAOwnershipValidationModule with signer", async () => { - const { - bundlerUrl, - whale: { viemWallet: signer }, - } = mumbai; - - const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer }); - // Should not require a signer or chainId - const smartAccount = await createSmartAccountClient({ - bundlerUrl, - defaultValidationModule, - signer, - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule); - }); - - it("should create a ECDSAOwnershipValidationModule without signer", async () => { - const { - bundlerUrl, - whale: { viemWallet: signer }, - } = mumbai; - - const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer }); - // Should not require a signer or chainId - const smartAccount = await createSmartAccountClient({ - bundlerUrl, - defaultValidationModule, - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule); - }); - - it("should create a ECDSAOwnershipValidationModule by default, without explicitly setting it on the smart account", async () => { - const { - bundlerUrl, - whale: { viemWallet: signer }, - } = mumbai; - const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer }); - const smartAccount = await createSmartAccountClient({ bundlerUrl, signer }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - const smartAccountValidationModuleAddress = await smartAccount.activeValidationModule.getAddress(); - expect(smartAccountValidationModuleAddress).toEqual(defaultValidationModule.moduleAddress); - }); -}); diff --git a/packages/modules/tests/modules.e2e.spec.ts b/packages/modules/tests/modules.e2e.spec.ts deleted file mode 100644 index 9de6d50ee..000000000 --- a/packages/modules/tests/modules.e2e.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { TestData } from "../../../tests"; -import { PaymasterMode, Transaction, createSmartAccountClient } from "@biconomy/account"; -import { DEFAULT_BATCHED_SESSION_ROUTER_MODULE, DEFAULT_ERC20_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE } from "../src"; - -describe("Account Tests", () => { - let mumbai: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [mumbai] = testDataPerChain; - }); - - it("should enable batched module", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = mumbai; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const isBRMenabled = await smartAccount.isModuleEnabled(DEFAULT_BATCHED_SESSION_ROUTER_MODULE); - - if (!isBRMenabled) { - const tx = await smartAccount.getEnableModuleData(DEFAULT_BATCHED_SESSION_ROUTER_MODULE); - const { wait } = await smartAccount.sendTransaction(tx, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - }); - const { success } = await wait(); - expect(success).toBe("true"); - } - }, 50000); - - it("should enable session module", async () => { - const { - whale: { viemWallet: signer }, - bundlerUrl, - biconomyPaymasterApiKey, - } = mumbai; - - const smartAccount = await createSmartAccountClient({ - signer, - bundlerUrl, - biconomyPaymasterApiKey, - }); - - const isSessionKeyEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE); - - if (!isSessionKeyEnabled) { - const tx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE); - const { wait } = await smartAccount.sendTransaction(tx, { - paymasterServiceData: { mode: PaymasterMode.SPONSORED }, - }); - const { success } = await wait(); - expect(success).toBe("true"); - } - }, 50000); -}); diff --git a/packages/modules/tests/modules.spec.ts b/packages/modules/tests/modules.spec.ts deleted file mode 100644 index a799a6760..000000000 --- a/packages/modules/tests/modules.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { TestData } from "../../../tests"; -import { createSmartAccountClient } from "@biconomy/account"; -import { createECDSAOwnershipValidationModule, createMultiChainValidationModule } from "../src"; - -describe("Account Tests", () => { - let ganache: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [ganache] = testDataPerChain; - }); - - it("should create a MultiChainValidationModule from an ethers signer using convertSigner", async () => { - const { - bundlerUrl, - whale: { ethersSigner: signer }, - viemChain, - } = ganache; - - const defaultValidationModule = await createMultiChainValidationModule({ signer }); - // Should not require a signer or chainId - const smartAccount = await createSmartAccountClient({ bundlerUrl, defaultValidationModule, rpcUrl: viemChain.rpcUrls.default.http[0], }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - // expect the relevant module to be set - expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule); - }, 50000); - - it("should create a ECDSAOwnershipValidationModule from a viem signer using convertSigner", async () => { - const { - bundlerUrl, - whale: { viemWallet: signer }, - viemChain, - } = ganache; - - const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer }); - // Should not require a signer or chainId - const smartAccount = await createSmartAccountClient({ - bundlerUrl, - defaultValidationModule, - rpcUrl: viemChain.rpcUrls.default.http[0], - }); - const address = await smartAccount.getAccountAddress(); - expect(address).toBeTruthy(); - // expect the relevant module to be set - expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule); - }, 50000); -}); diff --git a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts b/packages/modules/tests/multiChainValidationModule.e2e.spec.ts deleted file mode 100644 index 996be004c..000000000 --- a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { PaymasterMode } from "@biconomy/paymaster"; -import { TestData } from "../../../tests"; -import { createSmartAccountClient } from "../../account/src/index"; -import { Hex, encodeFunctionData, parseAbi } from "viem"; -import { DEFAULT_MULTICHAIN_MODULE, MultiChainValidationModule } from "@biconomy/modules"; -import { Logger } from "@biconomy/common"; - -describe("MultiChainValidation Module Tests", () => { - let mumbai: TestData; - let baseSepolia: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai, baseSepolia] = testDataPerChain; - }); - - it("Should mint an NFT gasless on baseSepolia and mumbai", async () => { - const { - whale: { alchemyWalletClientSigner: signerMumbai, publicAddress: recipientForBothChains }, - paymasterUrl: biconomyPaymasterApiKeyMumbai, - bundlerUrl: bundlerUrlMumbai, - chainId: chainIdMumbai, - } = mumbai; - - const { - whale: { alchemyWalletClientSigner: signerBase }, - paymasterUrl: biconomyPaymasterApiKeyBase, - bundlerUrl: bundlerUrlBase, - chainId: chainIdBase, - } = baseSepolia; - - const nftAddress: Hex = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e"; - - const multiChainModule = await MultiChainValidationModule.create({ - signer: signerMumbai, - moduleAddress: DEFAULT_MULTICHAIN_MODULE, - }); - - const [polygonAccount, baseAccount] = await Promise.all([ - createSmartAccountClient({ - chainId: chainIdMumbai, - signer: signerMumbai, - bundlerUrl: bundlerUrlMumbai, - defaultValidationModule: multiChainModule, - activeValidationModule: multiChainModule, - paymasterUrl: biconomyPaymasterApiKeyMumbai, - }), - createSmartAccountClient({ - chainId: chainIdBase, - signer: signerBase, - bundlerUrl: bundlerUrlBase, - defaultValidationModule: multiChainModule, - activeValidationModule: multiChainModule, - paymasterUrl: biconomyPaymasterApiKeyBase, - }), - ]); - - // Check if the smart account has been deployed - const [isPolygonDeployed, isBaseDeployed] = await Promise.all([polygonAccount.isAccountDeployed(), baseAccount.isAccountDeployed()]); - if (!isPolygonDeployed) { - const { wait } = await polygonAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); - const { success } = await wait(); - expect(success).toBe("true"); - } - if (!isBaseDeployed) { - const { wait } = await baseAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); - const { success } = await wait(); - expect(success).toBe("true"); - } - - const moduleEnabled1 = await polygonAccount.isModuleEnabled(DEFAULT_MULTICHAIN_MODULE); - const moduleActive1 = polygonAccount.activeValidationModule; - expect(moduleEnabled1).toBeTruthy(); - expect(moduleActive1.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE); - - const moduleEnabled2 = await baseAccount.isModuleEnabled(DEFAULT_MULTICHAIN_MODULE); - const moduleActive2 = polygonAccount.activeValidationModule; - expect(moduleEnabled2).toBeTruthy(); - expect(moduleActive2.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address owner) view returns (uint balance)"]), - functionName: "safeMint", - args: [recipientForBothChains], - }); - - const transaction = { - to: nftAddress, - data: encodedCall, - }; - - const [partialUserOp1, partialUserOp2] = await Promise.all([ - baseAccount.buildUserOp([transaction], { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }), - polygonAccount.buildUserOp([transaction], { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }), - ]); - - expect(partialUserOp1.paymasterAndData).not.toBe("0x"); - expect(partialUserOp2.paymasterAndData).not.toBe("0x"); - - // Sign the user ops using multiChainModule - const returnedOps = await multiChainModule.signUserOps([ - { userOp: partialUserOp1, chainId: chainIdBase }, - { userOp: partialUserOp2, chainId: chainIdMumbai }, - ]); - - // Send the signed user ops on both chains - const userOpResponse1 = await baseAccount.sendSignedUserOp(returnedOps[0] as any); - const userOpResponse2 = await polygonAccount.sendSignedUserOp(returnedOps[1] as any); - - Logger.log(userOpResponse1.userOpHash, "MULTICHAIN BASE USER OP HASH"); - Logger.log(userOpResponse2.userOpHash, "MULTICHAIN POLYGON USER OP HASH"); - - expect(userOpResponse1.userOpHash).toBeTruthy(); - expect(userOpResponse2.userOpHash).toBeTruthy(); - - const { success: success1 } = await userOpResponse1.wait(); - const { success: success2 } = await userOpResponse2.wait(); - - expect(success1).toBe("true"); - expect(success2).toBe("true"); - }, 50000); -}); diff --git a/packages/modules/tests/sessionValidationModule.e2e.spec.ts b/packages/modules/tests/sessionValidationModule.e2e.spec.ts deleted file mode 100644 index 286cfb9a7..000000000 --- a/packages/modules/tests/sessionValidationModule.e2e.spec.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { DEFAULT_SESSION_KEY_MANAGER_MODULE, createSessionKeyManagerModule } from "@biconomy/modules"; -import { SessionFileStorage } from "./utils/customSession"; -import { WalletClientSigner, createSmartAccountClient } from "../../account/src/index"; -import { Hex, encodeAbiParameters, encodeFunctionData, pad, parseAbi, parseEther, parseUnits, slice, toFunctionSelector } from "viem"; -import { TestData } from "../../../tests"; -import { checkBalance } from "../../../tests/utils"; -import { PaymasterMode } from "@biconomy/paymaster"; -import { Logger } from "@biconomy/common"; -import { getABISVMSessionKeyData } from "../src/utils/Helper"; -import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; - -describe("Session Validation Module Tests", () => { - let mumbai: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai] = testDataPerChain; - }); - - // TODO(Gabi): Fix Session Validation Module tests - it.skip("Should send a user op using Session Validation Module", async () => { - let sessionSigner: WalletClientSigner; - const { - whale: { - account: { address: sessionKeyEOA }, - privateKey: pvKey, - viemWallet, - }, - viemChain, - minnow: { publicAddress: recipient }, - publicClient, - chainId, - bundlerUrl, - biconomyPaymasterApiKey, - } = mumbai; - - // Create smart account - let smartAccount = await createSmartAccountClient({ - chainId, - signer: viemWallet, - bundlerUrl, - biconomyPaymasterApiKey, - index: 1, // Increasing index to not conflict with other test cases and use a new smart account - }); - - const accountAddress = await smartAccount.getAccountAddress(); - const sessionFileStorage: SessionFileStorage = new SessionFileStorage(accountAddress); - - // First we need to check if smart account is deployed - // if not deployed, send an empty transaction to deploy it - const isDeployed = await smartAccount.isAccountDeployed(); - - Logger.log("session", { isDeployed }); - - if (!isDeployed) { - const { wait } = await smartAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); - const { success } = await wait(); - expect(success).toBe("true"); - } - - try { - sessionSigner = await sessionFileStorage.getSignerByKey(sessionKeyEOA); - } catch (error) { - sessionSigner = await sessionFileStorage.addSigner({ pbKey: sessionKeyEOA, pvKey, chainId: viemChain }); - } - expect(sessionSigner).toBeTruthy(); - - // Create session module - const sessionModule = await createSessionKeyManagerModule({ - moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE, - smartAccountAddress: await smartAccount.getAddress(), - sessionStorageClient: sessionFileStorage, - }); - - const functionSelector = slice(toFunctionSelector("safeMint(address)"), 0, 4); - // Set enabled call on session - const sessionKeyData = await getABISVMSessionKeyData(sessionKeyEOA as Hex, { - destContract: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0" as Hex, // nft address - functionSelector: functionSelector, - valueLimit: parseEther("0"), - rules: [ - { - offset: 0, // offset 0 means we are checking first parameter of safeMint (recipient address) - condition: 0, // 0 = Condition.EQUAL - referenceValue: pad("0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", { size: 32 }), // recipient address - }, - ], - }); - - const abiSvmAddress = "0x000006bC2eCdAe38113929293d241Cf252D91861"; - - const sessionTxData = await sessionModule.createSessionData([ - { - validUntil: 0, - validAfter: 0, - sessionValidationModule: abiSvmAddress, - sessionPublicKey: sessionKeyEOA as Hex, - sessionKeyData: sessionKeyData as Hex, - }, - ]); - - const setSessionAllowedTrx = { - to: DEFAULT_SESSION_KEY_MANAGER_MODULE, - data: sessionTxData.data, - }; - - const txArray: any = []; - - // Check if module is enabled - const isEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE); - - if (!isEnabled) { - const enableModuleTrx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE); - txArray.push(enableModuleTrx); - txArray.push(setSessionAllowedTrx); - } else { - Logger.log("MODULE ALREADY ENABLED"); - txArray.push(setSessionAllowedTrx); - } - - const userOp = await smartAccount.buildUserOp(txArray, { - paymasterServiceData: { - mode: PaymasterMode.SPONSORED, - }, - }); - - const userOpResponse1 = await smartAccount.sendUserOp(userOp); - const transactionDetails = await userOpResponse1.wait(); - expect(transactionDetails.success).toBe("true"); - Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash); - - const encodedCall = encodeFunctionData({ - abi: parseAbi(["function safeMint(address _to)"]), - functionName: "safeMint", - args: ["0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549"], - }); - - const nftMintTx = { - to: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0", - data: encodedCall, - }; - - smartAccount = smartAccount.setActiveValidationModule(sessionModule); - - const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAccountAddress()); - - const userOpResponse2 = await smartAccount.sendTransaction(nftMintTx, { - params: { - sessionSigner: sessionSigner, - sessionValidationModule: abiSvmAddress, - }, - paymasterServiceData: { - mode: PaymasterMode.SPONSORED, - }, - }); - - expect(userOpResponse2.userOpHash).toBeTruthy(); - expect(userOpResponse2.userOpHash).not.toBeNull(); - - const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAccountAddress()); - - expect(maticBalanceAfter).toEqual(maticBalanceBefore); - - Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`); - }, 60000); -}); diff --git a/packages/modules/tests/utils/customSession.ts b/packages/modules/tests/utils/customSession.ts deleted file mode 100644 index 1326c4871..000000000 --- a/packages/modules/tests/utils/customSession.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as fs from "fs"; -import { SmartAccountSigner, WalletClientSigner, getChain } from "@alchemy/aa-core"; -import { SignerData } from "@biconomy/modules/src"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; -import { Hex, createWalletClient, http } from "viem"; -import { polygonMumbai } from "viem/chains"; -import { ISessionStorage, SessionLeafNode, SessionSearchParam, SessionStatus } from "@biconomy/modules/src/interfaces/ISessionStorage.js"; -import { Logger } from "@biconomy/common"; - -export class SessionFileStorage implements ISessionStorage { - private smartAccountAddress: string; - - constructor(smartAccountAddress: string) { - this.smartAccountAddress = smartAccountAddress.toLowerCase(); - } - - // This method reads data from the file and returns it in the JSON format - private async readDataFromFile(type: "sessions" | "signers"): Promise<any> { - return new Promise((resolve) => { - fs.readFile(this.getStorageFilePath(type), "utf8", (err, data) => { - if (err) { - // Handle errors appropriately - resolve(undefined); - } else { - if (!data) { - resolve(null); - } else { - resolve(JSON.parse(data)); - } - // resolve(JSON.parse(data)); - } - }); - }); - } - - private getStorageFilePath(type: "sessions" | "signers"): string { - return `./packages/modules/tests/utils/sessionStorageData/${this.smartAccountAddress}_${type}.json`; - } - - private async writeDataToFile(data: any, type: "sessions" | "signers"): Promise<void> { - return new Promise((resolve, reject) => { - const filePath = this.getStorageFilePath(type); - fs.writeFile(filePath, JSON.stringify(data), "utf8", (err) => { - if (err) { - // Handle errors appropriately - reject(err); - } else { - resolve(); - } - }); - }); - } - - private validateSearchParam(param: SessionSearchParam): void { - if (param.sessionID) { - return; - } else if (!param.sessionID && param.sessionPublicKey && param.sessionValidationModule) { - return; - } else { - throw new Error("Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address."); - } - } - - // Session store is in the form of mekrleRoot and leafnodes, each object will have a root and an array of leafNodes. - private async getSessionStore(): Promise<any> { - // eslint-disable-next-line no-useless-catch - try { - const data = await this.readDataFromFile("sessions"); - return data || { merkleRoot: "", leafNodes: [] }; - } catch (error) { - // Handle errors appropriately - throw error; - } - } - - private async getSignerStore(): Promise<any> { - // eslint-disable-next-line no-useless-catch - try { - const data = await this.readDataFromFile("signers"); - return data || {}; - } catch (error) { - // Handle errors appropriately - throw error; - } - } - - private getStorageKey(type: "sessions" | "signers"): string { - return `${this.smartAccountAddress}_${type}`; - } - - private toLowercaseAddress(address: string): Hex { - return address.toLowerCase() as Hex; - } - - async getSessionData(param: SessionSearchParam): Promise<SessionLeafNode> { - const sessions = (await this.getSessionStore()).leafNodes; - const session = sessions.find((s: SessionLeafNode) => { - if (param.sessionID) { - return s.sessionID === param.sessionID && (!param.status || s.status === param.status); - } else if (param.sessionPublicKey && param.sessionValidationModule) { - return ( - s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) && - s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) && - (!param.status || s.status === param.status) - ); - } else { - return undefined; - } - }); - - if (!session) { - throw new Error("Session not found."); - } - return session; - } - - async addSessionData(leaf: SessionLeafNode): Promise<void> { - Logger.log("Add session Data", leaf); - const data = await this.getSessionStore(); - leaf.sessionValidationModule = this.toLowercaseAddress(leaf.sessionValidationModule); - leaf.sessionPublicKey = this.toLowercaseAddress(leaf.sessionPublicKey); - data.leafNodes.push(leaf); - await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type - } - - async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise<void> { - this.validateSearchParam(param); - - const data = await this.getSessionStore(); - const session = data.leafNodes.find((s: SessionLeafNode) => { - if (param.sessionID) { - return s.sessionID === param.sessionID; - } else if (param.sessionPublicKey && param.sessionValidationModule) { - return ( - s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) && - s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) - ); - } else { - return undefined; - } - }); - - if (!session) { - throw new Error("Session not found."); - } - - session.status = status; - await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type - } - - async clearPendingSessions(): Promise<void> { - const data = await this.getSessionStore(); - data.leafNodes = data.leafNodes.filter((s: SessionLeafNode) => s.status !== "PENDING"); - await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type - } - - async addSigner(signerData: SignerData): Promise<WalletClientSigner> { - const signers = await this.getSignerStore(); - let signer: SignerData; - if (!signerData) { - const pkey = generatePrivateKey(); - signer = { - pvKey: pkey, - pbKey: privateKeyToAccount(pkey).publicKey, - }; - } else { - signer = signerData; - } - const accountSigner = privateKeyToAccount(signer.pvKey); - const viemChain = getChain(signerData?.chainId?.id || 1); - const client = createWalletClient({ - account: accountSigner, - chain: signerData.chainId, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - const walletClientSigner: SmartAccountSigner = new WalletClientSigner( - client, - "json-rpc", // signerType - ); - signers[this.toLowercaseAddress(accountSigner.address)] = { - pvKey: signer.pvKey, - pbKey: signer.pbKey, - }; - await this.writeDataToFile(signers, "signers"); // Use 'signers' as the type - return walletClientSigner; - } - - async getSignerByKey(sessionPublicKey: string): Promise<WalletClientSigner> { - const signers = await this.getSignerStore(); - Logger.log("Got signers", signers); - - const signerData: SignerData = signers[this.toLowercaseAddress(sessionPublicKey)]; - if (!signerData) { - throw new Error("Signer not found."); - } - Logger.log(signerData.pvKey, "PVKEY"); - - const signer = privateKeyToAccount(signerData.pvKey); - const walletClient = createWalletClient({ - account: signer, - transport: http(polygonMumbai.rpcUrls.default.http[0]), - }); - return new WalletClientSigner(walletClient, "json-rpc"); - } - - async getSignerBySession(param: SessionSearchParam): Promise<WalletClientSigner> { - const session = await this.getSessionData(param); - Logger.log("got session", session); - const walletClientSinger = await this.getSignerByKey(session.sessionPublicKey); - return walletClientSinger; - } - - async getAllSessionData(param?: SessionSearchParam): Promise<SessionLeafNode[]> { - const sessions = (await this.getSessionStore()).leafNodes; - if (!param || !param.status) { - return sessions; - } - return sessions.filter((s: SessionLeafNode) => s.status === param.status); - } - - async getMerkleRoot(): Promise<string> { - return (await this.getSessionStore()).merkleRoot; - } - - async setMerkleRoot(merkleRoot: string): Promise<void> { - const data = await this.getSessionStore(); - data.merkleRoot = merkleRoot; - await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type - } -} diff --git a/packages/modules/tests/utils/sessionStorageData/.gitkeep b/packages/modules/tests/utils/sessionStorageData/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/modules/tsconfig.build.json b/packages/modules/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/modules/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/modules/tsconfig.json b/packages/modules/tsconfig.json deleted file mode 100644 index adc19ded0..000000000 --- a/packages/modules/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node"], - }, - "include": ["src", "src/**/*.json"] -} diff --git a/packages/particle-auth/.esbuild.js b/packages/particle-auth/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/particle-auth/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/particle-auth/CHANGELOG.md b/packages/particle-auth/CHANGELOG.md deleted file mode 100644 index 9ebd16ef1..000000000 --- a/packages/particle-auth/CHANGELOG.md +++ /dev/null @@ -1,66 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -VERSION Bump Only. - -## 4.1.0 (2023-04-03) - -VERSION Bump Only. - -## 4.0.3 (2023-28-02) - -Fix build - -## 4.0.2 (2023-12-28) - -Fix build - -## 4.0.1 (2023-02-22) - -VERSION Bump Only. - -## 4.0.0 (2023-12-28) - -VERSION Bump Only. - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -VERSION Bump Only. - -## 3.1.1 (2023-11-09) - -### Features - -- Upgrade package version ([])(https://github.com/bcnmy/biconomy-client-sdk/commit/d467b85) - -## 3.1.0 (2023-09-20) - -Version Bump Only. - -# 3.0.0 (2023-08-28) - -### Features - -- particle auth integration ([7b8fb1d](https://github.com/bcnmy/biconomy-client-sdk/commit/7b8fb1d05e3cc0196bc15806fa48100701af181e)) - -## 3.0.0-alpha.0 (2023-07-12) - -## 2.0.1 (2023-06-10) - -### Bug Fixes - -- typo ([0a63ff1](https://github.com/bcnmy/biconomy-client-sdk/commit/0a63ff17bb38b1bc2fd68669b74c2efd5a959d31)) - -## 2.0.0 (2023-30-05) - -### Features - -- particle-auth ([7b8fb1d](https://github.com/bcnmy/biconomy-client-sdk/commit/7b8fb1d05e3cc0196bc15806fa48100701af181e)) diff --git a/packages/particle-auth/README.md b/packages/particle-auth/README.md deleted file mode 100644 index 8d3a34187..000000000 --- a/packages/particle-auth/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# `@biconomy/particle-auth` - -> A library to import the particle-auth for web directly from [Biconomy SDK](https://github.com/bcnmy/biconomy-client-sdk) - -## Usage - -```ts -import { ParticleNetwork, WalletEntryPosition } from "@biconomy/particle-auth"; -import { ParticleProvider } from "@biconomy/particle-auth"; -import Web3 from "web3"; - -const particle = new ParticleNetwork({ - projectId: "xx", - clientKey: "xx", - appId: "xx", - chainName: "Ethereum", //optional: current chain name, default Ethereum. - chainId: 1, //optional: current chain id, default 1. - wallet: { - //optional: by default, the wallet entry is displayed in the bottom right corner of the webpage. - displayWalletEntry: true, //show wallet entry when connect particle. - defaultWalletEntryPosition: WalletEntryPosition.BR, //wallet entry position - uiMode: "dark", //optional: light or dark, if not set, the default is the same as web auth. - supportChains: [ - { id: 1, name: "Ethereum" }, - { id: 5, name: "Ethereum" }, - ], // optional: web wallet support chains. - customStyle: {}, //optional: custom wallet style - }, -}); - -const particleProvider = new ParticleProvider(particle.auth); - -//if you use web3.js -window.web3 = new Web3(particleProvider); -window.web3.currentProvider.isParticleNetwork; // => true - -//if you use ethers.js -import { ethers } from "ethers"; -const ethersProvider = new ethers.providers.Web3Provider(particleProvider, "any"); -const ethersSigner = ethersProvider.getSigner(); -``` diff --git a/packages/particle-auth/package.json b/packages/particle-auth/package.json deleted file mode 100644 index 87f407661..000000000 --- a/packages/particle-auth/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@biconomy/particle-auth", - "version": "4.1.1", - "description": "Particle auth for Biconomy SDK", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "legos", - "batching", - "one-click", - "cross-chain", - "particle", - "particle-auth" - ], - "author": "Biconomy", - "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme", - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git" - }, - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json" - }, - "bugs": { - "url": "https://github.com/bcnmy/biconomy-client-sdk/issues" - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@particle-network/auth": "^1.2.1", - "@particle-network/biconomy": "^1.0.0", - "@particle-network/provider": "^1.2.0" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12" - } -} diff --git a/packages/particle-auth/src/index.ts b/packages/particle-auth/src/index.ts deleted file mode 100644 index 03966301b..000000000 --- a/packages/particle-auth/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import * as ParticleAuth from "@particle-network/auth"; -import * as BiconomyAccount from "@particle-network/biconomy"; -export { ParticleProvider, ParticleDelegateProvider } from "@particle-network/provider"; -export { ParticleAuth as ParticleAuthModule, BiconomyAccount as BiconomyAccountModule }; diff --git a/packages/particle-auth/tests/particle-auth.spec.ts b/packages/particle-auth/tests/particle-auth.spec.ts deleted file mode 100644 index 97866f6b6..000000000 --- a/packages/particle-auth/tests/particle-auth.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe("Particle Auth Tests", () => { - it("should have a basic test", () => { - expect(true).toBe(true); - }); -}); diff --git a/packages/particle-auth/tsconfig.build.json b/packages/particle-auth/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/particle-auth/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/particle-auth/tsconfig.json b/packages/particle-auth/tsconfig.json deleted file mode 100644 index cda17a184..000000000 --- a/packages/particle-auth/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - }, - "include": ["src", "src/**/*.json"] -} diff --git a/packages/paymaster/.esbuild.js b/packages/paymaster/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/paymaster/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/paymaster/CHANGELOG.md b/packages/paymaster/CHANGELOG.md deleted file mode 100644 index f4db34b38..000000000 --- a/packages/paymaster/CHANGELOG.md +++ /dev/null @@ -1,78 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -VERSION Bump Only. - -## 4.1.0 (2023-04-03) - -VERSION Bump Only. - -## 4.0.3 (2023-28-02) - -VERSION Bump Only. - -## 4.0.2 (2023-26-02) - -VERSION Bump Only. - -## 4.0.1 (2023-02-22) - -VERSION Bump Only. - -## 4.0.0 (2023-07-02) - -Export createPaymaster alias for static Paymaster.create call - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -VERSION Bump Only. - -## 3.1.1 (2023-11-09) - -### Bug Fixes - -- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) - -## 3.1.0 (2023-09-20) - -Version Bump Only. - -## 3.0.0 (2023-08-28) - -Modular SDK - consists stable version of below updates done in Alphas. - -## 3.0.0-alpha.0 (2023-08-02) - -### Features - -- letting maxFee and maxPriority not be undefined([46b985c](https://github.com/bcnmy/biconomy-client-sdk/commit/46b985c75fd135f151c9ac4380a65438cccc6f39)) -- passing on paymasterAndData([ae267f1])(https://github.com/bcnmy/biconomy-client-sdk/commit/ae267f1a103f37856eb233a38db7063bfcc4cb45) -- handle undefined values([e53d4a7])(https://github.com/bcnmy/biconomy-client-sdk/commit/e53d4a78aded8c8802786173daf12b27d445d4a0) -- handling userOp null values([c89ac42])(https://github.com/bcnmy/biconomy-client-sdk/commit/c89ac42ae1d7fd985ef2396d925cc63ec5cf926b) -- using signature provided by userop([0c40641])(https://github.com/bcnmy/biconomy-client-sdk/commit/0c40641e4cd6133f7348bb3e3022f8ab78fe299b) - -# 3.1.0-alpha.0 (2023-07-24) - -VERSION Bump Only. - -## 3.0.0-alpha.0 (2023-07-12) - -### Bug Fixes - -- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526)) -- linting ([d2f5f1a](https://github.com/bcnmy/biconomy-client-sdk/commit/d2f5f1afadc2a561c4ef01c0821a25b9d7fe776e)) - -### Features - -- covert gas limits to numbers for making pm service call ([b1fe96f](https://github.com/bcnmy/biconomy-client-sdk/commit/b1fe96f7a312ceaf7aa689939b7c69718c710dd1)) -- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7)) -- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4)) -- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206)) diff --git a/packages/paymaster/Readme.md b/packages/paymaster/Readme.md deleted file mode 100644 index 562a790f6..000000000 --- a/packages/paymaster/Readme.md +++ /dev/null @@ -1,74 +0,0 @@ -# **Paymaster** - -ERC4337, Account abstraction, introduces the concept of Paymasters. These specialised entities play a pivotal role in revolutionising the traditional gas payment system in EVM transactions. Paymasters, acting as third-party intermediaries, possess the capability to sponsor gas fees for an account, provided specific predefined conditions are satisfied. - -## Installation - -Using `npm` package manager - -```bash -npm i @biconomy/paymaster -``` - -OR - -Using `yarn` package manager - -```bash -yarn add @biconomy/paymaster -``` - -**Usage** - -```typescript -// This is how you create paymaster instance in your dapp's -import { IPaymaster, createPaymaster } from "@biconomy/paymaster"; - -// Currently this package only exports Biconomy Paymaster which acts as a Hybrid paymaster for gas abstraction. You can sponsor user transactions but can also make users pay gas in supported ERC20 tokens. - -const paymaster = await createPaymaster({ - paymasterUrl: "", // you can get this value from biconomy dashboard. https://dashboard.biconomy.io -}); -``` - -**paymasterUrl** you can get this value from biconomy dashboard. - -Following are the methods that can be called on paymaster instance - -```typescript -export interface IHybridPaymaster<T> extends IPaymaster { - getPaymasterAndData(userOp: Partial<UserOperation>, paymasterServiceData?: T): Promise<PaymasterAndDataResponse>; - buildTokenApprovalTransaction(tokenPaymasterRequest: BiconomyTokenPaymasterRequest): Promise<Transaction>; - getPaymasterFeeQuotesOrData(userOp: Partial<UserOperation>, paymasterServiceData: FeeQuotesOrDataDto): Promise<FeeQuotesOrDataResponse>; -} -``` - -One can also build their own Paymaster API class and submit a PR or just provide instance of it in the account package / use standalone to generate paymasterAndData - -It should follow below Interface. - -```typescript -export interface IPaymaster { - // Implementing class may add extra parameter (for example paymasterServiceData with it's own type) in below function signature - getPaymasterAndData(userOp: Partial<UserOperation>): Promise<PaymasterAndDataResponse>; - getDummyPaymasterAndData(userOp: Partial<UserOperation>): Promise<string>; -} -``` - -### Below API methods can be used for Biconomy Hybrid paymaster - -**[getPaymasterAndData](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#getPaymasterAndData)** - -This function accepts a **`Partial<UserOperation>`** object that includes all properties of **`userOp`** except for the **`signature`** and **`paymasterAndData`** field. It returns **`paymasterAndData`** as part of the **`PaymasterAndDataResponse`** - -**[buildTokenApprovalTransaction](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#buildTokenApprovalTransaction)** - -This function is specifically used for token paymaster sponsorship. The primary purpose of this function is to create an approve transaction for paymaster that gets batched with the rest of your transactions. - -Note: You don't need to call this function. It will automatically get called as part of the **`buildTokenPaymasterUserOp`** function call. - -**[getPaymasterFeeQuotesOrData](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#getPaymasterFeeQuotesOrData)** - -This function is used to fetch quote information or paymaster data based on provided userOperation and paymasterServiceData. If explicit mode is not provided it tries for sponsorship first and then falls back to serving fee quotes for supported/requested token/s - -Note: This function can return **paymasterAndData** as well in case all of the policies checks get passed. diff --git a/packages/paymaster/package.json b/packages/paymaster/package.json deleted file mode 100644 index 2b6008747..000000000 --- a/packages/paymaster/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@biconomy/paymaster", - "version": "4.1.1", - "description": "Biconomy Paymaster to interact with Paymaster Services that interacts with ( veriying and token ) paymasters", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "Ethereum", - "Veriying Paymaster", - "Token Paymaster", - "ERC4337", - "Gasless Transaction", - "Biconomy", - "SDK" - ], - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json", - "test": "jest tests/**/*.spec.ts --runInBand" - }, - "author": "Biconomy", - "repository": { - "type": "git", - "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git" - }, - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@alchemy/aa-core": "^3.1.1", - "@biconomy/common": "^4.1.1", - "viem": "^2.7.12" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12" - } -} diff --git a/packages/paymaster/src/index.ts b/packages/paymaster/src/index.ts deleted file mode 100644 index 4d78b3a0a..000000000 --- a/packages/paymaster/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BiconomyPaymaster } from "./BiconomyPaymaster.js"; -export * from "./interfaces/IPaymaster.js"; -export * from "./interfaces/IHybridPaymaster.js"; -export * from "./utils/Types.js"; -export * from "./BiconomyPaymaster.js"; - -export const Paymaster = BiconomyPaymaster; -export const createPaymaster = Paymaster.create; diff --git a/packages/paymaster/src/interfaces/IHybridPaymaster.ts b/packages/paymaster/src/interfaces/IHybridPaymaster.ts deleted file mode 100644 index 5b73bfd5e..000000000 --- a/packages/paymaster/src/interfaces/IHybridPaymaster.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type UserOperationStruct } from "@alchemy/aa-core"; -import { - FeeQuotesOrDataResponse, - BiconomyTokenPaymasterRequest, - FeeQuotesOrDataDto, - PaymasterAndDataResponse, - type Transaction, -} from "../utils/Types.js"; -import { IPaymaster } from "./IPaymaster.js"; - -export interface IHybridPaymaster<T> extends IPaymaster { - getPaymasterAndData(_userOp: Partial<UserOperationStruct>, _paymasterServiceData?: T): Promise<PaymasterAndDataResponse>; - getDummyPaymasterAndData(_userOp: Partial<UserOperationStruct>, _paymasterServiceData?: T): Promise<string>; - buildTokenApprovalTransaction(_tokenPaymasterRequest: BiconomyTokenPaymasterRequest): Promise<Transaction>; - getPaymasterFeeQuotesOrData(_userOp: Partial<UserOperationStruct>, _paymasterServiceData: FeeQuotesOrDataDto): Promise<FeeQuotesOrDataResponse>; -} diff --git a/packages/paymaster/src/interfaces/IPaymaster.ts b/packages/paymaster/src/interfaces/IPaymaster.ts deleted file mode 100644 index b9938797d..000000000 --- a/packages/paymaster/src/interfaces/IPaymaster.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type UserOperationStruct } from "@alchemy/aa-core"; -import { PaymasterAndDataResponse } from "../utils/Types.js"; - -export interface IPaymaster { - // Implementing class may add extra parameter (for example paymasterServiceData with it's own type) in below function signature - getPaymasterAndData(_userOp: Partial<UserOperationStruct>): Promise<PaymasterAndDataResponse>; - getDummyPaymasterAndData(_userOp: Partial<UserOperationStruct>): Promise<string>; -} diff --git a/packages/paymaster/src/utils/Types.ts b/packages/paymaster/src/utils/Types.ts deleted file mode 100644 index 9d5f849d4..000000000 --- a/packages/paymaster/src/utils/Types.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { BigNumberish } from "@alchemy/aa-core"; -export type Hex = `0x${string}`; - -export type PaymasterServiceErrorResponse = { - jsonrpc: string; - id: number; - error: JsonRpcError; -}; - -export type JsonRpcResponse = { - jsonrpc: string; - id: number; - result?: any; - error?: JsonRpcError; -}; - -export type JsonRpcError = { - code: string; - message: string; - data: any; -}; - -export type PaymasterConfig = { - paymasterUrl: string; - strictMode?: boolean; -}; - -export type SponsorUserOperationDto = { - /** mode: sponsored or erc20 */ - mode: PaymasterMode; - /** Always recommended, especially when using token paymaster */ - calculateGasLimits?: boolean; - /** Expiry duration in seconds */ - expiryDuration?: number; - /** Webhooks to be fired after user op is sent */ - webhookData?: Record<string, any>; - /** Smart account meta data */ - smartAccountInfo?: SmartAccountData; - /** the fee-paying token address */ - feeTokenAddress?: string; -}; - -export type FeeQuotesOrDataDto = { - /** mode: sponsored or erc20 */ - mode?: PaymasterMode; - /** Expiry duration in seconds */ - expiryDuration?: number; - /** Always recommended, especially when using token paymaster */ - calculateGasLimits?: boolean; - /** List of tokens to be used for fee quotes, if ommitted fees for all supported will be returned */ - tokenList?: string[]; - /** preferredToken: Can be ommitted to return all quotes */ - preferredToken?: string; - /** Webhooks to be fired after user op is sent */ - webhookData?: Record<string, any>; - /** Smart account meta data */ - smartAccountInfo?: SmartAccountData; -}; - -export type FeeQuoteParams = { - tokenList?: string[]; - preferredToken?: string; -}; - -export type FeeTokenInfo = { - feeTokenAddress: string; -}; - -export type SponsorpshipInfo = { - /** Webhooks to be fired after user op is sent */ - webhookData?: Record<string, any>; - /** Smart account meta data */ - smartAccountInfo: SmartAccountData; -}; - -export type SmartAccountData = { - /** name: Name of the smart account */ - name: string; - /** version: Version of the smart account */ - version: string; -}; - -export type PaymasterFeeQuote = { - /** symbol: Token symbol */ - symbol: string; - /** tokenAddress: Token address */ - tokenAddress: string; - /** decimal: Token decimal */ - decimal: number; - logoUrl?: string; - /** maxGasFee: in wei */ - maxGasFee: number; - /** maxGasFee: in dollars */ - maxGasFeeUSD?: number; - usdPayment?: number; - /** The premium paid on the token */ - premiumPercentage: number; - /** validUntil: Unix timestamp */ - validUntil?: number; -}; - -export type BiconomyTokenPaymasterRequest = { - /** The feeQuote to be used for the transaction */ - feeQuote: PaymasterFeeQuote; - /** The address of the spender. This is usually set to {@link FeeQuotesOrDataResponse.tokenPaymasterAddress} */ - spender: Hex; - /** Not recommended */ - maxApproval?: boolean; - /* skip option to patch callData if approval is already given to the paymaster */ - skipPatchCallData?: boolean; -}; - -export type FeeQuotesOrDataResponse = { - /** Array of results from the paymaster */ - feeQuotes?: PaymasterFeeQuote[]; - /** Normally set to the spender in the proceeding call to send the tx */ - tokenPaymasterAddress?: Hex; - /** Relevant Data returned from the paymaster */ - paymasterAndData?: Uint8Array | Hex; - /* Gas overhead of this UserOperation */ - preVerificationGas?: BigNumberish; - /* Actual gas used by the validation of this UserOperation */ - verificationGasLimit?: BigNumberish; - /* Value used by inner account execution */ - callGasLimit?: BigNumberish; -}; - -export type PaymasterAndDataResponse = { - paymasterAndData: Hex; - /* Gas overhead of this UserOperation */ - preVerificationGas: number; - /* Actual gas used by the validation of this UserOperation */ - verificationGasLimit: number; - /* Value used by inner account execution */ - callGasLimit: number; -}; - -export enum PaymasterMode { - ERC20 = "ERC20", - SPONSORED = "SPONSORED", -} - -// Converted to JsonRpcResponse with strict type -export type EstimateUserOpGasResponse = { - jsonrpc: string; - id: number; - result: UserOpGasResponse; - error?: JsonRpcError; -}; - -export type UserOpGasResponse = { - paymasterAndData: string; - /* Gas overhead of this UserOperation */ - preVerificationGas: string; - maxPriorityFeePerGas: string; - maxFeePerGas: string; - /* Actual gas used by the validation of this UserOperation */ - verificationGasLimit: string; - callGasLimit: string; -}; - -type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & - { - [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>; - }[Keys]; - -type ValueOrData = RequireAtLeastOne< - { - value: BigNumberish | string; - data: string; - }, - "value" | "data" ->; -export type Transaction = { - to: string; -} & ValueOrData; diff --git a/packages/paymaster/tests/paymaster.e2e.spec.ts b/packages/paymaster/tests/paymaster.e2e.spec.ts deleted file mode 100644 index 3a634f491..000000000 --- a/packages/paymaster/tests/paymaster.e2e.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TestData } from "../../../tests"; - -describe("Paymaster Unit Tests", () => { - let mumbai: TestData; - let baseSepolia: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-e2e-tests - [mumbai, baseSepolia] = testDataPerChain; - }); - - it("should have chain data for mumbai", () => { - expect(mumbai).toHaveProperty("chainId"); - }); - - it("should also have chain data for base", () => { - expect(baseSepolia).toHaveProperty("chainId"); - }); -}); diff --git a/packages/paymaster/tests/paymaster.spec.ts b/packages/paymaster/tests/paymaster.spec.ts deleted file mode 100644 index 0b3508a6b..000000000 --- a/packages/paymaster/tests/paymaster.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TestData } from "../../../tests"; - -describe("Paymaster Unit Tests", () => { - let ganache: TestData; - - beforeEach(() => { - // @ts-ignore: Comes from setup-unit-tests - [ganache] = testDataPerChain; - }); - - it("should have chain data for mumbai", () => { - expect(ganache).toHaveProperty("chainId"); - }); -}); diff --git a/packages/paymaster/tsconfig.build.json b/packages/paymaster/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/paymaster/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/paymaster/tsconfig.json b/packages/paymaster/tsconfig.json deleted file mode 100644 index d6269c535..000000000 --- a/packages/paymaster/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "types": ["node"] - }, - "include": ["src", "src/**/*.json"] -} diff --git a/packages/transak/.esbuild.js b/packages/transak/.esbuild.js deleted file mode 100644 index ca355e346..000000000 --- a/packages/transak/.esbuild.js +++ /dev/null @@ -1,58 +0,0 @@ -const esbuildPluginTsc = require("esbuild-plugin-tsc"); -const esbuild = require("esbuild"); -const { dependencies, peerDependencies = {} } = require("./package.json"); -const { Generator } = require("npm-dts"); - -const COMMON_SETTINGS = { - entryPoints: ["src/index.ts"], - minify: true, - bundle: true, - plugins: [esbuildPluginTsc({ force: true })], -}; - -const ESM_SETTINGS = { - ...COMMON_SETTINGS, - sourcemap: true, - outfile: "dist/esm/index.js", - platform: "browser", - target: "esnext", - format: "esm", - mainFields: ["browser", "module", "main"], -}; -const buildForESM = async () => await esbuild.build(ESM_SETTINGS); - -const CJS_SETTINGS = { - ...COMMON_SETTINGS, - format: "cjs", - sourcemap: false, - outfile: "dist/cjs/index.js", - platform: "node", -}; - -const watchForCJS = async () => { - let ctx = await esbuild.context(CJS_SETTINGS); - await ctx.watch(); - await ctx.serve({ servedir: "dist/src" }); - console.log("watching..."); -}; - -const buildForCJS = async () => await esbuild.build(CJS_SETTINGS); -const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate(); - -(async () => { - const buildType = process.argv.slice(2)[0]; - const shouldWatch = process.argv.slice(3)[0] === "--watch"; - if (!buildType) { - console.log("No build type provided"); - process.exit(1); - } - console.log(`Building for ${buildType}`); - if (buildType === "ESM") { - await buildForESM(); - } else if (buildType === "CJS") { - console.log("watching? " + shouldWatch); - await (shouldWatch ? watchForCJS : buildForCJS)(); - } else if (buildType === "TYP") { - await buildForTYP(); - } -})(); diff --git a/packages/transak/CHANGELOG.md b/packages/transak/CHANGELOG.md deleted file mode 100644 index 4af2afc36..000000000 --- a/packages/transak/CHANGELOG.md +++ /dev/null @@ -1,62 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## 4.1.1 (2023-07-03) - -VERSION Bump Only. - -## 4.1.0 (2023-04-03) - -VERSION Bump Only. - -## 4.0.3 (2023-28-02) - -VERSION Bump Only. - -## 4.0.2 (2023-26-02) - -VERSION Bump Only. - -## 4.0.1 (2023-26-02) - -VERSION Bump Only. - -## 4.0.0 (2023-12-28) - -VERSION Bump Only. - -## 3.1.3 (2023-12-28) - -VERSION Bump Only. - -## 3.1.2 (2023-12-28) - -VERSION Bump Only. - -## 3.1.1 (2023-11-09) - -VERSION Bump Only. - -## 3.1.0 (2023-09-20) - -### Bug Fixes - -- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c)) - -# 3.0.0 (2023-08-28) - -VERSION Bump Only. - -## 2.0.0 (2023-04-07) - -### Features - -- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a)) - -## 1.0.0 (2023-01-03) - -### Features - -- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a)) diff --git a/packages/transak/README.md b/packages/transak/README.md deleted file mode 100644 index ea5b73266..000000000 --- a/packages/transak/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# `@biconomy/transak` - -> A library to import the transak for web directly from [Biconomy SDK](https://github.com/bcnmy/biconomy-client-sdk) - -## Usage - -No need to create api key from transak dashboard. - -```ts -import Transak from "@biconomy/transak"; -const transak = new Transak("STAGING"); -transak.init(); -``` diff --git a/packages/transak/package.json b/packages/transak/package.json deleted file mode 100644 index 4232ed243..000000000 --- a/packages/transak/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@biconomy/transak", - "version": "4.1.1", - "description": "transak for biconomy sdk", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "typings": "./dist/types/index.d.ts", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" - }, - "./package.json": "./package.json" - }, - "keywords": [ - "legos", - "batching", - "one-click", - "cross-chain", - "transak" - ], - "author": "Biconomy", - "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme", - "license": "MIT", - "files": [ - "dist/*", - "README.md" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git" - }, - "scripts": { - "unbuild": "rimraf dist *.tsbuildinfo", - "build:watch": "yarn build:tsc --watch", - "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite", - "build": "yarn unbuild && yarn build:tsc", - "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ", - "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", - "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify", - "format": "prettier --write \"{src,tests}/**/*.ts\"", - "lint": "tslint -p tsconfig.json" - }, - "bugs": { - "url": "https://github.com/bcnmy/biconomy-client-sdk/issues" - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@transak/transak-sdk": "^1.2.3" - }, - "devDependencies": { - "@types/node": "^20.11.10", - "esbuild": "^0.19.11", - "esbuild-plugin-tsc": "^0.4.0", - "npm-dts": "^1.3.12" - } -} diff --git a/packages/transak/src/index.ts b/packages/transak/src/index.ts deleted file mode 100644 index 36f5dcfd9..000000000 --- a/packages/transak/src/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -// @ts-ignore -import transakSDK from "@transak/transak-sdk"; -import { ITransakDto, environments } from "./interface.js"; - -class TransakSDK { - apiKey: string; - - /* eslint-disable @typescript-eslint/no-explicit-any */ - transak: any; - - constructor(environment: environments, transakData: ITransakDto = {}) { - if (environment === "PRODUCTION") { - this.apiKey = "f7d64c91-8f89-4018-9577-9098e42290af"; - } else { - this.apiKey = "c71ecd4a-0819-46a7-8d63-c8b7148aaf63"; - } - const transak = new transakSDK({ - apiKey: this.apiKey, - widgetHeight: "625px", - widgetWidth: "500px", - environment: environment, - ...transakData, - }); - this.transak = transak; - } - - init(): void { - try { - this.transak.init(); - /* eslint-disable @typescript-eslint/no-explicit-any */ - } catch (err: any) { - throw new Error(`Error while init transakSDK ${err}`); - } - } - - getTransak(): any { - return this.transak; - } -} - -export default TransakSDK; diff --git a/packages/transak/src/interface.ts b/packages/transak/src/interface.ts deleted file mode 100644 index fd1218340..000000000 --- a/packages/transak/src/interface.ts +++ /dev/null @@ -1,64 +0,0 @@ -export type environments = "PRODUCTION" | "STAGING"; - -export interface IConfigBasic { - // apiKey: string - // environment: environments - redirectURL?: string; - cryptoCurrencyCode?: string; - fiatCurrencyCode?: string; - themeColor?: string; - defaultCryptoCurrency?: string; - defaultFiatCurrency?: string; - walletAddress?: string; - fiatAmount?: number; - defaultFiatAmount?: number; - defaultCryptoAmount?: number; - fiatCurrency?: string; - countryCode?: string; - paymentMethod?: string; - defaultPaymentMethod?: string; - isAutoFillUserData?: boolean; - isFeeCalculationHidden?: boolean; - email?: string; - disablePaymentMethods?: string; - partnerOrderId?: string; - partnerCustomerId?: string; - exchangeScreenTitle?: string; - hideMenu?: boolean; - accessToken?: string; - hideExchangeScreen?: boolean; - isDisableCrypto?: boolean; - disableWalletAddressForm?: boolean; - defaultNetwork?: string; - network?: string; - widgetWidth?: string | number; - widgetHeight?: string | number; -} - -export interface ITransakDto extends IConfigBasic { - networks?: string; - cryptoCurrencyList?: string; - userData?: { - firstName: string; - lastName: string; - email: string; - mobileNumber: string; - dob: string; - address: { - addressLine1: string; - addressLine2: string; - city: string; - state: string; - postCode: string; - countryCode: string; - }; - }; - walletAddressesData?: { - networks?: { - [key: string]: { address: string; addressAdditionalData?: string }; - }; - coins?: { - [key: string]: { address: string; addressAdditionalData?: string }; - }; - }; -} diff --git a/packages/transak/tests/transak.spec.ts b/packages/transak/tests/transak.spec.ts deleted file mode 100644 index 4c5cad00c..000000000 --- a/packages/transak/tests/transak.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe("Transak Tests", () => { - it("should have a basic test", () => { - expect(true).toBe(true); - }); -}); diff --git a/packages/transak/tsconfig.build.json b/packages/transak/tsconfig.build.json deleted file mode 100644 index 4ac8b8026..000000000 --- a/packages/transak/tsconfig.build.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "Build", - "compilerOptions": { - "lib": ["es2022", "dom"], - "target": "es2021", - "types": ["node"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "verbatimModuleSyntax": false, - "useDefineForClassFields": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "useUnknownInCatchVariables": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "declaration": true, - "inlineSources": true, - "noEmit": false, - "sourceMap": true - }, - "exclude": ["**/*/node_modules", "**/*/tests", "tests"], - "include": ["src"] -} \ No newline at end of file diff --git a/packages/transak/tsconfig.json b/packages/transak/tsconfig.json deleted file mode 100644 index d9b305a9a..000000000 --- a/packages/transak/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.settings.json", - "compilerOptions": { - "composite": true, - "outDir": "dist", - "baseUrl": "src", - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node"] - }, - "include": ["src", "src/**/*.json"] -} diff --git a/rebuild.sh b/rebuild.sh deleted file mode 100755 index 39c4c1a94..000000000 --- a/rebuild.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -rm -rf package-lock.json -rm -rf yarn.lock -rm -rf node_modules - -rm -rf packages/account/node_modules -rm -rf packages/account/yarn.lock -rm -rf packages/account/package-lock.json -rm -rf packages/account/dist - -rm -rf packages/bundler/node_modules -rm -rf packages/bundler/yarn.lock -rm -rf packages/bundler/package-lock.json -rm -rf packages/bundler/dist - -rm -rf packages/common/node_modules -rm -rf packages/common/yarn.lock -rm -rf packages/common/package-lock.json -rm -rf packages/common/dist - -rm -rf packages/paymaster/node_modules -rm -rf packages/paymaster/yarn.lock -rm -rf packages/paymaster/package-lock.json -rm -rf packages/paymaster/dist - -rm -rf packages/modules/node_modules -rm -rf packages/modules/yarn.lock -rm -rf packages/modules/package-lock.json -rm -rf packages/modules/dist - -rm -rf packages/transak/node_modules -rm -rf packages/transak/yarn.lock -rm -rf packages/transak/package-lock.json -rm -rf packages/transak/dist - -rm -rf packages/particle-auth/node_modules -rm -rf packages/particle-auth/yarn.lock -rm -rf packages/particle-auth/package-lock.json -rm -rf packages/particle-auth/dist - -#npx lerna bootstrap --force-local -#npm run build -#npm link \ No newline at end of file diff --git a/src/account/BaseSmartContractAccount.ts b/src/account/BaseSmartContractAccount.ts new file mode 100644 index 000000000..c6b0568ff --- /dev/null +++ b/src/account/BaseSmartContractAccount.ts @@ -0,0 +1,354 @@ +import { + http, + type Address, + type GetContractReturnType, + type Hash, + type Hex, + type PublicClient, + createPublicClient, + getContract, + trim +} from "viem" +import { EntryPointAbi } from "./abi/EntryPointAbi.js" +import { Logger, type SmartAccountSigner, getChain } from "./index.js" +import { DEFAULT_ENTRYPOINT_ADDRESS } from "./utils/Constants.js" +import type { + BasSmartContractAccountProps, + BatchUserOperationCallData, + ISmartContractAccount, + SignTypedDataParams +} from "./utils/Types.js" +import { wrapSignatureWith6492 } from "./utils/Utils.js" + +export enum DeploymentState { + UNDEFINED = "0x0", + NOT_DEPLOYED = "0x1", + DEPLOYED = "0x2" +} + +export abstract class BaseSmartContractAccount< + TSigner extends SmartAccountSigner = SmartAccountSigner +> implements ISmartContractAccount<TSigner> +{ + protected factoryAddress: Address + + protected deploymentState: DeploymentState = DeploymentState.UNDEFINED + + protected accountAddress?: Address + + protected accountInitCode?: Hex + + protected signer: TSigner + + protected entryPoint: GetContractReturnType< + typeof EntryPointAbi, + PublicClient + > + + protected entryPointAddress: Address + + readonly rpcProvider: PublicClient + + constructor(params: BasSmartContractAccountProps) { + this.entryPointAddress = + params.entryPointAddress ?? DEFAULT_ENTRYPOINT_ADDRESS + + this.rpcProvider = createPublicClient({ + chain: params.viemChain ?? getChain(params.chainId), + transport: http( + params.rpcUrl || getChain(params.chainId).rpcUrls.default.http[0] + ) + }) as PublicClient + + this.accountAddress = params.accountAddress + this.factoryAddress = params.factoryAddress + this.signer = params.signer as TSigner + this.accountInitCode = params.initCode + + this.entryPoint = getContract({ + address: this.entryPointAddress, + abi: EntryPointAbi, + client: this.rpcProvider as PublicClient + }) + } + + //#region abstract-methods + + /** + * This method should return a signature that will not `revert` during validation. + * It does not have to pass validation, just not cause the contract to revert. + * This is required for gas estimation so that the gas estimate are accurate. + * + */ + abstract getDummySignature(): Hash + + /** + * this method should return the abi encoded function data for a call to your contract's `execute` method + * + * @param target -- equivalent to `to` in a normal transaction + * @param value -- equivalent to `value` in a normal transaction + * @param data -- equivalent to `data` in a normal transaction + * @returns abi encoded function data for a call to your contract's `execute` method + */ + abstract encodeExecute( + target: string, + value: bigint, + data: string + ): Promise<Hash> + + /** + * this should return an ERC-191 compliant message and is used to sign UO Hashes + * + * @param msg -- the message to sign + */ + abstract signMessage(msg: string | Uint8Array): Promise<Hash> + + /** + * this should return the init code that will be used to create an account if one does not exist. + * This is the concatenation of the account's factory address and the abi encoded function data of the account factory's `createAccount` method. + * https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/SenderCreator.sol#L12 + */ + protected abstract getAccountInitCode(): Promise<Hash> + + //#endregion abstract-methods + + //#region optional-methods + + /** + * If your account handles 1271 signatures of personal_sign differently + * than it does UserOperations, you can implement two different approaches to signing + * + * @param uoHash -- The hash of the UserOperation to sign + * @returns the signature of the UserOperation + */ + async signUserOperationHash(uoHash: Hash): Promise<Hash> { + return this.signMessage(uoHash) + } + + /** + * If your contract supports signing and verifying typed data, + * you should implement this method. + * + * @param _params -- Typed Data params to sign + */ + async signTypedData(_params: SignTypedDataParams): Promise<`0x${string}`> { + throw new Error("signTypedData not supported") + } + + /** + * This method should wrap the result of `signMessage` as per + * [EIP-6492](https://eips.ethereum.org/EIPS/eip-6492) + * + * @param msg -- the message to sign + */ + async signMessageWith6492(msg: string | Uint8Array): Promise<`0x${string}`> { + const [isDeployed, signature] = await Promise.all([ + this.isAccountDeployed(), + this.signMessage(msg) + ]) + + return this.create6492Signature(isDeployed, signature) + } + + /** + * Similar to the signMessageWith6492 method above, + * this method should wrap the result of `signTypedData` as per + * [EIP-6492](https://eips.ethereum.org/EIPS/eip-6492) + * + * @param params -- Typed Data params to sign + */ + async signTypedDataWith6492( + params: SignTypedDataParams + ): Promise<`0x${string}`> { + const [isDeployed, signature] = await Promise.all([ + this.isAccountDeployed(), + this.signTypedData(params) + ]) + + return this.create6492Signature(isDeployed, signature) + } + + /** + * Not all contracts support batch execution. + * If your contract does, this method should encode a list of + * transactions into the call data that will be passed to your + * contract's batch execution method. + * + * @param _txs -- the transactions to batch execute + */ + async encodeBatchExecute( + _txs: BatchUserOperationCallData + ): Promise<`0x${string}`> { + throw new Error("Batch execution not supported") + } + + /** + * If your contract supports UUPS, you can implement this method which can be + * used to upgrade the implementation of the account. + * + * @param upgradeToImplAddress -- the implementation address of the contract you want to upgrade to + * @param upgradeToInitData -- the initialization data required by that account + */ + encodeUpgradeToAndCall = async ( + _upgradeToImplAddress: Address, + _upgradeToInitData: Hex + ): Promise<Hex> => { + throw new Error("Upgrade ToAndCall Not Supported") + } + //#endregion optional-methods + + // Extra implementations + async getNonce(): Promise<bigint> { + if (!(await this.isAccountDeployed())) { + return 0n + } + const address = await this.getAddress() + return this.entryPoint.read.getNonce([address, BigInt(0)]) + } + + async getInitCode(): Promise<Hex> { + if (this.deploymentState === DeploymentState.DEPLOYED) { + return "0x" + } + + const contractCode = await this.rpcProvider.getBytecode({ + address: await this.getAddress() + }) + + if ((contractCode?.length ?? 0) > 2) { + this.deploymentState = DeploymentState.DEPLOYED + return "0x" + } + + this.deploymentState = DeploymentState.NOT_DEPLOYED + + return this._getAccountInitCode() + } + + async getAddress(): Promise<Address> { + if (!this.accountAddress) { + const initCode = await this._getAccountInitCode() + Logger.log("[BaseSmartContractAccount](getAddress) initCode: ", initCode) + try { + await this.entryPoint.simulate.getSenderAddress([initCode]) + } catch (err: any) { + Logger.log( + "[BaseSmartContractAccount](getAddress) getSenderAddress err: ", + err + ) + + if (err.cause?.data?.errorName === "SenderAddressResult") { + this.accountAddress = err.cause.data.args[0] as Address + Logger.log( + "[BaseSmartContractAccount](getAddress) entryPoint.getSenderAddress result:", + this.accountAddress + ) + return this.accountAddress + } + + if (err.details === "Invalid URL") { + throw new Error("Invalid URL") + } + } + + throw new Error("Failed to get counterfactual account address") + } + + return this.accountAddress + } + + extend = <R>(fn: (self: this) => R): this & R => { + const extended = fn(this) as any + // this should make it so extensions can't overwrite the base methods + for (const key in this) { + delete extended[key] + } + return Object.assign(this, extended) + } + + getSigner(): TSigner { + return this.signer + } + + getFactoryAddress(): Address { + return this.factoryAddress + } + + getEntryPointAddress(): Address { + return this.entryPointAddress + } + + async isAccountDeployed(): Promise<boolean> { + return (await this.getDeploymentState()) === DeploymentState.DEPLOYED + } + + async getDeploymentState(): Promise<DeploymentState> { + if (this.deploymentState === DeploymentState.UNDEFINED) { + const initCode = await this.getInitCode() + return initCode === "0x" + ? DeploymentState.DEPLOYED + : DeploymentState.NOT_DEPLOYED + } + return this.deploymentState + } + + /** + * https://eips.ethereum.org/EIPS/eip-4337#first-time-account-creation + * The initCode field (if non-zero length) is parsed as a 20-byte address, + * followed by calldata to pass to this address. + * The factory address is the first 40 char after the 0x, and the callData is the rest. + */ + protected async parseFactoryAddressFromAccountInitCode(): Promise< + [Address, Hex] + > { + const initCode = await this._getAccountInitCode() + const factoryAddress = `0x${initCode.substring(2, 42)}` as Address + const factoryCalldata = `0x${initCode.substring(42)}` as Hex + return [factoryAddress, factoryCalldata] + } + + protected async getImplementationAddress(): Promise<"0x0" | Address> { + const accountAddress = await this.getAddress() + + const storage = await this.rpcProvider.getStorageAt({ + address: accountAddress, + // This is the default slot for the implementation address for Proxies + slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" + }) + + if (storage == null) { + throw new Error( + "Failed to get storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" + ) + } + + return trim(storage) + } + + private async _getAccountInitCode(): Promise<Hash> { + return this.accountInitCode ?? this.getAccountInitCode() + } + + private async create6492Signature( + isDeployed: boolean, + signature: Hash + ): Promise<Hash> { + if (isDeployed) { + return signature + } + + const [factoryAddress, factoryCalldata] = + await this.parseFactoryAddressFromAccountInitCode() + + Logger.log( + `[BaseSmartContractAccount](create6492Signature)\ + factoryAddress: ${factoryAddress}, factoryCalldata: ${factoryCalldata}` + ) + + return wrapSignatureWith6492({ + factoryAddress, + factoryCalldata, + signature + }) + } +} diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts similarity index 55% rename from packages/account/src/BiconomySmartAccountV2.ts rename to src/account/BiconomySmartAccountV2.ts index 465054880..f92040cfb 100644 --- a/packages/account/src/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -1,159 +1,205 @@ import { - Hex, - keccak256, - encodePacked, - getCreate2Address, - encodeAbiParameters, - parseAbiParameters, - toHex, - toBytes, - encodeFunctionData, - PublicClient, - createPublicClient, http, + type GetContractReturnType, + type Hex, + type PublicClient, concatHex, - GetContractReturnType, - getContract, + createPublicClient, decodeFunctionData, - parseAbi, + encodeAbiParameters, + encodeFunctionData, + encodePacked, formatUnits, -} from "viem"; + getContract, + getCreate2Address, + keccak256, + parseAbi, + parseAbiParameters, + toBytes, + toHex +} from "viem" +import type { IBundler } from "../bundler/IBundler.js" import { - BaseSmartContractAccount, - getChain, - type BigNumberish, - type UserOperationStruct, - BatchUserOperationCallData, - SmartAccountSigner, -} from "@alchemy/aa-core"; -import { isNullOrUndefined, isValidRpcUrl, packUserOp, compareChainIds, addressEquals } from "./utils/Utils.js"; -import { BaseValidationModule, ModuleInfo, SendUserOpParams, createECDSAOwnershipValidationModule } from "@biconomy/modules"; + Bundler, + type UserOpResponse, + extractChainIdFromBundlerUrl +} from "../bundler/index.js" +import { + BaseValidationModule, + type ModuleInfo, + type SendUserOpParams, + createECDSAOwnershipValidationModule +} from "../modules" import { - IHybridPaymaster, - IPaymaster, + BiconomyPaymaster, + type FeeQuotesOrDataDto, + type FeeQuotesOrDataResponse, + type IHybridPaymaster, + type IPaymaster, Paymaster, PaymasterMode, - SponsorUserOperationDto, - Bundler, - IBundler, - UserOpResponse, - extractChainIdFromBundlerUrl, + type SponsorUserOperationDto +} from "../paymaster" +import { + type BigNumberish, + Logger, + type SmartAccountSigner, + type StateOverrideSet, + type UserOperationStruct, convertSigner, - NATIVE_TOKEN_ALIAS, -} from "./index.js"; + getChain +} from "./" +import { BaseSmartContractAccount } from "./BaseSmartContractAccount.js" +import { AccountResolverAbi } from "./abi/AccountResolver.js" +import { BiconomyFactoryAbi } from "./abi/Factory.js" +import { BiconomyAccountAbi } from "./abi/SmartAccount.js" import { - BiconomyTokenPaymasterRequest, + ADDRESS_RESOLVER_ADDRESS, + ADDRESS_ZERO, + BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION, + DEFAULT_BICONOMY_FACTORY_ADDRESS, + DEFAULT_ENTRYPOINT_ADDRESS, + DEFAULT_FALLBACK_HANDLER_ADDRESS, + ERC20_ABI, + ERROR_MESSAGES, + NATIVE_TOKEN_ALIAS, + PROXY_CREATION_CODE +} from "./utils/Constants.js" +import type { + BalancePayload, + BatchUserOperationCallData, BiconomySmartAccountV2Config, - CounterFactualAddressParam, + BiconomySmartAccountV2ConfigConstructorProps, + BiconomyTokenPaymasterRequest, BuildUserOpOptions, + CounterFactualAddressParam, NonceOptions, - Transaction, - QueryParamsForAddressResolver, - BiconomySmartAccountV2ConfigConstructorProps, PaymasterUserOperationDto, + QueryParamsForAddressResolver, SimulationType, - BalancePayload, SupportedToken, - WithdrawalRequest, -} from "./utils/Types.js"; + Transaction, + WithdrawalRequest +} from "./utils/Types.js" import { - ADDRESS_RESOLVER_ADDRESS, - BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION, - DEFAULT_BICONOMY_FACTORY_ADDRESS, - DEFAULT_FALLBACK_HANDLER_ADDRESS, - PROXY_CREATION_CODE, - ADDRESS_ZERO, - DEFAULT_ENTRYPOINT_ADDRESS, - ERROR_MESSAGES, - ERC20_ABI, -} from "./utils/Constants.js"; -import { BiconomyFactoryAbi } from "./abi/Factory.js"; -import { BiconomyAccountAbi } from "./abi/SmartAccount.js"; -import { AccountResolverAbi } from "./abi/AccountResolver.js"; -import { Logger, StateOverrideSet } from "@biconomy/common"; -import { BiconomyPaymaster, FeeQuotesOrDataDto, FeeQuotesOrDataResponse } from "@biconomy/paymaster"; + addressEquals, + compareChainIds, + isNullOrUndefined, + isValidRpcUrl, + packUserOp +} from "./utils/Utils.js" -type UserOperationKey = keyof UserOperationStruct; +type UserOperationKey = keyof UserOperationStruct export class BiconomySmartAccountV2 extends BaseSmartContractAccount { - private SENTINEL_MODULE = "0x0000000000000000000000000000000000000001"; + private SENTINEL_MODULE = "0x0000000000000000000000000000000000000001" - private index: number; + private index: number - private chainId: number; + private chainId: number - private provider: PublicClient; + private provider: PublicClient - paymaster?: IPaymaster; + paymaster?: IPaymaster - bundler?: IBundler; + bundler?: IBundler - private accountContract?: GetContractReturnType<typeof BiconomyAccountAbi, PublicClient>; + private accountContract?: GetContractReturnType< + typeof BiconomyAccountAbi, + PublicClient + > - private defaultFallbackHandlerAddress: Hex; + private defaultFallbackHandlerAddress: Hex - private implementationAddress: Hex; + private implementationAddress: Hex - private scanForUpgradedAccountsFromV1!: boolean; + private scanForUpgradedAccountsFromV1!: boolean - private maxIndexForScan!: number; + private maxIndexForScan!: number // Validation module responsible for account deployment initCode. This acts as a default authorization module. - defaultValidationModule!: BaseValidationModule; + defaultValidationModule!: BaseValidationModule // Deployed Smart Account can have more than one module enabled. When sending a transaction activeValidationModule is used to prepare and validate userOp signature. - activeValidationModule!: BaseValidationModule; + activeValidationModule!: BaseValidationModule - private constructor(readonly biconomySmartAccountConfig: BiconomySmartAccountV2ConfigConstructorProps) { + private constructor( + readonly biconomySmartAccountConfig: BiconomySmartAccountV2ConfigConstructorProps + ) { super({ ...biconomySmartAccountConfig, - chain: biconomySmartAccountConfig.viemChain ?? getChain(biconomySmartAccountConfig.chainId), - rpcClient: biconomySmartAccountConfig.rpcUrl || getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0], - entryPointAddress: (biconomySmartAccountConfig.entryPointAddress as Hex) ?? DEFAULT_ENTRYPOINT_ADDRESS, - accountAddress: (biconomySmartAccountConfig.accountAddress as Hex) ?? undefined, - factoryAddress: biconomySmartAccountConfig.factoryAddress ?? DEFAULT_BICONOMY_FACTORY_ADDRESS, - }); - - this.defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule; - this.activeValidationModule = biconomySmartAccountConfig.activeValidationModule; - - this.index = biconomySmartAccountConfig.index ?? 0; - this.chainId = biconomySmartAccountConfig.chainId; - this.bundler = biconomySmartAccountConfig.bundler; - this.implementationAddress = biconomySmartAccountConfig.implementationAddress ?? (BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION.V2_0_0 as Hex); + chain: + biconomySmartAccountConfig.viemChain ?? + getChain(biconomySmartAccountConfig.chainId), + rpcClient: + biconomySmartAccountConfig.rpcUrl || + getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0], + entryPointAddress: + (biconomySmartAccountConfig.entryPointAddress as Hex) ?? + DEFAULT_ENTRYPOINT_ADDRESS, + accountAddress: + (biconomySmartAccountConfig.accountAddress as Hex) ?? undefined, + factoryAddress: + biconomySmartAccountConfig.factoryAddress ?? + DEFAULT_BICONOMY_FACTORY_ADDRESS + }) + + this.defaultValidationModule = + biconomySmartAccountConfig.defaultValidationModule + this.activeValidationModule = + biconomySmartAccountConfig.activeValidationModule + + this.index = biconomySmartAccountConfig.index ?? 0 + this.chainId = biconomySmartAccountConfig.chainId + this.bundler = biconomySmartAccountConfig.bundler + this.implementationAddress = + biconomySmartAccountConfig.implementationAddress ?? + (BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION.V2_0_0 as Hex) if (biconomySmartAccountConfig.paymasterUrl) { this.paymaster = new Paymaster({ - paymasterUrl: biconomySmartAccountConfig.paymasterUrl, - }); + paymasterUrl: biconomySmartAccountConfig.paymasterUrl + }) } else if (biconomySmartAccountConfig.biconomyPaymasterApiKey) { this.paymaster = new Paymaster({ - paymasterUrl: `https://paymaster.biconomy.io/api/v1/${biconomySmartAccountConfig.chainId}/${biconomySmartAccountConfig.biconomyPaymasterApiKey}`, - }); + paymasterUrl: `https://paymaster.biconomy.io/api/v1/${biconomySmartAccountConfig.chainId}/${biconomySmartAccountConfig.biconomyPaymasterApiKey}` + }) } else { - this.paymaster = biconomySmartAccountConfig.paymaster; + this.paymaster = biconomySmartAccountConfig.paymaster } - this.bundler = biconomySmartAccountConfig.bundler; + this.bundler = biconomySmartAccountConfig.bundler const defaultFallbackHandlerAddress = - this.factoryAddress === DEFAULT_BICONOMY_FACTORY_ADDRESS ? DEFAULT_FALLBACK_HANDLER_ADDRESS : biconomySmartAccountConfig.defaultFallbackHandler; + this.factoryAddress === DEFAULT_BICONOMY_FACTORY_ADDRESS + ? DEFAULT_FALLBACK_HANDLER_ADDRESS + : biconomySmartAccountConfig.defaultFallbackHandler if (!defaultFallbackHandlerAddress) { - throw new Error("Default Fallback Handler address is not provided"); + throw new Error("Default Fallback Handler address is not provided") } - this.defaultFallbackHandlerAddress = defaultFallbackHandlerAddress; + this.defaultFallbackHandlerAddress = defaultFallbackHandlerAddress // Added bang operator to avoid null check as the constructor have these params as optional - this.defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule!; - this.activeValidationModule = biconomySmartAccountConfig.activeValidationModule!; + this.defaultValidationModule = + // biome-ignore lint/style/noNonNullAssertion: <explanation> + biconomySmartAccountConfig.defaultValidationModule! + this.activeValidationModule = + // biome-ignore lint/style/noNonNullAssertion: <explanation> + biconomySmartAccountConfig.activeValidationModule! this.provider = createPublicClient({ - chain: biconomySmartAccountConfig.viemChain ?? getChain(biconomySmartAccountConfig.chainId), - transport: http(biconomySmartAccountConfig.rpcUrl || getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0]), - }); - - this.scanForUpgradedAccountsFromV1 = biconomySmartAccountConfig.scanForUpgradedAccountsFromV1 ?? false; - this.maxIndexForScan = biconomySmartAccountConfig.maxIndexForScan ?? 10; + chain: + biconomySmartAccountConfig.viemChain ?? + getChain(biconomySmartAccountConfig.chainId), + transport: http( + biconomySmartAccountConfig.rpcUrl || + getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0] + ) + }) + + this.scanForUpgradedAccountsFromV1 = + biconomySmartAccountConfig.scanForUpgradedAccountsFromV1 ?? false + this.maxIndexForScan = biconomySmartAccountConfig.maxIndexForScan ?? 10 } /** @@ -172,11 +218,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient, BiconomySmartAccountV2 } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -189,50 +235,71 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); * */ - public static async create(biconomySmartAccountConfig: BiconomySmartAccountV2Config): Promise<BiconomySmartAccountV2> { - let chainId = biconomySmartAccountConfig.chainId; - let rpcUrl = biconomySmartAccountConfig.rpcUrl; - let resolvedSmartAccountSigner!: SmartAccountSigner; + public static async create( + biconomySmartAccountConfig: BiconomySmartAccountV2Config + ): Promise<BiconomySmartAccountV2> { + let chainId = biconomySmartAccountConfig.chainId + let rpcUrl = biconomySmartAccountConfig.rpcUrl + let resolvedSmartAccountSigner!: SmartAccountSigner // Signer needs to be initialised here before defaultValidationModule is set if (biconomySmartAccountConfig.signer) { - const signerResult = await convertSigner(biconomySmartAccountConfig.signer, !!chainId); + const signerResult = await convertSigner( + biconomySmartAccountConfig.signer, + !!chainId, + rpcUrl + ) if (!chainId && !!signerResult.chainId) { - chainId = signerResult.chainId; + chainId = signerResult.chainId } if (!rpcUrl && !!signerResult.rpcUrl) { if (isValidRpcUrl(signerResult.rpcUrl)) { - rpcUrl = signerResult.rpcUrl; + rpcUrl = signerResult.rpcUrl } } - resolvedSmartAccountSigner = signerResult.signer; + resolvedSmartAccountSigner = signerResult.signer } if (!chainId) { // Get it from bundler if (biconomySmartAccountConfig.bundlerUrl) { - chainId = extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundlerUrl); + chainId = extractChainIdFromBundlerUrl( + biconomySmartAccountConfig.bundlerUrl + ) } else if (biconomySmartAccountConfig.bundler) { - const bundlerUrlFromBundler = biconomySmartAccountConfig.bundler.getBundlerUrl(); - chainId = extractChainIdFromBundlerUrl(bundlerUrlFromBundler); + const bundlerUrlFromBundler = + biconomySmartAccountConfig.bundler.getBundlerUrl() + chainId = extractChainIdFromBundlerUrl(bundlerUrlFromBundler) } } if (!chainId) { - throw new Error("chainId required"); + throw new Error("chainId required") } - const bundler: IBundler = biconomySmartAccountConfig.bundler ?? new Bundler({ bundlerUrl: biconomySmartAccountConfig.bundlerUrl!, chainId }); - let defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule; + const bundler: IBundler = + biconomySmartAccountConfig.bundler ?? + new Bundler({ + // biome-ignore lint/style/noNonNullAssertion: <explanation> + bundlerUrl: biconomySmartAccountConfig.bundlerUrl!, + chainId + }) + let defaultValidationModule = + biconomySmartAccountConfig.defaultValidationModule // Note: If no module is provided, we will use ECDSA_OWNERSHIP as default if (!defaultValidationModule) { - const newModule = await createECDSAOwnershipValidationModule({ signer: resolvedSmartAccountSigner! }); - defaultValidationModule = newModule; + const newModule = await createECDSAOwnershipValidationModule({ + // biome-ignore lint/style/noNonNullAssertion: <explanation> + signer: resolvedSmartAccountSigner! + }) + defaultValidationModule = newModule } - const activeValidationModule = biconomySmartAccountConfig?.activeValidationModule ?? defaultValidationModule; + const activeValidationModule = + biconomySmartAccountConfig?.activeValidationModule ?? + defaultValidationModule if (!resolvedSmartAccountSigner) { - resolvedSmartAccountSigner = await activeValidationModule.getSigner(); + resolvedSmartAccountSigner = await activeValidationModule.getSigner() } if (!resolvedSmartAccountSigner) { - throw new Error("signer required"); + throw new Error("signer required") } const config: BiconomySmartAccountV2ConfigConstructorProps = { ...biconomySmartAccountConfig, @@ -241,34 +308,40 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { chainId, bundler, signer: resolvedSmartAccountSigner, - rpcUrl, - }; + rpcUrl + } // We check if chain ids match (skip this if chainId is passed by in the config) // This check is at the end of the function for cases when the signer is not passed in the config but a validation modules is and we get the signer from the validation module in this case if (!biconomySmartAccountConfig.chainId) { - await compareChainIds(biconomySmartAccountConfig.signer || resolvedSmartAccountSigner, config, false); + await compareChainIds( + biconomySmartAccountConfig.signer || resolvedSmartAccountSigner, + config, + false + ) } - return new BiconomySmartAccountV2(config); + return new BiconomySmartAccountV2(config) } // Calls the getCounterFactualAddress - async getAddress(params?: CounterFactualAddressParam): Promise<Hex> { + override async getAddress(params?: CounterFactualAddressParam): Promise<Hex> { if (this.accountAddress == null) { // means it needs deployment - this.accountAddress = await this.getCounterFactualAddress(params); + this.accountAddress = await this.getCounterFactualAddress(params) } - return this.accountAddress; + return this.accountAddress } // Calls the getCounterFactualAddress - async getAccountAddress(params?: CounterFactualAddressParam): Promise<`0x${string}`> { - if (this.accountAddress == null || this.accountAddress == undefined) { + async getAccountAddress( + params?: CounterFactualAddressParam + ): Promise<`0x${string}`> { + if (this.accountAddress == null || this.accountAddress === undefined) { // means it needs deployment - this.accountAddress = await this.getCounterFactualAddress(params); + this.accountAddress = await this.getCounterFactualAddress(params) } - return this.accountAddress; + return this.accountAddress } /** @@ -284,25 +357,25 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * - * const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); - * const [usdtBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]); + * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([token]); * - * console.log(usdtBalanceFromSmartAccount); + * console.log(tokenBalanceFromSmartAccount); * // { * // amount: 1000000000000000n, * // decimals: 6, - * // address: "0xda5289fcaaf71d52a80a254da614a192b693e977", + * // address: "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a", * // formattedAmount: "1000000", - * // chainId: 80001 + * // chainId: 80002 * // } * * // or to get the nativeToken balance @@ -315,26 +388,35 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * // decimals: 18, * // address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", * // formattedAmount: "1", - * // chainId: 80001 + * // chainId: 80002 * // } * */ - public async getBalances(addresses?: Array<Hex>): Promise<Array<BalancePayload>> { - const accountAddress = await this.getAccountAddress(); - const result: BalancePayload[] = []; + public async getBalances( + addresses?: Array<Hex> + ): Promise<Array<BalancePayload>> { + const accountAddress = await this.getAccountAddress() + const result: BalancePayload[] = [] if (addresses) { const tokenContracts = addresses.map((address) => getContract({ address, abi: parseAbi(ERC20_ABI), - client: this.provider, - }), - ); - - const balancePromises = tokenContracts.map((tokenContract) => tokenContract.read.balanceOf([accountAddress])) as Promise<bigint>[]; - const decimalsPromises = tokenContracts.map((tokenContract) => tokenContract.read.decimals()) as Promise<number>[]; - const [balances, decimalsPerToken] = await Promise.all([Promise.all(balancePromises), Promise.all(decimalsPromises)]); + client: this.provider + }) + ) + + const balancePromises = tokenContracts.map((tokenContract) => + tokenContract.read.balanceOf([accountAddress]) + ) as Promise<bigint>[] + const decimalsPromises = tokenContracts.map((tokenContract) => + tokenContract.read.decimals() + ) as Promise<number>[] + const [balances, decimalsPerToken] = await Promise.all([ + Promise.all(balancePromises), + Promise.all(decimalsPromises) + ]) balances.forEach((amount, index) => result.push({ @@ -342,22 +424,22 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { decimals: decimalsPerToken[index], address: addresses[index], formattedAmount: formatUnits(amount, decimalsPerToken[index]), - chainId: this.chainId, - }), - ); + chainId: this.chainId + }) + ) } - const balance = await this.provider.getBalance({ address: accountAddress }); + const balance = await this.provider.getBalance({ address: accountAddress }) result.push({ amount: balance, decimals: 18, address: NATIVE_TOKEN_ALIAS, formattedAmount: formatUnits(balance, 18), - chainId: this.chainId, - }); + chainId: this.chainId + }) - return result; + return result } /** @@ -374,7 +456,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createWalletClient, http } from "viem"; * import { polygonMumbai } from "viem/chains"; * - * const USDT = "0xda5289fcaaf71d52a80a254da614a192b693e977"; + * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; * const signer = createWalletClient({ * account, * chain: polygonMumbai, @@ -385,7 +467,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * const { wait } = await smartAccount.withdraw( * [ - * { address: USDT }, // omit the amount to withdraw the full balance + * { address: token }, // omit the amount to withdraw the full balance * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } * ], * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request @@ -405,166 +487,219 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { public async withdraw( withdrawalRequests?: WithdrawalRequest[] | null, defaultRecipient?: Hex | null, - buildUseropDto?: BuildUserOpOptions, + buildUseropDto?: BuildUserOpOptions ): Promise<UserOpResponse> { - const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + const accountAddress = + this.accountAddress ?? (await this.getAccountAddress()) - if (!defaultRecipient && withdrawalRequests?.some(({ recipient }) => !recipient)) { - throw new Error(ERROR_MESSAGES.NO_RECIPIENT); + if ( + !defaultRecipient && + withdrawalRequests?.some(({ recipient }) => !recipient) + ) { + throw new Error(ERROR_MESSAGES.NO_RECIPIENT) } // Remove the native token from the withdrawal requests - let tokenRequests = withdrawalRequests?.filter(({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)) ?? []; + let tokenRequests = + withdrawalRequests?.filter( + ({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS) + ) ?? [] // Check if the amount is not present in all withdrawal requests - const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount); + const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount) // Get the balances of the tokens if the amount is not present in the withdrawal requests if (shouldFetchMaxBalances) { - const balances = await this.getBalances(tokenRequests.map(({ address }) => address)); + const balances = await this.getBalances( + tokenRequests.map(({ address }) => address) + ) tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ address, - amount: amount ?? balances[i].amount, - })); + amount: amount ?? balances[i].amount + })) } // Create the transactions - const txs: Transaction[] = tokenRequests.map(({ address, amount, recipient: recipientFromRequest }) => ({ - to: address, - data: encodeFunctionData({ - abi: parseAbi(ERC20_ABI), - functionName: "transfer", - args: [recipientFromRequest || defaultRecipient, amount], - }), - })); + const txs: Transaction[] = tokenRequests.map( + ({ address, amount, recipient: recipientFromRequest }) => ({ + to: address, + data: encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: "transfer", + args: [recipientFromRequest || defaultRecipient, amount] + }) + }) + ) // Check if eth alias is present in the original withdrawal requests - const nativeTokenRequest = withdrawalRequests?.find(({ address }) => addressEquals(address, NATIVE_TOKEN_ALIAS)); - const hasNoRequests = !withdrawalRequests?.length; + const nativeTokenRequest = withdrawalRequests?.find(({ address }) => + addressEquals(address, NATIVE_TOKEN_ALIAS) + ) + const hasNoRequests = !withdrawalRequests?.length if (!!nativeTokenRequest || hasNoRequests) { // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster. - if (!nativeTokenRequest?.amount && !buildUseropDto?.paymasterServiceData?.mode) { - throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT); + if ( + !nativeTokenRequest?.amount && + !buildUseropDto?.paymasterServiceData?.mode + ) { + throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT) } // get eth balance if not present in withdrawal requests - const nativeTokenAmountToWithdraw = nativeTokenRequest?.amount ?? (await this.provider.getBalance({ address: accountAddress })); + const nativeTokenAmountToWithdraw = + nativeTokenRequest?.amount ?? + (await this.provider.getBalance({ address: accountAddress })) txs.push({ to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex, - value: nativeTokenAmountToWithdraw, - }); + value: nativeTokenAmountToWithdraw + }) } - return this.sendTransaction(txs, buildUseropDto); + return this.sendTransaction(txs, buildUseropDto) } /** * Return the account's address. This value is valid even before deploying the contract. */ - async getCounterFactualAddress(params?: CounterFactualAddressParam): Promise<Hex> { - const validationModule = params?.validationModule ?? this.defaultValidationModule; - const index = params?.index ?? this.index; - - const maxIndexForScan = params?.maxIndexForScan ?? this.maxIndexForScan; + async getCounterFactualAddress( + params?: CounterFactualAddressParam + ): Promise<Hex> { + const validationModule = + params?.validationModule ?? this.defaultValidationModule + const index = params?.index ?? this.index + + const maxIndexForScan = params?.maxIndexForScan ?? this.maxIndexForScan // Review: default behavior - const scanForUpgradedAccountsFromV1 = params?.scanForUpgradedAccountsFromV1 ?? this.scanForUpgradedAccountsFromV1; + const scanForUpgradedAccountsFromV1 = + params?.scanForUpgradedAccountsFromV1 ?? + this.scanForUpgradedAccountsFromV1 // if it's intended to detect V1 upgraded accounts if (scanForUpgradedAccountsFromV1) { - const eoaSigner = await validationModule.getSigner(); - const eoaAddress = (await eoaSigner.getAddress()) as Hex; - const moduleAddress = validationModule.getAddress() as Hex; - const moduleSetupData = (await validationModule.getInitData()) as Hex; + const eoaSigner = await validationModule.getSigner() + const eoaAddress = (await eoaSigner.getAddress()) as Hex + const moduleAddress = validationModule.getAddress() as Hex + const moduleSetupData = (await validationModule.getInitData()) as Hex const queryParams = { eoaAddress, index, moduleAddress, moduleSetupData, - maxIndexForScan, - }; - const accountAddress = await this.getV1AccountsUpgradedToV2(queryParams); + maxIndexForScan + } + const accountAddress = await this.getV1AccountsUpgradedToV2(queryParams) if (accountAddress !== ADDRESS_ZERO) { - return accountAddress; + return accountAddress } } - const counterFactualAddressV2 = await this.getCounterFactualAddressV2({ validationModule, index }); - return counterFactualAddressV2; + const counterFactualAddressV2 = await this.getCounterFactualAddressV2({ + validationModule, + index + }) + return counterFactualAddressV2 } - private async getCounterFactualAddressV2(params?: CounterFactualAddressParam): Promise<Hex> { - const validationModule = params?.validationModule ?? this.defaultValidationModule; - const index = params?.index ?? this.index; + private async getCounterFactualAddressV2( + params?: CounterFactualAddressParam + ): Promise<Hex> { + const validationModule = + params?.validationModule ?? this.defaultValidationModule + const index = params?.index ?? this.index try { const initCalldata = encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "init", - args: [this.defaultFallbackHandlerAddress, validationModule.getAddress() as Hex, (await validationModule.getInitData()) as Hex], - }); - - const proxyCreationCodeHash = keccak256(encodePacked(["bytes", "uint256"], [PROXY_CREATION_CODE, BigInt(this.implementationAddress)])); - - const salt = keccak256(encodePacked(["bytes32", "uint256"], [keccak256(initCalldata), BigInt(index)])); + args: [ + this.defaultFallbackHandlerAddress, + validationModule.getAddress() as Hex, + (await validationModule.getInitData()) as Hex + ] + }) + + const proxyCreationCodeHash = keccak256( + encodePacked( + ["bytes", "uint256"], + [PROXY_CREATION_CODE, BigInt(this.implementationAddress)] + ) + ) + + const salt = keccak256( + encodePacked( + ["bytes32", "uint256"], + [keccak256(initCalldata), BigInt(index)] + ) + ) const counterFactualAddress = getCreate2Address({ from: this.factoryAddress, salt: salt, - bytecodeHash: proxyCreationCodeHash, - }); + bytecodeHash: proxyCreationCodeHash + }) - return counterFactualAddress; + return counterFactualAddress } catch (e) { - throw new Error(`Failed to get counterfactual address, ${e}`); + throw new Error(`Failed to get counterfactual address, ${e}`) } } - async _getAccountContract(): Promise<GetContractReturnType<typeof BiconomyAccountAbi, PublicClient>> { + async _getAccountContract(): Promise< + GetContractReturnType<typeof BiconomyAccountAbi, PublicClient> + > { if (this.accountContract == null) { this.accountContract = getContract({ address: await this.getAddress(), abi: BiconomyAccountAbi, - client: this.provider as PublicClient, - }); + client: this.provider as PublicClient + }) } - return this.accountContract; + return this.accountContract } isActiveValidationModuleDefined(): boolean { - if (!this.activeValidationModule) throw new Error("Must provide an instance of active validation module."); - return true; + if (!this.activeValidationModule) + throw new Error("Must provide an instance of active validation module.") + return true } isDefaultValidationModuleDefined(): boolean { - if (!this.defaultValidationModule) throw new Error("Must provide an instance of default validation module."); - return true; + if (!this.defaultValidationModule) + throw new Error("Must provide an instance of default validation module.") + return true } - setActiveValidationModule(validationModule: BaseValidationModule): BiconomySmartAccountV2 { + setActiveValidationModule( + validationModule: BaseValidationModule + ): BiconomySmartAccountV2 { if (validationModule instanceof BaseValidationModule) { - this.activeValidationModule = validationModule; + this.activeValidationModule = validationModule } - return this; + return this } - setDefaultValidationModule(validationModule: BaseValidationModule): BiconomySmartAccountV2 { + setDefaultValidationModule( + validationModule: BaseValidationModule + ): BiconomySmartAccountV2 { if (validationModule instanceof BaseValidationModule) { - this.defaultValidationModule = validationModule; + this.defaultValidationModule = validationModule } - return this; + return this } - async getV1AccountsUpgradedToV2(params: QueryParamsForAddressResolver): Promise<Hex> { - const maxIndexForScan = params.maxIndexForScan ?? this.maxIndexForScan; + async getV1AccountsUpgradedToV2( + params: QueryParamsForAddressResolver + ): Promise<Hex> { + const maxIndexForScan = params.maxIndexForScan ?? this.maxIndexForScan const addressResolver = getContract({ address: ADDRESS_RESOLVER_ADDRESS, abi: AccountResolverAbi, client: { - public: this.provider as PublicClient, - }, - }); + public: this.provider as PublicClient + } + }) // Note: depending on moduleAddress and moduleSetupData passed call this. otherwise could call resolveAddresses() if (params.moduleAddress && params.moduleSetupData) { @@ -572,25 +707,27 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { params.eoaAddress, maxIndexForScan, params.moduleAddress, - params.moduleSetupData, - ]); + params.moduleSetupData + ]) const desiredV1Account = result.find( - (smartAccountInfo: { factoryVersion: string; currentVersion: string; deploymentIndex: { toString: () => any } }) => + (smartAccountInfo: { + factoryVersion: string + currentVersion: string + deploymentIndex: { toString: () => any } + }) => smartAccountInfo.factoryVersion === "v1" && smartAccountInfo.currentVersion === "2.0.0" && - Number(smartAccountInfo.deploymentIndex.toString()) === params.index, - ); + Number(smartAccountInfo.deploymentIndex.toString()) === params.index + ) if (desiredV1Account) { - const smartAccountAddress = desiredV1Account.accountAddress; - return smartAccountAddress; - } else { - return ADDRESS_ZERO; + const smartAccountAddress = desiredV1Account.accountAddress + return smartAccountAddress } - } else { - return ADDRESS_ZERO; + return ADDRESS_ZERO } + return ADDRESS_ZERO } /** @@ -598,16 +735,20 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * This value holds the "factory" address, followed by this account's information */ async getAccountInitCode(): Promise<Hex> { - this.isDefaultValidationModuleDefined(); + this.isDefaultValidationModuleDefined() return concatHex([ this.factoryAddress as Hex, encodeFunctionData({ abi: BiconomyFactoryAbi, functionName: "deployCounterFactualAccount", - args: [this.defaultValidationModule.getAddress() as Hex, (await this.defaultValidationModule.getInitData()) as Hex, BigInt(this.index)], - }), - ]); + args: [ + this.defaultValidationModule.getAddress() as Hex, + (await this.defaultValidationModule.getInitData()) as Hex, + BigInt(this.index) + ] + }) + ]) } /** @@ -622,8 +763,8 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { return encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "execute_ncC", - args: [to, value, data], - }); + args: [to, value, data] + }) } /** @@ -633,56 +774,68 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * @param data represent array of data associated with each transaction * @returns encoded data for executeBatch function */ - async encodeExecuteBatch(to: Array<Hex>, value: Array<bigint>, data: Array<Hex>): Promise<Hex> { + async encodeExecuteBatch( + to: Array<Hex>, + value: Array<bigint>, + data: Array<Hex> + ): Promise<Hex> { return encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "executeBatch_y6U", - args: [to, value, data], - }); + args: [to, value, data] + }) } - override async encodeBatchExecute(txs: BatchUserOperationCallData): Promise<Hex> { + override async encodeBatchExecute( + txs: BatchUserOperationCallData + ): Promise<Hex> { const [targets, datas, value] = txs.reduce( (accum, curr) => { - accum[0].push(curr.target); - accum[1].push(curr.data); - accum[2].push(curr.value || BigInt(0)); + accum[0].push(curr.target) + accum[1].push(curr.data) + accum[2].push(curr.value || BigInt(0)) - return accum; + return accum }, - [[], [], []] as [Hex[], Hex[], bigint[]], - ); + [[], [], []] as [Hex[], Hex[], bigint[]] + ) - return this.encodeExecuteBatch(targets, value, datas); + return this.encodeExecuteBatch(targets, value, datas) } // dummy signature depends on the validation module supplied. async getDummySignatures(params?: ModuleInfo): Promise<Hex> { - this.isActiveValidationModuleDefined(); - return (await this.activeValidationModule.getDummySignature(params)) as Hex; + this.isActiveValidationModuleDefined() + return (await this.activeValidationModule.getDummySignature(params)) as Hex } // TODO: review this getDummySignature(): Hex { - throw new Error("Method not implemented! Call getDummySignatures instead."); + throw new Error("Method not implemented! Call getDummySignatures instead.") } // Might use provided paymaster instance to get dummy data (from pm service) getDummyPaymasterData(): string { - return "0x"; + return "0x" } - validateUserOp(userOp: Partial<UserOperationStruct>, requiredFields: UserOperationKey[]): boolean { + validateUserOp( + userOp: Partial<UserOperationStruct>, + requiredFields: UserOperationKey[] + ): boolean { for (const field of requiredFields) { if (isNullOrUndefined(userOp[field])) { - throw new Error(`${String(field)} is missing in the UserOp`); + throw new Error(`${String(field)} is missing in the UserOp`) } } - return true; + return true } - async signUserOp(userOp: Partial<UserOperationStruct>, params?: SendUserOpParams): Promise<UserOperationStruct> { - this.isActiveValidationModuleDefined(); + async signUserOp( + userOp: Partial<UserOperationStruct>, + params?: SendUserOpParams + ): Promise<UserOperationStruct> { + this.isActiveValidationModuleDefined() const requiredFields: UserOperationKey[] = [ "sender", "nonce", @@ -693,90 +846,124 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { "preVerificationGas", "maxFeePerGas", "maxPriorityFeePerGas", - "paymasterAndData", - ]; - this.validateUserOp(userOp, requiredFields); - const userOpHash = await this.getUserOpHash(userOp); + "paymasterAndData" + ] + this.validateUserOp(userOp, requiredFields) + const userOpHash = await this.getUserOpHash(userOp) - const moduleSig = (await this.activeValidationModule.signUserOpHash(userOpHash, params)) as Hex; + const moduleSig = (await this.activeValidationModule.signUserOpHash( + userOpHash, + params + )) as Hex - const signatureWithModuleAddress = this.getSignatureWithModuleAddress(moduleSig, this.activeValidationModule.getAddress() as Hex); + const signatureWithModuleAddress = this.getSignatureWithModuleAddress( + moduleSig, + this.activeValidationModule.getAddress() as Hex + ) - userOp.signature = signatureWithModuleAddress; - return userOp as UserOperationStruct; + userOp.signature = signatureWithModuleAddress + return userOp as UserOperationStruct } - getSignatureWithModuleAddress(moduleSignature: Hex, moduleAddress?: Hex): Hex { - const moduleAddressToUse = moduleAddress ?? (this.activeValidationModule.getAddress() as Hex); - return encodeAbiParameters(parseAbiParameters("bytes, address"), [moduleSignature, moduleAddressToUse]); + getSignatureWithModuleAddress( + moduleSignature: Hex, + moduleAddress?: Hex + ): Hex { + const moduleAddressToUse = + moduleAddress ?? (this.activeValidationModule.getAddress() as Hex) + return encodeAbiParameters(parseAbiParameters("bytes, address"), [ + moduleSignature, + moduleAddressToUse + ]) } public async getPaymasterUserOp( userOp: Partial<UserOperationStruct>, - paymasterServiceData: PaymasterUserOperationDto, + paymasterServiceData: PaymasterUserOperationDto ): Promise<Partial<UserOperationStruct>> { if (paymasterServiceData.mode === PaymasterMode.SPONSORED) { - return this.getPaymasterAndData(userOp, paymasterServiceData); - } else if (paymasterServiceData.mode === PaymasterMode.ERC20) { + return this.getPaymasterAndData(userOp, paymasterServiceData) + } + if (paymasterServiceData.mode === PaymasterMode.ERC20) { if (paymasterServiceData?.feeQuote) { - const { feeQuote, spender, maxApproval = false } = paymasterServiceData; - Logger.log("there is a feeQuote: ", feeQuote); - if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED); - if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH); - if (paymasterServiceData.skipPatchCallData && paymasterServiceData.skipPatchCallData === true) { + const { feeQuote, spender, maxApproval = false } = paymasterServiceData + Logger.log("there is a feeQuote: ", feeQuote) + if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED) + if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH) + if ( + paymasterServiceData.skipPatchCallData && + paymasterServiceData.skipPatchCallData === true + ) { return this.getPaymasterAndData(userOp, { ...paymasterServiceData, - feeTokenAddress: feeQuote.tokenAddress, - }); + feeTokenAddress: feeQuote.tokenAddress + }) } const partialUserOp = await this.buildTokenPaymasterUserOp(userOp, { ...paymasterServiceData, spender, maxApproval, - feeQuote, - }); + feeQuote + }) return this.getPaymasterAndData(partialUserOp, { ...paymasterServiceData, feeTokenAddress: feeQuote.tokenAddress, - calculateGasLimits: true, // Always recommended and especially when using token paymaster - }); - } else if (paymasterServiceData?.preferredToken) { - const { preferredToken } = paymasterServiceData; - Logger.log("there is a preferred token: ", preferredToken); - const feeQuotesResponse = await this.getPaymasterFeeQuotesOrData(userOp, paymasterServiceData); - const spender = feeQuotesResponse.tokenPaymasterAddress; - const feeQuote = feeQuotesResponse.feeQuotes?.[0]; - if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED); - if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH); - return this.getPaymasterUserOp(userOp, { ...paymasterServiceData, feeQuote, spender }); // Recursively call getPaymasterUserOp with the feeQuote - } else { - Logger.log("ERC20 mode without feeQuote or preferredToken provided. Passing through unchanged."); - return userOp; + calculateGasLimits: true // Always recommended and especially when using token paymaster + }) + } + if (paymasterServiceData?.preferredToken) { + const { preferredToken } = paymasterServiceData + Logger.log("there is a preferred token: ", preferredToken) + const feeQuotesResponse = await this.getPaymasterFeeQuotesOrData( + userOp, + paymasterServiceData + ) + const spender = feeQuotesResponse.tokenPaymasterAddress + const feeQuote = feeQuotesResponse.feeQuotes?.[0] + if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED) + if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH) + return this.getPaymasterUserOp(userOp, { + ...paymasterServiceData, + feeQuote, + spender + }) // Recursively call getPaymasterUserOp with the feeQuote } + Logger.log( + "ERC20 mode without feeQuote or preferredToken provided. Passing through unchanged." + ) + return userOp } - throw new Error("Invalid paymaster mode"); + throw new Error("Invalid paymaster mode") } private async getPaymasterAndData( userOp: Partial<UserOperationStruct>, - paymasterServiceData: PaymasterUserOperationDto, + paymasterServiceData: PaymasterUserOperationDto ): Promise<Partial<UserOperationStruct>> { - const paymaster = this.paymaster as IHybridPaymaster<PaymasterUserOperationDto>; - const paymasterData = await paymaster.getPaymasterAndData(userOp, paymasterServiceData); - return { ...userOp, ...paymasterData }; + const paymaster = this + .paymaster as IHybridPaymaster<PaymasterUserOperationDto> + const paymasterData = await paymaster.getPaymasterAndData( + userOp, + paymasterServiceData + ) + return { ...userOp, ...paymasterData } } private async getPaymasterFeeQuotesOrData( userOp: Partial<UserOperationStruct>, - feeQuotesOrData: FeeQuotesOrDataDto, + feeQuotesOrData: FeeQuotesOrDataDto ): Promise<FeeQuotesOrDataResponse> { - const paymaster = this.paymaster as IHybridPaymaster<PaymasterUserOperationDto>; + const paymaster = this + .paymaster as IHybridPaymaster<PaymasterUserOperationDto> const tokenList = feeQuotesOrData?.preferredToken ? [feeQuotesOrData?.preferredToken] : feeQuotesOrData?.tokenList?.length ? feeQuotesOrData?.tokenList - : []; - return paymaster.getPaymasterFeeQuotesOrData(userOp, { ...feeQuotesOrData, tokenList }); + : [] + return paymaster.getPaymasterFeeQuotesOrData(userOp, { + ...feeQuotesOrData, + tokenList + }) } /** @@ -791,11 +978,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -828,12 +1015,18 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { */ public async getTokenFees( manyOrOneTransactions: Transaction | Transaction[], - buildUseropDto: BuildUserOpOptions, + buildUseropDto: BuildUserOpOptions ): Promise<FeeQuotesOrDataResponse> { - const txs = Array.isArray(manyOrOneTransactions) ? manyOrOneTransactions : [manyOrOneTransactions]; - const userOp = await this.buildUserOp(txs, buildUseropDto); - if (!buildUseropDto.paymasterServiceData) throw new Error("paymasterServiceData was not provided"); - return this.getPaymasterFeeQuotesOrData(userOp, buildUseropDto.paymasterServiceData); + const txs = Array.isArray(manyOrOneTransactions) + ? manyOrOneTransactions + : [manyOrOneTransactions] + const userOp = await this.buildUserOp(txs, buildUseropDto) + if (!buildUseropDto.paymasterServiceData) + throw new Error("paymasterServiceData was not provided") + return this.getPaymasterFeeQuotesOrData( + userOp, + buildUseropDto.paymasterServiceData + ) } /** @@ -845,11 +1038,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -872,13 +1065,21 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { { data: "0x", value: BigInt(0), - to: await this.getAccountAddress(), + to: await this.getAccountAddress() }, { - paymasterServiceData: { mode: PaymasterMode.ERC20 }, - }, - ); - return (feeQuotesResponse?.feeQuotes ?? []).map(({ maxGasFee: _, maxGasFeeUSD: __, validUntil: ___, usdPayment: ____, ...rest }) => rest); + paymasterServiceData: { mode: PaymasterMode.ERC20 } + } + ) + return (feeQuotesResponse?.feeQuotes ?? []).map( + ({ + maxGasFee: _, + maxGasFeeUSD: __, + validUntil: ___, + usdPayment: ____, + ...rest + }) => rest + ) } /** @@ -899,11 +1100,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -925,11 +1126,18 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const { success, receipt } = await wait(); * */ - async sendUserOp(userOp: Partial<UserOperationStruct>, params?: SendUserOpParams): Promise<UserOpResponse> { - delete userOp.signature; - const userOperation = await this.signUserOp(userOp, params); - const bundlerResponse = await this.sendSignedUserOp(userOperation, params?.simulationType); - return bundlerResponse; + async sendUserOp( + userOp: Partial<UserOperationStruct>, + params?: SendUserOpParams + ): Promise<UserOpResponse> { + // biome-ignore lint/performance/noDelete: <explanation> + delete userOp.signature + const userOperation = await this.signUserOp(userOp, params) + const bundlerResponse = await this.sendSignedUserOp( + userOperation, + params?.simulationType + ) + return bundlerResponse } /** @@ -939,7 +1147,10 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * @description This function call will take 'signedUserOp' as input and send it to the bundler * @returns */ - async sendSignedUserOp(userOp: UserOperationStruct, simulationType?: SimulationType): Promise<UserOpResponse> { + async sendSignedUserOp( + userOp: UserOperationStruct, + simulationType?: SimulationType + ): Promise<UserOpResponse> { const requiredFields: UserOperationKey[] = [ "sender", "nonce", @@ -951,90 +1162,128 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { "maxFeePerGas", "maxPriorityFeePerGas", "paymasterAndData", - "signature", - ]; - this.validateUserOp(userOp, requiredFields); - if (!this.bundler) throw new Error("Bundler is not provided"); - Logger.warn("userOp being sent to the bundler", userOp); - const bundlerResponse = await this.bundler.sendUserOp(userOp, simulationType); - return bundlerResponse; + "signature" + ] + this.validateUserOp(userOp, requiredFields) + if (!this.bundler) throw new Error("Bundler is not provided") + Logger.warn("userOp being sent to the bundler", userOp) + const bundlerResponse = await this.bundler.sendUserOp( + userOp, + simulationType + ) + return bundlerResponse } async getUserOpHash(userOp: Partial<UserOperationStruct>): Promise<Hex> { - const userOpHash = keccak256(packUserOp(userOp, true) as Hex); - const enc = encodeAbiParameters(parseAbiParameters("bytes32, address, uint256"), [userOpHash, this.entryPoint.address, BigInt(this.chainId)]); - return keccak256(enc); + const userOpHash = keccak256(packUserOp(userOp, true) as Hex) + const enc = encodeAbiParameters( + parseAbiParameters("bytes32, address, uint256"), + [userOpHash, this.entryPoint.address, BigInt(this.chainId)] + ) + return keccak256(enc) } - async estimateUserOpGas(userOp: Partial<UserOperationStruct>, stateOverrideSet?: StateOverrideSet): Promise<Partial<UserOperationStruct>> { - if (!this.bundler) throw new Error("Bundler is not provided"); - const requiredFields: UserOperationKey[] = ["sender", "nonce", "initCode", "callData"]; - this.validateUserOp(userOp, requiredFields); + async estimateUserOpGas( + userOp: Partial<UserOperationStruct>, + stateOverrideSet?: StateOverrideSet + ): Promise<Partial<UserOperationStruct>> { + if (!this.bundler) throw new Error("Bundler is not provided") + const requiredFields: UserOperationKey[] = [ + "sender", + "nonce", + "initCode", + "callData" + ] + this.validateUserOp(userOp, requiredFields) - const finalUserOp = userOp; + const finalUserOp = userOp // Making call to bundler to get gas estimations for userOp - const { callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas } = await this.bundler.estimateUserOpGas( - userOp, - stateOverrideSet, - ); + const { + callGasLimit, + verificationGasLimit, + preVerificationGas, + maxFeePerGas, + maxPriorityFeePerGas + } = await this.bundler.estimateUserOpGas(userOp, stateOverrideSet) // if neither user sent gas fee nor the bundler, estimate gas from provider - if (!userOp.maxFeePerGas && !userOp.maxPriorityFeePerGas && (!maxFeePerGas || !maxPriorityFeePerGas)) { - const feeData = await this.provider.estimateFeesPerGas(); + if ( + !userOp.maxFeePerGas && + !userOp.maxPriorityFeePerGas && + (!maxFeePerGas || !maxPriorityFeePerGas) + ) { + const feeData = await this.provider.estimateFeesPerGas() if (feeData.maxFeePerGas?.toString()) { - finalUserOp.maxFeePerGas = ("0x" + feeData.maxFeePerGas.toString(16)) as Hex; + finalUserOp.maxFeePerGas = `0x${feeData.maxFeePerGas.toString( + 16 + )}` as Hex } else if (feeData.gasPrice?.toString()) { - finalUserOp.maxFeePerGas = ("0x" + feeData.gasPrice.toString(16)) as Hex; + finalUserOp.maxFeePerGas = `0x${feeData.gasPrice.toString(16)}` as Hex } else { - finalUserOp.maxFeePerGas = ("0x" + (await this.provider.getGasPrice()).toString(16)) as Hex; + finalUserOp.maxFeePerGas = `0x${( + await this.provider.getGasPrice() + ).toString(16)}` as Hex } if (feeData.maxPriorityFeePerGas?.toString()) { - finalUserOp.maxPriorityFeePerGas = ("0x" + feeData.maxPriorityFeePerGas?.toString()) as Hex; + finalUserOp.maxPriorityFeePerGas = + `0x${feeData.maxPriorityFeePerGas?.toString()}` as Hex } else if (feeData.gasPrice?.toString()) { - finalUserOp.maxPriorityFeePerGas = toHex(Number(feeData.gasPrice?.toString())); + finalUserOp.maxPriorityFeePerGas = toHex( + Number(feeData.gasPrice?.toString()) + ) } else { - finalUserOp.maxPriorityFeePerGas = ("0x" + (await this.provider.getGasPrice()).toString(16)) as Hex; + finalUserOp.maxPriorityFeePerGas = `0x${( + await this.provider.getGasPrice() + ).toString(16)}` as Hex } } else { - finalUserOp.maxFeePerGas = toHex(Number(maxFeePerGas)) ?? userOp.maxFeePerGas; - finalUserOp.maxPriorityFeePerGas = toHex(Number(maxPriorityFeePerGas)) ?? userOp.maxPriorityFeePerGas; + finalUserOp.maxFeePerGas = + toHex(Number(maxFeePerGas)) ?? userOp.maxFeePerGas + finalUserOp.maxPriorityFeePerGas = + toHex(Number(maxPriorityFeePerGas)) ?? userOp.maxPriorityFeePerGas } - finalUserOp.verificationGasLimit = toHex(Number(verificationGasLimit)) ?? userOp.verificationGasLimit; - finalUserOp.callGasLimit = toHex(Number(callGasLimit)) ?? userOp.callGasLimit; - finalUserOp.preVerificationGas = toHex(Number(preVerificationGas)) ?? userOp.preVerificationGas; + finalUserOp.verificationGasLimit = + toHex(Number(verificationGasLimit)) ?? userOp.verificationGasLimit + finalUserOp.callGasLimit = + toHex(Number(callGasLimit)) ?? userOp.callGasLimit + finalUserOp.preVerificationGas = + toHex(Number(preVerificationGas)) ?? userOp.preVerificationGas if (!finalUserOp.paymasterAndData) { - finalUserOp.paymasterAndData = "0x"; + finalUserOp.paymasterAndData = "0x" } - return finalUserOp; + return finalUserOp } - // Could call it nonce space - async getNonce(nonceKey?: number): Promise<bigint> { - const nonceSpace = nonceKey ?? 0; + override async getNonce(nonceKey?: number): Promise<bigint> { + const nonceSpace = nonceKey ?? 0 try { - const address = await this.getAddress(); - return await this.entryPoint.read.getNonce([address, BigInt(nonceSpace)]); + const address = await this.getAddress() + return await this.entryPoint.read.getNonce([address, BigInt(nonceSpace)]) } catch (e) { - return BigInt(0); + return BigInt(0) } } - private async getBuildUserOpNonce(nonceOptions: NonceOptions | undefined): Promise<BigNumberish> { - let nonce = BigInt(0); + private async getBuildUserOpNonce( + nonceOptions: NonceOptions | undefined + ): Promise<BigNumberish> { + let nonce = BigInt(0) try { if (nonceOptions?.nonceOverride) { - nonce = BigInt(nonceOptions?.nonceOverride); + nonce = BigInt(nonceOptions?.nonceOverride) } else { - const _nonceSpace = nonceOptions?.nonceKey ?? 0; - nonce = await this.getNonce(_nonceSpace); + const _nonceSpace = nonceOptions?.nonceKey ?? 0 + nonce = await this.getNonce(_nonceSpace) } } catch (error) { // Not throwing this error as nonce would be 0 if this.getNonce() throw exception, which is expected flow for undeployed account - Logger.warn("Error while getting nonce for the account. This is expected for undeployed accounts set nonce to 0"); + Logger.warn( + "Error while getting nonce for the account. This is expected for undeployed accounts set nonce to 0" + ) } - return nonce; + return nonce } /** @@ -1050,11 +1299,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -1074,9 +1323,20 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const { transactionHash, userOperationReceipt } = await wait(); * */ - async sendTransaction(manyOrOneTransactions: Transaction | Transaction[], buildUseropDto?: BuildUserOpOptions): Promise<UserOpResponse> { - const userOp = await this.buildUserOp(Array.isArray(manyOrOneTransactions) ? manyOrOneTransactions : [manyOrOneTransactions], buildUseropDto); - return this.sendUserOp(userOp, { simulationType: buildUseropDto?.simulationType, ...buildUseropDto?.params }); + async sendTransaction( + manyOrOneTransactions: Transaction | Transaction[], + buildUseropDto?: BuildUserOpOptions + ): Promise<UserOpResponse> { + const userOp = await this.buildUserOp( + Array.isArray(manyOrOneTransactions) + ? manyOrOneTransactions + : [manyOrOneTransactions], + buildUseropDto + ) + return this.sendUserOp(userOp, { + simulationType: buildUseropDto?.simulationType, + ...buildUseropDto?.params + }) } /** @@ -1092,11 +1352,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -1115,30 +1375,39 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const userOp = await smartAccount.buildUserOp([{ to: "0x...", data: encodedCall }]); * */ - async buildUserOp(transactions: Transaction[], buildUseropDto?: BuildUserOpOptions): Promise<Partial<UserOperationStruct>> { - const to = transactions.map((element: Transaction) => element.to as Hex); - const data = transactions.map((element: Transaction) => (element.data as Hex) ?? "0x"); - const value = transactions.map((element: Transaction) => (element.value as bigint) ?? BigInt(0)); - - const initCodeFetchPromise = this.getInitCode(); - const dummySignatureFetchPromise = this.getDummySignatures(buildUseropDto?.params); + async buildUserOp( + transactions: Transaction[], + buildUseropDto?: BuildUserOpOptions + ): Promise<Partial<UserOperationStruct>> { + const to = transactions.map((element: Transaction) => element.to as Hex) + const data = transactions.map( + (element: Transaction) => (element.data as Hex) ?? "0x" + ) + const value = transactions.map( + (element: Transaction) => (element.value as bigint) ?? BigInt(0) + ) + + const initCodeFetchPromise = this.getInitCode() + const dummySignatureFetchPromise = this.getDummySignatures( + buildUseropDto?.params + ) const [nonceFromFetch, initCode, signature] = await Promise.all([ this.getBuildUserOpNonce(buildUseropDto?.nonceOptions), initCodeFetchPromise, - dummySignatureFetchPromise, - ]); + dummySignatureFetchPromise + ]) if (transactions.length === 0) { - throw new Error("Transactions array cannot be empty"); + throw new Error("Transactions array cannot be empty") } - let callData: Hex = "0x"; + let callData: Hex = "0x" if (!buildUseropDto?.useEmptyDeployCallData) { if (transactions.length > 1 || buildUseropDto?.forceEncodeForBatch) { - callData = await this.encodeExecuteBatch(to, value, data); + callData = await this.encodeExecuteBatch(to, value, data) } else { // transactions.length must be 1 - callData = await this.encodeExecute(to[0], value[0], data[0]); + callData = await this.encodeExecute(to[0], value[0], data[0]) } } @@ -1146,52 +1415,64 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { sender: (await this.getAccountAddress()) as Hex, nonce: toHex(nonceFromFetch), initCode, - callData, - }; + callData + } // for this Smart Account current validation module dummy signature will be used to estimate gas - userOp.signature = signature; + userOp.signature = signature if ( buildUseropDto?.paymasterServiceData && buildUseropDto?.paymasterServiceData.mode === PaymasterMode.SPONSORED && this.paymaster instanceof BiconomyPaymaster ) { - const gasFeeValues = await this.bundler?.getGasFeeValues(); + const gasFeeValues = await this.bundler?.getGasFeeValues() // populate gasfee values and make a call to paymaster - userOp.maxFeePerGas = gasFeeValues?.maxFeePerGas as Hex; - userOp.maxPriorityFeePerGas = gasFeeValues?.maxPriorityFeePerGas as Hex; - - userOp = await this.getPaymasterUserOp(userOp, buildUseropDto.paymasterServiceData); - return userOp; - } else { - userOp = await this.estimateUserOpGas(userOp); + userOp.maxFeePerGas = gasFeeValues?.maxFeePerGas as Hex + userOp.maxPriorityFeePerGas = gasFeeValues?.maxPriorityFeePerGas as Hex + + userOp = await this.getPaymasterUserOp( + userOp, + buildUseropDto.paymasterServiceData + ) + return userOp + } + userOp = await this.estimateUserOpGas(userOp) - if (buildUseropDto?.paymasterServiceData) { - userOp = await this.getPaymasterUserOp(userOp, buildUseropDto.paymasterServiceData); - } - return userOp; + if (buildUseropDto?.paymasterServiceData) { + userOp = await this.getPaymasterUserOp( + userOp, + buildUseropDto.paymasterServiceData + ) } + return userOp } - private validateUserOpAndPaymasterRequest(userOp: Partial<UserOperationStruct>, tokenPaymasterRequest: BiconomyTokenPaymasterRequest): void { + private validateUserOpAndPaymasterRequest( + userOp: Partial<UserOperationStruct>, + tokenPaymasterRequest: BiconomyTokenPaymasterRequest + ): void { if (isNullOrUndefined(userOp.callData)) { - throw new Error("UserOp callData cannot be undefined"); + throw new Error("UserOp callData cannot be undefined") } - const feeTokenAddress = tokenPaymasterRequest?.feeQuote?.tokenAddress; - Logger.warn("Requested fee token is ", feeTokenAddress); + const feeTokenAddress = tokenPaymasterRequest?.feeQuote?.tokenAddress + Logger.warn("Requested fee token is ", feeTokenAddress) if (!feeTokenAddress || feeTokenAddress === ADDRESS_ZERO) { - throw new Error("Invalid or missing token address. Token address must be part of the feeQuote in tokenPaymasterRequest"); + throw new Error( + "Invalid or missing token address. Token address must be part of the feeQuote in tokenPaymasterRequest" + ) } - const spender = tokenPaymasterRequest?.spender; - Logger.warn("Spender address is ", spender); + const spender = tokenPaymasterRequest?.spender + Logger.warn("Spender address is ", spender) if (!spender || spender === ADDRESS_ZERO) { - throw new Error("Invalid or missing spender address. Sepnder address must be part of tokenPaymasterRequest"); + throw new Error( + "Invalid or missing spender address. Sepnder address must be part of tokenPaymasterRequest" + ) } } @@ -1206,96 +1487,127 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { */ async buildTokenPaymasterUserOp( userOp: Partial<UserOperationStruct>, - tokenPaymasterRequest: BiconomyTokenPaymasterRequest, + tokenPaymasterRequest: BiconomyTokenPaymasterRequest ): Promise<Partial<UserOperationStruct>> { - this.validateUserOpAndPaymasterRequest(userOp, tokenPaymasterRequest); + this.validateUserOpAndPaymasterRequest(userOp, tokenPaymasterRequest) try { - let batchTo: Array<Hex> = []; - let batchValue: Array<bigint> = []; - let batchData: Array<Hex> = []; + let batchTo: Array<Hex> = [] + let batchValue: Array<bigint> = [] + let batchData: Array<Hex> = [] - let newCallData = userOp.callData; - Logger.warn("Received information about fee token address and quote ", tokenPaymasterRequest); + let newCallData = userOp.callData + Logger.warn( + "Received information about fee token address and quote ", + tokenPaymasterRequest + ) if (this.paymaster && this.paymaster instanceof Paymaster) { // Make a call to paymaster.buildTokenApprovalTransaction() with necessary details // Review: might request this form of an array of Transaction - const approvalRequest: Transaction = await (this.paymaster as IHybridPaymaster<SponsorUserOperationDto>).buildTokenApprovalTransaction( - tokenPaymasterRequest, - ); - Logger.warn("ApprovalRequest is for erc20 token ", approvalRequest.to); - - if (approvalRequest.data === "0x" || approvalRequest.to === ADDRESS_ZERO) { - return userOp; + const approvalRequest: Transaction = await ( + this.paymaster as IHybridPaymaster<SponsorUserOperationDto> + ).buildTokenApprovalTransaction(tokenPaymasterRequest) + Logger.warn("ApprovalRequest is for erc20 token ", approvalRequest.to) + + if ( + approvalRequest.data === "0x" || + approvalRequest.to === ADDRESS_ZERO + ) { + return userOp } if (isNullOrUndefined(userOp.callData)) { - throw new Error("UserOp callData cannot be undefined"); + throw new Error("UserOp callData cannot be undefined") } const decodedSmartAccountData = decodeFunctionData({ abi: BiconomyAccountAbi, - data: userOp.callData as Hex, - }); + data: userOp.callData as Hex + }) if (!decodedSmartAccountData) { - throw new Error("Could not parse userOp call data for this smart account"); + throw new Error( + "Could not parse userOp call data for this smart account" + ) } - const smartAccountExecFunctionName = decodedSmartAccountData.functionName; - - Logger.warn(`Originally an ${smartAccountExecFunctionName} method call for Biconomy Account V2`); - if (smartAccountExecFunctionName === "execute" || smartAccountExecFunctionName === "execute_ncC") { - const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args; - const toOriginal = methodArgsSmartWalletExecuteCall[0]; - const valueOriginal = methodArgsSmartWalletExecuteCall[1]; - const dataOriginal = methodArgsSmartWalletExecuteCall[2]; - - batchTo.push(toOriginal); - batchValue.push(valueOriginal); - batchData.push(dataOriginal); - } else if (smartAccountExecFunctionName === "executeBatch" || smartAccountExecFunctionName === "executeBatch_y6U") { - const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args; - batchTo = [...methodArgsSmartWalletExecuteCall[0]]; - batchValue = [...methodArgsSmartWalletExecuteCall[1]]; - batchData = [...methodArgsSmartWalletExecuteCall[2]]; + const smartAccountExecFunctionName = + decodedSmartAccountData.functionName + + Logger.warn( + `Originally an ${smartAccountExecFunctionName} method call for Biconomy Account V2` + ) + if ( + smartAccountExecFunctionName === "execute" || + smartAccountExecFunctionName === "execute_ncC" + ) { + const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args + const toOriginal = methodArgsSmartWalletExecuteCall[0] + const valueOriginal = methodArgsSmartWalletExecuteCall[1] + const dataOriginal = methodArgsSmartWalletExecuteCall[2] + + batchTo.push(toOriginal) + batchValue.push(valueOriginal) + batchData.push(dataOriginal) + } else if ( + smartAccountExecFunctionName === "executeBatch" || + smartAccountExecFunctionName === "executeBatch_y6U" + ) { + const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args + batchTo = [...methodArgsSmartWalletExecuteCall[0]] + batchValue = [...methodArgsSmartWalletExecuteCall[1]] + batchData = [...methodArgsSmartWalletExecuteCall[2]] } - if (approvalRequest.to && approvalRequest.data && approvalRequest.value) { - batchTo = [approvalRequest.to as Hex, ...batchTo]; - batchValue = [BigInt(Number(approvalRequest.value.toString())), ...batchValue]; - batchData = [approvalRequest.data as Hex, ...batchData]; - - newCallData = await this.encodeExecuteBatch(batchTo, batchValue, batchData); + if ( + approvalRequest.to && + approvalRequest.data && + approvalRequest.value + ) { + batchTo = [approvalRequest.to as Hex, ...batchTo] + batchValue = [ + BigInt(Number(approvalRequest.value.toString())), + ...batchValue + ] + batchData = [approvalRequest.data as Hex, ...batchData] + + newCallData = await this.encodeExecuteBatch( + batchTo, + batchValue, + batchData + ) } const finalUserOp: Partial<UserOperationStruct> = { ...userOp, - callData: newCallData, - }; + callData: newCallData + } // Optionally Requesting to update gas limits again (especially callGasLimit needs to be re-calculated) - return finalUserOp; + return finalUserOp } } catch (error) { - Logger.log("Failed to update userOp. Sending back original op"); - Logger.error("Failed to update callData with error", error); - return userOp; + Logger.log("Failed to update userOp. Sending back original op") + Logger.error("Failed to update callData with error", error) + return userOp } - return userOp; + return userOp } async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise<Hex> { - this.isActiveValidationModuleDefined(); - const moduleSig = (await this.activeValidationModule.signUserOpHash(userOpHash, params)) as Hex; - - const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters("bytes, address"), [ - moduleSig, - this.activeValidationModule.getAddress() as Hex, - ]); - - return signatureWithModuleAddress; + this.isActiveValidationModuleDefined() + const moduleSig = (await this.activeValidationModule.signUserOpHash( + userOpHash, + params + )) as Hex + + const signatureWithModuleAddress = encodeAbiParameters( + parseAbiParameters("bytes, address"), + [moduleSig, this.activeValidationModule.getAddress() as Hex] + ) + + return signatureWithModuleAddress } /** @@ -1314,11 +1626,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * import { createClient } from "viem" * import { createSmartAccountClient } from "@biconomy/account" * import { createWalletClient, http } from "viem"; - * import { polygonMumbai } from "viem/chains"; + * import { polygonAmoy } from "viem/chains"; * * const signer = createWalletClient({ * account, - * chain: polygonMumbai, + * chain: polygonAmoy, * transport: http(), * }); * @@ -1342,124 +1654,152 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * const { success, receipt } = await wait(); * */ - public async deploy(buildUseropDto?: BuildUserOpOptions): Promise<UserOpResponse> { - const accountAddress = this.accountAddress ?? (await this.getAccountAddress()); + public async deploy( + buildUseropDto?: BuildUserOpOptions + ): Promise<UserOpResponse> { + const accountAddress = + this.accountAddress ?? (await this.getAccountAddress()) // Check that the account has not already been deployed - const byteCode = await this.provider?.getBytecode({ address: accountAddress as Hex }); + const byteCode = await this.provider?.getBytecode({ + address: accountAddress as Hex + }) if (byteCode !== undefined) { - throw new Error(ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED); + throw new Error(ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED) } // Check that the account has enough native token balance to deploy, if not using a paymaster if (!buildUseropDto?.paymasterServiceData?.mode) { - const nativeTokenBalance = await this.provider?.getBalance({ address: accountAddress }); + const nativeTokenBalance = await this.provider?.getBalance({ + address: accountAddress + }) if (nativeTokenBalance === BigInt(0)) { - throw new Error(ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY); + throw new Error(ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY) } } - const useEmptyDeployCallData = true; + const useEmptyDeployCallData = true return this.sendTransaction( { to: accountAddress, - data: "0x", + data: "0x" }, - { ...buildUseropDto, useEmptyDeployCallData }, - ); + { ...buildUseropDto, useEmptyDeployCallData } + ) } async signMessage(message: string | Uint8Array): Promise<Hex> { - this.isActiveValidationModuleDefined(); - const dataHash = typeof message === "string" ? toBytes(message) : message; - let signature = await this.activeValidationModule.signMessage(dataHash); + this.isActiveValidationModuleDefined() + const dataHash = typeof message === "string" ? toBytes(message) : message + let signature = await this.activeValidationModule.signMessage(dataHash) - const potentiallyIncorrectV = parseInt(signature.slice(-2), 16); + const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - signature = signature.slice(0, -2) + correctV.toString(16); + const correctV = potentiallyIncorrectV + 27 + signature = signature.slice(0, -2) + correctV.toString(16) } if (signature.slice(0, 2) !== "0x") { - signature = "0x" + signature; + signature = `0x${signature}` } - signature = encodeAbiParameters(parseAbiParameters("bytes, address"), [signature as Hex, this.defaultValidationModule.getAddress()]); - return signature as Hex; + signature = encodeAbiParameters(parseAbiParameters("bytes, address"), [ + signature as Hex, + this.defaultValidationModule.getAddress() + ]) + return signature as Hex } - async getIsValidSignatureData(messageHash: Hex, signature: Hex): Promise<Hex> { + async getIsValidSignatureData( + messageHash: Hex, + signature: Hex + ): Promise<Hex> { return encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "isValidSignature", - args: [messageHash, signature], - }); + args: [messageHash, signature] + }) } async enableModule(moduleAddress: Hex): Promise<UserOpResponse> { - const tx: Transaction = await this.getEnableModuleData(moduleAddress); - const partialUserOp = await this.buildUserOp([tx]); - return this.sendUserOp(partialUserOp); + const tx: Transaction = await this.getEnableModuleData(moduleAddress) + const partialUserOp = await this.buildUserOp([tx]) + return this.sendUserOp(partialUserOp) } async getEnableModuleData(moduleAddress: Hex): Promise<Transaction> { const callData = encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "enableModule", - args: [moduleAddress], - }); + args: [moduleAddress] + }) const tx: Transaction = { to: await this.getAddress(), value: "0x00", - data: callData, - }; - return tx; + data: callData + } + return tx } - async getSetupAndEnableModuleData(moduleAddress: Hex, moduleSetupData: Hex): Promise<Transaction> { + async getSetupAndEnableModuleData( + moduleAddress: Hex, + moduleSetupData: Hex + ): Promise<Transaction> { const callData = encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "setupAndEnableModule", - args: [moduleAddress, moduleSetupData], - }); + args: [moduleAddress, moduleSetupData] + }) const tx: Transaction = { to: await this.getAddress(), value: "0x00", - data: callData, - }; - return tx; + data: callData + } + return tx } - async disableModule(prevModule: Hex, moduleAddress: Hex): Promise<UserOpResponse> { - const tx: Transaction = await this.getDisableModuleData(prevModule, moduleAddress); - const partialUserOp = await this.buildUserOp([tx]); - return this.sendUserOp(partialUserOp); + async disableModule( + prevModule: Hex, + moduleAddress: Hex + ): Promise<UserOpResponse> { + const tx: Transaction = await this.getDisableModuleData( + prevModule, + moduleAddress + ) + const partialUserOp = await this.buildUserOp([tx]) + return this.sendUserOp(partialUserOp) } - async getDisableModuleData(prevModule: Hex, moduleAddress: Hex): Promise<Transaction> { + async getDisableModuleData( + prevModule: Hex, + moduleAddress: Hex + ): Promise<Transaction> { const callData = encodeFunctionData({ abi: BiconomyAccountAbi, functionName: "disableModule", - args: [prevModule, moduleAddress], - }); + args: [prevModule, moduleAddress] + }) const tx: Transaction = { to: await this.getAddress(), value: "0x00", - data: callData, - }; - return tx; + data: callData + } + return tx } async isModuleEnabled(moduleAddress: Hex): Promise<boolean> { - const accountContract = await this._getAccountContract(); - return accountContract.read.isModuleEnabled([moduleAddress]); + const accountContract = await this._getAccountContract() + return accountContract.read.isModuleEnabled([moduleAddress]) } // Review async getAllModules(pageSize?: number): Promise<Array<string>> { - pageSize = pageSize ?? 100; - const accountContract = await this._getAccountContract(); - const result = await accountContract.read.getModulesPaginated([this.SENTINEL_MODULE as Hex, BigInt(pageSize)]); - const modules: Array<string> = result[0] as Array<string>; - return modules; + const _pageSize = pageSize ?? 100 + const accountContract = await this._getAccountContract() + const result = await accountContract.read.getModulesPaginated([ + this.SENTINEL_MODULE as Hex, + BigInt(_pageSize) + ]) + const modules: Array<string> = result[0] as Array<string> + return modules } } diff --git a/packages/account/src/abi/Factory.ts b/src/account/Factory.ts similarity index 76% rename from packages/account/src/abi/Factory.ts rename to src/account/Factory.ts index 3498dd958..c7d148bb2 100644 --- a/packages/account/src/abi/Factory.ts +++ b/src/account/Factory.ts @@ -6,23 +6,23 @@ export const BiconomyFactoryAbi = [ indexed: true, internalType: "address", name: "account", - type: "address", + type: "address" }, { indexed: true, internalType: "address", name: "initialAuthModule", - type: "address", + type: "address" }, { indexed: true, internalType: "uint256", name: "index", - type: "uint256", - }, + type: "uint256" + } ], name: "AccountCreation", - type: "event", + type: "event" }, { anonymous: false, @@ -31,17 +31,17 @@ export const BiconomyFactoryAbi = [ indexed: true, internalType: "address", name: "account", - type: "address", + type: "address" }, { indexed: true, internalType: "address", name: "initialAuthModule", - type: "address", - }, + type: "address" + } ], name: "AccountCreationWithoutIndex", - type: "event", + type: "event" }, { inputs: [], @@ -50,92 +50,92 @@ export const BiconomyFactoryAbi = [ { internalType: "bytes", name: "", - type: "bytes", - }, + type: "bytes" + } ], stateMutability: "pure", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "moduleSetupContract", - type: "address", + type: "address" }, { internalType: "bytes", name: "moduleSetupData", - type: "bytes", - }, + type: "bytes" + } ], name: "deployAccount", outputs: [ { internalType: "address", name: "proxy", - type: "address", - }, + type: "address" + } ], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "moduleSetupContract", - type: "address", + type: "address" }, { internalType: "bytes", name: "moduleSetupData", - type: "bytes", + type: "bytes" }, { internalType: "uint256", name: "index", - type: "uint256", - }, + type: "uint256" + } ], name: "deployCounterFactualAccount", outputs: [ { internalType: "address", name: "proxy", - type: "address", - }, + type: "address" + } ], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "moduleSetupContract", - type: "address", + type: "address" }, { internalType: "bytes", name: "moduleSetupData", - type: "bytes", + type: "bytes" }, { internalType: "uint256", name: "index", - type: "uint256", - }, + type: "uint256" + } ], name: "getAddressForCounterFactualAccount", outputs: [ { internalType: "address", name: "_account", - type: "address", - }, + type: "address" + } ], stateMutability: "view", - type: "function", - }, -] as const; + type: "function" + } +] as const diff --git a/packages/account/src/abi/SmartAccount.ts b/src/account/SmartAccount.ts similarity index 58% rename from packages/account/src/abi/SmartAccount.ts rename to src/account/SmartAccount.ts index 73eb8fb91..541267158 100644 --- a/packages/account/src/abi/SmartAccount.ts +++ b/src/account/SmartAccount.ts @@ -1,30 +1,90 @@ export const BiconomyAccountAbi = [ - { inputs: [{ internalType: "contract IEntryPoint", name: "anEntryPoint", type: "address" }], stateMutability: "nonpayable", type: "constructor" }, + { + inputs: [ + { + internalType: "contract IEntryPoint", + name: "anEntryPoint", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, { inputs: [], name: "AlreadyInitialized", type: "error" }, { inputs: [], name: "BaseImplementationCannotBeZero", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotAnEntryPoint", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPoint", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPointOrOwner", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotEntryPointOrSelf", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotOwner", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "CallerIsNotSelf", type: "error" }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotAnEntryPoint", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPoint", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPointOrOwner", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPointOrSelf", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotOwner", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotSelf", + type: "error" + }, { inputs: [], name: "DelegateCallsOnly", type: "error" }, { inputs: [], name: "EntryPointCannotBeZero", type: "error" }, { inputs: [], name: "HandlerCannotBeZero", type: "error" }, - { inputs: [{ internalType: "address", name: "implementationAddress", type: "address" }], name: "InvalidImplementation", type: "error" }, - { inputs: [{ internalType: "address", name: "caller", type: "address" }], name: "MixedAuthFail", type: "error" }, - { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleAlreadyEnabled", type: "error" }, + { + inputs: [ + { + internalType: "address", + name: "implementationAddress", + type: "address" + } + ], + name: "InvalidImplementation", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "MixedAuthFail", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleAlreadyEnabled", + type: "error" + }, { inputs: [ { internalType: "address", name: "expectedModule", type: "address" }, { internalType: "address", name: "returnedModule", type: "address" }, - { internalType: "address", name: "prevModule", type: "address" }, + { internalType: "address", name: "prevModule", type: "address" } ], name: "ModuleAndPrevModuleMismatch", - type: "error", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleCannotBeZeroOrSentinel", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleNotEnabled", + type: "error" }, - { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleCannotBeZeroOrSentinel", type: "error" }, - { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "ModuleNotEnabled", type: "error" }, { inputs: [], name: "ModulesAlreadyInitialized", type: "error" }, { inputs: [], name: "ModulesSetupExecutionFailed", type: "error" }, { inputs: [], name: "OwnerCanNotBeSelf", type: "error" }, @@ -36,137 +96,283 @@ export const BiconomyAccountAbi = [ { internalType: "uint256", name: "destLength", type: "uint256" }, { internalType: "uint256", name: "valueLength", type: "uint256" }, { internalType: "uint256", name: "funcLength", type: "uint256" }, - { internalType: "uint256", name: "operationLength", type: "uint256" }, + { internalType: "uint256", name: "operationLength", type: "uint256" } ], name: "WrongBatchProvided", - type: "error", + type: "error" + }, + { + inputs: [ + { internalType: "bytes", name: "contractSignature", type: "bytes" } + ], + name: "WrongContractSignature", + type: "error" }, - { inputs: [{ internalType: "bytes", name: "contractSignature", type: "bytes" }], name: "WrongContractSignature", type: "error" }, { inputs: [ { internalType: "uint256", name: "uintS", type: "uint256" }, - { internalType: "uint256", name: "contractSignatureLength", type: "uint256" }, - { internalType: "uint256", name: "signatureLength", type: "uint256" }, + { + internalType: "uint256", + name: "contractSignatureLength", + type: "uint256" + }, + { internalType: "uint256", name: "signatureLength", type: "uint256" } ], name: "WrongContractSignatureFormat", - type: "error", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "moduleAddressProvided", + type: "address" + } + ], + name: "WrongValidationModule", + type: "error" }, - { inputs: [{ internalType: "address", name: "moduleAddressProvided", type: "address" }], name: "WrongValidationModule", type: "error" }, { anonymous: false, inputs: [ - { indexed: true, internalType: "address", name: "previousHandler", type: "address" }, - { indexed: true, internalType: "address", name: "handler", type: "address" }, + { + indexed: true, + internalType: "address", + name: "previousHandler", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "handler", + type: "address" + } ], name: "ChangedFallbackHandler", - type: "event", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "DisabledModule", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "EnabledModule", + type: "event" }, - { anonymous: false, inputs: [{ indexed: false, internalType: "address", name: "module", type: "address" }], name: "DisabledModule", type: "event" }, - { anonymous: false, inputs: [{ indexed: false, internalType: "address", name: "module", type: "address" }], name: "EnabledModule", type: "event" }, { anonymous: false, inputs: [ { indexed: true, internalType: "address", name: "to", type: "address" }, - { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, + { + indexed: true, + internalType: "uint256", + name: "value", + type: "uint256" + }, { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, - { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, - { indexed: false, internalType: "uint256", name: "txGas", type: "uint256" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + }, + { + indexed: false, + internalType: "uint256", + name: "txGas", + type: "uint256" + } ], name: "ExecutionFailure", - type: "event", + type: "event" }, { anonymous: false, - inputs: [{ indexed: true, internalType: "address", name: "module", type: "address" }], + inputs: [ + { + indexed: true, + internalType: "address", + name: "module", + type: "address" + } + ], name: "ExecutionFromModuleFailure", - type: "event", + type: "event" }, { anonymous: false, - inputs: [{ indexed: true, internalType: "address", name: "module", type: "address" }], + inputs: [ + { + indexed: true, + internalType: "address", + name: "module", + type: "address" + } + ], name: "ExecutionFromModuleSuccess", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: true, internalType: "address", name: "to", type: "address" }, - { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, + { + indexed: true, + internalType: "uint256", + name: "value", + type: "uint256" + }, { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, - { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, - { indexed: false, internalType: "uint256", name: "txGas", type: "uint256" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + }, + { + indexed: false, + internalType: "uint256", + name: "txGas", + type: "uint256" + } ], name: "ExecutionSuccess", - type: "event", + type: "event" }, { anonymous: false, inputs: [ - { indexed: true, internalType: "address", name: "oldImplementation", type: "address" }, - { indexed: true, internalType: "address", name: "newImplementation", type: "address" }, + { + indexed: true, + internalType: "address", + name: "oldImplementation", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "newImplementation", + type: "address" + } ], name: "ImplementationUpdated", - type: "event", + type: "event" }, { anonymous: false, inputs: [ - { indexed: false, internalType: "address", name: "module", type: "address" }, + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + }, { indexed: false, internalType: "address", name: "to", type: "address" }, - { indexed: false, internalType: "uint256", name: "value", type: "uint256" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256" + }, { indexed: false, internalType: "bytes", name: "data", type: "bytes" }, - { indexed: false, internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + } ], name: "ModuleTransaction", - type: "event", + type: "event" }, { anonymous: false, inputs: [ - { indexed: true, internalType: "address", name: "sender", type: "address" }, - { indexed: true, internalType: "uint256", name: "value", type: "uint256" }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address" + }, + { indexed: true, internalType: "uint256", name: "value", type: "uint256" } ], name: "SmartAccountReceivedNativeToken", - type: "event", + type: "event" }, { stateMutability: "nonpayable", type: "fallback" }, - { inputs: [], name: "VERSION", outputs: [{ internalType: "string", name: "", type: "string" }], stateMutability: "view", type: "function" }, - { inputs: [], name: "addDeposit", outputs: [], stateMutability: "payable", type: "function" }, + { + inputs: [], + name: "VERSION", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "addDeposit", + outputs: [], + stateMutability: "payable", + type: "function" + }, { inputs: [ { internalType: "address", name: "prevModule", type: "address" }, - { internalType: "address", name: "module", type: "address" }, + { internalType: "address", name: "module", type: "address" } ], name: "disableModule", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "enableModule", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [], name: "entryPoint", - outputs: [{ internalType: "contract IEntryPoint", name: "", type: "address" }], + outputs: [ + { internalType: "contract IEntryPoint", name: "", type: "address" } + ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address[]", name: "to", type: "address[]" }, { internalType: "uint256[]", name: "value", type: "uint256[]" }, { internalType: "bytes[]", name: "data", type: "bytes[]" }, - { internalType: "enum Enum.Operation[]", name: "operations", type: "uint8[]" }, + { + internalType: "enum Enum.Operation[]", + name: "operations", + type: "uint8[]" + } ], name: "execBatchTransactionFromModule", outputs: [{ internalType: "bool", name: "success", type: "bool" }], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ @@ -174,191 +380,201 @@ export const BiconomyAccountAbi = [ { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, - { internalType: "uint256", name: "txGas", type: "uint256" }, + { internalType: "uint256", name: "txGas", type: "uint256" } ], name: "execTransactionFromModule", outputs: [{ internalType: "bool", name: "success", type: "bool" }], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, - { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" } ], name: "execTransactionFromModule", outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "to", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, { internalType: "bytes", name: "data", type: "bytes" }, - { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" } ], name: "execTransactionFromModuleReturnData", outputs: [ { internalType: "bool", name: "success", type: "bool" }, - { internalType: "bytes", name: "returnData", type: "bytes" }, + { internalType: "bytes", name: "returnData", type: "bytes" } ], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "dest", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "func", type: "bytes" }, + { internalType: "bytes", name: "func", type: "bytes" } ], name: "execute", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address[]", name: "dest", type: "address[]" }, { internalType: "uint256[]", name: "value", type: "uint256[]" }, - { internalType: "bytes[]", name: "func", type: "bytes[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" } ], name: "executeBatch", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address[]", name: "dest", type: "address[]" }, { internalType: "uint256[]", name: "value", type: "uint256[]" }, - { internalType: "bytes[]", name: "func", type: "bytes[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" } ], name: "executeBatch_y6U", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "dest", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "func", type: "bytes" }, + { internalType: "bytes", name: "func", type: "bytes" } ], name: "execute_ncC", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" + }, + { + inputs: [], + name: "getDeposit", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function" }, - { inputs: [], name: "getDeposit", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", type: "function" }, { inputs: [], name: "getFallbackHandler", outputs: [{ internalType: "address", name: "_handler", type: "address" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [], name: "getImplementation", - outputs: [{ internalType: "address", name: "_implementation", type: "address" }], + outputs: [ + { internalType: "address", name: "_implementation", type: "address" } + ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "start", type: "address" }, - { internalType: "uint256", name: "pageSize", type: "uint256" }, + { internalType: "uint256", name: "pageSize", type: "uint256" } ], name: "getModulesPaginated", outputs: [ { internalType: "address[]", name: "array", type: "address[]" }, - { internalType: "address", name: "next", type: "address" }, + { internalType: "address", name: "next", type: "address" } ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "handler", type: "address" }, { internalType: "address", name: "moduleSetupContract", type: "address" }, - { internalType: "bytes", name: "moduleSetupData", type: "bytes" }, + { internalType: "bytes", name: "moduleSetupData", type: "bytes" } ], name: "init", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [{ internalType: "address", name: "module", type: "address" }], name: "isModuleEnabled", outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "bytes32", name: "dataHash", type: "bytes32" }, - { internalType: "bytes", name: "signature", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" } ], name: "isValidSignature", outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [{ internalType: "uint192", name: "_key", type: "uint192" }], name: "nonce", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [{ internalType: "uint256", name: "", type: "uint256" }], name: "noncesDeprecated", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [], name: "ownerDeprecated", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [{ internalType: "address", name: "handler", type: "address" }], name: "setFallbackHandler", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "setupContract", type: "address" }, - { internalType: "bytes", name: "setupData", type: "bytes" }, + { internalType: "bytes", name: "setupData", type: "bytes" } ], name: "setupAndEnableModule", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], name: "supportsInterface", outputs: [{ internalType: "bool", name: "", type: "bool" }], stateMutability: "view", - type: "function", + type: "function" }, { - inputs: [{ internalType: "address", name: "_implementation", type: "address" }], + inputs: [ + { internalType: "address", name: "_implementation", type: "address" } + ], name: "updateImplementation", outputs: [], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ @@ -369,34 +585,52 @@ export const BiconomyAccountAbi = [ { internalType: "bytes", name: "initCode", type: "bytes" }, { internalType: "bytes", name: "callData", type: "bytes" }, { internalType: "uint256", name: "callGasLimit", type: "uint256" }, - { internalType: "uint256", name: "verificationGasLimit", type: "uint256" }, - { internalType: "uint256", name: "preVerificationGas", type: "uint256" }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, { internalType: "uint256", name: "maxFeePerGas", type: "uint256" }, - { internalType: "uint256", name: "maxPriorityFeePerGas", type: "uint256" }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, { internalType: "bytes", name: "paymasterAndData", type: "bytes" }, - { internalType: "bytes", name: "signature", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" } ], internalType: "struct UserOperation", name: "userOp", - type: "tuple", + type: "tuple" }, { internalType: "bytes32", name: "userOpHash", type: "bytes32" }, - { internalType: "uint256", name: "missingAccountFunds", type: "uint256" }, + { internalType: "uint256", name: "missingAccountFunds", type: "uint256" } ], name: "validateUserOp", - outputs: [{ internalType: "uint256", name: "validationData", type: "uint256" }], + outputs: [ + { internalType: "uint256", name: "validationData", type: "uint256" } + ], stateMutability: "nonpayable", - type: "function", + type: "function" }, { inputs: [ - { internalType: "address payable", name: "withdrawAddress", type: "address" }, - { internalType: "uint256", name: "amount", type: "uint256" }, + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + }, + { internalType: "uint256", name: "amount", type: "uint256" } ], name: "withdrawDepositTo", outputs: [], stateMutability: "payable", - type: "function", + type: "function" }, - { stateMutability: "payable", type: "receive" }, -] as const; + { stateMutability: "payable", type: "receive" } +] as const diff --git a/packages/account/src/abi/AccountResolver.ts b/src/account/abi/AccountResolver.ts similarity index 81% rename from packages/account/src/abi/AccountResolver.ts rename to src/account/abi/AccountResolver.ts index 0cbffc749..2dfd45303 100644 --- a/packages/account/src/abi/AccountResolver.ts +++ b/src/account/abi/AccountResolver.ts @@ -3,22 +3,22 @@ export const AccountResolverAbi = [ inputs: [ { internalType: "address", name: "_v1Factory", type: "address" }, { internalType: "address", name: "_v2Factory", type: "address" }, - { internalType: "address", name: "_ecdsaModule", type: "address" }, + { internalType: "address", name: "_ecdsaModule", type: "address" } ], stateMutability: "nonpayable", - type: "constructor", + type: "constructor" }, { inputs: [], name: "ecdsaOwnershipModule", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "_eoa", type: "address" }, - { internalType: "uint8", name: "_maxIndex", type: "uint8" }, + { internalType: "uint8", name: "_maxIndex", type: "uint8" } ], name: "resolveAddresses", outputs: [ @@ -26,25 +26,29 @@ export const AccountResolverAbi = [ components: [ { internalType: "address", name: "accountAddress", type: "address" }, { internalType: "address", name: "factoryAddress", type: "address" }, - { internalType: "address", name: "currentImplementation", type: "address" }, + { + internalType: "address", + name: "currentImplementation", + type: "address" + }, { internalType: "string", name: "currentVersion", type: "string" }, { internalType: "string", name: "factoryVersion", type: "string" }, - { internalType: "uint256", name: "deploymentIndex", type: "uint256" }, + { internalType: "uint256", name: "deploymentIndex", type: "uint256" } ], internalType: "struct IAddressResolver.SmartAccountResult[]", name: "", - type: "tuple[]", - }, + type: "tuple[]" + } ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "_eoa", type: "address" }, { internalType: "uint8", name: "_maxIndex", type: "uint8" }, { internalType: "address", name: "_moduleAddress", type: "address" }, - { internalType: "bytes", name: "_moduleSetupData", type: "bytes" }, + { internalType: "bytes", name: "_moduleSetupData", type: "bytes" } ], name: "resolveAddressesFlexibleForV2", outputs: [ @@ -52,23 +56,27 @@ export const AccountResolverAbi = [ components: [ { internalType: "address", name: "accountAddress", type: "address" }, { internalType: "address", name: "factoryAddress", type: "address" }, - { internalType: "address", name: "currentImplementation", type: "address" }, + { + internalType: "address", + name: "currentImplementation", + type: "address" + }, { internalType: "string", name: "currentVersion", type: "string" }, { internalType: "string", name: "factoryVersion", type: "string" }, - { internalType: "uint256", name: "deploymentIndex", type: "uint256" }, + { internalType: "uint256", name: "deploymentIndex", type: "uint256" } ], internalType: "struct IAddressResolver.SmartAccountResult[]", name: "", - type: "tuple[]", - }, + type: "tuple[]" + } ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { internalType: "address", name: "_eoa", type: "address" }, - { internalType: "uint8", name: "_maxIndex", type: "uint8" }, + { internalType: "uint8", name: "_maxIndex", type: "uint8" } ], name: "resolveAddressesV1", outputs: [ @@ -76,31 +84,35 @@ export const AccountResolverAbi = [ components: [ { internalType: "address", name: "accountAddress", type: "address" }, { internalType: "address", name: "factoryAddress", type: "address" }, - { internalType: "address", name: "currentImplementation", type: "address" }, + { + internalType: "address", + name: "currentImplementation", + type: "address" + }, { internalType: "string", name: "currentVersion", type: "string" }, { internalType: "string", name: "factoryVersion", type: "string" }, - { internalType: "uint256", name: "deploymentIndex", type: "uint256" }, + { internalType: "uint256", name: "deploymentIndex", type: "uint256" } ], internalType: "struct IAddressResolver.SmartAccountResult[]", name: "", - type: "tuple[]", - }, + type: "tuple[]" + } ], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [], name: "smartAccountFactoryV1", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", - type: "function", + type: "function" }, { inputs: [], name: "smartAccountFactoryV2", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", - type: "function", - }, -] as const; + type: "function" + } +] as const diff --git a/src/account/abi/EntryPointAbi.ts b/src/account/abi/EntryPointAbi.ts new file mode 100644 index 000000000..695b3e7e7 --- /dev/null +++ b/src/account/abi/EntryPointAbi.ts @@ -0,0 +1,1309 @@ +export const EntryPointAbi = [ + { + inputs: [ + { + internalType: "uint256", + name: "preOpGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "paid", + type: "uint256" + }, + { + internalType: "uint48", + name: "validAfter", + type: "uint48" + }, + { + internalType: "uint48", + name: "validUntil", + type: "uint48" + }, + { + internalType: "bool", + name: "targetSuccess", + type: "bool" + }, + { + internalType: "bytes", + name: "targetResult", + type: "bytes" + } + ], + name: "ExecutionResult", + type: "error" + }, + { + inputs: [ + { + internalType: "uint256", + name: "opIndex", + type: "uint256" + }, + { + internalType: "string", + name: "reason", + type: "string" + } + ], + name: "FailedOp", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + } + ], + name: "SenderAddressResult", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "aggregator", + type: "address" + } + ], + name: "SignatureValidationFailed", + type: "error" + }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "preOpGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "prefund", + type: "uint256" + }, + { + internalType: "bool", + name: "sigFailed", + type: "bool" + }, + { + internalType: "uint48", + name: "validAfter", + type: "uint48" + }, + { + internalType: "uint48", + name: "validUntil", + type: "uint48" + }, + { + internalType: "bytes", + name: "paymasterContext", + type: "bytes" + } + ], + internalType: "struct IEntryPoint.ReturnInfo", + name: "returnInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "senderInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "factoryInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "paymasterInfo", + type: "tuple" + } + ], + name: "ValidationResult", + type: "error" + }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "preOpGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "prefund", + type: "uint256" + }, + { + internalType: "bool", + name: "sigFailed", + type: "bool" + }, + { + internalType: "uint48", + name: "validAfter", + type: "uint48" + }, + { + internalType: "uint48", + name: "validUntil", + type: "uint48" + }, + { + internalType: "bytes", + name: "paymasterContext", + type: "bytes" + } + ], + internalType: "struct IEntryPoint.ReturnInfo", + name: "returnInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "senderInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "factoryInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "paymasterInfo", + type: "tuple" + }, + { + components: [ + { + internalType: "address", + name: "aggregator", + type: "address" + }, + { + components: [ + { + internalType: "uint256", + name: "stake", + type: "uint256" + }, + { + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + internalType: "struct IStakeManager.StakeInfo", + name: "stakeInfo", + type: "tuple" + } + ], + internalType: "struct IEntryPoint.AggregatorStakeInfo", + name: "aggregatorInfo", + type: "tuple" + } + ], + name: "ValidationResultWithAggregation", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "userOpHash", + type: "bytes32" + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address" + }, + { + indexed: false, + internalType: "address", + name: "factory", + type: "address" + }, + { + indexed: false, + internalType: "address", + name: "paymaster", + type: "address" + } + ], + name: "AccountDeployed", + type: "event" + }, + { + anonymous: false, + inputs: [], + name: "BeforeExecution", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "totalDeposit", + type: "uint256" + } + ], + name: "Deposited", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "aggregator", + type: "address" + } + ], + name: "SignatureAggregatorChanged", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "totalStaked", + type: "uint256" + }, + { + indexed: false, + internalType: "uint256", + name: "unstakeDelaySec", + type: "uint256" + } + ], + name: "StakeLocked", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "withdrawTime", + type: "uint256" + } + ], + name: "StakeUnlocked", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: false, + internalType: "address", + name: "withdrawAddress", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256" + } + ], + name: "StakeWithdrawn", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "userOpHash", + type: "bytes32" + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "paymaster", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + indexed: false, + internalType: "bool", + name: "success", + type: "bool" + }, + { + indexed: false, + internalType: "uint256", + name: "actualGasCost", + type: "uint256" + }, + { + indexed: false, + internalType: "uint256", + name: "actualGasUsed", + type: "uint256" + } + ], + name: "UserOperationEvent", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "userOpHash", + type: "bytes32" + }, + { + indexed: true, + internalType: "address", + name: "sender", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + indexed: false, + internalType: "bytes", + name: "revertReason", + type: "bytes" + } + ], + name: "UserOperationRevertReason", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: false, + internalType: "address", + name: "withdrawAddress", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256" + } + ], + name: "Withdrawn", + type: "event" + }, + { + inputs: [], + name: "SIG_VALIDATION_FAILED", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + } + ], + name: "_validateSenderAndPaymaster", + outputs: [], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "uint32", + name: "unstakeDelaySec", + type: "uint32" + } + ], + name: "addStake", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "depositTo", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "deposits", + outputs: [ + { + internalType: "uint112", + name: "deposit", + type: "uint112" + }, + { + internalType: "bool", + name: "staked", + type: "bool" + }, + { + internalType: "uint112", + name: "stake", + type: "uint112" + }, + { + internalType: "uint32", + name: "unstakeDelaySec", + type: "uint32" + }, + { + internalType: "uint48", + name: "withdrawTime", + type: "uint48" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "getDepositInfo", + outputs: [ + { + components: [ + { + internalType: "uint112", + name: "deposit", + type: "uint112" + }, + { + internalType: "bool", + name: "staked", + type: "bool" + }, + { + internalType: "uint112", + name: "stake", + type: "uint112" + }, + { + internalType: "uint32", + name: "unstakeDelaySec", + type: "uint32" + }, + { + internalType: "uint48", + name: "withdrawTime", + type: "uint48" + } + ], + internalType: "struct IStakeManager.DepositInfo", + name: "info", + type: "tuple" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint192", + name: "key", + type: "uint192" + } + ], + name: "getNonce", + outputs: [ + { + internalType: "uint256", + name: "nonce", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "initCode", + type: "bytes" + } + ], + name: "getSenderAddress", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct UserOperation", + name: "userOp", + type: "tuple" + } + ], + name: "getUserOpHash", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct UserOperation[]", + name: "userOps", + type: "tuple[]" + }, + { + internalType: "contract IAggregator", + name: "aggregator", + type: "address" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct IEntryPoint.UserOpsPerAggregator[]", + name: "opsPerAggregator", + type: "tuple[]" + }, + { + internalType: "address payable", + name: "beneficiary", + type: "address" + } + ], + name: "handleAggregatedOps", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct UserOperation[]", + name: "ops", + type: "tuple[]" + }, + { + internalType: "address payable", + name: "beneficiary", + type: "address" + } + ], + name: "handleOps", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "uint192", + name: "key", + type: "uint192" + } + ], + name: "incrementNonce", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + components: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "address", + name: "paymaster", + type: "address" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + } + ], + internalType: "struct EntryPoint.MemoryUserOp", + name: "mUserOp", + type: "tuple" + }, + { + internalType: "bytes32", + name: "userOpHash", + type: "bytes32" + }, + { + internalType: "uint256", + name: "prefund", + type: "uint256" + }, + { + internalType: "uint256", + name: "contextOffset", + type: "uint256" + }, + { + internalType: "uint256", + name: "preOpGas", + type: "uint256" + } + ], + internalType: "struct EntryPoint.UserOpInfo", + name: "opInfo", + type: "tuple" + }, + { + internalType: "bytes", + name: "context", + type: "bytes" + } + ], + name: "innerHandleOp", + outputs: [ + { + internalType: "uint256", + name: "actualGasCost", + type: "uint256" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + }, + { + internalType: "uint192", + name: "", + type: "uint192" + } + ], + name: "nonceSequenceNumber", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct UserOperation", + name: "op", + type: "tuple" + }, + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "bytes", + name: "targetCallData", + type: "bytes" + } + ], + name: "simulateHandleOp", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256" + }, + { + internalType: "bytes", + name: "initCode", + type: "bytes" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct UserOperation", + name: "userOp", + type: "tuple" + } + ], + name: "simulateValidation", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "unlockStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + } + ], + name: "withdrawStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + }, + { + internalType: "uint256", + name: "withdrawAmount", + type: "uint256" + } + ], + name: "withdrawTo", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + stateMutability: "payable", + type: "receive" + } +] as const diff --git a/src/account/abi/Factory.ts b/src/account/abi/Factory.ts new file mode 100644 index 000000000..c7d148bb2 --- /dev/null +++ b/src/account/abi/Factory.ts @@ -0,0 +1,141 @@ +export const BiconomyFactoryAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "initialAuthModule", + type: "address" + }, + { + indexed: true, + internalType: "uint256", + name: "index", + type: "uint256" + } + ], + name: "AccountCreation", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "initialAuthModule", + type: "address" + } + ], + name: "AccountCreationWithoutIndex", + type: "event" + }, + { + inputs: [], + name: "accountCreationCode", + outputs: [ + { + internalType: "bytes", + name: "", + type: "bytes" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "moduleSetupContract", + type: "address" + }, + { + internalType: "bytes", + name: "moduleSetupData", + type: "bytes" + } + ], + name: "deployAccount", + outputs: [ + { + internalType: "address", + name: "proxy", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "moduleSetupContract", + type: "address" + }, + { + internalType: "bytes", + name: "moduleSetupData", + type: "bytes" + }, + { + internalType: "uint256", + name: "index", + type: "uint256" + } + ], + name: "deployCounterFactualAccount", + outputs: [ + { + internalType: "address", + name: "proxy", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "moduleSetupContract", + type: "address" + }, + { + internalType: "bytes", + name: "moduleSetupData", + type: "bytes" + }, + { + internalType: "uint256", + name: "index", + type: "uint256" + } + ], + name: "getAddressForCounterFactualAccount", + outputs: [ + { + internalType: "address", + name: "_account", + type: "address" + } + ], + stateMutability: "view", + type: "function" + } +] as const diff --git a/src/account/abi/SmartAccount.ts b/src/account/abi/SmartAccount.ts new file mode 100644 index 000000000..541267158 --- /dev/null +++ b/src/account/abi/SmartAccount.ts @@ -0,0 +1,636 @@ +export const BiconomyAccountAbi = [ + { + inputs: [ + { + internalType: "contract IEntryPoint", + name: "anEntryPoint", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { inputs: [], name: "AlreadyInitialized", type: "error" }, + { inputs: [], name: "BaseImplementationCannotBeZero", type: "error" }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotAnEntryPoint", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPoint", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPointOrOwner", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotEntryPointOrSelf", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotOwner", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "CallerIsNotSelf", + type: "error" + }, + { inputs: [], name: "DelegateCallsOnly", type: "error" }, + { inputs: [], name: "EntryPointCannotBeZero", type: "error" }, + { inputs: [], name: "HandlerCannotBeZero", type: "error" }, + { + inputs: [ + { + internalType: "address", + name: "implementationAddress", + type: "address" + } + ], + name: "InvalidImplementation", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "caller", type: "address" }], + name: "MixedAuthFail", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleAlreadyEnabled", + type: "error" + }, + { + inputs: [ + { internalType: "address", name: "expectedModule", type: "address" }, + { internalType: "address", name: "returnedModule", type: "address" }, + { internalType: "address", name: "prevModule", type: "address" } + ], + name: "ModuleAndPrevModuleMismatch", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleCannotBeZeroOrSentinel", + type: "error" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "ModuleNotEnabled", + type: "error" + }, + { inputs: [], name: "ModulesAlreadyInitialized", type: "error" }, + { inputs: [], name: "ModulesSetupExecutionFailed", type: "error" }, + { inputs: [], name: "OwnerCanNotBeSelf", type: "error" }, + { inputs: [], name: "OwnerCannotBeZero", type: "error" }, + { inputs: [], name: "OwnerProvidedIsSame", type: "error" }, + { inputs: [], name: "TransferToZeroAddressAttempt", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "destLength", type: "uint256" }, + { internalType: "uint256", name: "valueLength", type: "uint256" }, + { internalType: "uint256", name: "funcLength", type: "uint256" }, + { internalType: "uint256", name: "operationLength", type: "uint256" } + ], + name: "WrongBatchProvided", + type: "error" + }, + { + inputs: [ + { internalType: "bytes", name: "contractSignature", type: "bytes" } + ], + name: "WrongContractSignature", + type: "error" + }, + { + inputs: [ + { internalType: "uint256", name: "uintS", type: "uint256" }, + { + internalType: "uint256", + name: "contractSignatureLength", + type: "uint256" + }, + { internalType: "uint256", name: "signatureLength", type: "uint256" } + ], + name: "WrongContractSignatureFormat", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "moduleAddressProvided", + type: "address" + } + ], + name: "WrongValidationModule", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousHandler", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "handler", + type: "address" + } + ], + name: "ChangedFallbackHandler", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "DisabledModule", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "EnabledModule", + type: "event" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: true, + internalType: "uint256", + name: "value", + type: "uint256" + }, + { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + }, + { + indexed: false, + internalType: "uint256", + name: "txGas", + type: "uint256" + } + ], + name: "ExecutionFailure", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "ExecutionFromModuleFailure", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "module", + type: "address" + } + ], + name: "ExecutionFromModuleSuccess", + type: "event" + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: true, + internalType: "uint256", + name: "value", + type: "uint256" + }, + { indexed: true, internalType: "bytes", name: "data", type: "bytes" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + }, + { + indexed: false, + internalType: "uint256", + name: "txGas", + type: "uint256" + } + ], + name: "ExecutionSuccess", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldImplementation", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "newImplementation", + type: "address" + } + ], + name: "ImplementationUpdated", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "module", + type: "address" + }, + { indexed: false, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256" + }, + { indexed: false, internalType: "bytes", name: "data", type: "bytes" }, + { + indexed: false, + internalType: "enum Enum.Operation", + name: "operation", + type: "uint8" + } + ], + name: "ModuleTransaction", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "sender", + type: "address" + }, + { indexed: true, internalType: "uint256", name: "value", type: "uint256" } + ], + name: "SmartAccountReceivedNativeToken", + type: "event" + }, + { stateMutability: "nonpayable", type: "fallback" }, + { + inputs: [], + name: "VERSION", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "addDeposit", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "prevModule", type: "address" }, + { internalType: "address", name: "module", type: "address" } + ], + name: "disableModule", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "enableModule", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "entryPoint", + outputs: [ + { internalType: "contract IEntryPoint", name: "", type: "address" } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address[]", name: "to", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "data", type: "bytes[]" }, + { + internalType: "enum Enum.Operation[]", + name: "operations", + type: "uint8[]" + } + ], + name: "execBatchTransactionFromModule", + outputs: [{ internalType: "bool", name: "success", type: "bool" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" }, + { internalType: "uint256", name: "txGas", type: "uint256" } + ], + name: "execTransactionFromModule", + outputs: [{ internalType: "bool", name: "success", type: "bool" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" } + ], + name: "execTransactionFromModule", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Enum.Operation", name: "operation", type: "uint8" } + ], + name: "execTransactionFromModuleReturnData", + outputs: [ + { internalType: "bool", name: "success", type: "bool" }, + { internalType: "bytes", name: "returnData", type: "bytes" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "dest", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "func", type: "bytes" } + ], + name: "execute", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address[]", name: "dest", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" } + ], + name: "executeBatch", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address[]", name: "dest", type: "address[]" }, + { internalType: "uint256[]", name: "value", type: "uint256[]" }, + { internalType: "bytes[]", name: "func", type: "bytes[]" } + ], + name: "executeBatch_y6U", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "dest", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "func", type: "bytes" } + ], + name: "execute_ncC", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "getDeposit", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "getFallbackHandler", + outputs: [{ internalType: "address", name: "_handler", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "getImplementation", + outputs: [ + { internalType: "address", name: "_implementation", type: "address" } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "start", type: "address" }, + { internalType: "uint256", name: "pageSize", type: "uint256" } + ], + name: "getModulesPaginated", + outputs: [ + { internalType: "address[]", name: "array", type: "address[]" }, + { internalType: "address", name: "next", type: "address" } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "handler", type: "address" }, + { internalType: "address", name: "moduleSetupContract", type: "address" }, + { internalType: "bytes", name: "moduleSetupData", type: "bytes" } + ], + name: "init", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "module", type: "address" }], + name: "isModuleEnabled", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "bytes32", name: "dataHash", type: "bytes32" }, + { internalType: "bytes", name: "signature", type: "bytes" } + ], + name: "isValidSignature", + outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [{ internalType: "uint192", name: "_key", type: "uint192" }], + name: "nonce", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "noncesDeprecated", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "ownerDeprecated", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [{ internalType: "address", name: "handler", type: "address" }], + name: "setFallbackHandler", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "setupContract", type: "address" }, + { internalType: "bytes", name: "setupData", type: "bytes" } + ], + name: "setupAndEnableModule", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { internalType: "address", name: "_implementation", type: "address" } + ], + name: "updateImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "sender", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "bytes", name: "initCode", type: "bytes" }, + { internalType: "bytes", name: "callData", type: "bytes" }, + { internalType: "uint256", name: "callGasLimit", type: "uint256" }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { internalType: "uint256", name: "maxFeePerGas", type: "uint256" }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { internalType: "bytes", name: "paymasterAndData", type: "bytes" }, + { internalType: "bytes", name: "signature", type: "bytes" } + ], + internalType: "struct UserOperation", + name: "userOp", + type: "tuple" + }, + { internalType: "bytes32", name: "userOpHash", type: "bytes32" }, + { internalType: "uint256", name: "missingAccountFunds", type: "uint256" } + ], + name: "validateUserOp", + outputs: [ + { internalType: "uint256", name: "validationData", type: "uint256" } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + }, + { internalType: "uint256", name: "amount", type: "uint256" } + ], + name: "withdrawDepositTo", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { stateMutability: "payable", type: "receive" } +] as const diff --git a/src/account/index.ts b/src/account/index.ts new file mode 100644 index 000000000..50364553f --- /dev/null +++ b/src/account/index.ts @@ -0,0 +1,11 @@ +import { BiconomySmartAccountV2 } from "./BiconomySmartAccountV2.js" +import type { BiconomySmartAccountV2Config } from "./utils/Types.js" + +export * from "./utils/index.js" +export * from "./signers/local-account.js" +export * from "./signers/wallet-client.js" +export * from "./BiconomySmartAccountV2.js" + +export const createSmartAccountClient = BiconomySmartAccountV2.create + +export type SmartWalletConfig = BiconomySmartAccountV2Config diff --git a/src/account/signers/local-account.ts b/src/account/signers/local-account.ts new file mode 100644 index 000000000..65bf3c521 --- /dev/null +++ b/src/account/signers/local-account.ts @@ -0,0 +1,55 @@ +import type { + HDAccount, + Hex, + LocalAccount, + PrivateKeyAccount, + SignableMessage, + TypedData, + TypedDataDefinition +} from "viem" +import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts" +import type { SmartAccountSigner } from "../utils/Types.js" + +export class LocalAccountSigner< + T extends HDAccount | PrivateKeyAccount | LocalAccount +> implements SmartAccountSigner<T> +{ + inner: T + signerType: string + + constructor(inner: T) { + this.inner = inner + this.signerType = inner.type // type: "local" + } + + readonly signMessage: (message: SignableMessage) => Promise<`0x${string}`> = ( + message + ) => { + return this.inner.signMessage({ message }) + } + + readonly signTypedData = async < + const TTypedData extends TypedData | { [key: string]: unknown }, + TPrimaryType extends string = string + >( + params: TypedDataDefinition<TTypedData, TPrimaryType> + ): Promise<Hex> => { + return this.inner.signTypedData(params) + } + + readonly getAddress: () => Promise<`0x${string}`> = async () => { + return this.inner.address + } + + static mnemonicToAccountSigner(key: string): LocalAccountSigner<HDAccount> { + const signer = mnemonicToAccount(key) + return new LocalAccountSigner(signer) + } + + static privateKeyToAccountSigner( + key: Hex + ): LocalAccountSigner<PrivateKeyAccount> { + const signer = privateKeyToAccount(key) + return new LocalAccountSigner(signer) + } +} diff --git a/src/account/signers/wallet-client.ts b/src/account/signers/wallet-client.ts new file mode 100644 index 000000000..69c10fe5a --- /dev/null +++ b/src/account/signers/wallet-client.ts @@ -0,0 +1,48 @@ +import { + type Hex, + type SignableMessage, + type TypedData, + type TypedDataDefinition, + type WalletClient, + getAddress +} from "viem" +import type { SmartAccountSigner } from "../utils/Types.js" + +export class WalletClientSigner implements SmartAccountSigner<WalletClient> { + signerType: string + inner: WalletClient + + constructor(client: WalletClient, signerType: string) { + this.inner = client + if (!signerType) { + throw new Error(`InvalidSignerTypeError: ${signerType}`) + } + this.signerType = signerType + } + + getAddress: () => Promise<`0x${string}`> = async () => { + const addresses = await this.inner.getAddresses() + return getAddress(addresses[0]) + } + + readonly signMessage: (message: SignableMessage) => Promise<`0x${string}`> = + async (message) => { + const account = this.inner.account ?? (await this.getAddress()) + + return this.inner.signMessage({ message, account }) + } + + signTypedData = async < + const TTypedData extends TypedData | { [key: string]: unknown }, + TPrimaryType extends string = string + >( + typedData: TypedDataDefinition<TTypedData, TPrimaryType> + ): Promise<Hex> => { + const account = this.inner.account ?? (await this.getAddress()) + + return this.inner.signTypedData({ + account, + ...typedData + }) + } +} diff --git a/packages/account/src/utils/Constants.ts b/src/account/utils/Constants.ts similarity index 58% rename from packages/account/src/utils/Constants.ts rename to src/account/utils/Constants.ts index 3f594ded6..edd7ef64b 100644 --- a/packages/account/src/utils/Constants.ts +++ b/src/account/utils/Constants.ts @@ -1,80 +1,93 @@ -import { Hex } from "viem"; -import { - EntryPointAddresses, +import type { Hex } from "viem" +import type { BiconomyFactories, - BiconomyImplementations, - EntryPointAddressesByVersion, BiconomyFactoriesByVersion, + BiconomyImplementations, BiconomyImplementationsByVersion, -} from "./Types.js"; + EntryPointAddresses, + EntryPointAddressesByVersion +} from "./Types.js" -export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; +export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" // will always be latest entrypoint address -export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789"; +export const DEFAULT_ENTRYPOINT_ADDRESS = + "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789" export const ENTRYPOINT_ADDRESSES: EntryPointAddresses = { "0x27a4db290b89ae3373ce4313cbeae72112ae7da9": "V0_0_5", - "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789": "V0_0_6", -}; + "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789": "V0_0_6" +} // will always be latest factory address -export const DEFAULT_BICONOMY_FACTORY_ADDRESS = "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5"; -export const DEFAULT_FALLBACK_HANDLER_ADDRESS = "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1"; +export const DEFAULT_BICONOMY_FACTORY_ADDRESS = + "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5" +export const DEFAULT_FALLBACK_HANDLER_ADDRESS = + "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1" export const BICONOMY_FACTORY_ADDRESSES: BiconomyFactories = { "0x000000f9ee1842bb72f6bbdd75e6d3d4e3e9594c": "V1_0_0", - "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5": "V2_0_0", -}; + "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5": "V2_0_0" +} // will always be latest implementation address -export const DEFAULT_BICONOMY_IMPLEMENTATION_ADDRESS = "0x0000002512019Dafb59528B82CB92D3c5D2423aC"; +export const DEFAULT_BICONOMY_IMPLEMENTATION_ADDRESS = + "0x0000002512019Dafb59528B82CB92D3c5D2423aC" export const BICONOMY_IMPLEMENTATION_ADDRESSES: BiconomyImplementations = { "0x00006b7e42e01957da540dc6a8f7c30c4d816af5": "V1_0_0", - "0x0000002512019Dafb59528B82CB92D3c5D2423aC": "V2_0_0", -}; + "0x0000002512019Dafb59528B82CB92D3c5D2423aC": "V2_0_0" +} export const ENTRYPOINT_ADDRESSES_BY_VERSION: EntryPointAddressesByVersion = { V0_0_5: "0x27a4db290b89ae3373ce4313cbeae72112ae7da9", - V0_0_6: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", -}; + V0_0_6: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789" +} -export const BICONOMY_FACTORY_ADDRESSES_BY_VERSION: BiconomyFactoriesByVersion = Object.fromEntries( - Object.entries(BICONOMY_FACTORY_ADDRESSES).map(([k, v]) => [v, k]), -); +export const BICONOMY_FACTORY_ADDRESSES_BY_VERSION: BiconomyFactoriesByVersion = + Object.fromEntries( + Object.entries(BICONOMY_FACTORY_ADDRESSES).map(([k, v]) => [v, k]) + ) -export const BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION: BiconomyImplementationsByVersion = Object.fromEntries( - Object.entries(BICONOMY_IMPLEMENTATION_ADDRESSES).map(([k, v]) => [v, k]), -); +export const BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION: BiconomyImplementationsByVersion = + Object.fromEntries( + Object.entries(BICONOMY_IMPLEMENTATION_ADDRESSES).map(([k, v]) => [v, k]) + ) -export const EIP1559_UNSUPPORTED_NETWORKS: Array<number> = [97, 56, 1442, 1101]; +export const EIP1559_UNSUPPORTED_NETWORKS: Array<number> = [97, 56, 1442, 1101] export const PROXY_CREATION_CODE = - "0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033"; + "0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033" -export const ADDRESS_RESOLVER_ADDRESS = "0x00000E81673606e07fC79CE5F1b3B26957844468"; +export const ADDRESS_RESOLVER_ADDRESS = + "0x00000E81673606e07fC79CE5F1b3B26957844468" export const DefaultGasLimit = { callGasLimit: 800000, verificationGasLimit: 1000000, - preVerificationGas: 100000, -}; + preVerificationGas: 100000 +} export const ERROR_MESSAGES = { ACCOUNT_ALREADY_DEPLOYED: "Account already deployed", - NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY: "Native token balance is not available during deploy", - NO_RECIPIENT: "One or more of your withdrawals is missing a recipient", + NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY: + "Native token balance is not available during deploy", SPENDER_REQUIRED: "spender is required for ERC20 mode", - NO_FEE_QUOTE: "FeeQuote was not provided, please call smartAccount.getTokenFees() to get feeQuote", + NO_FEE_QUOTE: + "FeeQuote was not provided, please call smartAccount.getTokenFees() to get feeQuote", FAILED_FEE_QUOTE_FETCH: "Failed to fetch fee quote", CHAIN_NOT_FOUND: "Chain not found", - NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT: "'Amount' is required for withdrawal of native token without using a paymaster", -}; + NO_RECIPIENT: "Recipient is required", + NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT: + "'Amount' is required for withdrawal of native token without using a paymaster", + MISSING_RPC_URL: + "rpcUrl is required for PrivateKeyAccount signer type, please provide it in the config" +} -export const NATIVE_TOKEN_ALIAS: Hex = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; +export const NATIVE_TOKEN_ALIAS: Hex = + "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" export const ERC20_ABI = [ "function transfer(address to, uint256 value) external returns (bool)", "function transferFrom(address from, address to, uint256 value) external returns (bool)", "function approve(address spender, uint256 value) external returns (bool)", "function allowance(address owner, address spender) external view returns (uint256)", "function balanceOf(address owner) external view returns (uint256)", - "function decimals() external view returns (uint8)", -]; + "function decimals() external view returns (uint8)" +] diff --git a/src/account/utils/EthersSigner.ts b/src/account/utils/EthersSigner.ts new file mode 100644 index 000000000..5019597be --- /dev/null +++ b/src/account/utils/EthersSigner.ts @@ -0,0 +1,41 @@ +import type { Hex, SignableMessage } from "viem" +import type { LightSigner, SmartAccountSigner } from "../utils/Types.js" + +export class EthersSigner<T extends LightSigner> + implements SmartAccountSigner<T> +{ + signerType = "ethers" + + inner: T + + constructor(inner: T, signerType: string) { + this.inner = inner + this.signerType = signerType + } + + async getAddress() { + return (await this.inner.getAddress()) as Hex + } + + async signMessage(_message: SignableMessage): Promise<Hex> { + const message = typeof _message === "string" ? _message : _message.raw + const signature = await this.inner?.signMessage(message) + return this.#correctSignature(signature as Hex) + } + + async signTypedData(_notUsed: any): Promise<Hex> { + throw new Error("signTypedData is not supported for Ethers Signer") + } + + #correctSignature = (_signature: Hex): Hex => { + let signature = _signature + const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) + if (![27, 28].includes(potentiallyIncorrectV)) { + const correctV = potentiallyIncorrectV + 27 + signature = signature.slice(0, -2) + correctV.toString(16) + } + return signature as Hex + } +} + +export default EthersSigner diff --git a/src/account/utils/HttpRequests.ts b/src/account/utils/HttpRequests.ts new file mode 100644 index 000000000..07e900225 --- /dev/null +++ b/src/account/utils/HttpRequests.ts @@ -0,0 +1,72 @@ +import { getAAError } from "../../bundler/utils/getAAError.js" +import { Logger } from "./Logger.js" +import type { Service } from "./Types.js" + +export enum HttpMethod { + Get = "get", + Post = "post", + Delete = "delete" +} + +/* eslint-disable @typescript-eslint/no-explicit-any */ +export interface HttpRequest { + url: string + method: HttpMethod + body?: Record<string, any> +} + +export async function sendRequest<T>( + { url, method, body }: HttpRequest, + service: Service +): Promise<T> { + const response = await fetch(url, { + method, + headers: { + Accept: "application/json", + "Content-Type": "application/json" + }, + body: JSON.stringify(body) + }) + + // biome-ignore lint/suspicious/noImplicitAnyLet: <explanation> + let jsonResponse: any + try { + jsonResponse = await response.json() + Logger.log(`${service} RPC Response`, jsonResponse) + } catch (error) { + if (!response.ok) { + throw await getAAError(response.statusText, service) + } + } + + if (response.ok) { + return jsonResponse as T + } + if (jsonResponse.error) { + throw await getAAError( + `Error coming from ${service}: ${jsonResponse.error.message}` + ) + } + if (jsonResponse.message) { + throw await getAAError(jsonResponse.message) + } + if (jsonResponse.msg) { + throw await getAAError(jsonResponse.msg) + } + if (jsonResponse.data) { + throw await getAAError(jsonResponse.data) + } + if (jsonResponse.detail) { + throw await getAAError(jsonResponse.detail) + } + if (jsonResponse.message) { + throw await getAAError(jsonResponse.message) + } + if (jsonResponse.nonFieldErrors) { + throw await getAAError(jsonResponse.nonFieldErrors) + } + if (jsonResponse.delegate) { + throw await getAAError(jsonResponse.delegate) + } + throw await getAAError(response.statusText) +} diff --git a/packages/common/src/utils/Logger.ts b/src/account/utils/Logger.ts similarity index 69% rename from packages/common/src/utils/Logger.ts rename to src/account/utils/Logger.ts index 0bdcae373..fd0aad9cb 100644 --- a/packages/common/src/utils/Logger.ts +++ b/src/account/utils/Logger.ts @@ -4,9 +4,15 @@ * * @param {any} message Message to be logged */ + +// biome-ignore lint/complexity/noStaticOnlyClass: <explanation> class Logger { // By default, the logger is not in debug mode. - static isDebug: boolean = process.env.BICONOMY_SDK_DEBUG === "true" ? true : process.env.REACT_APP_BICONOMY_SDK_DEBUG === "true" ? true : false; + static isDebug: boolean = [ + "BICONOMY_SDK_DEBUG", + "REACT_APP_BICONOMY_SDK_DEBUG", + "NEXT_PUBLIC_BICONOMY_SDK_DEBUG" + ].some((key) => process.env[key]?.toString() === "true") /** * \x1b[0m is an escape sequence to reset the color of the text @@ -17,33 +23,33 @@ class Logger { */ /* eslint-disable @typescript-eslint/no-explicit-any */ static log(message: string, value?: any): void { - const timestamp = new Date().toISOString(); - const logMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[36m${message}\x1b[0m:`; + const timestamp = new Date().toISOString() + const logMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[36m${message}\x1b[0m:` if (Logger.isDebug) { - console.log(logMessage, value === undefined ? "" : value); + console.log(logMessage, value === undefined ? "" : value) } } /* eslint-disable @typescript-eslint/no-explicit-any */ static warn(message: string, value?: any): void { - const timestamp = new Date().toISOString(); - const warnMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[33mWARN\x1b[0m: \x1b[36m${message}\x1b[0m`; + const timestamp = new Date().toISOString() + const warnMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[33mWARN\x1b[0m: \x1b[36m${message}\x1b[0m` if (Logger.isDebug) { - console.warn(warnMessage, value === undefined ? "" : value); + console.warn(warnMessage, value === undefined ? "" : value) } } /* eslint-disable @typescript-eslint/no-explicit-any */ static error(message: string, value?: any): void { - const timestamp = new Date().toISOString(); - const errorMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[31mERROR\x1b[0m: \x1b[36m${message}\x1b[0m`; + const timestamp = new Date().toISOString() + const errorMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[31mERROR\x1b[0m: \x1b[36m${message}\x1b[0m` if (Logger.isDebug) { - console.error(errorMessage, value === undefined ? "" : value); + console.error(errorMessage, value === undefined ? "" : value) } } } -export { Logger }; +export { Logger } diff --git a/src/account/utils/Types.ts b/src/account/utils/Types.ts new file mode 100644 index 000000000..857e51167 --- /dev/null +++ b/src/account/utils/Types.ts @@ -0,0 +1,597 @@ +import type { + Address, + Chain, + Hash, + Hex, + PrivateKeyAccount, + PublicClient, + SignTypedDataParameters, + SignableMessage, + TypedData, + TypedDataDefinition, + WalletClient +} from "viem" +import type { IBundler } from "../../bundler" +import type { BaseValidationModule, ModuleInfo } from "../../modules" +import type { + FeeQuotesOrDataDto, + IPaymaster, + PaymasterFeeQuote, + PaymasterMode, + SmartAccountData, + SponsorUserOperationDto +} from "../../paymaster" + +export type EntryPointAddresses = Record<string, string> +export type BiconomyFactories = Record<string, string> +export type BiconomyImplementations = Record<string, string> +export type EntryPointAddressesByVersion = Record<string, string> +export type BiconomyFactoriesByVersion = Record<string, string> +export type BiconomyImplementationsByVersion = Record<string, string> + +export type SmartAccountConfig = { + /** entryPointAddress: address of the entry point */ + entryPointAddress: string + /** factoryAddress: address of the smart account factory */ + bundler?: IBundler +} + +export interface BalancePayload { + /** address: The address of the account */ + address: string + /** chainId: The chainId of the network */ + chainId: number + /** amount: The amount of the balance */ + amount: bigint + /** decimals: The number of decimals */ + decimals: number + /** formattedAmount: The amount of the balance formatted */ + formattedAmount: string +} + +export interface WithdrawalRequest { + /** The address of the asset */ + address: Hex + /** The amount to withdraw. Expects unformatted amount. Will use max amount if unset */ + amount?: bigint + /** The destination address of the funds. The second argument from the `withdraw(...)` function will be used as the default if left unset. */ + recipient?: Hex +} + +export interface GasOverheads { + /** fixed: fixed gas overhead */ + fixed: number + /** perUserOp: per user operation gas overhead */ + perUserOp: number + /** perUserOpWord: per user operation word gas overhead */ + perUserOpWord: number + /** zeroByte: per byte gas overhead */ + zeroByte: number + /** nonZeroByte: per non zero byte gas overhead */ + nonZeroByte: number + /** bundleSize: per signature bundleSize */ + bundleSize: number + /** sigSize: sigSize gas overhead */ + sigSize: number +} + +export type BaseSmartAccountConfig = { + /** index: helps to not conflict with other smart account instances */ + index?: number + /** provider: WalletClientSigner from viem */ + provider?: WalletClient + /** entryPointAddress: address of the smart account entry point */ + entryPointAddress?: string + /** accountAddress: address of the smart account, potentially counterfactual */ + accountAddress?: string + /** overheads: {@link GasOverheads} */ + overheads?: Partial<GasOverheads> + /** paymaster: {@link IPaymaster} interface */ + paymaster?: IPaymaster + /** chainId: chainId of the network */ + chainId?: number +} + +export type BiconomyTokenPaymasterRequest = { + /** feeQuote: {@link PaymasterFeeQuote} */ + feeQuote: PaymasterFeeQuote + /** spender: The address of the spender who is paying for the transaction, this can usually be set to feeQuotesResponse.tokenPaymasterAddress */ + spender: Hex + /** maxApproval: If set to true, the paymaster will approve the maximum amount of tokens required for the transaction. Not recommended */ + maxApproval?: boolean + /* skip option to patch callData if approval is already given to the paymaster */ + skipPatchCallData?: boolean +} + +export type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick< + T, + Exclude<keyof T, Keys> +> & + { + [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> + }[Keys] + +export type ConditionalBundlerProps = RequireAtLeastOne< + { + bundler: IBundler + bundlerUrl: string + }, + "bundler" | "bundlerUrl" +> +export type ResolvedBundlerProps = { + bundler: IBundler +} +export type ConditionalValidationProps = RequireAtLeastOne< + { + defaultValidationModule: BaseValidationModule + signer: SupportedSigner + }, + "defaultValidationModule" | "signer" +> + +export type ResolvedValidationProps = { + /** defaultValidationModule: {@link BaseValidationModule} */ + defaultValidationModule: BaseValidationModule + /** activeValidationModule: {@link BaseValidationModule}. The active validation module. Will default to the defaultValidationModule */ + activeValidationModule: BaseValidationModule + /** signer: ethers Wallet, viemWallet or alchemys SmartAccountSigner */ + signer: SmartAccountSigner + /** chainId: chainId of the network */ + chainId: number +} + +export type BiconomySmartAccountV2ConfigBaseProps = { + /** Factory address of biconomy factory contract or some other contract you have deployed on chain */ + factoryAddress?: Hex + /** Sender address: If you want to override the Signer address with some other address and get counterfactual address can use this to pass the EOA and get SA address */ + senderAddress?: Hex + /** implementation of smart contract address or some other contract you have deployed and want to override */ + implementationAddress?: Hex + /** defaultFallbackHandler: override the default fallback contract address */ + defaultFallbackHandler?: Hex + /** rpcUrl: Rpc url, optional, we set default rpc url if not passed. */ + rpcUrl?: string // as good as Provider + /** paymasterUrl: The Paymaster URL retrieved from the Biconomy dashboard */ + paymasterUrl?: string + /** biconomyPaymasterApiKey: The API key retrieved from the Biconomy dashboard */ + biconomyPaymasterApiKey?: string + /** activeValidationModule: The active validation module. Will default to the defaultValidationModule */ + activeValidationModule?: BaseValidationModule + /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */ + scanForUpgradedAccountsFromV1?: boolean + /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */ + maxIndexForScan?: number + /** Can be used to optionally override the chain with a custom chain if it doesn't already exist in viems list of supported chains */ + viemChain?: Chain + /** The initial code to be used for the smart account */ + initCode?: Hex +} +export type BiconomySmartAccountV2Config = + BiconomySmartAccountV2ConfigBaseProps & + BaseSmartAccountConfig & + ConditionalBundlerProps & + ConditionalValidationProps + +export type BiconomySmartAccountV2ConfigConstructorProps = + BiconomySmartAccountV2ConfigBaseProps & + BaseSmartAccountConfig & + ResolvedBundlerProps & + ResolvedValidationProps + +export type BuildUserOpOptions = { + /** overrides: Explicitly set gas values */ + // overrides?: Overrides; + /** Not currently in use */ + // skipBundlerGasEstimation?: boolean; + /** params relevant to the module, mostly relevant to sessions */ + params?: ModuleInfo + /** nonceOptions: For overriding the nonce */ + nonceOptions?: NonceOptions + /** forceEncodeForBatch: For encoding the user operation for batch */ + forceEncodeForBatch?: boolean + /** paymasterServiceData: Options specific to transactions that involve a paymaster */ + paymasterServiceData?: PaymasterUserOperationDto + /** simulationType: Determine which parts of the tx a bundler will simulate: "validation" | "validation_and_execution". */ + simulationType?: SimulationType + /** stateOverrideSet: For overriding the state */ + stateOverrideSet?: StateOverrideSet + /** set to true if the tx is being used *only* to deploy the smartContract, so "0x" is set as the userOp.callData */ + useEmptyDeployCallData?: boolean +} + +export type NonceOptions = { + /** nonceKey: The key to use for nonce */ + nonceKey?: number + /** nonceOverride: The nonce to use for the transaction */ + nonceOverride?: number +} + +export type SimulationType = "validation" | "validation_and_execution" + +export type Overrides = { + /* Value used by inner account execution */ + callGasLimit?: Hex + /* Actual gas used by the validation of this UserOperation */ + verificationGasLimit?: Hex + /* Gas overhead of this UserOperation */ + preVerificationGas?: Hex + /* Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) */ + maxFeePerGas?: Hex + /* Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) */ + maxPriorityFeePerGas?: Hex + /* Address of paymaster sponsoring the transaction, followed by extra data to send to the paymaster ("0x" for self-sponsored transaction) */ + paymasterData?: Hex + /* Data passed into the account along with the nonce during the verification step */ + signature?: Hex +} + +export type InitilizationData = { + accountIndex?: number + signerAddress?: string +} + +export type PaymasterUserOperationDto = SponsorUserOperationDto & + FeeQuotesOrDataDto & { + /** mode: sponsored or erc20 */ + mode: PaymasterMode + /** Always recommended, especially when using token paymaster */ + calculateGasLimits?: boolean + /** Expiry duration in seconds */ + expiryDuration?: number + /** Webhooks to be fired after user op is sent */ + webhookData?: Record<string, any> + /** Smart account meta data */ + smartAccountInfo?: SmartAccountData + /** the fee-paying token address */ + feeTokenAddress?: string + /** The fee quote */ + feeQuote?: PaymasterFeeQuote + /** The address of the spender. This is usually set to FeeQuotesOrDataResponse.tokenPaymasterAddress */ + spender?: Hex + /** Not recommended */ + maxApproval?: boolean + /* skip option to patch callData if approval is already given to the paymaster */ + skipPatchCallData?: boolean + } + +export type InitializeV2Data = { + accountIndex?: number +} + +export type EstimateUserOpGasParams = { + userOp: Partial<UserOperationStruct> + // overrides?: Overrides; + /** Currrently has no effect */ + // skipBundlerGasEstimation?: boolean; + /** paymasterServiceData: Options specific to transactions that involve a paymaster */ + paymasterServiceData?: SponsorUserOperationDto +} + +export interface TransactionDetailsForUserOp { + /** target: The address of the contract to call */ + target: string + /** data: The data to send to the contract */ + data: string + /** value: The value to send to the contract */ + value?: BigNumberish + /** gasLimit: The gas limit to use for the transaction */ + gasLimit?: BigNumberish + /** maxFeePerGas: The maximum fee per gas to use for the transaction */ + maxFeePerGas?: BigNumberish + /** maxPriorityFeePerGas: The maximum priority fee per gas to use for the transaction */ + maxPriorityFeePerGas?: BigNumberish + /** nonce: The nonce to use for the transaction */ + nonce?: BigNumberish +} + +export type CounterFactualAddressParam = { + index?: number + validationModule?: BaseValidationModule + /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */ + scanForUpgradedAccountsFromV1?: boolean + /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */ + maxIndexForScan?: number +} + +export type QueryParamsForAddressResolver = { + eoaAddress: Hex + index: number + moduleAddress: Hex + moduleSetupData: Hex + maxIndexForScan?: number +} + +export type SmartAccountInfo = { + /** accountAddress: The address of the smart account */ + accountAddress: Hex + /** factoryAddress: The address of the smart account factory */ + factoryAddress: Hex + /** currentImplementation: The address of the current implementation */ + currentImplementation: string + /** currentVersion: The version of the smart account */ + currentVersion: string + /** factoryVersion: The version of the factory */ + factoryVersion: string + /** deploymentIndex: The index of the deployment */ + deploymentIndex: BigNumberish +} + +export type ValueOrData = RequireAtLeastOne< + { + value: BigNumberish | string + data: string + }, + "value" | "data" +> +export type Transaction = { + to: string +} & ValueOrData + +export type SupportedToken = Omit< + PaymasterFeeQuote, + "maxGasFeeUSD" | "usdPayment" | "maxGasFee" | "validUntil" +> + +export type Signer = LightSigner & { + // biome-ignore lint/suspicious/noExplicitAny: any is used here to allow for the ethers provider + provider: any +} +export type SupportedSignerName = "alchemy" | "ethers" | "viem" +export type SupportedSigner = + | SmartAccountSigner + | WalletClient + | Signer + | LightSigner + | PrivateKeyAccount +export type Service = "Bundler" | "Paymaster" + +export interface LightSigner { + getAddress(): Promise<string> + signMessage(message: string | Uint8Array): Promise<string> +} + +export type StateOverrideSet = { + [key: string]: { + balance?: string + nonce?: string + code?: string + state?: object + stateDiff?: object + } +} + +export type BigNumberish = Hex | number | bigint +export type BytesLike = Uint8Array | Hex + +//#region UserOperationStruct +// based on @account-abstraction/common +// this is used for building requests +export interface UserOperationStruct { + /* the origin of the request */ + sender: string + /* nonce of the transaction, returned from the entry point for this Address */ + nonce: BigNumberish + /* the initCode for creating the sender if it does not exist yet, otherwise "0x" */ + initCode: BytesLike | "0x" + /* the callData passed to the target */ + callData: BytesLike + /* Value used by inner account execution */ + callGasLimit?: BigNumberish + /* Actual gas used by the validation of this UserOperation */ + verificationGasLimit?: BigNumberish + /* Gas overhead of this UserOperation */ + preVerificationGas?: BigNumberish + /* Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) */ + maxFeePerGas?: BigNumberish + /* Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) */ + maxPriorityFeePerGas?: BigNumberish + /* Address of paymaster sponsoring the transaction, followed by extra data to send to the paymaster ("0x" for self-sponsored transaction) */ + paymasterAndData: BytesLike | "0x" + /* Data passed into the account along with the nonce during the verification step */ + signature: BytesLike +} +//#endregion UserOperationStruct + +//#region SmartAccountSigner +/** + * A signer that can sign messages and typed data. + * + * @template Inner - the generic type of the inner client that the signer wraps to provide functionality such as signing, etc. + * + * @var signerType - the type of the signer (e.g. local, hardware, etc.) + * @var inner - the inner client of @type {Inner} + * + * @method getAddress - get the address of the signer + * @method signMessage - sign a message + * @method signTypedData - sign typed data + */ +export interface SmartAccountSigner<Inner = any> { + signerType: string + inner: Inner + + getAddress: () => Promise<Address> + + signMessage: (message: SignableMessage) => Promise<Hex> + + signTypedData: < + const TTypedData extends TypedData | { [key: string]: unknown }, + TPrimaryType extends string = string + >( + params: TypedDataDefinition<TTypedData, TPrimaryType> + ) => Promise<Hex> +} +//#endregion SmartAccountSigner + +//#region UserOperationCallData +export type UserOperationCallData = + | { + /* the target of the call */ + target: Address + /* the data passed to the target */ + data: Hex + /* the amount of native token to send to the target (default: 0) */ + value?: bigint + } + | Hex +//#endregion UserOperationCallData + +//#region BatchUserOperationCallData +export type BatchUserOperationCallData = Exclude<UserOperationCallData, Hex>[] +//#endregion BatchUserOperationCallData + +export type SignTypedDataParams = Omit<SignTypedDataParameters, "privateKey"> + +export type BasSmartContractAccountProps = + BiconomySmartAccountV2ConfigConstructorProps & { + /** chain: The chain from viem */ + chain: Chain + /** rpcClient: The rpc url string */ + rpcClient: string + /** factoryAddress: The address of the factory */ + factoryAddress: Hex + /** entryPointAddress: The address of the entry point */ + entryPointAddress: Hex + /** accountAddress: The address of the account */ + accountAddress?: Address + } + +export interface ISmartContractAccount< + TSigner extends SmartAccountSigner = SmartAccountSigner +> { + /** + * The RPC provider the account uses to make RPC calls + */ + readonly rpcProvider: PublicClient + + /** + * @returns the init code for the account + */ + getInitCode(): Promise<Hex> + + /** + * This is useful for estimating gas costs. It should return a signature that doesn't cause the account to revert + * when validation is run during estimation. + * + * @returns a dummy signature that doesn't cause the account to revert during estimation + */ + getDummySignature(): Hex + + /** + * Encodes a call to the account's execute function. + * + * @param target - the address receiving the call data + * @param value - optionally the amount of native token to send + * @param data - the call data or "0x" if empty + */ + encodeExecute(target: string, value: bigint, data: string): Promise<Hex> + + /** + * Encodes a batch of transactions to the account's batch execute function. + * NOTE: not all accounts support batching. + * @param txs - An Array of objects containing the target, value, and data for each transaction + * @returns the encoded callData for a UserOperation + */ + encodeBatchExecute(txs: BatchUserOperationCallData): Promise<Hex> + + /** + * @returns the nonce of the account + */ + getNonce(): Promise<bigint> + + /** + * If your account handles 1271 signatures of personal_sign differently + * than it does UserOperations, you can implement two different approaches to signing + * + * @param uoHash -- The hash of the UserOperation to sign + * @returns the signature of the UserOperation + */ + signUserOperationHash(uoHash: Hash): Promise<Hash> + + /** + * Returns a signed and prefixed message. + * + * @param msg - the message to sign + * @returns the signature of the message + */ + signMessage(msg: string | Uint8Array | Hex): Promise<Hex> + + /** + * Signs a typed data object as per ERC-712 + * + * @param params - {@link SignTypedDataParams} + * @returns the signed hash for the message passed + */ + signTypedData(params: SignTypedDataParams): Promise<Hash> + + /** + * If the account is not deployed, it will sign the message and then wrap it in 6492 format + * + * @param msg - the message to sign + * @returns ths signature wrapped in 6492 format + */ + signMessageWith6492(msg: string | Uint8Array | Hex): Promise<Hex> + + /** + * If the account is not deployed, it will sign the typed data blob and then wrap it in 6492 format + * + * @param params - {@link SignTypedDataParams} + * @returns the signed hash for the params passed in wrapped in 6492 format + */ + signTypedDataWith6492(params: SignTypedDataParams): Promise<Hash> + + /** + * @returns the address of the account + */ + getAddress(): Promise<Address> + + /** + * @returns the current account signer instance that the smart account client + * operations are being signed with. + * + * The signer is expected to be the owner or one of the owners of the account + * for the signatures to be valid for the acting account. + */ + getSigner(): TSigner + + /** + * @returns the address of the factory contract for the smart account + */ + getFactoryAddress(): Address + + /** + * @returns the address of the entry point contract for the smart account + */ + getEntryPointAddress(): Address + + /** + * Allows you to add additional functionality and utility methods to this account + * via a decorator pattern. + * + * NOTE: this method does not allow you to override existing methods on the account. + * + * @example + * ```ts + * const account = new BaseSmartCobntractAccount(...).extend((account) => ({ + * readAccountState: async (...args) => { + * return this.rpcProvider.readContract({ + * address: await this.getAddress(), + * abi: ThisContractsAbi + * args: args + * }); + * } + * })); + * + * account.debugSendUserOperation(...); + * ``` + * + * @param extendFn -- this function gives you access to the created account instance and returns an object + * with the extension methods + * @returns -- the account with the extension methods added + */ + extend: <R>(extendFn: (self: this) => R) => this & R + + encodeUpgradeToAndCall: ( + upgradeToImplAddress: Address, + upgradeToInitData: Hex + ) => Promise<Hex> +} diff --git a/src/account/utils/Utils.ts b/src/account/utils/Utils.ts new file mode 100644 index 000000000..979368c75 --- /dev/null +++ b/src/account/utils/Utils.ts @@ -0,0 +1,160 @@ +import { + type Address, + type Hash, + type Hex, + concat, + encodeAbiParameters, + keccak256, + parseAbiParameters +} from "viem" +import type { UserOperationStruct } from "../../account" +import { type SupportedSigner, convertSigner } from "../../account" +import { extractChainIdFromBundlerUrl } from "../../bundler" +import { extractChainIdFromPaymasterUrl } from "../../bundler" +import type { BiconomySmartAccountV2Config } from "./Types.js" + +/** + * pack the userOperation + * @param op + * @param forSignature "true" if the hash is needed to calculate the getUserOpHash() + * "false" to pack entire UserOp, for calculating the calldata cost of putting it on-chain. + */ +export function packUserOp( + op: Partial<UserOperationStruct>, + forSignature = true +): string { + if (!op.initCode || !op.callData || !op.paymasterAndData) + throw new Error("Missing userOp properties") + if (forSignature) { + return encodeAbiParameters( + parseAbiParameters( + "address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32" + ), + [ + op.sender as Hex, + BigInt(op.nonce as Hex), + keccak256(op.initCode as Hex), + keccak256(op.callData as Hex), + BigInt(op.callGasLimit as Hex), + BigInt(op.verificationGasLimit as Hex), + BigInt(op.preVerificationGas as Hex), + BigInt(op.maxFeePerGas as Hex), + BigInt(op.maxPriorityFeePerGas as Hex), + keccak256(op.paymasterAndData as Hex) + ] + ) + } + // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) + return encodeAbiParameters( + parseAbiParameters( + "address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes" + ), + [ + op.sender as Hex, + BigInt(op.nonce as Hex), + op.initCode as Hex, + op.callData as Hex, + BigInt(op.callGasLimit as Hex), + BigInt(op.verificationGasLimit as Hex), + BigInt(op.preVerificationGas as Hex), + BigInt(op.maxFeePerGas as Hex), + BigInt(op.maxPriorityFeePerGas as Hex), + op.paymasterAndData as Hex, + op.signature as Hex + ] + ) +} + +export const isNullOrUndefined = (value: any): value is undefined => { + return value === null || value === undefined +} + +export const compareChainIds = async ( + signer: SupportedSigner, + biconomySmartAccountConfig: BiconomySmartAccountV2Config, + skipChainIdCalls: boolean + // biome-ignore lint/suspicious/noConfusingVoidType: <explanation> +): Promise<Error | void> => { + const signerResult = await convertSigner( + signer, + skipChainIdCalls, + biconomySmartAccountConfig.rpcUrl + ) + + const chainIdFromBundler = biconomySmartAccountConfig.bundlerUrl + ? extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundlerUrl) + : biconomySmartAccountConfig.bundler + ? extractChainIdFromBundlerUrl( + biconomySmartAccountConfig.bundler.getBundlerUrl() + ) + : undefined + + const chainIdFromPaymasterUrl = biconomySmartAccountConfig.paymasterUrl + ? extractChainIdFromPaymasterUrl(biconomySmartAccountConfig.paymasterUrl) + : undefined + + if (!isNullOrUndefined(signerResult.chainId)) { + if ( + chainIdFromBundler !== undefined && + signerResult.chainId !== chainIdFromBundler + ) { + throw new Error( + `Chain IDs from signer (${signerResult.chainId}) and bundler (${chainIdFromBundler}) do not match.` + ) + } + if ( + chainIdFromPaymasterUrl !== undefined && + signerResult.chainId !== chainIdFromPaymasterUrl + ) { + throw new Error( + `Chain IDs from signer (${signerResult.chainId}) and paymaster (${chainIdFromPaymasterUrl}) do not match.` + ) + } + } else { + if ( + chainIdFromBundler !== undefined && + chainIdFromPaymasterUrl !== undefined && + chainIdFromBundler !== chainIdFromPaymasterUrl + ) { + throw new Error( + `Chain IDs from bundler (${chainIdFromBundler}) and paymaster (${chainIdFromPaymasterUrl}) do not match.` + ) + } + } +} + +export const isValidRpcUrl = (url: string): boolean => { + const regex = /^(https:\/\/|wss:\/\/).*/ + return regex.test(url) +} + +export const addressEquals = (a?: string, b?: string): boolean => + !!a && !!b && a?.toLowerCase() === b.toLowerCase() + +export type SignWith6492Params = { + factoryAddress: Address + factoryCalldata: Hex + signature: Hash +} + +export const wrapSignatureWith6492 = ({ + factoryAddress, + factoryCalldata, + signature +}: SignWith6492Params): Hash => { + // wrap the signature as follows: https://eips.ethereum.org/EIPS/eip-6492 + // concat( + // abi.encode( + // (create2Factory, factoryCalldata, originalERC1271Signature), + // (address, bytes, bytes)), + // magicBytes + // ) + return concat([ + encodeAbiParameters(parseAbiParameters("address, bytes, bytes"), [ + factoryAddress, + factoryCalldata, + signature + ]), + "0x6492649264926492649264926492649264926492649264926492649264926492" + ]) +} diff --git a/src/account/utils/convertSigner.ts b/src/account/utils/convertSigner.ts new file mode 100644 index 000000000..191c84ebd --- /dev/null +++ b/src/account/utils/convertSigner.ts @@ -0,0 +1,101 @@ +import { + http, + type PrivateKeyAccount, + type WalletClient, + createWalletClient +} from "viem" +import { WalletClientSigner } from "../../account" +import type { Signer, SmartAccountSigner, SupportedSigner } from "../../account" +import { EthersSigner } from "./EthersSigner.js" + +interface SmartAccountResult { + signer: SmartAccountSigner + chainId: number | null + rpcUrl: string | undefined +} + +function isPrivateKeyAccount( + signer: SupportedSigner +): signer is PrivateKeyAccount { + return (signer as PrivateKeyAccount).type === "local" +} + +function isWalletClient(signer: SupportedSigner): signer is WalletClient { + return (signer as WalletClient).type === "walletClient" +} + +function isEthersSigner(signer: SupportedSigner): signer is Signer { + return (signer as Signer).provider !== undefined +} + +function isAlchemySigner( + signer: SupportedSigner +): signer is SmartAccountSigner { + return (signer as SmartAccountSigner).signerType !== undefined +} + +export const convertSigner = async ( + signer: SupportedSigner, + skipChainIdCalls = false, + _rpcUrl?: string +): Promise<SmartAccountResult> => { + let resolvedSmartAccountSigner: SmartAccountSigner + let rpcUrl: string | undefined = _rpcUrl + let chainId: number | null = null + + if (!isAlchemySigner(signer)) { + if (isEthersSigner(signer)) { + const ethersSigner = signer as Signer + if (!skipChainIdCalls) { + // If chainId not provided, get it from walletClient + if (!ethersSigner.provider) { + throw new Error("Cannot consume an ethers Wallet without a provider") + } + const chainIdFromProvider = await ethersSigner.provider.getNetwork() + if (!chainIdFromProvider?.chainId) { + throw new Error("Cannot consume an ethers Wallet without a chainId") + } + chainId = Number(chainIdFromProvider.chainId) + } + // convert ethers Wallet to alchemy's SmartAccountSigner under the hood + resolvedSmartAccountSigner = new EthersSigner(ethersSigner, "ethers") + // @ts-ignore + rpcUrl = ethersSigner.provider?.connection?.url ?? undefined + } else if (isWalletClient(signer)) { + const walletClient = signer as WalletClient + if (!walletClient.account) { + throw new Error("Cannot consume a viem wallet without an account") + } + if (!skipChainIdCalls) { + // If chainId not provided, get it from walletClient + if (!walletClient.chain) { + throw new Error("Cannot consume a viem wallet without a chainId") + } + chainId = walletClient.chain.id + } + // convert viems walletClient to alchemy's SmartAccountSigner under the hood + resolvedSmartAccountSigner = new WalletClientSigner(walletClient, "viem") + rpcUrl = walletClient?.transport?.url ?? undefined + } else if (isPrivateKeyAccount(signer)) { + if (rpcUrl !== null && rpcUrl !== undefined) { + const walletClient = createWalletClient({ + account: signer as PrivateKeyAccount, + transport: http(rpcUrl) + }) + resolvedSmartAccountSigner = new WalletClientSigner( + walletClient, + "viem" + ) + } else { + throw new Error( + "rpcUrl is required for PrivateKeyAccount signer type, please provide it in the config" + ) + } + } else { + throw new Error("Unsupported signer") + } + } else { + resolvedSmartAccountSigner = signer as SmartAccountSigner + } + return { signer: resolvedSmartAccountSigner, rpcUrl, chainId } +} diff --git a/src/account/utils/getChain.ts b/src/account/utils/getChain.ts new file mode 100644 index 000000000..63bb51401 --- /dev/null +++ b/src/account/utils/getChain.ts @@ -0,0 +1,18 @@ +import * as chains from "viem/chains" +import type { Chain } from "viem/chains" + +/** + * Utility method for converting a chainId to a {@link Chain} object + * + * @param chainId + * @returns a {@link Chain} object for the given chainId + * @throws if the chainId is not found + */ +export const getChain = (chainId: number): Chain => { + for (const chain of Object.values(chains)) { + if (chain.id === chainId) { + return chain + } + } + throw new Error("Chain not found") +} diff --git a/src/account/utils/index.ts b/src/account/utils/index.ts new file mode 100644 index 000000000..b1f3d8378 --- /dev/null +++ b/src/account/utils/index.ts @@ -0,0 +1,8 @@ +export * from "./Types.js" +export * from "./Utils.js" +export * from "./Constants.js" +export * from "./convertSigner.js" +export * from "./getChain.js" +export * from "./Logger.js" +export * from "./HttpRequests.js" +export * from "./EthersSigner.js" diff --git a/packages/bundler/src/Bundler.ts b/src/bundler/Bundler.ts similarity index 55% rename from packages/bundler/src/Bundler.ts rename to src/bundler/Bundler.ts index 3782d7066..6772b131f 100644 --- a/packages/bundler/src/Bundler.ts +++ b/src/bundler/Bundler.ts @@ -1,33 +1,36 @@ -import { getChain, type UserOperationStruct } from "@alchemy/aa-core"; -import { createPublicClient, http, PublicClient } from "viem"; -import { IBundler } from "./interfaces/IBundler.js"; +import { http, type PublicClient, createPublicClient } from "viem" +import type { StateOverrideSet, UserOperationStruct } from "../account" +import type { SimulationType } from "../account" +import { HttpMethod, getChain, sendRequest } from "../account" +import type { IBundler } from "./interfaces/IBundler.js" import { - GetUserOperationReceiptResponse, - GetUserOpByHashResponse, + DEFAULT_ENTRYPOINT_ADDRESS, + UserOpReceiptIntervals, + UserOpReceiptMaxDurationIntervals, + UserOpWaitForTxHashIntervals, + UserOpWaitForTxHashMaxDurationIntervals +} from "./utils/Constants.js" +import { + getTimestampInSeconds, + transformUserOP +} from "./utils/HelperFunction.js" +import type { + BundlerConfigWithChainId, Bundlerconfig, - UserOpResponse, EstimateUserOpGasResponse, - UserOpReceipt, - SendUserOpResponse, - UserOpGasResponse, - UserOpByHashResponse, - GetGasFeeValuesResponse, GasFeeValues, - UserOpStatus, + GetGasFeeValuesResponse, + GetUserOpByHashResponse, + GetUserOperationReceiptResponse, GetUserOperationStatusResponse, - SimulationType, - BundlerConfigWithChainId, -} from "./utils/Types.js"; -import { transformUserOP, getTimestampInSeconds } from "./utils/HelperFunction.js"; -import { - UserOpReceiptIntervals, - UserOpWaitForTxHashIntervals, - UserOpWaitForTxHashMaxDurationIntervals, - UserOpReceiptMaxDurationIntervals, - DEFAULT_ENTRYPOINT_ADDRESS, -} from "./utils/Constants.js"; -import { extractChainIdFromBundlerUrl } from "./utils/Utils.js"; -import { sendRequest, HttpMethod, StateOverrideSet } from "@biconomy/common"; + SendUserOpResponse, + UserOpByHashResponse, + UserOpGasResponse, + UserOpReceipt, + UserOpResponse, + UserOpStatus +} from "./utils/Types.js" +import { extractChainIdFromBundlerUrl } from "./utils/Utils.js" /** * This class implements IBundler interface. @@ -35,53 +38,59 @@ import { sendRequest, HttpMethod, StateOverrideSet } from "@biconomy/common"; * Checkout the proposal for more details on Bundlers. */ export class Bundler implements IBundler { - private bundlerConfig: BundlerConfigWithChainId; + private bundlerConfig: BundlerConfigWithChainId // eslint-disable-next-line no-unused-vars - UserOpReceiptIntervals!: { [key in number]?: number }; + UserOpReceiptIntervals!: { [key in number]?: number } - UserOpWaitForTxHashIntervals!: { [key in number]?: number }; + UserOpWaitForTxHashIntervals!: { [key in number]?: number } - UserOpReceiptMaxDurationIntervals!: { [key in number]?: number }; + UserOpReceiptMaxDurationIntervals!: { [key in number]?: number } - UserOpWaitForTxHashMaxDurationIntervals!: { [key in number]?: number }; + UserOpWaitForTxHashMaxDurationIntervals!: { [key in number]?: number } - private provider: PublicClient; + private provider: PublicClient constructor(bundlerConfig: Bundlerconfig) { - const parsedChainId: number = bundlerConfig?.chainId || extractChainIdFromBundlerUrl(bundlerConfig.bundlerUrl); - this.bundlerConfig = { ...bundlerConfig, chainId: parsedChainId }; + const parsedChainId: number = + bundlerConfig?.chainId || + extractChainIdFromBundlerUrl(bundlerConfig.bundlerUrl) + this.bundlerConfig = { ...bundlerConfig, chainId: parsedChainId } this.provider = createPublicClient({ chain: bundlerConfig.viemChain ?? getChain(parsedChainId), - transport: http((bundlerConfig.viemChain || getChain(parsedChainId)).rpcUrls.default.http[0]), - }); + transport: http( + (bundlerConfig.viemChain || getChain(parsedChainId)).rpcUrls.default + .http[0] + ) + }) this.UserOpReceiptIntervals = { ...UserOpReceiptIntervals, - ...bundlerConfig.userOpReceiptIntervals, - }; + ...bundlerConfig.userOpReceiptIntervals + } this.UserOpWaitForTxHashIntervals = { ...UserOpWaitForTxHashIntervals, - ...bundlerConfig.userOpWaitForTxHashIntervals, - }; + ...bundlerConfig.userOpWaitForTxHashIntervals + } this.UserOpReceiptMaxDurationIntervals = { ...UserOpReceiptMaxDurationIntervals, - ...bundlerConfig.userOpReceiptMaxDurationIntervals, - }; + ...bundlerConfig.userOpReceiptMaxDurationIntervals + } this.UserOpWaitForTxHashMaxDurationIntervals = { ...UserOpWaitForTxHashMaxDurationIntervals, - ...bundlerConfig.userOpWaitForTxHashMaxDurationIntervals, - }; + ...bundlerConfig.userOpWaitForTxHashMaxDurationIntervals + } - this.bundlerConfig.entryPointAddress = bundlerConfig.entryPointAddress || DEFAULT_ENTRYPOINT_ADDRESS; + this.bundlerConfig.entryPointAddress = + bundlerConfig.entryPointAddress || DEFAULT_ENTRYPOINT_ADDRESS } public getBundlerUrl(): string { - return `${this.bundlerConfig.bundlerUrl}`; + return `${this.bundlerConfig.bundlerUrl}` } /** @@ -89,11 +98,14 @@ export class Bundler implements IBundler { * @description This function will fetch gasPrices from bundler * @returns Promise<UserOpGasPricesResponse> */ - async estimateUserOpGas(userOp: UserOperationStruct, stateOverrideSet?: StateOverrideSet): Promise<UserOpGasResponse> { + async estimateUserOpGas( + _userOp: UserOperationStruct, + stateOverrideSet?: StateOverrideSet + ): Promise<UserOpGasResponse> { // expected dummySig and possibly dummmy paymasterAndData should be provided by the caller // bundler doesn't know account and paymaster implementation - userOp = transformUserOP(userOp); - const bundlerUrl = this.getBundlerUrl(); + const userOp = transformUserOP(_userOp) + const bundlerUrl = this.getBundlerUrl() const response: EstimateUserOpGasResponse = await sendRequest( { @@ -105,20 +117,23 @@ export class Bundler implements IBundler { ? [userOp, this.bundlerConfig.entryPointAddress, stateOverrideSet] : [userOp, this.bundlerConfig.entryPointAddress], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); + "Bundler" + ) - const userOpGasResponse = response.result; + const userOpGasResponse = response.result for (const key in userOpGasResponse) { - if (key === "maxFeePerGas" || key === "maxPriorityFeePerGas") continue; - if (userOpGasResponse[key as keyof UserOpGasResponse] === undefined || userOpGasResponse[key as keyof UserOpGasResponse] === null) { - throw new Error(`Got undefined ${key} from bundler`); + if (key === "maxFeePerGas" || key === "maxPriorityFeePerGas") continue + if ( + userOpGasResponse[key as keyof UserOpGasResponse] === undefined || + userOpGasResponse[key as keyof UserOpGasResponse] === null + ) { + throw new Error(`Got undefined ${key} from bundler`) } } - return userOpGasResponse; + return userOpGasResponse } /** @@ -127,15 +142,18 @@ export class Bundler implements IBundler { * @description This function will send signed userOp to bundler to get mined on chain * @returns Promise<UserOpResponse> */ - async sendUserOp(userOp: UserOperationStruct, simulationParam?: SimulationType): Promise<UserOpResponse> { - const chainId = this.bundlerConfig.chainId; + async sendUserOp( + _userOp: UserOperationStruct, + simulationParam?: SimulationType + ): Promise<UserOpResponse> { + const chainId = this.bundlerConfig.chainId // transformUserOP will convert all bigNumber values to string - userOp = transformUserOP(userOp); + const userOp = transformUserOP(_userOp) const simType = { - simulation_type: simulationParam || "validation", - }; - const params = [userOp, this.bundlerConfig.entryPointAddress, simType]; - const bundlerUrl = this.getBundlerUrl(); + simulation_type: simulationParam || "validation" + } + const params = [userOp, this.bundlerConfig.entryPointAddress, simType] + const bundlerUrl = this.getBundlerUrl() const sendUserOperationResponse: SendUserOpResponse = await sendRequest( { url: bundlerUrl, @@ -144,94 +162,106 @@ export class Bundler implements IBundler { method: "eth_sendUserOperation", params: params, id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); + "Bundler" + ) const response: UserOpResponse = { userOpHash: sendUserOperationResponse.result, wait: (confirmations?: number): Promise<UserOpReceipt> => { // Note: maxDuration can be defined per chainId - const maxDuration = this.UserOpReceiptMaxDurationIntervals[chainId] || 30000; // default 30 seconds - let totalDuration = 0; + const maxDuration = + this.UserOpReceiptMaxDurationIntervals[chainId] || 30000 // default 30 seconds + let totalDuration = 0 return new Promise<UserOpReceipt>((resolve, reject) => { - const intervalValue = this.UserOpReceiptIntervals[chainId] || 5000; // default 5 seconds + const intervalValue = this.UserOpReceiptIntervals[chainId] || 5000 // default 5 seconds const intervalId = setInterval(async () => { try { - const userOpResponse = await this.getUserOpReceipt(sendUserOperationResponse.result); - if (userOpResponse && userOpResponse.receipt && userOpResponse.receipt.blockNumber) { + const userOpResponse = await this.getUserOpReceipt( + sendUserOperationResponse.result + ) + if (userOpResponse?.receipt?.blockNumber) { if (confirmations) { - const latestBlock = await this.provider.getBlockNumber(); - const confirmedBlocks = Number(latestBlock) - userOpResponse.receipt.blockNumber; + const latestBlock = await this.provider.getBlockNumber() + const confirmedBlocks = + Number(latestBlock) - userOpResponse.receipt.blockNumber if (confirmations >= confirmedBlocks) { - clearInterval(intervalId); - resolve(userOpResponse); - return; + clearInterval(intervalId) + resolve(userOpResponse) + return } } else { - clearInterval(intervalId); - resolve(userOpResponse); - return; + clearInterval(intervalId) + resolve(userOpResponse) + return } } } catch (error) { - clearInterval(intervalId); - reject(error); - return; + clearInterval(intervalId) + reject(error) + return } - totalDuration += intervalValue; + totalDuration += intervalValue if (totalDuration >= maxDuration) { - clearInterval(intervalId); + clearInterval(intervalId) reject( new Error( - `Exceeded maximum duration (${maxDuration / 1000} sec) waiting to get receipt for userOpHash ${ + `Exceeded maximum duration (${ + maxDuration / 1000 + } sec) waiting to get receipt for userOpHash ${ sendUserOperationResponse.result - }. Try getting the receipt manually using eth_getUserOperationReceipt rpc method on bundler`, - ), - ); + }. Try getting the receipt manually using eth_getUserOperationReceipt rpc method on bundler` + ) + ) } - }, intervalValue); - }); + }, intervalValue) + }) }, waitForTxHash: (): Promise<UserOpStatus> => { - const maxDuration = this.UserOpWaitForTxHashMaxDurationIntervals[chainId] || 20000; // default 20 seconds - let totalDuration = 0; + const maxDuration = + this.UserOpWaitForTxHashMaxDurationIntervals[chainId] || 20000 // default 20 seconds + let totalDuration = 0 return new Promise<UserOpStatus>((resolve, reject) => { - const intervalValue = this.UserOpWaitForTxHashIntervals[chainId] || 500; // default 0.5 seconds + const intervalValue = + this.UserOpWaitForTxHashIntervals[chainId] || 500 // default 0.5 seconds const intervalId = setInterval(async () => { try { - const userOpStatus = await this.getUserOpStatus(sendUserOperationResponse.result); - if (userOpStatus && userOpStatus.state && userOpStatus.transactionHash) { - clearInterval(intervalId); - resolve(userOpStatus); - return; + const userOpStatus = await this.getUserOpStatus( + sendUserOperationResponse.result + ) + if (userOpStatus?.state && userOpStatus.transactionHash) { + clearInterval(intervalId) + resolve(userOpStatus) + return } } catch (error) { - clearInterval(intervalId); - reject(error); - return; + clearInterval(intervalId) + reject(error) + return } - totalDuration += intervalValue; + totalDuration += intervalValue if (totalDuration >= maxDuration) { - clearInterval(intervalId); + clearInterval(intervalId) reject( new Error( - `Exceeded maximum duration (${maxDuration / 1000} sec) waiting to get receipt for userOpHash ${ + `Exceeded maximum duration (${ + maxDuration / 1000 + } sec) waiting to get receipt for userOpHash ${ sendUserOperationResponse.result - }. Try getting the receipt manually using eth_getUserOperationReceipt rpc method on bundler`, - ), - ); + }. Try getting the receipt manually using eth_getUserOperationReceipt rpc method on bundler` + ) + ) } - }, intervalValue); - }); - }, - }; - return response; + }, intervalValue) + }) + } + } + return response } /** @@ -241,7 +271,7 @@ export class Bundler implements IBundler { * @returns Promise<UserOpReceipt> */ async getUserOpReceipt(userOpHash: string): Promise<UserOpReceipt> { - const bundlerUrl = this.getBundlerUrl(); + const bundlerUrl = this.getBundlerUrl() const response: GetUserOperationReceiptResponse = await sendRequest( { url: bundlerUrl, @@ -250,13 +280,13 @@ export class Bundler implements IBundler { method: "eth_getUserOperationReceipt", params: [userOpHash], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); - const userOpReceipt: UserOpReceipt = response.result; - return userOpReceipt; + "Bundler" + ) + const userOpReceipt: UserOpReceipt = response.result + return userOpReceipt } /** @@ -266,7 +296,7 @@ export class Bundler implements IBundler { * @returns Promise<UserOpReceipt> */ async getUserOpStatus(userOpHash: string): Promise<UserOpStatus> { - const bundlerUrl = this.getBundlerUrl(); + const bundlerUrl = this.getBundlerUrl() const response: GetUserOperationStatusResponse = await sendRequest( { url: bundlerUrl, @@ -275,13 +305,13 @@ export class Bundler implements IBundler { method: "biconomy_getUserOperationStatus", params: [userOpHash], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); - const userOpStatus: UserOpStatus = response.result; - return userOpStatus; + "Bundler" + ) + const userOpStatus: UserOpStatus = response.result + return userOpStatus } /** @@ -291,7 +321,7 @@ export class Bundler implements IBundler { * @returns Promise<UserOpByHashResponse> */ async getUserOpByHash(userOpHash: string): Promise<UserOpByHashResponse> { - const bundlerUrl = this.getBundlerUrl(); + const bundlerUrl = this.getBundlerUrl() const response: GetUserOpByHashResponse = await sendRequest( { url: bundlerUrl, @@ -300,20 +330,20 @@ export class Bundler implements IBundler { method: "eth_getUserOperationByHash", params: [userOpHash], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); - const userOpByHashResponse: UserOpByHashResponse = response.result; - return userOpByHashResponse; + "Bundler" + ) + const userOpByHashResponse: UserOpByHashResponse = response.result + return userOpByHashResponse } /** * @description This function will return the gas fee values */ async getGasFeeValues(): Promise<GasFeeValues> { - const bundlerUrl = this.getBundlerUrl(); + const bundlerUrl = this.getBundlerUrl() const response: GetGasFeeValuesResponse = await sendRequest( { url: bundlerUrl, @@ -322,15 +352,15 @@ export class Bundler implements IBundler { method: "biconomy_getGasFeeValues", params: [], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Bundler", - ); - return response.result; + "Bundler" + ) + return response.result } public static async create(config: Bundlerconfig): Promise<Bundler> { - return new Bundler(config); + return new Bundler(config) } } diff --git a/src/bundler/IBundler.ts b/src/bundler/IBundler.ts new file mode 100644 index 000000000..1e15c7c19 --- /dev/null +++ b/src/bundler/IBundler.ts @@ -0,0 +1,26 @@ +import type { SimulationType } from "../account" +import type { StateOverrideSet, UserOperationStruct } from "../account" +import type { + GasFeeValues, + UserOpByHashResponse, + UserOpGasResponse, + UserOpReceipt, + UserOpResponse, + UserOpStatus +} from "./utils/Types.js" + +export interface IBundler { + estimateUserOpGas( + _userOp: Partial<UserOperationStruct>, + stateOverrideSet?: StateOverrideSet + ): Promise<UserOpGasResponse> + sendUserOp( + _userOp: UserOperationStruct, + _simulationType?: SimulationType + ): Promise<UserOpResponse> + getUserOpReceipt(_userOpHash: string): Promise<UserOpReceipt> + getUserOpByHash(_userOpHash: string): Promise<UserOpByHashResponse> + getGasFeeValues(): Promise<GasFeeValues> + getUserOpStatus(_userOpHash: string): Promise<UserOpStatus> + getBundlerUrl(): string +} diff --git a/src/bundler/index.ts b/src/bundler/index.ts new file mode 100644 index 000000000..5986083f4 --- /dev/null +++ b/src/bundler/index.ts @@ -0,0 +1,8 @@ +import { Bundler } from "./Bundler.js" + +export * from "./interfaces/IBundler.js" +export * from "./Bundler.js" +export * from "./utils/Utils.js" +export * from "./utils/Types.js" + +export const createBundler = Bundler.create diff --git a/src/bundler/interfaces/IBundler.ts b/src/bundler/interfaces/IBundler.ts new file mode 100644 index 000000000..aa7f551fe --- /dev/null +++ b/src/bundler/interfaces/IBundler.ts @@ -0,0 +1,29 @@ +import type { + SimulationType, + StateOverrideSet, + UserOperationStruct +} from "../../account" +import type { + GasFeeValues, + UserOpByHashResponse, + UserOpGasResponse, + UserOpReceipt, + UserOpResponse, + UserOpStatus +} from "../utils/Types.js" + +export interface IBundler { + estimateUserOpGas( + _userOp: Partial<UserOperationStruct>, + stateOverrideSet?: StateOverrideSet + ): Promise<UserOpGasResponse> + sendUserOp( + _userOp: UserOperationStruct, + _simulationType?: SimulationType + ): Promise<UserOpResponse> + getUserOpReceipt(_userOpHash: string): Promise<UserOpReceipt> + getUserOpByHash(_userOpHash: string): Promise<UserOpByHashResponse> + getGasFeeValues(): Promise<GasFeeValues> + getUserOpStatus(_userOpHash: string): Promise<UserOpStatus> + getBundlerUrl(): string +} diff --git a/packages/bundler/src/utils/Constants.ts b/src/bundler/utils/Constants.ts similarity index 61% rename from packages/bundler/src/utils/Constants.ts rename to src/bundler/utils/Constants.ts index 8ffd436a5..7c0510526 100644 --- a/packages/bundler/src/utils/Constants.ts +++ b/src/bundler/utils/Constants.ts @@ -1,27 +1,30 @@ export const UserOpReceiptIntervals: { [key in number]?: number } = { - [1]: 10000, -}; + [1]: 10000 +} // Note: Default value is 500(0.5sec) export const UserOpWaitForTxHashIntervals: { [key in number]?: number } = { - [1]: 1000, -}; + [1]: 1000 +} // Note: Default value is 30000 (30sec) export const UserOpReceiptMaxDurationIntervals: { [key in number]?: number } = { [1]: 300000, - [80001]: 50000, + [80002]: 50000, [137]: 60000, [56]: 50000, [97]: 50000, [421613]: 50000, [42161]: 50000, - [59140]: 50000, // linea testnet -}; + [59140]: 50000 // linea testnet +} // Note: Default value is 20000 (20sec) -export const UserOpWaitForTxHashMaxDurationIntervals: { [key in number]?: number } = { - [1]: 20000, -}; +export const UserOpWaitForTxHashMaxDurationIntervals: { + [key in number]?: number +} = { + [1]: 20000 +} -export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789"; +export const DEFAULT_ENTRYPOINT_ADDRESS = + "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789" diff --git a/packages/bundler/src/utils/HelperFunction.ts b/src/bundler/utils/HelperFunction.ts similarity index 52% rename from packages/bundler/src/utils/HelperFunction.ts rename to src/bundler/utils/HelperFunction.ts index 670e04d31..ecdaf688d 100644 --- a/packages/bundler/src/utils/HelperFunction.ts +++ b/src/bundler/utils/HelperFunction.ts @@ -1,32 +1,36 @@ -import type { BigNumberish, UserOperationStruct } from "@alchemy/aa-core"; +import type { BigNumberish, UserOperationStruct } from "../../account" // Will convert the userOp hex, bigInt and number values to hex strings -export const transformUserOP = (userOp: UserOperationStruct): UserOperationStruct => { +export const transformUserOP = ( + userOp: UserOperationStruct +): UserOperationStruct => { try { - const userOperation = { ...userOp }; + const userOperation = { ...userOp } const keys: (keyof UserOperationStruct)[] = [ "nonce", "callGasLimit", "verificationGasLimit", "preVerificationGas", "maxFeePerGas", - "maxPriorityFeePerGas", - ]; + "maxPriorityFeePerGas" + ] for (const key of keys) { if (userOperation[key] && userOperation[key] !== "0x") { - userOperation[key] = ("0x" + BigInt(userOp[key] as BigNumberish).toString(16)) as `0x${string}`; + userOperation[key] = `0x${BigInt(userOp[key] as BigNumberish).toString( + 16 + )}` as `0x${string}` } } - return userOperation; + return userOperation } catch (error) { - throw `Failed to transform user operation: ${error}`; + throw `Failed to transform user operation: ${error}` } -}; +} /** * @description this function will return current timestamp in seconds * @returns Number */ export const getTimestampInSeconds = (): number => { - return Math.floor(Date.now() / 1000); -}; + return Math.floor(Date.now() / 1000) +} diff --git a/packages/bundler/src/utils/Types.ts b/src/bundler/utils/Types.ts similarity index 51% rename from packages/bundler/src/utils/Types.ts rename to src/bundler/utils/Types.ts index 1da57281f..d04b4505d 100644 --- a/packages/bundler/src/utils/Types.ts +++ b/src/bundler/utils/Types.ts @@ -1,124 +1,122 @@ -import { UserOperationStruct } from "@alchemy/aa-core"; -import { Chain, Hex } from "viem"; +import type { Chain, Hex } from "viem" +import type { UserOperationStruct } from "../../account" export type Bundlerconfig = { - bundlerUrl: string; - entryPointAddress?: string; - chainId?: number; + bundlerUrl: string + entryPointAddress?: string + chainId?: number // eslint-disable-next-line no-unused-vars - userOpReceiptIntervals?: { [key in number]?: number }; - userOpWaitForTxHashIntervals?: { [key in number]?: number }; - userOpReceiptMaxDurationIntervals?: { [key in number]?: number }; - userOpWaitForTxHashMaxDurationIntervals?: { [key in number]?: number }; + userOpReceiptIntervals?: { [key in number]?: number } + userOpWaitForTxHashIntervals?: { [key in number]?: number } + userOpReceiptMaxDurationIntervals?: { [key in number]?: number } + userOpWaitForTxHashMaxDurationIntervals?: { [key in number]?: number } /** Can be used to optionally override the chain with a custom chain if it doesn't already exist in viems list of supported chains */ - viemChain?: Chain; -}; -export type BundlerConfigWithChainId = Bundlerconfig & { chainId: number }; + viemChain?: Chain +} +export type BundlerConfigWithChainId = Bundlerconfig & { chainId: number } export type UserOpReceipt = { /* The request hash of the UserOperation. */ - userOpHash: string; + userOpHash: string /* The entry point address used for the UserOperation. */ - entryPoint: string; + entryPoint: string /* The paymaster used for this UserOperation (or empty). */ - paymaster: string; + paymaster: string /* The actual amount paid (by account or paymaster) for this UserOperation. */ - actualGasCost: Hex; + actualGasCost: Hex /* The total gas used by this UserOperation (including preVerification, creation, validation, and execution). */ - actualGasUsed: Hex; + actualGasUsed: Hex /* Indicates whether the execution completed without reverting. */ - success: "true" | "false"; + success: "true" | "false" /* In case of revert, this is the revert reason. */ - reason: string; + reason: string /* The logs generated by this UserOperation (not including logs of other UserOperations in the same bundle). */ - logs: Array<any>; // The logs generated by this UserOperation (not including logs of other UserOperations in the same bundle) + logs: Array<any> // The logs generated by this UserOperation (not including logs of other UserOperations in the same bundle) /* The TransactionReceipt object for the entire bundle, not only for this UserOperation. */ - receipt: any; -}; + receipt: any +} // review export type UserOpStatus = { - state: string; // for now // could be an enum - transactionHash?: string; - userOperationReceipt?: UserOpReceipt; -}; - -export type SimulationType = "validation" | "validation_and_execution"; + state: string // for now // could be an enum + transactionHash?: string + userOperationReceipt?: UserOpReceipt +} // Converted to JsonRpcResponse with strict type export type GetUserOperationReceiptResponse = { - jsonrpc: string; - id: number; - result: UserOpReceipt; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: UserOpReceipt + error?: JsonRpcError +} export type GetUserOperationStatusResponse = { - jsonrpc: string; - id: number; - result: UserOpStatus; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: UserOpStatus + error?: JsonRpcError +} // Converted to JsonRpcResponse with strict type export type SendUserOpResponse = { - jsonrpc: string; - id: number; - result: string; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: string + error?: JsonRpcError +} export type UserOpResponse = { - userOpHash: string; - wait(_confirmations?: number): Promise<UserOpReceipt>; + userOpHash: string + wait(_confirmations?: number): Promise<UserOpReceipt> // Review: waitForTxHash(): vs waitForTxHash?(): - waitForTxHash(): Promise<UserOpStatus>; -}; + waitForTxHash(): Promise<UserOpStatus> +} // Converted to JsonRpcResponse with strict type export type EstimateUserOpGasResponse = { - jsonrpc: string; - id: number; - result: UserOpGasResponse; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: UserOpGasResponse + error?: JsonRpcError +} export type UserOpGasResponse = { - preVerificationGas: string; - verificationGasLimit: string; - callGasLimit: string; - maxPriorityFeePerGas: string; - maxFeePerGas: string; -}; + preVerificationGas: string + verificationGasLimit: string + callGasLimit: string + maxPriorityFeePerGas: string + maxFeePerGas: string +} // Converted to JsonRpcResponse with strict type export type GetUserOpByHashResponse = { - jsonrpc: string; - id: number; - result: UserOpByHashResponse; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: UserOpByHashResponse + error?: JsonRpcError +} export type UserOpByHashResponse = UserOperationStruct & { - transactionHash: string; - blockNumber: number; - blockHash: string; - entryPoint: string; -}; + transactionHash: string + blockNumber: number + blockHash: string + entryPoint: string +} /* eslint-disable @typescript-eslint/no-explicit-any */ export type JsonRpcError = { - code: string; - message: string; - data: any; -}; + code: string + message: string + data: any +} export type GetGasFeeValuesResponse = { - jsonrpc: string; - id: number; - result: GasFeeValues; - error?: JsonRpcError; -}; + jsonrpc: string + id: number + result: GasFeeValues + error?: JsonRpcError +} export type GasFeeValues = { - maxPriorityFeePerGas: string; - maxFeePerGas: string; -}; + maxPriorityFeePerGas: string + maxFeePerGas: string +} diff --git a/src/bundler/utils/Utils.ts b/src/bundler/utils/Utils.ts new file mode 100644 index 000000000..700a2bb59 --- /dev/null +++ b/src/bundler/utils/Utils.ts @@ -0,0 +1,23 @@ +export const extractChainIdFromBundlerUrl = (url: string): number => { + try { + const regex = /\/api\/v2\/(\d+)\/[a-zA-Z0-9.-]+$/ + // biome-ignore lint/style/noNonNullAssertion: <explanation> + const match = regex.exec(url)! + return Number.parseInt(match[1]) + } catch (error) { + throw new Error("Invalid chain id") + } +} + +export const extractChainIdFromPaymasterUrl = (url: string): number => { + try { + const regex = /\/api\/v\d+\/(\d+)\// + const match = regex.exec(url) + if (!match) { + throw new Error("Invalid URL format") + } + return Number.parseInt(match[1]) + } catch (error) { + throw new Error("Invalid chain id") + } +} diff --git a/src/bundler/utils/getAAError.ts b/src/bundler/utils/getAAError.ts new file mode 100644 index 000000000..051d5bbd2 --- /dev/null +++ b/src/bundler/utils/getAAError.ts @@ -0,0 +1,68 @@ +import { BaseError } from "viem" +import type { Service } from "../../account" + +export type KnownError = { + name: string + regex: string + description: string + causes: string[] + solutions: string[] + docsUrl?: string +} + +export const ERRORS_URL = "https://bcnmy.github.io/aa-errors/errors.json" +export const DOCS_URL = "https://docs.biconomy.io/troubleshooting/commonerrors" + +const knownErrors: KnownError[] = [] + +const matchError = (message: string): null | KnownError => + knownErrors.find( + (knownError: KnownError) => + message.toLowerCase().indexOf(knownError.regex) > -1 + ) ?? null + +const buildErrorStrings = (error: KnownError, service?: Service): string[] => + [ + `${error.description}\n`, + error.causes?.length + ? ["Potential cause(s): \n", ...error.causes, ""].join("\n") + : "", + error.solutions?.length + ? ["Potential solution(s): \n", ...error.solutions].join("\n") + : "", + service ? `\nSent via: ${service}` : "" + ].filter(Boolean) + +type AccountAbstractionErrorParams = { + docsSlug?: string + metaMessages?: string[] + details?: string +} + +class AccountAbstractionError extends BaseError { + override name = "AccountAbstractionError" + + constructor(title: string, params: AccountAbstractionErrorParams = {}) { + super(title, params) + } +} + +export const getAAError = async (message: string, service?: Service) => { + if (!knownErrors.length) { + const errors = (await (await fetch(ERRORS_URL)).json()) as KnownError[] + knownErrors.push(...errors) + } + + const details: string = + `${service} - ${typeof message}` === "string" + ? message + : JSON.stringify(message) + const matchedError = matchError(details) + const metaMessages = matchedError + ? buildErrorStrings(matchedError, service) + : [] + const title = matchedError ? matchedError.name : "Unknown Error" + const docsSlug = matchedError?.docsUrl ?? DOCS_URL + + return new AccountAbstractionError(title, { docsSlug, metaMessages, details }) +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 000000000..b7976357d --- /dev/null +++ b/src/index.ts @@ -0,0 +1,4 @@ +export * from "./account" +export * from "./bundler" +export * from "./paymaster" +export * from "./modules" diff --git a/src/modules/BaseValidationModule.ts b/src/modules/BaseValidationModule.ts new file mode 100644 index 000000000..265a4f9cf --- /dev/null +++ b/src/modules/BaseValidationModule.ts @@ -0,0 +1,51 @@ +import type { Hex } from "viem" +import { DEFAULT_ENTRYPOINT_ADDRESS, type SmartAccountSigner } from "../account" +import type { IValidationModule } from "./interfaces/IValidationModule.js" +import type { BaseValidationModuleConfig, ModuleInfo } from "./utils/Types.js" + +export abstract class BaseValidationModule implements IValidationModule { + entryPointAddress: Hex + + constructor(moduleConfig: BaseValidationModuleConfig) { + const { entryPointAddress } = moduleConfig + + this.entryPointAddress = entryPointAddress || DEFAULT_ENTRYPOINT_ADDRESS + } + + abstract getAddress(): Hex + + setEntryPointAddress(entryPointAddress: Hex): void { + this.entryPointAddress = entryPointAddress + } + + abstract getInitData(): Promise<Hex> + + // Anything required to get dummy signature can be passed as params + abstract getDummySignature(_params?: ModuleInfo): Promise<Hex> + + abstract getSigner(): Promise<SmartAccountSigner> + + // Signer specific or any other additional information can be passed as params + abstract signUserOpHash( + _userOpHash: string, + _params?: ModuleInfo + ): Promise<Hex> + + abstract signMessage(_message: Uint8Array | string): Promise<string> + + async signMessageSmartAccountSigner( + _message: string | Uint8Array, + signer: SmartAccountSigner + ): Promise<string> { + const message = typeof _message === "string" ? _message : { raw: _message } + let signature: `0x${string}` = await signer.signMessage(message) + + const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) + if (![27, 28].includes(potentiallyIncorrectV)) { + const correctV = potentiallyIncorrectV + 27 + signature = `0x${signature.slice(0, -2) + correctV.toString(16)}` + } + + return signature + } +} diff --git a/src/modules/BatchedSessionRouterModule.ts b/src/modules/BatchedSessionRouterModule.ts new file mode 100644 index 000000000..42f607d80 --- /dev/null +++ b/src/modules/BatchedSessionRouterModule.ts @@ -0,0 +1,363 @@ +import { + type Hex, + concat, + encodeAbiParameters, + keccak256, + pad, + parseAbiParameters, + toBytes, + toHex +} from "viem" +import { type SmartAccountSigner, convertSigner } from "../account" +import { BaseValidationModule } from "./BaseValidationModule.js" +import { SessionKeyManagerModule } from "./SessionKeyManagerModule.js" +import type { + SessionSearchParam, + SessionStatus +} from "./interfaces/ISessionStorage.js" +import { + BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION, + DEFAULT_BATCHED_SESSION_ROUTER_MODULE, + DEFAULT_SESSION_KEY_MANAGER_MODULE +} from "./utils/Constants.js" +// @ts-nocheck +import type { + BatchedSessionRouterModuleConfig, + CreateSessionDataParams, + CreateSessionDataResponse, + ModuleInfo, + ModuleVersion, + SessionDataTuple +} from "./utils/Types.js" + +export class BatchedSessionRouterModule extends BaseValidationModule { + version: ModuleVersion = "V1_0_0" + + moduleAddress!: Hex + + sessionManagerModuleAddress!: Hex + + sessionKeyManagerModule!: SessionKeyManagerModule + + readonly mockEcdsaSessionKeySig: Hex = + "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b" + + /** + * This constructor is private. Use the static create method to instantiate SessionKeyManagerModule + * @param moduleConfig The configuration for the module + * @returns An instance of SessionKeyManagerModule + */ + private constructor(moduleConfig: BatchedSessionRouterModuleConfig) { + super(moduleConfig) + } + + /** + * Asynchronously creates and initializes an instance of SessionKeyManagerModule + * @param moduleConfig The configuration for the module + * @returns A Promise that resolves to an instance of SessionKeyManagerModule + */ + public static async create( + moduleConfig: BatchedSessionRouterModuleConfig + ): Promise<BatchedSessionRouterModule> { + const instance = new BatchedSessionRouterModule(moduleConfig) + + if (moduleConfig.moduleAddress) { + instance.moduleAddress = moduleConfig.moduleAddress + } else if (moduleConfig.version) { + const moduleAddr = BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION[ + moduleConfig.version + ] as Hex + if (!moduleAddr) { + throw new Error(`Invalid version ${moduleConfig.version}`) + } + instance.moduleAddress = moduleAddr + instance.version = moduleConfig.version as ModuleVersion + } else { + instance.moduleAddress = DEFAULT_BATCHED_SESSION_ROUTER_MODULE + // Note: in this case Version remains the default one + } + + instance.sessionManagerModuleAddress = + moduleConfig.sessionManagerModuleAddress ?? + DEFAULT_SESSION_KEY_MANAGER_MODULE + + if (!moduleConfig.sessionKeyManagerModule) { + // generate sessionModule + const sessionModule = await SessionKeyManagerModule.create({ + moduleAddress: instance.sessionManagerModuleAddress, + smartAccountAddress: moduleConfig.smartAccountAddress, + storageType: moduleConfig.storageType + }) + + instance.sessionKeyManagerModule = sessionModule + } else { + instance.sessionKeyManagerModule = moduleConfig.sessionKeyManagerModule + instance.sessionManagerModuleAddress = + moduleConfig.sessionKeyManagerModule.getAddress() + } + + return instance + } + + /** + * Method to create session data for any module. The session data is used to create a leaf in the merkle tree + * @param leavesData The data of one or more leaves to be used to create session data + * @returns The session data + */ + createSessionData = async ( + leavesData: CreateSessionDataParams[] + ): Promise<CreateSessionDataResponse> => { + return this.sessionKeyManagerModule.createSessionData(leavesData) + } + + /** + * This method is used to sign the user operation using the session signer + * @param userOp The user operation to be signed + * @param sessionParams Information about all the sessions to be used to sign the user operation which has a batch execution + * @returns The signature of the user operation + */ + async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise<Hex> { + const sessionParams = params?.batchSessionParams + if (!sessionParams || sessionParams.length === 0) { + throw new Error("Session parameters are not provided") + } + + const sessionDataTupleArray: SessionDataTuple[] = [] + + // signer must be the same for all the sessions + const { signer: sessionSigner } = await convertSigner( + sessionParams[0].sessionSigner, + false + ) + + const signature = await sessionSigner.signMessage({ + raw: toBytes(userOpHash) + }) + + for (const sessionParam of sessionParams) { + if (!sessionParam.sessionSigner) { + throw new Error("Session signer is not provided.") + } + if (!sessionParam.sessionID && !sessionParam.sessionValidationModule) { + throw new Error( + "sessionID or sessionValidationModule should be provided." + ) + } + + const sessionSignerData = + await this.sessionKeyManagerModule.sessionStorageClient.getSessionData( + sessionParam.sessionID + ? { + sessionID: sessionParam.sessionID + } + : { + sessionValidationModule: sessionParam.sessionValidationModule, + sessionPublicKey: await sessionSigner.getAddress() + } + ) + + const leafDataHex = concat([ + pad(toHex(sessionSignerData.validUntil), { size: 6 }), + pad(toHex(sessionSignerData.validAfter), { size: 6 }), + pad(sessionSignerData.sessionValidationModule, { size: 20 }), + sessionSignerData.sessionKeyData + ]) + + const proof = this.sessionKeyManagerModule.merkleTree.getHexProof( + keccak256(leafDataHex) + ) + + const sessionDataTuple: SessionDataTuple = [ + sessionSignerData.validUntil, + sessionSignerData.validAfter, + sessionSignerData.sessionValidationModule, + sessionSignerData.sessionKeyData, + proof, + sessionParam.additionalSessionData ?? "0x" + ] + + sessionDataTupleArray.push(sessionDataTuple) + } + + // Generate the padded signature + const abiParameters = [ + { type: "address" }, + { + type: "tuple[]", + components: [ + { type: "uint48" }, + { type: "uint48" }, + { type: "address" }, + { type: "bytes" }, + { type: "bytes32[]" }, + { type: "bytes" } + ] + }, + { type: "bytes" } + ] + + const paddedSignature = encodeAbiParameters(abiParameters, [ + this.getSessionKeyManagerAddress(), + sessionDataTupleArray, + signature + ]) + + return paddedSignature as Hex + } + + /** + * Update the session data pending state to active + * @param param The search param to find the session data + * @param status The status to be updated + * @returns + */ + async updateSessionStatus( + param: SessionSearchParam, + status: SessionStatus + ): Promise<void> { + this.sessionKeyManagerModule.sessionStorageClient.updateSessionStatus( + param, + status + ) + } + + /** + * @remarks This method is used to clear all the pending sessions + * @returns + */ + async clearPendingSessions(): Promise<void> { + this.sessionKeyManagerModule.sessionStorageClient.clearPendingSessions() + } + + /** + * @returns SessionKeyManagerModule address + */ + getAddress(): Hex { + return this.moduleAddress + } + + /** + * @returns SessionKeyManagerModule address + */ + getSessionKeyManagerAddress(): Hex { + return this.sessionManagerModuleAddress + } + + /** + * @remarks This is the version of the module contract + */ + async getSigner(): Promise<SmartAccountSigner> { + throw new Error("Method not implemented.") + } + + /** + * @remarks This is the dummy signature for the module, used in buildUserOp for bundler estimation + * @returns Dummy signature + */ + async getDummySignature(params?: ModuleInfo): Promise<Hex> { + const sessionParams = params?.batchSessionParams + if (!sessionParams || sessionParams.length === 0) { + throw new Error("Session parameters are not provided") + } + + const sessionDataTupleArray: SessionDataTuple[] = [] + + // if needed we could do mock signature over userOpHashAndModuleAddress + + // signer must be the same for all the sessions + const { signer: sessionSigner } = await convertSigner( + sessionParams[0].sessionSigner, + false + ) + + for (const sessionParam of sessionParams) { + if (!sessionParam.sessionSigner) { + throw new Error("Session signer is not provided.") + } + + if (!sessionParam.sessionID && !sessionParam.sessionValidationModule) { + throw new Error( + "sessionID or sessionValidationModule should be provided." + ) + } + + const sessionSignerData = + await this.sessionKeyManagerModule.sessionStorageClient.getSessionData( + sessionParam.sessionID + ? { + sessionID: sessionParam.sessionID + } + : { + sessionValidationModule: sessionParam.sessionValidationModule, + sessionPublicKey: await sessionSigner.getAddress() + } + ) + + const leafDataHex = concat([ + pad(toHex(sessionSignerData.validUntil), { size: 6 }), + pad(toHex(sessionSignerData.validAfter), { size: 6 }), + pad(sessionSignerData.sessionValidationModule, { size: 20 }), + sessionSignerData.sessionKeyData + ]) + + const proof = this.sessionKeyManagerModule.merkleTree.getHexProof( + keccak256(leafDataHex) + ) + + const sessionDataTuple: SessionDataTuple = [ + BigInt(sessionSignerData.validUntil), + BigInt(sessionSignerData.validAfter), + sessionSignerData.sessionValidationModule, + sessionSignerData.sessionKeyData, + proof, + sessionParam.additionalSessionData ?? "0x" + ] + + sessionDataTupleArray.push(sessionDataTuple) + } + + // Generate the padded signature + + const abiParameters = [ + { type: "address" }, + { + type: "tuple[]", + components: [ + { type: "uint48" }, + { type: "uint48" }, + { type: "address" }, + { type: "bytes" }, + { type: "bytes32[]" }, + { type: "bytes" } + ] + }, + { type: "bytes" } + ] + + const paddedSignature = encodeAbiParameters(abiParameters, [ + this.getSessionKeyManagerAddress(), + sessionDataTupleArray, + this.mockEcdsaSessionKeySig + ]) + + const dummySig = encodeAbiParameters(parseAbiParameters("bytes, address"), [ + paddedSignature as Hex, + this.getAddress() + ]) + return dummySig + } + + /** + * @remarks Other modules may need additional attributes to build init data + */ + async getInitData(): Promise<Hex> { + throw new Error("Method not implemented.") + } + + /** + * @remarks This Module dont have knowledge of signer. So, this method is not implemented + */ + async signMessage(_message: Uint8Array | string): Promise<string> { + throw new Error("Method not implemented.") + } +} diff --git a/packages/modules/src/ECDSAOwnershipValidationModule.ts b/src/modules/ECDSAOwnershipValidationModule.ts similarity index 55% rename from packages/modules/src/ECDSAOwnershipValidationModule.ts rename to src/modules/ECDSAOwnershipValidationModule.ts index 32cfc9af2..0d472c3e6 100644 --- a/packages/modules/src/ECDSAOwnershipValidationModule.ts +++ b/src/modules/ECDSAOwnershipValidationModule.ts @@ -1,75 +1,96 @@ -import { Hex, encodeFunctionData, getAddress, parseAbi, toBytes } from "viem"; -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { ECDSAOwnershipValidationModuleConfig, ECDSAOwnershipValidationModuleConfigConstructorProps, ModuleVersion } from "./utils/Types.js"; -import { DEFAULT_ECDSA_OWNERSHIP_MODULE, ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION } from "./utils/Constants.js"; -import { convertSigner } from "@biconomy/common"; -import { BaseValidationModule } from "./BaseValidationModule.js"; +import { + type Hex, + encodeFunctionData, + getAddress, + parseAbi, + toBytes +} from "viem" +import { type SmartAccountSigner, convertSigner } from "../account" +import { BaseValidationModule } from "./BaseValidationModule.js" +import { + DEFAULT_ECDSA_OWNERSHIP_MODULE, + ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION +} from "./utils/Constants.js" +import type { + ECDSAOwnershipValidationModuleConfig, + ECDSAOwnershipValidationModuleConfigConstructorProps, + ModuleVersion +} from "./utils/Types.js" // Could be renamed with suffix API export class ECDSAOwnershipValidationModule extends BaseValidationModule { - signer: SmartAccountSigner; + signer: SmartAccountSigner - moduleAddress!: Hex; + moduleAddress!: Hex - version: ModuleVersion = "V1_0_0"; + version: ModuleVersion = "V1_0_0" - private constructor(moduleConfig: ECDSAOwnershipValidationModuleConfigConstructorProps) { - super(moduleConfig); - this.signer = moduleConfig.signer; + private constructor( + moduleConfig: ECDSAOwnershipValidationModuleConfigConstructorProps + ) { + super(moduleConfig) + this.signer = moduleConfig.signer } - public static async create(moduleConfig: ECDSAOwnershipValidationModuleConfig): Promise<ECDSAOwnershipValidationModule> { + public static async create( + moduleConfig: ECDSAOwnershipValidationModuleConfig + ): Promise<ECDSAOwnershipValidationModule> { // Signer needs to be initialised here before defaultValidationModule is set - const { signer } = await convertSigner(moduleConfig.signer, false); - const configForConstructor: ECDSAOwnershipValidationModuleConfigConstructorProps = { ...moduleConfig, signer }; + const { signer } = await convertSigner(moduleConfig.signer, false) + const configForConstructor: ECDSAOwnershipValidationModuleConfigConstructorProps = + { ...moduleConfig, signer } // TODO: (Joe) stop doing things in a 'create' call after the instance has been created - const instance = new ECDSAOwnershipValidationModule(configForConstructor); + const instance = new ECDSAOwnershipValidationModule(configForConstructor) if (moduleConfig.moduleAddress) { - instance.moduleAddress = moduleConfig.moduleAddress; + instance.moduleAddress = moduleConfig.moduleAddress } else if (moduleConfig.version) { - const moduleAddr = ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex; + const moduleAddr = ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION[ + moduleConfig.version + ] as Hex if (!moduleAddr) { - throw new Error(`Invalid version ${moduleConfig.version}`); + throw new Error(`Invalid version ${moduleConfig.version}`) } - instance.moduleAddress = moduleAddr; - instance.version = moduleConfig.version as ModuleVersion; + instance.moduleAddress = moduleAddr + instance.version = moduleConfig.version as ModuleVersion } else { - instance.moduleAddress = DEFAULT_ECDSA_OWNERSHIP_MODULE; + instance.moduleAddress = DEFAULT_ECDSA_OWNERSHIP_MODULE // Note: in this case Version remains the default one } - return instance; + return instance } getAddress(): Hex { - return this.moduleAddress; + return this.moduleAddress } async getSigner(): Promise<SmartAccountSigner> { - return Promise.resolve(this.signer); + return Promise.resolve(this.signer) } async getDummySignature(): Promise<Hex> { - const moduleAddress = getAddress(this.getAddress()); - const dynamicPart = moduleAddress.substring(2).padEnd(40, "0"); - return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000`; + const moduleAddress = getAddress(this.getAddress()) + const dynamicPart = moduleAddress.substring(2).padEnd(40, "0") + return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000` } // Note: other modules may need additional attributes to build init data async getInitData(): Promise<Hex> { - const ecdsaOwnerAddress = await this.signer.getAddress(); - const moduleRegistryParsedAbi = parseAbi(["function initForSmartAccount(address owner)"]); + const ecdsaOwnerAddress = await this.signer.getAddress() + const moduleRegistryParsedAbi = parseAbi([ + "function initForSmartAccount(address owner)" + ]) const ecdsaOwnershipInitData = encodeFunctionData({ abi: moduleRegistryParsedAbi, functionName: "initForSmartAccount", - args: [ecdsaOwnerAddress], - }); - return ecdsaOwnershipInitData; + args: [ecdsaOwnerAddress] + }) + return ecdsaOwnershipInitData } async signUserOpHash(userOpHash: string): Promise<Hex> { - const sig = await this.signer.signMessage({ raw: toBytes(userOpHash) }); - return sig; + const sig = await this.signer.signMessage({ raw: toBytes(userOpHash) }) + return sig } /** @@ -80,14 +101,14 @@ export class ECDSAOwnershipValidationModule extends BaseValidationModule { * @throws {Error} If the signer type is invalid or unsupported. */ async signMessage(_message: Uint8Array | string): Promise<string> { - const message = typeof _message === "string" ? _message : { raw: _message }; - let signature = await this.signer.signMessage(message); + const message = typeof _message === "string" ? _message : { raw: _message } + let signature = await this.signer.signMessage(message) - const potentiallyIncorrectV = parseInt(signature.slice(-2), 16); + const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) if (![27, 28].includes(potentiallyIncorrectV)) { - const correctV = potentiallyIncorrectV + 27; - signature = signature.slice(0, -2) + correctV.toString(16); + const correctV = potentiallyIncorrectV + 27 + signature = signature.slice(0, -2) + correctV.toString(16) } - return signature; + return signature } } diff --git a/src/modules/MultichainValidationModule.ts b/src/modules/MultichainValidationModule.ts new file mode 100644 index 000000000..1affc9c6f --- /dev/null +++ b/src/modules/MultichainValidationModule.ts @@ -0,0 +1,212 @@ +import { MerkleTree } from "merkletreejs" +import { + type Hex, + concat, + encodeAbiParameters, + encodeFunctionData, + getAddress, + keccak256, + pad, + parseAbi, + parseAbiParameters, + toBytes, + toHex +} from "viem" +import { + Logger, + type SmartAccountSigner, + type UserOperationStruct, + convertSigner +} from "../account" +import { BaseValidationModule } from "./BaseValidationModule.js" +import { + DEFAULT_MULTICHAIN_MODULE, + MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION +} from "./utils/Constants.js" +import { getUserOpHash } from "./utils/Helper.js" +import type { + ModuleVersion, + MultiChainUserOpDto, + MultiChainValidationModuleConfig, + MultiChainValidationModuleConfigConstructorProps +} from "./utils/Types.js" + +export class MultiChainValidationModule extends BaseValidationModule { + signer: SmartAccountSigner + + moduleAddress!: Hex + + version: ModuleVersion = "V1_0_0" + + private constructor( + moduleConfig: MultiChainValidationModuleConfigConstructorProps + ) { + super(moduleConfig) + this.signer = moduleConfig.signer + } + + public static async create( + moduleConfig: MultiChainValidationModuleConfig + ): Promise<MultiChainValidationModule> { + // Signer needs to be initialised here before defaultValidationModule is set + const { signer } = await convertSigner(moduleConfig.signer, false) + const configForConstructor: MultiChainValidationModuleConfigConstructorProps = + { ...moduleConfig, signer } + + // TODO: (Joe) stop doing things in a 'create' call after the instance has been created + const instance = new MultiChainValidationModule(configForConstructor) + if (moduleConfig.moduleAddress) { + instance.moduleAddress = moduleConfig.moduleAddress + } else if (moduleConfig.version) { + const moduleAddr = MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION[ + moduleConfig.version + ] as Hex + if (!moduleAddr) { + throw new Error(`Invalid version ${moduleConfig.version}`) + } + instance.moduleAddress = moduleAddr + instance.version = moduleConfig.version as ModuleVersion + } else { + instance.moduleAddress = DEFAULT_MULTICHAIN_MODULE + // Note: in this case Version remains the default one + } + return instance + } + + getAddress(): Hex { + return this.moduleAddress + } + + async getSigner(): Promise<SmartAccountSigner> { + return Promise.resolve(this.signer) + } + + async getDummySignature(): Promise<Hex> { + const moduleAddress = getAddress(this.getAddress()) + const dynamicPart = moduleAddress.substring(2).padEnd(40, "0") + return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000` + } + + // Note: other modules may need additional attributes to build init data + async getInitData(): Promise<Hex> { + const ecdsaOwnerAddress = await this.signer.getAddress() + const moduleRegistryParsedAbi = parseAbi([ + "function initForSmartAccount(address owner)" + ]) + const ecdsaOwnershipInitData = encodeFunctionData({ + abi: moduleRegistryParsedAbi, + functionName: "initForSmartAccount", + args: [ecdsaOwnerAddress] + }) + return ecdsaOwnershipInitData + } + + async signUserOpHash(userOpHash: string): Promise<Hex> { + const sig = await this.signer.signMessage({ raw: toBytes(userOpHash) }) + return sig + } + + /** + * Signs a message using the appropriate method based on the type of signer. + * + * @param {Uint8Array | string} message - The message to be signed. + * @returns {Promise<string>} A promise resolving to the signature or error message. + * @throws {Error} If the signer type is invalid or unsupported. + */ + async signMessage(_message: Uint8Array | string): Promise<string> { + const message = typeof _message === "string" ? _message : { raw: _message } + let signature = await this.signer.signMessage(message) + + const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) + if (![27, 28].includes(potentiallyIncorrectV)) { + const correctV = potentiallyIncorrectV + 27 + signature = signature.slice(0, -2) + correctV.toString(16) + } + return signature + } + + async signUserOps( + multiChainUserOps: MultiChainUserOpDto[] + ): Promise<UserOperationStruct[]> { + try { + const leaves: string[] = [] + + // Iterate over each userOp and process them + for (const multiChainOp of multiChainUserOps) { + const validUntil = multiChainOp.validUntil ?? 0 + const validAfter = multiChainOp.validAfter ?? 0 + const leaf = concat([ + pad(toHex(validUntil), { size: 6 }), + pad(toHex(validAfter), { size: 6 }), + pad( + getUserOpHash( + multiChainOp.userOp, + this.entryPointAddress, + multiChainOp.chainId + ), + { size: 32 } + ) + ]) + + leaves.push(keccak256(leaf)) + } + + // Create a new Merkle tree using the leaves array + const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }) + + let multichainSignature = await this.signer.signMessage({ + raw: toBytes(merkleTree.getHexRoot()) + }) + + const potentiallyIncorrectV = Number.parseInt( + multichainSignature.slice(-2), + 16 + ) + if (![27, 28].includes(potentiallyIncorrectV)) { + const correctV = potentiallyIncorrectV + 27 + multichainSignature = + multichainSignature.slice(0, -2) + correctV.toString(16) + } + + // Create an array to store updated userOps + const updatedUserOps: UserOperationStruct[] = [] + + for (let i = 0; i < leaves.length; i++) { + const merkleProof = merkleTree.getHexProof(leaves[i]) + + const validUntil = multiChainUserOps[i].validUntil ?? 0 + const validAfter = multiChainUserOps[i].validAfter ?? 0 + + // Create the moduleSignature + const moduleSignature = encodeAbiParameters( + parseAbiParameters(["uint48, uint48, bytes32, bytes32[], bytes"]), + [ + validUntil, + validAfter, + merkleTree.getHexRoot() as Hex, + merkleProof as Hex[], + multichainSignature as Hex + ] + ) + + // Note: Because accountV2 does not directly call this method. hence we need to add validation module address to the signature + const signatureWithModuleAddress = encodeAbiParameters( + parseAbiParameters(["bytes, address"]), + [moduleSignature, this.getAddress()] + ) + + // Update userOp with the final signature + const updatedUserOp: UserOperationStruct = { + ...(multiChainUserOps[i].userOp as UserOperationStruct), + signature: signatureWithModuleAddress as `0x${string}` + } + + updatedUserOps.push(updatedUserOp) + } + return updatedUserOps + } catch (error) { + Logger.error("Error in signing multi chain userops") + throw new Error(JSON.stringify(error)) + } + } +} diff --git a/packages/modules/src/PasskeyValidationModule.ts b/src/modules/PasskeyValidationModule.ts similarity index 100% rename from packages/modules/src/PasskeyValidationModule.ts rename to src/modules/PasskeyValidationModule.ts diff --git a/packages/modules/src/SessionKeyManagerModule.ts b/src/modules/SessionKeyManagerModule.ts similarity index 54% rename from packages/modules/src/SessionKeyManagerModule.ts rename to src/modules/SessionKeyManagerModule.ts index 560c9ac60..c325c4dd5 100644 --- a/packages/modules/src/SessionKeyManagerModule.ts +++ b/src/modules/SessionKeyManagerModule.ts @@ -1,32 +1,50 @@ -import { Hex, concat, encodeAbiParameters, encodeFunctionData, keccak256, pad, parseAbi, parseAbiParameters, toBytes, toHex } from "viem"; -import { MerkleTree } from "merkletreejs"; -import { SmartAccountSigner } from "@alchemy/aa-core"; +import { MerkleTree } from "merkletreejs" import { - SessionKeyManagerModuleConfig, - ModuleVersion, - CreateSessionDataParams, - ModuleInfo, - CreateSessionDataResponse, - StorageType, -} from "./utils/Types.js"; -import { SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION, DEFAULT_SESSION_KEY_MANAGER_MODULE } from "./utils/Constants.js"; -import { generateRandomHex } from "./utils/Uid.js"; -import { BaseValidationModule } from "./BaseValidationModule.js"; -import { SessionLocalStorage } from "./session-storage/SessionLocalStorage.js"; -import { ISessionStorage, SessionLeafNode, SessionSearchParam, SessionStatus } from "./interfaces/ISessionStorage.js"; -import { convertSigner } from "@biconomy/common"; + type Hex, + concat, + encodeAbiParameters, + encodeFunctionData, + keccak256, + pad, + parseAbi, + parseAbiParameters, + toBytes, + toHex +} from "viem" +import { type SmartAccountSigner, convertSigner } from "../account" +import { BaseValidationModule } from "./BaseValidationModule.js" +import type { + ISessionStorage, + SessionLeafNode, + SessionSearchParam, + SessionStatus +} from "./interfaces/ISessionStorage.js" +import { SessionLocalStorage } from "./session-storage/SessionLocalStorage.js" +import { + DEFAULT_SESSION_KEY_MANAGER_MODULE, + SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION +} from "./utils/Constants.js" +import { + type CreateSessionDataParams, + type CreateSessionDataResponse, + type ModuleInfo, + type ModuleVersion, + type SessionKeyManagerModuleConfig, + StorageType +} from "./utils/Types.js" +import { generateRandomHex } from "./utils/Uid.js" export class SessionKeyManagerModule extends BaseValidationModule { - version: ModuleVersion = "V1_0_0"; + version: ModuleVersion = "V1_0_0" - moduleAddress!: Hex; + moduleAddress!: Hex - merkleTree!: MerkleTree; + merkleTree!: MerkleTree - sessionStorageClient!: ISessionStorage; + sessionStorageClient!: ISessionStorage readonly mockEcdsaSessionKeySig: Hex = - "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b"; + "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b" /** * This constructor is private. Use the static create method to instantiate SessionKeyManagerModule @@ -34,7 +52,7 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @returns An instance of SessionKeyManagerModule */ private constructor(moduleConfig: SessionKeyManagerModuleConfig) { - super(moduleConfig); + super(moduleConfig) } /** @@ -42,53 +60,62 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @param moduleConfig The configuration for the module * @returns A Promise that resolves to an instance of SessionKeyManagerModule */ - public static async create(moduleConfig: SessionKeyManagerModuleConfig): Promise<SessionKeyManagerModule> { + public static async create( + moduleConfig: SessionKeyManagerModuleConfig + ): Promise<SessionKeyManagerModule> { // TODO: (Joe) stop doing things in a 'create' call after the instance has been created - const instance = new SessionKeyManagerModule(moduleConfig); + const instance = new SessionKeyManagerModule(moduleConfig) if (moduleConfig.moduleAddress) { - instance.moduleAddress = moduleConfig.moduleAddress; + instance.moduleAddress = moduleConfig.moduleAddress } else if (moduleConfig.version) { - const moduleAddr = SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex; + const moduleAddr = SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION[ + moduleConfig.version + ] as Hex if (!moduleAddr) { - throw new Error(`Invalid version ${moduleConfig.version}`); + throw new Error(`Invalid version ${moduleConfig.version}`) } - instance.moduleAddress = moduleAddr; - instance.version = moduleConfig.version as ModuleVersion; + instance.moduleAddress = moduleAddr + instance.version = moduleConfig.version as ModuleVersion } else { - instance.moduleAddress = DEFAULT_SESSION_KEY_MANAGER_MODULE; + instance.moduleAddress = DEFAULT_SESSION_KEY_MANAGER_MODULE // Note: in this case Version remains the default one } if (moduleConfig.sessionStorageClient) { - instance.sessionStorageClient = moduleConfig.sessionStorageClient; + instance.sessionStorageClient = moduleConfig.sessionStorageClient } else { switch (moduleConfig.storageType) { case StorageType.LOCAL_STORAGE: - instance.sessionStorageClient = new SessionLocalStorage(moduleConfig.smartAccountAddress); - break; + instance.sessionStorageClient = new SessionLocalStorage( + moduleConfig.smartAccountAddress + ) + break default: - instance.sessionStorageClient = new SessionLocalStorage(moduleConfig.smartAccountAddress); + instance.sessionStorageClient = new SessionLocalStorage( + moduleConfig.smartAccountAddress + ) } } - const existingSessionData = await instance.sessionStorageClient.getAllSessionData(); + const existingSessionData = + await instance.sessionStorageClient.getAllSessionData() const existingSessionDataLeafs = existingSessionData.map((sessionData) => { const leafDataHex = concat([ pad(toHex(sessionData.validUntil), { size: 6 }), pad(toHex(sessionData.validAfter), { size: 6 }), pad(sessionData.sessionValidationModule, { size: 20 }), - sessionData.sessionKeyData, - ]); - return keccak256(leafDataHex); - }); + sessionData.sessionKeyData + ]) + return keccak256(leafDataHex) + }) instance.merkleTree = new MerkleTree(existingSessionDataLeafs, keccak256, { sortPairs: true, - hashLeaves: false, - }); + hashLeaves: false + }) - return instance; + return instance } /** @@ -96,58 +123,63 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @param leavesData The data of one or more leaves to be used to create session data * @returns The session data */ - createSessionData = async (leavesData: CreateSessionDataParams[]): Promise<CreateSessionDataResponse> => { - const sessionKeyManagerModuleABI = parseAbi(["function setMerkleRoot(bytes32 _merkleRoot)"]); + createSessionData = async ( + leavesData: CreateSessionDataParams[] + ): Promise<CreateSessionDataResponse> => { + const sessionKeyManagerModuleABI = parseAbi([ + "function setMerkleRoot(bytes32 _merkleRoot)" + ]) - const leavesToAdd: Buffer[] = []; - const sessionIDInfo: string[] = []; + const leavesToAdd: Buffer[] = [] + const sessionIDInfo: string[] = [] for (const leafData of leavesData) { const leafDataHex = concat([ pad(toHex(leafData.validUntil), { size: 6 }), pad(toHex(leafData.validAfter), { size: 6 }), pad(leafData.sessionValidationModule, { size: 20 }), - leafData.sessionKeyData, - ]); + leafData.sessionKeyData + ]) - const generatedSessionId = leafData.preferredSessionId ?? generateRandomHex(); + const generatedSessionId = + leafData.preferredSessionId ?? generateRandomHex() // TODO: verify this, might not be buffer - leavesToAdd.push(keccak256(leafDataHex) as unknown as Buffer); - sessionIDInfo.push(generatedSessionId); + leavesToAdd.push(keccak256(leafDataHex) as unknown as Buffer) + sessionIDInfo.push(generatedSessionId) const sessionLeafNode = { ...leafData, sessionID: generatedSessionId, - status: "PENDING" as SessionStatus, - }; + status: "PENDING" as SessionStatus + } - await this.sessionStorageClient.addSessionData(sessionLeafNode); + await this.sessionStorageClient.addSessionData(sessionLeafNode) } - this.merkleTree.addLeaves(leavesToAdd); + this.merkleTree.addLeaves(leavesToAdd) - const leaves = this.merkleTree.getLeaves(); + const leaves = this.merkleTree.getLeaves() const newMerkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true, - hashLeaves: false, - }); + hashLeaves: false + }) - this.merkleTree = newMerkleTree; + this.merkleTree = newMerkleTree const setMerkleRootData = encodeFunctionData({ abi: sessionKeyManagerModuleABI, functionName: "setMerkleRoot", - args: [this.merkleTree.getHexRoot() as Hex], - }); + args: [this.merkleTree.getHexRoot() as Hex] + }) - await this.sessionStorageClient.setMerkleRoot(this.merkleTree.getHexRoot()); + await this.sessionStorageClient.setMerkleRoot(this.merkleTree.getHexRoot()) return { data: setMerkleRootData, - sessionIDInfo: sessionIDInfo, - }; - }; + sessionIDInfo: sessionIDInfo + } + } /** * This method is used to sign the user operation using the session signer @@ -156,60 +188,74 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @returns The signature of the user operation */ async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise<Hex> { - if (!(params && params.sessionSigner)) { - throw new Error("Session signer is not provided."); + if (!params?.sessionSigner) { + throw new Error("Session signer is not provided.") } - const { signer: sessionSigner } = await convertSigner(params.sessionSigner, false); + const { signer: sessionSigner } = await convertSigner( + params.sessionSigner, + false + ) // Use the sessionSigner to sign the user operation - const signature = await sessionSigner.signMessage({ raw: toBytes(userOpHash) }); + const signature = await sessionSigner.signMessage({ + raw: toBytes(userOpHash) + }) - const sessionSignerData = await this.getLeafInfo(params); + const sessionSignerData = await this.getLeafInfo(params) const leafDataHex = concat([ pad(toHex(sessionSignerData.validUntil), { size: 6 }), pad(toHex(sessionSignerData.validAfter), { size: 6 }), pad(sessionSignerData.sessionValidationModule, { size: 20 }), - sessionSignerData.sessionKeyData, - ]); + sessionSignerData.sessionKeyData + ]) // Generate the padded signature with (validUntil,validAfter,sessionVerificationModuleAddress,validationData,merkleProof,signature) - let paddedSignature: Hex = encodeAbiParameters(parseAbiParameters("uint48, uint48, address, bytes, bytes32[], bytes"), [ - sessionSignerData.validUntil, - sessionSignerData.validAfter, - sessionSignerData.sessionValidationModule, - sessionSignerData.sessionKeyData, - this.merkleTree.getHexProof(keccak256(leafDataHex)) as Hex[], - signature, - ]); + let paddedSignature: Hex = encodeAbiParameters( + parseAbiParameters("uint48, uint48, address, bytes, bytes32[], bytes"), + [ + sessionSignerData.validUntil, + sessionSignerData.validAfter, + sessionSignerData.sessionValidationModule, + sessionSignerData.sessionKeyData, + this.merkleTree.getHexProof(keccak256(leafDataHex)) as Hex[], + signature + ] + ) if (params?.additionalSessionData) { - paddedSignature += params.additionalSessionData; + paddedSignature += params.additionalSessionData } - return paddedSignature as Hex; + return paddedSignature as Hex } private async getLeafInfo(params: ModuleInfo): Promise<SessionLeafNode> { - if (!(params && params.sessionSigner)) { - throw new Error("Session signer is not provided."); + if (!params?.sessionSigner) { + throw new Error("Session signer is not provided.") } - const { signer: sessionSigner } = await convertSigner(params.sessionSigner, false); - let sessionSignerData; + const { signer: sessionSigner } = await convertSigner( + params.sessionSigner, + false + ) + // biome-ignore lint/suspicious/noImplicitAnyLet: <explanation> + let sessionSignerData if (params?.sessionID) { sessionSignerData = await this.sessionStorageClient.getSessionData({ - sessionID: params.sessionID, - }); + sessionID: params.sessionID + }) } else if (params?.sessionValidationModule) { sessionSignerData = await this.sessionStorageClient.getSessionData({ sessionValidationModule: params.sessionValidationModule, - sessionPublicKey: await sessionSigner.getAddress(), - }); + sessionPublicKey: await sessionSigner.getAddress() + }) } else { - throw new Error("sessionID or sessionValidationModule should be provided."); + throw new Error( + "sessionID or sessionValidationModule should be provided." + ) } - return sessionSignerData; + return sessionSignerData } /** @@ -218,8 +264,11 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @param status The status to be updated * @returns */ - async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise<void> { - this.sessionStorageClient.updateSessionStatus(param, status); + async updateSessionStatus( + param: SessionSearchParam, + status: SessionStatus + ): Promise<void> { + this.sessionStorageClient.updateSessionStatus(param, status) } /** @@ -227,21 +276,21 @@ export class SessionKeyManagerModule extends BaseValidationModule { * @returns */ async clearPendingSessions(): Promise<void> { - this.sessionStorageClient.clearPendingSessions(); + this.sessionStorageClient.clearPendingSessions() } /** * @returns SessionKeyManagerModule address */ getAddress(): Hex { - return this.moduleAddress; + return this.moduleAddress } /** * @remarks This is the version of the module contract */ async getSigner(): Promise<SmartAccountSigner> { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } /** @@ -250,45 +299,51 @@ export class SessionKeyManagerModule extends BaseValidationModule { */ async getDummySignature(params?: ModuleInfo): Promise<Hex> { if (!params) { - throw new Error("Session signer is not provided."); + throw new Error("Session signer is not provided.") } - const sessionSignerData = await this.getLeafInfo(params); + const sessionSignerData = await this.getLeafInfo(params) const leafDataHex = concat([ pad(toHex(sessionSignerData.validUntil), { size: 6 }), pad(toHex(sessionSignerData.validAfter), { size: 6 }), pad(sessionSignerData.sessionValidationModule, { size: 20 }), - sessionSignerData.sessionKeyData, - ]); + sessionSignerData.sessionKeyData + ]) // Generate the padded signature with (validUntil,validAfter,sessionVerificationModuleAddress,validationData,merkleProof,signature) - let paddedSignature: Hex = encodeAbiParameters(parseAbiParameters("uint48, uint48, address, bytes, bytes32[], bytes"), [ - sessionSignerData.validUntil, - sessionSignerData.validAfter, - sessionSignerData.sessionValidationModule, - sessionSignerData.sessionKeyData, - this.merkleTree.getHexProof(keccak256(leafDataHex)) as Hex[], - this.mockEcdsaSessionKeySig, - ]); + let paddedSignature: Hex = encodeAbiParameters( + parseAbiParameters("uint48, uint48, address, bytes, bytes32[], bytes"), + [ + sessionSignerData.validUntil, + sessionSignerData.validAfter, + sessionSignerData.sessionValidationModule, + sessionSignerData.sessionKeyData, + this.merkleTree.getHexProof(keccak256(leafDataHex)) as Hex[], + this.mockEcdsaSessionKeySig + ] + ) if (params?.additionalSessionData) { - paddedSignature += params.additionalSessionData; + paddedSignature += params.additionalSessionData } - const dummySig = encodeAbiParameters(parseAbiParameters(["bytes, address"]), [paddedSignature as Hex, this.getAddress()]); + const dummySig = encodeAbiParameters( + parseAbiParameters(["bytes, address"]), + [paddedSignature as Hex, this.getAddress()] + ) - return dummySig; + return dummySig } /** * @remarks Other modules may need additional attributes to build init data */ async getInitData(): Promise<Hex> { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } /** * @remarks This Module dont have knowledge of signer. So, this method is not implemented */ async signMessage(_message: Uint8Array | string): Promise<string> { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } } diff --git a/src/modules/index.ts b/src/modules/index.ts new file mode 100644 index 000000000..3279ad1fa --- /dev/null +++ b/src/modules/index.ts @@ -0,0 +1,30 @@ +export * from "./utils/Types.js" +export * from "./utils/Constants.js" +export * from "./interfaces/IValidationModule.js" +export * from "./interfaces/ISessionValidationModule.js" +export * from "./BaseValidationModule.js" +export * from "./ECDSAOwnershipValidationModule.js" +export * from "./MultichainValidationModule.js" +export * from "./SessionKeyManagerModule.js" +export * from "./BatchedSessionRouterModule.js" +export * from "./session-validation-modules/ERC20SessionValidationModule.js" + +import { + BatchedSessionRouterModule, + ECDSAOwnershipValidationModule, + ERC20SessionValidationModule, + MultiChainValidationModule, + SessionKeyManagerModule +} from "./index.js" + +export const createBatchedSessionRouterModule = + BatchedSessionRouterModule.create +export const createMultiChainValidationModule = + MultiChainValidationModule.create +export const createECDSAOwnershipValidationModule = + ECDSAOwnershipValidationModule.create +export const createSessionKeyManagerModule = SessionKeyManagerModule.create +export const createERC20SessionValidationModule = + ERC20SessionValidationModule.create + +// export * from './PasskeyValidationModule' diff --git a/packages/modules/src/interfaces/ISessionStorage.ts b/src/modules/interfaces/ISessionStorage.ts similarity index 71% rename from packages/modules/src/interfaces/ISessionStorage.ts rename to src/modules/interfaces/ISessionStorage.ts index 41505fb1d..6372b77e3 100644 --- a/packages/modules/src/interfaces/ISessionStorage.ts +++ b/src/modules/interfaces/ISessionStorage.ts @@ -1,85 +1,88 @@ -import { Hex } from "viem"; -import { SmartAccountSigner } from "@alchemy/aa-core"; -import { SignerData } from "../utils/Types.js"; +import type { Hex } from "viem" +import type { SmartAccountSigner } from "../../account" +import type { SignerData } from "../utils/Types.js" -export type SessionStatus = "PENDING" | "ACTIVE" | "INACTIVE" | "EXPIRED"; +export type SessionStatus = "PENDING" | "ACTIVE" | "INACTIVE" | "EXPIRED" export type SessionLeafNode = { - validUntil: number; - validAfter: number; - sessionValidationModule: Hex; - sessionKeyData: Hex; - sessionPublicKey: Hex; - sessionID?: string; - status: SessionStatus; -}; + validUntil: number + validAfter: number + sessionValidationModule: Hex + sessionKeyData: Hex + sessionPublicKey: Hex + sessionID?: string + status: SessionStatus +} export type SessionSearchParam = { - sessionID?: string; - sessionPublicKey?: Hex; - sessionValidationModule?: Hex; - status?: SessionStatus; -}; + sessionID?: string + sessionPublicKey?: Hex + sessionValidationModule?: Hex + status?: SessionStatus +} export interface ISessionStorage { /** * Adds a session leaf node to the session storage * @param leaf SessionLeafNode to be added to the session storage */ - addSessionData(_leaf: SessionLeafNode): Promise<void>; + addSessionData(_leaf: SessionLeafNode): Promise<void> /** * Fetch a session leaf node from the session storage * @param param SessionSearchParam to be used to fetch the session leaf node */ - getSessionData(_param: SessionSearchParam): Promise<SessionLeafNode>; + getSessionData(_param: SessionSearchParam): Promise<SessionLeafNode> /** * Updates the session status of a session leaf node in the session storage * @param param SessionSearchParam to be used to fetch the session leaf node * @param status New session status to be updated */ - updateSessionStatus(_param: SessionSearchParam, _status: SessionStatus): Promise<void>; + updateSessionStatus( + _param: SessionSearchParam, + _status: SessionStatus + ): Promise<void> /** * Clears all the pending sessions from the session storage */ - clearPendingSessions(): Promise<void>; + clearPendingSessions(): Promise<void> /** * If a signer object is passed, it will be added to the session storage * If no signer object is passed, it'll create a random signer and add it to the session storage * @param signer Optional signer to be added to the session storage */ - addSigner(_signer?: SignerData): Promise<SmartAccountSigner>; + addSigner(_signer?: SignerData): Promise<SmartAccountSigner> /** * Fetch a signer from the session storage * @param signerPublicKey Public key of the signer to be fetched */ - getSignerByKey(_signerPublicKey: string): Promise<SmartAccountSigner>; + getSignerByKey(_signerPublicKey: string): Promise<SmartAccountSigner> /** * Fetch a signer from the session storage based on the session search param * @param param SessionSearchParam to be used to fetch the signer */ - getSignerBySession(_param: SessionSearchParam): Promise<SmartAccountSigner>; + getSignerBySession(_param: SessionSearchParam): Promise<SmartAccountSigner> /** * Fetch all the session leaf nodes from the session storage based on the session search param. * If no param is passed, it'll fetch all the session leaf nodes from the session storage * @param param SessionSearchParam to be used to fetch the session leaf nodes */ - getAllSessionData(_param?: SessionSearchParam): Promise<SessionLeafNode[]>; + getAllSessionData(_param?: SessionSearchParam): Promise<SessionLeafNode[]> /** * Fetch merkle root from the session storage */ - getMerkleRoot(): Promise<string>; + getMerkleRoot(): Promise<string> /** * Set merkle root in the session storage * @param merkleRoot Merkle root to be set in the session storage */ - setMerkleRoot(_merkleRoot: string): Promise<void>; + setMerkleRoot(_merkleRoot: string): Promise<void> } diff --git a/packages/modules/src/interfaces/ISessionValidationModule.ts b/src/modules/interfaces/ISessionValidationModule.ts similarity index 84% rename from packages/modules/src/interfaces/ISessionValidationModule.ts rename to src/modules/interfaces/ISessionValidationModule.ts index ee1c3abef..d0e8f5be8 100644 --- a/packages/modules/src/interfaces/ISessionValidationModule.ts +++ b/src/modules/interfaces/ISessionValidationModule.ts @@ -9,6 +9,6 @@ * @author Sachin Tomar <sachin.tomar@biconomy.io> */ export interface ISessionValidationModule<T> { - getSessionKeyData(_sessionData: T): Promise<string>; - getAddress(): string; + getSessionKeyData(_sessionData: T): Promise<string> + getAddress(): string } diff --git a/src/modules/interfaces/IValidationModule.ts b/src/modules/interfaces/IValidationModule.ts new file mode 100644 index 000000000..a6bedc379 --- /dev/null +++ b/src/modules/interfaces/IValidationModule.ts @@ -0,0 +1,11 @@ +import type { Hex } from "viem" +import type { SmartAccountSigner } from "../../account" + +export interface IValidationModule { + getAddress(): Hex + getInitData(): Promise<Hex> + getSigner(): Promise<SmartAccountSigner> + signUserOpHash(_userOpHash: string): Promise<Hex> + signMessage(_message: string | Uint8Array): Promise<string> + getDummySignature(): Promise<Hex> +} diff --git a/src/modules/session-storage/SessionFileStorage.ts b/src/modules/session-storage/SessionFileStorage.ts new file mode 100644 index 000000000..932e2d2c6 --- /dev/null +++ b/src/modules/session-storage/SessionFileStorage.ts @@ -0,0 +1,273 @@ +import { http, type Hex, createWalletClient } from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { polygonMumbai } from "viem/chains" +import { + Logger, + type SmartAccountSigner, + WalletClientSigner, + getChain +} from "../../account" +import type { + ISessionStorage, + SessionLeafNode, + SessionSearchParam, + SessionStatus +} from "../interfaces/ISessionStorage" +import type { SignerData } from "../utils/Types" + +export class SessionFileStorage implements ISessionStorage { + private smartAccountAddress: string + + constructor(smartAccountAddress: string) { + this.smartAccountAddress = smartAccountAddress.toLowerCase() + } + + // This method reads data from the file and returns it in the JSON format + private async readDataFromFile(type: "sessions" | "signers"): Promise<any> { + return new Promise((resolve) => { + // @ts-ignore + fs.readFile(this.getStorageFilePath(type), "utf8", (err, data) => { + if (err) { + // Handle errors appropriately + resolve(undefined) + } else { + if (!data) { + resolve(null) + } else { + resolve(JSON.parse(data)) + } + // resolve(JSON.parse(data)); + } + }) + }) + } + + private getStorageFilePath(type: "sessions" | "signers"): string { + return `${__dirname}/sessionStorageData/${this.smartAccountAddress}_${type}.json` + } + + private async writeDataToFile( + data: any, + type: "sessions" | "signers" + ): Promise<void> { + console.log("") + return new Promise((resolve, reject) => { + const filePath = this.getStorageFilePath(type) + // @ts-ignore + fs.writeFile(filePath, JSON.stringify(data), "utf8", (err) => { + if (err) { + // Handle errors appropriately + console.log({ err }, JSON.stringify(data)) + reject(err) + } else { + resolve() + } + }) + }) + } + + private validateSearchParam(param: SessionSearchParam): void { + if (param.sessionID) { + return + } + if ( + !param.sessionID && + param.sessionPublicKey && + param.sessionValidationModule + ) { + return + } + throw new Error( + "Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address." + ) + } + + // Session store is in the form of mekrleRoot and leafnodes, each object will have a root and an array of leafNodes. + private async getSessionStore(): Promise<any> { + // eslint-disable-next-line no-useless-catch + try { + const data = await this.readDataFromFile("sessions") + return data || { merkleRoot: "", leafNodes: [] } + } catch (error) { + // Handle errors appropriately + console.log({ error }) + } + } + + private async getSignerStore(): Promise<any> { + // eslint-disable-next-line no-useless-catch + try { + const data = await this.readDataFromFile("signers") + return data || {} + } catch (error) { + console.log({ error }) + // Handle errors appropriately + } + } + + // private getStorageKey(type: "sessions" | "signers"): string { + // return `${this.smartAccountAddress}_${type}` + // } + + private toLowercaseAddress(address: string): Hex { + return address.toLowerCase() as Hex + } + + async getSessionData(param: SessionSearchParam): Promise<SessionLeafNode> { + const sessions = (await this.getSessionStore()).leafNodes + const session = sessions.find((s: SessionLeafNode) => { + if (param.sessionID) { + return ( + s.sessionID === param.sessionID && + (!param.status || s.status === param.status) + ) + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) && + (!param.status || s.status === param.status) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + return session + } + + async addSessionData(leaf: SessionLeafNode): Promise<void> { + Logger.log("Add session Data", leaf) + const data = await this.getSessionStore() + leaf.sessionValidationModule = this.toLowercaseAddress( + leaf.sessionValidationModule + ) + leaf.sessionPublicKey = this.toLowercaseAddress(leaf.sessionPublicKey) + data.leafNodes.push(leaf) + await this.writeDataToFile(data, "sessions") // Use 'sessions' as the type + } + + async updateSessionStatus( + param: SessionSearchParam, + status: SessionStatus + ): Promise<void> { + this.validateSearchParam(param) + + const data = await this.getSessionStore() + const session = data.leafNodes.find((s: SessionLeafNode) => { + if (param.sessionID) { + return s.sessionID === param.sessionID + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + + session.status = status + await this.writeDataToFile(data, "sessions") // Use 'sessions' as the type + } + + async clearPendingSessions(): Promise<void> { + const data = await this.getSessionStore() + data.leafNodes = data.leafNodes.filter( + (s: SessionLeafNode) => s.status !== "PENDING" + ) + await this.writeDataToFile(data, "sessions") // Use 'sessions' as the type + } + + async addSigner(signerData: SignerData): Promise<WalletClientSigner> { + const signers = await this.getSignerStore() + let signer: SignerData + if (!signerData) { + const pkey = generatePrivateKey() + signer = { + pvKey: pkey, + pbKey: privateKeyToAccount(pkey).publicKey + } + } else { + signer = signerData + } + const accountSigner = privateKeyToAccount(signer.pvKey) + const viemChain = getChain(signerData?.chainId?.id || 1) + const client = createWalletClient({ + account: accountSigner, + chain: signerData.chainId, + transport: http(viemChain.rpcUrls.default.http[0]) + }) + const walletClientSigner: SmartAccountSigner = new WalletClientSigner( + client, + "json-rpc" // signerType + ) + signers[this.toLowercaseAddress(accountSigner.address)] = { + pvKey: signer.pvKey, + pbKey: signer.pbKey + } + await this.writeDataToFile(signers, "signers") // Use 'signers' as the type + return walletClientSigner + } + + async getSignerByKey(sessionPublicKey: string): Promise<WalletClientSigner> { + const signers = await this.getSignerStore() + Logger.log("Got signers", signers) + + const signerData: SignerData = + signers[this.toLowercaseAddress(sessionPublicKey)] + + if (!signerData) { + throw new Error("Signer not found.") + } + Logger.log(signerData.pvKey, "PVKEY") + + const signer = privateKeyToAccount(signerData.pvKey) + const walletClient = createWalletClient({ + account: signer, + transport: http(polygonMumbai.rpcUrls.default.http[0]) + }) + return new WalletClientSigner(walletClient, "json-rpc") + } + + async getSignerBySession( + param: SessionSearchParam + ): Promise<WalletClientSigner> { + const session = await this.getSessionData(param) + Logger.log("got session", session) + const walletClientSinger = await this.getSignerByKey( + session.sessionPublicKey + ) + return walletClientSinger + } + + async getAllSessionData( + param?: SessionSearchParam + ): Promise<SessionLeafNode[]> { + const sessions = (await this.getSessionStore()).leafNodes + if (!param || !param.status) { + return sessions + } + return sessions.filter((s: SessionLeafNode) => s.status === param.status) + } + + async getMerkleRoot(): Promise<string> { + return (await this.getSessionStore()).merkleRoot + } + + async setMerkleRoot(merkleRoot: string): Promise<void> { + const data = await this.getSessionStore() + data.merkleRoot = merkleRoot + await this.writeDataToFile(data, "sessions") // Use 'sessions' as the type + } +} diff --git a/src/modules/session-storage/SessionLocalStorage.ts b/src/modules/session-storage/SessionLocalStorage.ts new file mode 100644 index 000000000..82fe10121 --- /dev/null +++ b/src/modules/session-storage/SessionLocalStorage.ts @@ -0,0 +1,208 @@ +import { http, type Hex, createWalletClient, toHex } from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { mainnet } from "viem/chains" +import { type SmartAccountSigner, WalletClientSigner } from "../../account" +import type { + ISessionStorage, + SessionLeafNode, + SessionSearchParam, + SessionStatus +} from "../interfaces/ISessionStorage.js" +import type { SignerData } from "../utils/Types.js" + +export class SessionLocalStorage implements ISessionStorage { + private smartAccountAddress: string + + constructor(smartAccountAddress: string) { + this.smartAccountAddress = smartAccountAddress.toLowerCase() + } + + private validateSearchParam(param: SessionSearchParam): void { + if ( + param.sessionID || + (!param.sessionID && + param.sessionPublicKey && + param.sessionValidationModule) + ) { + return + } + throw new Error( + "Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address." + ) + } + + private getSessionStore(): any { + // @ts-ignore: LocalStorage is not available in node + const data = localStorage.getItem(this.getStorageKey("sessions")) + return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] } + } + + private getSignerStore(): any { + // @ts-ignore: LocalStorage is not available in node + const data = localStorage.getItem(this.getStorageKey("signers")) + return data ? JSON.parse(data) : {} + } + + private getStorageKey(type: "sessions" | "signers"): string { + return `${this.smartAccountAddress}_${type}` + } + + private toLowercaseAddress(address: string): string { + return address.toLowerCase() + } + + async addSessionData(leaf: SessionLeafNode): Promise<void> { + const data = this.getSessionStore() + leaf.sessionValidationModule = this.toLowercaseAddress( + leaf.sessionValidationModule + ) as Hex + leaf.sessionPublicKey = this.toLowercaseAddress( + leaf.sessionPublicKey + ) as Hex + data.leafNodes.push(leaf) + // @ts-ignore: LocalStorage is not available in node + localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async getSessionData(param: SessionSearchParam): Promise<SessionLeafNode> { + this.validateSearchParam(param) + + const sessions = this.getSessionStore().leafNodes + const session = sessions.find((s: SessionLeafNode) => { + if (param.sessionID) { + return ( + s.sessionID === param.sessionID && + (!param.status || s.status === param.status) + ) + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) && + (!param.status || s.status === param.status) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + return session + } + + async updateSessionStatus( + param: SessionSearchParam, + status: SessionStatus + ): Promise<void> { + this.validateSearchParam(param) + + const data = this.getSessionStore() + const session = data.leafNodes.find((s: SessionLeafNode) => { + if (param.sessionID) { + return s.sessionID === param.sessionID + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + + session.status = status + // @ts-ignore: LocalStorage is not available in node + localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async clearPendingSessions(): Promise<void> { + const data = this.getSessionStore() + data.leafNodes = data.leafNodes.filter( + (s: SessionLeafNode) => s.status !== "PENDING" + ) + // @ts-ignore: LocalStorage is not available in node + localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async addSigner(signerData: SignerData): Promise<SmartAccountSigner> { + const signers = this.getSignerStore() + let signer: SignerData + if (!signerData) { + const pkey = generatePrivateKey() + signer = { + pvKey: pkey, + pbKey: privateKeyToAccount(pkey).publicKey + } + } else { + signer = signerData + } + const accountSigner = privateKeyToAccount(toHex(signer.pvKey)) + const client = createWalletClient({ + account: accountSigner, + chain: signerData.chainId, + transport: http() + }) + const walletClientSigner = new WalletClientSigner( + client, + "json-rpc" // signerType + ) + signers[this.toLowercaseAddress(accountSigner.address)] = signerData + // @ts-ignore: LocalStorage is not available in node + localStorage.setItem(this.getStorageKey("signers"), JSON.stringify(signers)) + return walletClientSigner + } + + async getSignerByKey(sessionPublicKey: string): Promise<SmartAccountSigner> { + const signers = this.getSignerStore() + const signerData = signers[this.toLowercaseAddress(sessionPublicKey)] + if (!signerData) { + throw new Error("Signer not found.") + } + const account = privateKeyToAccount(signerData.privateKey) + const client = createWalletClient({ + account, + chain: mainnet, + transport: http() + }) + const signer = new WalletClientSigner(client, "viem") + return signer + } + + async getSignerBySession( + param: SessionSearchParam + ): Promise<SmartAccountSigner> { + const session = await this.getSessionData(param) + return this.getSignerByKey(session.sessionPublicKey) + } + + async getAllSessionData( + param?: SessionSearchParam + ): Promise<SessionLeafNode[]> { + const sessions = this.getSessionStore().leafNodes + if (!param || !param.status) { + return sessions + } + return sessions.filter((s: SessionLeafNode) => s.status === param.status) + } + + async getMerkleRoot(): Promise<string> { + return this.getSessionStore().merkleRoot + } + + setMerkleRoot(merkleRoot: string): Promise<void> { + const data = this.getSessionStore() + data.merkleRoot = merkleRoot + // @ts-ignore: LocalStorage is not available in node + localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + return Promise.resolve() + } +} diff --git a/src/modules/session-storage/SessionMemoryStorage.ts b/src/modules/session-storage/SessionMemoryStorage.ts new file mode 100644 index 000000000..b6d6e4196 --- /dev/null +++ b/src/modules/session-storage/SessionMemoryStorage.ts @@ -0,0 +1,219 @@ +import { http, type Hex, createWalletClient } from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { mainnet } from "viem/chains" +import { type SmartAccountSigner, WalletClientSigner } from "../../account" +import type { + ISessionStorage, + SessionLeafNode, + SessionSearchParam, + SessionStatus +} from "../interfaces/ISessionStorage.js" +import type { SignerData } from "../utils/Types.js" + +type MemoryStore = { + _store: Record<string, string> + getItem: (key: string) => string | undefined + setItem: (key: string, value: string) => void +} +const memoryStorage: MemoryStore = { + _store: {}, + getItem: (key: string): string => { + return memoryStorage._store[key] + }, + setItem: (key: string, value: string) => { + memoryStorage._store[key] = value + } +} + +export class SessionMemoryStorage implements ISessionStorage { + private smartAccountAddress: string + + constructor(smartAccountAddress: string) { + this.smartAccountAddress = smartAccountAddress.toLowerCase() + } + + private validateSearchParam(param: SessionSearchParam): void { + if ( + param.sessionID || + (!param.sessionID && + param.sessionPublicKey && + param.sessionValidationModule) + ) { + return + } + throw new Error( + "Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address." + ) + } + + private getSessionStore(): any { + const data = memoryStorage.getItem(this.getStorageKey("sessions")) + return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] } + } + + private getSignerStore(): any { + const data = memoryStorage.getItem(this.getStorageKey("signers")) + return data ? JSON.parse(data) : {} + } + + private getStorageKey(type: "sessions" | "signers"): string { + return `${this.smartAccountAddress}_${type}` + } + + private toLowercaseAddress(address: string): string { + return address.toLowerCase() + } + + async addSessionData(leaf: SessionLeafNode): Promise<void> { + const data = this.getSessionStore() + leaf.sessionValidationModule = this.toLowercaseAddress( + leaf.sessionValidationModule + ) as Hex + leaf.sessionPublicKey = this.toLowercaseAddress( + leaf.sessionPublicKey + ) as Hex + data.leafNodes.push(leaf) + memoryStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async getSessionData(param: SessionSearchParam): Promise<SessionLeafNode> { + this.validateSearchParam(param) + + const sessions = this.getSessionStore().leafNodes + const session = sessions.find((s: SessionLeafNode) => { + if (param.sessionID) { + return ( + s.sessionID === param.sessionID && + (!param.status || s.status === param.status) + ) + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) && + (!param.status || s.status === param.status) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + return session + } + + async updateSessionStatus( + param: SessionSearchParam, + status: SessionStatus + ): Promise<void> { + this.validateSearchParam(param) + + const data = this.getSessionStore() + const session = data.leafNodes.find((s: SessionLeafNode) => { + if (param.sessionID) { + return s.sessionID === param.sessionID + } + if (param.sessionPublicKey && param.sessionValidationModule) { + return ( + s.sessionPublicKey === + this.toLowercaseAddress(param.sessionPublicKey) && + s.sessionValidationModule === + this.toLowercaseAddress(param.sessionValidationModule) + ) + } + return undefined + }) + + if (!session) { + throw new Error("Session not found.") + } + + session.status = status + memoryStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async clearPendingSessions(): Promise<void> { + const data = this.getSessionStore() + data.leafNodes = data.leafNodes.filter( + (s: SessionLeafNode) => s.status !== "PENDING" + ) + memoryStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + } + + async addSigner(signerData: SignerData): Promise<SmartAccountSigner> { + const signers = this.getSignerStore() + let signer: SignerData + if (!signerData) { + const pkey = generatePrivateKey() + signer = { + pvKey: pkey, + pbKey: privateKeyToAccount(pkey).publicKey + } + } else { + signer = signerData + } + const accountSigner = privateKeyToAccount(signer.pvKey) + const client = createWalletClient({ + account: accountSigner, + chain: signerData.chainId, + transport: http() + }) + const walletClientSigner = new WalletClientSigner( + client, + "json-rpc" // signerType + ) + signers[this.toLowercaseAddress(accountSigner.address)] = signerData + memoryStorage.setItem( + this.getStorageKey("signers"), + JSON.stringify(signers) + ) + return walletClientSigner + } + + async getSignerByKey(sessionPublicKey: string): Promise<SmartAccountSigner> { + const signers = this.getSignerStore() + const signerData = signers[this.toLowercaseAddress(sessionPublicKey)] + if (!signerData) { + throw new Error("Signer not found.") + } + const account = privateKeyToAccount(signerData.privateKey) + const client = createWalletClient({ + account, + chain: mainnet, + transport: http() + }) + const signer = new WalletClientSigner(client, "viem") + return signer + } + + async getSignerBySession( + param: SessionSearchParam + ): Promise<SmartAccountSigner> { + const session = await this.getSessionData(param) + return this.getSignerByKey(session.sessionPublicKey) + } + + async getAllSessionData( + param?: SessionSearchParam + ): Promise<SessionLeafNode[]> { + const sessions = this.getSessionStore().leafNodes + if (!param || !param.status) { + return sessions + } + return sessions.filter((s: SessionLeafNode) => s.status === param.status) + } + + async getMerkleRoot(): Promise<string> { + return this.getSessionStore().merkleRoot + } + + setMerkleRoot(merkleRoot: string): Promise<void> { + const data = this.getSessionStore() + data.merkleRoot = merkleRoot + memoryStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data)) + return Promise.resolve() + } +} diff --git a/packages/modules/src/session-validation-modules/ERC20SessionValidationModule.ts b/src/modules/session-validation-modules/ERC20SessionValidationModule.ts similarity index 54% rename from packages/modules/src/session-validation-modules/ERC20SessionValidationModule.ts rename to src/modules/session-validation-modules/ERC20SessionValidationModule.ts index 7791f1967..1e047cc6e 100644 --- a/packages/modules/src/session-validation-modules/ERC20SessionValidationModule.ts +++ b/src/modules/session-validation-modules/ERC20SessionValidationModule.ts @@ -1,6 +1,9 @@ -import { ISessionValidationModule } from "../interfaces/ISessionValidationModule.js"; -import { ERC20SessionKeyData, SessionValidationModuleConfig } from "../utils/Types.js"; -import { encodeAbiParameters, parseAbiParameters } from "viem"; +import { encodeAbiParameters, parseAbiParameters } from "viem" +import type { ISessionValidationModule } from "../interfaces/ISessionValidationModule.js" +import type { + ERC20SessionKeyData, + SessionValidationModuleConfig +} from "../utils/Types.js" /** * Session validation module for ERC20 token transfers. @@ -8,10 +11,12 @@ import { encodeAbiParameters, parseAbiParameters } from "viem"; * * @author Sachin Tomar <sachin.tomar@biconomy.io> */ -export class ERC20SessionValidationModule implements ISessionValidationModule<ERC20SessionKeyData> { - moduleAddress!: string; +export class ERC20SessionValidationModule + implements ISessionValidationModule<ERC20SessionKeyData> +{ + moduleAddress!: string - version = "V1_0_0"; + version = "V1_0_0" /** * This constructor is private. Use the static create method to instantiate ERC20SessionValidationModule @@ -20,9 +25,9 @@ export class ERC20SessionValidationModule implements ISessionValidationModule<ER */ private constructor(moduleConfig: SessionValidationModuleConfig) { if (!moduleConfig.moduleAddress) { - throw new Error("Module address is required"); + throw new Error("Module address is required") } - this.moduleAddress = moduleConfig.moduleAddress; + this.moduleAddress = moduleConfig.moduleAddress } /** @@ -30,41 +35,46 @@ export class ERC20SessionValidationModule implements ISessionValidationModule<ER * @param moduleConfig The configuration for the module * @returns A Promise that resolves to an instance of ERC20SessionValidationModule */ - public static async create(moduleConfig: SessionValidationModuleConfig): Promise<ERC20SessionValidationModule> { - const module = new ERC20SessionValidationModule(moduleConfig); - return module; + public static async create( + moduleConfig: SessionValidationModuleConfig + ): Promise<ERC20SessionValidationModule> { + const module = new ERC20SessionValidationModule(moduleConfig) + return module } async getSessionKeyData(sessionData: ERC20SessionKeyData): Promise<string> { - this._validateSessionKeyData(sessionData); - const sessionKeyData = encodeAbiParameters(parseAbiParameters("address, address, address, uint256"), [ - sessionData.sessionKey, - sessionData.token, - sessionData.recipient, - sessionData.maxAmount, - ]); - return sessionKeyData; + this._validateSessionKeyData(sessionData) + const sessionKeyData = encodeAbiParameters( + parseAbiParameters("address, address, address, uint256"), + [ + sessionData.sessionKey, + sessionData.token, + sessionData.recipient, + sessionData.maxAmount + ] + ) + return sessionKeyData } private _validateSessionKeyData(sessionData: ERC20SessionKeyData): void { if (!sessionData) { - throw new Error("Session data is required"); + throw new Error("Session data is required") } if (!sessionData.sessionKey) { - throw new Error("Session key is required in sessionData"); + throw new Error("Session key is required in sessionData") } if (!sessionData.token) { - throw new Error("Token address is required in sessionData"); + throw new Error("Token address is required in sessionData") } if (!sessionData.recipient) { - throw new Error("Recipient address is required in sessionData"); + throw new Error("Recipient address is required in sessionData") } if (!sessionData.maxAmount) { - throw new Error("MaxAmount is required in sessionData"); + throw new Error("MaxAmount is required in sessionData") } } getAddress(): string { - return this.moduleAddress; + return this.moduleAddress } } diff --git a/src/modules/utils/Constants.ts b/src/modules/utils/Constants.ts new file mode 100644 index 000000000..4c8c34192 --- /dev/null +++ b/src/modules/utils/Constants.ts @@ -0,0 +1,35 @@ +import type { ModuleVersion } from "./Types.js" + +export const DEFAULT_MODULE_VERSION: ModuleVersion = "V1_0_0" + +// Note: we could append these defaults with ADDRESS suffix +export const DEFAULT_ECDSA_OWNERSHIP_MODULE = + "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e" + +export const ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION = { + V1_0_0: "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e" +} + +export const DEFAULT_SESSION_KEY_MANAGER_MODULE = + "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489" + +export const SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION = { + V1_0_0: "0x000000456b395c4e107e0302553B90D1eF4a32e9", + V1_0_1: "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489" +} + +export const DEFAULT_BATCHED_SESSION_ROUTER_MODULE = + "0x00000D09967410f8C76752A104c9848b57ebba55" + +export const BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION = { + V1_0_0: "0x00000D09967410f8C76752A104c9848b57ebba55" +} + +export const DEFAULT_ERC20_MODULE = "0x000000D50C68705bd6897B2d17c7de32FB519fDA" + +export const DEFAULT_MULTICHAIN_MODULE = + "0x000000824dc138db84FD9109fc154bdad332Aa8E" + +export const MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION = { + V1_0_0: "0x000000824dc138db84FD9109fc154bdad332Aa8E" +} diff --git a/src/modules/utils/Helper.ts b/src/modules/utils/Helper.ts new file mode 100644 index 000000000..aa125e759 --- /dev/null +++ b/src/modules/utils/Helper.ts @@ -0,0 +1,105 @@ +import { + type Hex, + concat, + encodeAbiParameters, + keccak256, + pad, + parseAbiParameters, + toHex +} from "viem" +import type { UserOperationStruct } from "../../account" + +export interface Rule { + offset: number + condition: number + referenceValue: `0x${string}` +} + +export interface Permission { + destContract: `0x${string}` + functionSelector: `0x${string}` + valueLimit: bigint + rules: Rule[] +} + +function packUserOp( + op: Partial<UserOperationStruct>, + forSignature = true +): string { + if (!op.initCode || !op.callData || !op.paymasterAndData) + throw new Error("Missing userOp properties") + if (forSignature) { + return encodeAbiParameters( + parseAbiParameters( + "address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32" + ), + [ + op.sender as Hex, + BigInt(op.nonce as Hex), + keccak256(op.initCode as Hex), + keccak256(op.callData as Hex), + BigInt(op.callGasLimit as Hex), + BigInt(op.verificationGasLimit as Hex), + BigInt(op.preVerificationGas as Hex), + BigInt(op.maxFeePerGas as Hex), + BigInt(op.maxPriorityFeePerGas as Hex), + keccak256(op.paymasterAndData as Hex) + ] + ) + } + // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) + return encodeAbiParameters( + parseAbiParameters( + "address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes" + ), + [ + op.sender as Hex, + BigInt(op.nonce as Hex), + op.initCode as Hex, + op.callData as Hex, + BigInt(op.callGasLimit as Hex), + BigInt(op.verificationGasLimit as Hex), + BigInt(op.preVerificationGas as Hex), + BigInt(op.maxFeePerGas as Hex), + BigInt(op.maxPriorityFeePerGas as Hex), + op.paymasterAndData as Hex, + op.signature as Hex + ] + ) +} + +export const getUserOpHash = ( + userOp: Partial<UserOperationStruct>, + entryPointAddress: Hex, + chainId: number +): Hex => { + const userOpHash = keccak256(packUserOp(userOp, true) as Hex) + const enc = encodeAbiParameters( + parseAbiParameters("bytes32, address, uint256"), + [userOpHash, entryPointAddress, BigInt(chainId)] + ) + return keccak256(enc) +} + +export async function getABISVMSessionKeyData( + sessionKey: `0x${string}` | Uint8Array, + permission: Permission +): Promise<`0x${string}` | Uint8Array> { + let sessionKeyData = concat([ + sessionKey, + permission.destContract, + permission.functionSelector, + pad(toHex(permission.valueLimit), { size: 16 }), + pad(toHex(permission.rules.length), { size: 2 }) // this can't be more 2**11 (see below), so uint16 (2 bytes) is enough + ]) as `0x${string}` + + for (let i = 0; i < permission.rules.length; i++) { + sessionKeyData = concat([ + sessionKeyData, + pad(toHex(permission.rules[i].offset), { size: 2 }), // offset is uint16, so there can't be more than 2**16/32 args = 2**11 + pad(toHex(permission.rules[i].condition), { size: 1 }), // uint8 + permission.rules[i].referenceValue + ]) + } + return sessionKeyData +} diff --git a/packages/modules/src/utils/Types.ts b/src/modules/utils/Types.ts similarity index 58% rename from packages/modules/src/utils/Types.ts rename to src/modules/utils/Types.ts index 68adf5194..26c0badcf 100644 --- a/packages/modules/src/utils/Types.ts +++ b/src/modules/utils/Types.ts @@ -1,160 +1,177 @@ -import { Chain, Hex } from "viem"; -import { SmartAccountSigner, UserOperationStruct } from "@alchemy/aa-core"; -import { SessionKeyManagerModule } from "../SessionKeyManagerModule.js"; -import { ISessionStorage } from "../interfaces/ISessionStorage.js"; -import { SupportedSigner } from "@biconomy/common"; -export type ModuleVersion = "V1_0_0"; // | 'V1_0_1' +import type { Chain, Hex } from "viem" +import type { + SimulationType, + SmartAccountSigner, + SupportedSigner, + UserOperationStruct +} from "../../account" +import type { SessionKeyManagerModule } from "../SessionKeyManagerModule.js" +import type { ISessionStorage } from "../interfaces/ISessionStorage.js" +export type ModuleVersion = "V1_0_0" // | 'V1_0_1' export interface BaseValidationModuleConfig { /** entryPointAddress: address of the entry point */ - entryPointAddress?: Hex; + entryPointAddress?: Hex } -export interface ECDSAOwnershipValidationModuleConfig extends BaseValidationModuleConfig { +export interface ECDSAOwnershipValidationModuleConfig + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** Signer: viemWallet or ethers signer. Ingested when passed into smartAccount */ - signer: SupportedSigner; + signer: SupportedSigner } -export interface ECDSAOwnershipValidationModuleConfigConstructorProps extends BaseValidationModuleConfig { +export interface ECDSAOwnershipValidationModuleConfigConstructorProps + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** Signer: Converted from viemWallet or ethers signer to SmartAccountSigner */ - signer: SmartAccountSigner; + signer: SmartAccountSigner } -export interface SessionKeyManagerModuleConfig extends BaseValidationModuleConfig { +export interface SessionKeyManagerModuleConfig + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** SmartAccount address */ - smartAccountAddress: string; - storageType?: StorageType; - sessionStorageClient?: ISessionStorage; + smartAccountAddress: string + storageType?: StorageType + sessionStorageClient?: ISessionStorage } -export interface BatchedSessionRouterModuleConfig extends BaseValidationModuleConfig { +export interface BatchedSessionRouterModuleConfig + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** Session Key Manager module: Could be BaseValidationModule */ - sessionKeyManagerModule?: SessionKeyManagerModule; + sessionKeyManagerModule?: SessionKeyManagerModule /** Session Key Manager module address */ - sessionManagerModuleAddress?: Hex; + sessionManagerModuleAddress?: Hex /** Address of the associated smart account */ - smartAccountAddress: string; + smartAccountAddress: string /** Storage type, e.g. local storage */ - storageType?: StorageType; + storageType?: StorageType } export enum StorageType { - LOCAL_STORAGE, + LOCAL_STORAGE = 0 } +export type SessionDataTuple = [ + bigint | number, + bigint | number, + Hex, + Hex, + string[], + string +] + export type SessionParams = { /** Redundant now as we've favoured uuid() */ - sessionID?: string; + sessionID?: string /** Session Signer: viemWallet or ethers signer. Ingested when passed into smartAccount */ - sessionSigner: SupportedSigner; + sessionSigner: SupportedSigner /** The session validation module is a sub-module smart-contract which works with session key manager validation module. It validates the userop calldata against the defined session permissions (session key data) within the contract. */ - sessionValidationModule?: Hex; + sessionValidationModule?: Hex /** Additional info if needed to be appended in signature */ - additionalSessionData?: string; -}; + additionalSessionData?: string +} export type ModuleInfo = { // Could be a full object of below params and that way it can be an array too! // sessionParams?: SessionParams[] // where SessionParams is below four - sessionID?: string; + sessionID?: string /** Session Signer: viemWallet or ethers signer. Ingested when passed into smartAccount */ - sessionSigner?: SupportedSigner; + sessionSigner?: SupportedSigner /** The session validation module is a sub-module smart-contract which works with session key manager validation module. It validates the userop calldata against the defined session permissions (session key data) within the contract. */ - sessionValidationModule?: Hex; + sessionValidationModule?: Hex /** Additional info if needed to be appended in signature */ - additionalSessionData?: string; - batchSessionParams?: SessionParams[]; -}; + additionalSessionData?: string + batchSessionParams?: SessionParams[] +} export interface SendUserOpParams extends ModuleInfo { /** "validation_and_execution" is recommended during development for improved debugging & devEx, but will add some additional latency to calls. "validation" can be used in production ro remove this latency once flows have been tested. */ - simulationType?: SimulationType; + simulationType?: SimulationType } -export type SimulationType = "validation" | "validation_and_execution"; - export type SignerData = { /** Public key */ - pbKey: string; + pbKey: string /** Private key */ - pvKey: `0x${string}`; + pvKey: `0x${string}` /** Network Id */ - chainId?: Chain; -}; + chainId?: Chain +} export type CreateSessionDataResponse = { - data: string; - sessionIDInfo: Array<string>; -}; + data: string + sessionIDInfo: Array<string> +} export interface CreateSessionDataParams { /** window end for the session key */ - validUntil: number; + validUntil: number /** window start for the session key */ - validAfter: number; - sessionValidationModule: Hex; - sessionPublicKey: Hex; - sessionKeyData: Hex; + validAfter: number + sessionValidationModule: Hex + sessionPublicKey: Hex + sessionKeyData: Hex /** we generate uuid based sessionId. but if you prefer to track it on your side and attach custom session identifier this can be passed */ - preferredSessionId?: string; + preferredSessionId?: string } -export interface MultiChainValidationModuleConfig extends BaseValidationModuleConfig { +export interface MultiChainValidationModuleConfig + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** Signer: viemWallet or ethers signer. Ingested when passed into smartAccount */ - signer: SupportedSigner; + signer: SupportedSigner } -export interface MultiChainValidationModuleConfigConstructorProps extends BaseValidationModuleConfig { +export interface MultiChainValidationModuleConfigConstructorProps + extends BaseValidationModuleConfig { /** Address of the module */ - moduleAddress?: Hex; + moduleAddress?: Hex /** Version of the module */ - version?: ModuleVersion; + version?: ModuleVersion /** Signer: viemWallet or ethers signer. Ingested when passed into smartAccount */ - signer: SmartAccountSigner; + signer: SmartAccountSigner } export type MultiChainUserOpDto = { /** window end timestamp */ - validUntil?: number; + validUntil?: number /** window start timestamp */ - validAfter?: number; - chainId: number; - userOp: Partial<UserOperationStruct>; -}; + validAfter?: number + chainId: number + userOp: Partial<UserOperationStruct> +} export interface BaseSessionKeyData { - sessionKey: Hex; + sessionKey: Hex } export interface ERC20SessionKeyData extends BaseSessionKeyData { /** ERC20 token address */ - token: Hex; + token: Hex /** Recipient address */ - recipient: Hex; + recipient: Hex /** ERC20 amount (Bigint) */ - maxAmount: bigint; + maxAmount: bigint } export interface SessionValidationModuleConfig { /** Address of the module */ - moduleAddress: string; + moduleAddress: string } diff --git a/packages/modules/src/utils/Uid.ts b/src/modules/utils/Uid.ts similarity index 62% rename from packages/modules/src/utils/Uid.ts rename to src/modules/utils/Uid.ts index 5cf4a6cca..58080849d 100644 --- a/packages/modules/src/utils/Uid.ts +++ b/src/modules/utils/Uid.ts @@ -1,12 +1,12 @@ // small uid generator, hex: 0-9, a-f (10 chars) export const generateRandomHex = (): string => { - const hexChars = "0123456789abcdef"; - let result = ""; + const hexChars = "0123456789abcdef" + let result = "" for (let i = 0; i < 10; i++) { - const randomIndex = Math.floor(Math.random() * hexChars.length); - result += hexChars[randomIndex]; + const randomIndex = Math.floor(Math.random() * hexChars.length) + result += hexChars[randomIndex] } - return result; -}; + return result +} diff --git a/packages/paymaster/src/BiconomyPaymaster.ts b/src/paymaster/BiconomyPaymaster.ts similarity index 55% rename from packages/paymaster/src/BiconomyPaymaster.ts rename to src/paymaster/BiconomyPaymaster.ts index aa0af3f86..36e3e55ad 100644 --- a/packages/paymaster/src/BiconomyPaymaster.ts +++ b/src/paymaster/BiconomyPaymaster.ts @@ -1,39 +1,46 @@ -import { encodeFunctionData, parseAbi } from "viem"; -import type { BigNumberish, UserOperationStruct } from "@alchemy/aa-core"; +import { encodeFunctionData, parseAbi } from "viem" import { - PaymasterFeeQuote, - PaymasterConfig, - FeeQuotesOrDataResponse, - FeeQuotesOrDataDto, - SponsorUserOperationDto, - JsonRpcResponse, - BiconomyTokenPaymasterRequest, + type BiconomyTokenPaymasterRequest, + type BigNumberish, + HttpMethod, + Logger, + type Transaction, + type UserOperationStruct, + sendRequest +} from "../account" +import type { IHybridPaymaster } from "./interfaces/IHybridPaymaster.js" +import { ADDRESS_ZERO, ERC20_ABI, MAX_UINT256 } from "./utils/Constants.js" +import { getTimestampInSeconds } from "./utils/Helpers.js" +import { + type FeeQuotesOrDataDto, + type FeeQuotesOrDataResponse, + type Hex, + type JsonRpcResponse, + type PaymasterAndDataResponse, + type PaymasterConfig, + type PaymasterFeeQuote, PaymasterMode, - PaymasterAndDataResponse, - Transaction, - Hex, -} from "./utils/Types.js"; -import { IHybridPaymaster } from "./interfaces/IHybridPaymaster.js"; -import { MAX_UINT256, ERC20_ABI, ADDRESS_ZERO } from "./utils/Constants.js"; -import { sendRequest, HttpMethod, Logger } from "@biconomy/common"; -import { getTimestampInSeconds } from "./utils/Helpers.js"; + type SponsorUserOperationDto +} from "./utils/Types.js" const defaultPaymasterConfig: PaymasterConfig = { paymasterUrl: "", - strictMode: false, // Set your desired default value for strictMode here -}; + strictMode: false // Set your desired default value for strictMode here +} /** * @dev Hybrid - Generic Gas Abstraction paymaster */ -export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationDto> { - paymasterConfig: PaymasterConfig; +export class BiconomyPaymaster + implements IHybridPaymaster<SponsorUserOperationDto> +{ + paymasterConfig: PaymasterConfig constructor(config: PaymasterConfig) { const mergedConfig: PaymasterConfig = { ...defaultPaymasterConfig, - ...config, - }; - this.paymasterConfig = mergedConfig; + ...config + } + this.paymasterConfig = mergedConfig } /** @@ -41,27 +48,41 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD * @param userOp The partial user operation. * @returns A Promise that resolves to the prepared partial user operation. */ - private async prepareUserOperation(userOp: Partial<UserOperationStruct>): Promise<Partial<UserOperationStruct>> { - const userOperation = { ...userOp }; + private async prepareUserOperation( + userOp: Partial<UserOperationStruct> + ): Promise<Partial<UserOperationStruct>> { + const userOperation = { ...userOp } try { - const keys1: (keyof UserOperationStruct)[] = ["nonce", "maxFeePerGas", "maxPriorityFeePerGas"]; + const keys1: (keyof UserOperationStruct)[] = [ + "nonce", + "maxFeePerGas", + "maxPriorityFeePerGas" + ] for (const key of keys1) { if (userOperation[key] && userOperation[key] !== "0x") { - userOperation[key] = ("0x" + BigInt(userOp[key] as BigNumberish).toString(16)) as `0x${string}`; + userOperation[key] = `0x${BigInt( + userOp[key] as BigNumberish + ).toString(16)}` as `0x${string}` } } - const keys2: (keyof UserOperationStruct)[] = ["callGasLimit", "verificationGasLimit", "preVerificationGas"]; + const keys2: (keyof UserOperationStruct)[] = [ + "callGasLimit", + "verificationGasLimit", + "preVerificationGas" + ] for (const key of keys2) { if (userOperation[key] && userOperation[key] !== "0x") { - userOperation[key] = BigInt(userOp[key] as BigNumberish).toString() as `0x${string}`; + userOperation[key] = BigInt( + userOp[key] as BigNumberish + ).toString() as `0x${string}` } } } catch (error) { - throw `Failed to transform user operation: ${error}`; + throw `Failed to transform user operation: ${error}` } - userOperation.signature = userOp.signature || "0x"; - userOperation.paymasterAndData = userOp.paymasterAndData || "0x"; - return userOperation; + userOperation.signature = userOp.signature || "0x" + userOperation.paymasterAndData = userOp.paymasterAndData || "0x" + return userOperation } /** @@ -70,10 +91,12 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD * @param provider Optional provider object. * @returns A Promise that resolves to the built transaction object. */ - async buildTokenApprovalTransaction(tokenPaymasterRequest: BiconomyTokenPaymasterRequest): Promise<Transaction> { - const feeTokenAddress: string = tokenPaymasterRequest.feeQuote.tokenAddress; + async buildTokenApprovalTransaction( + tokenPaymasterRequest: BiconomyTokenPaymasterRequest + ): Promise<Transaction> { + const feeTokenAddress: string = tokenPaymasterRequest.feeQuote.tokenAddress - const spender = tokenPaymasterRequest.spender; + const spender = tokenPaymasterRequest.spender // logging provider object isProvider // Logger.log("provider object passed - is provider", provider?._isProvider); @@ -82,21 +105,29 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD // Note: should also check in caller if the approval is already given, if yes return object with address or data 0 // Note: we would need userOp here to get the account/owner info to check allowance - let requiredApproval = BigInt(0); + let requiredApproval = BigInt(0) - if (tokenPaymasterRequest.maxApproval && tokenPaymasterRequest.maxApproval == true) { - requiredApproval = BigInt(MAX_UINT256); + if ( + tokenPaymasterRequest.maxApproval && + tokenPaymasterRequest.maxApproval === true + ) { + requiredApproval = BigInt(MAX_UINT256) } else { - requiredApproval = BigInt(Math.ceil(tokenPaymasterRequest.feeQuote.maxGasFee * Math.pow(10, tokenPaymasterRequest.feeQuote.decimal))); + requiredApproval = BigInt( + Math.ceil( + tokenPaymasterRequest.feeQuote.maxGasFee * + 10 ** tokenPaymasterRequest.feeQuote.decimal + ) + ) } try { - const parsedAbi = parseAbi(ERC20_ABI); + const parsedAbi = parseAbi(ERC20_ABI) const data = encodeFunctionData({ abi: parsedAbi, functionName: "approve", - args: [spender, requiredApproval], - }); + args: [spender, requiredApproval] + }) // TODO? // Note: For some tokens we may need to set allowance to 0 first so that would return batch of transactions and changes the return type to Transaction[] @@ -114,10 +145,10 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD return { to: feeTokenAddress, value: "0x00", - data: data, - }; + data: data + } } catch (error) { - throw new Error("Failed to encode function data"); + throw new Error("Failed to encode function data") } } @@ -128,39 +159,46 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD * @returns A Promise that resolves to the fee quotes or data response. */ async getPaymasterFeeQuotesOrData( - userOp: Partial<UserOperationStruct>, - paymasterServiceData: FeeQuotesOrDataDto, + _userOp: Partial<UserOperationStruct>, + paymasterServiceData: FeeQuotesOrDataDto ): Promise<FeeQuotesOrDataResponse> { - userOp = await this.prepareUserOperation(userOp); + const userOp = await this.prepareUserOperation(_userOp) - let mode = null; - let expiryDuration = null; - const calculateGasLimits = paymasterServiceData.calculateGasLimits ?? true; - let preferredToken = null; - let feeTokensArray: string[] = []; + let mode: PaymasterMode | null = null + let expiryDuration: number | null = null + const calculateGasLimits = paymasterServiceData.calculateGasLimits ?? true + let preferredToken: string | null = null + let feeTokensArray: string[] = [] // could make below null let smartAccountInfo = { name: "BICONOMY", - version: "2.0.0", - }; - let webhookData = null; + version: "2.0.0" + } + let webhookData: Record<string, any> | null = null if (paymasterServiceData.mode) { - mode = paymasterServiceData.mode; + mode = paymasterServiceData.mode // Validation on the mode passed / define allowed enums } if (paymasterServiceData.expiryDuration) { - expiryDuration = paymasterServiceData.expiryDuration; + expiryDuration = paymasterServiceData.expiryDuration } - preferredToken = paymasterServiceData?.preferredToken ? paymasterServiceData?.preferredToken : preferredToken; + preferredToken = paymasterServiceData?.preferredToken + ? paymasterServiceData?.preferredToken + : preferredToken - feeTokensArray = (paymasterServiceData?.tokenList?.length !== 0 ? paymasterServiceData?.tokenList : feeTokensArray) as string[]; + feeTokensArray = ( + paymasterServiceData?.tokenList?.length !== 0 + ? paymasterServiceData?.tokenList + : feeTokensArray + ) as string[] - webhookData = paymasterServiceData?.webhookData ?? webhookData; + webhookData = paymasterServiceData?.webhookData ?? webhookData - smartAccountInfo = paymasterServiceData?.smartAccountInfo ?? smartAccountInfo; + smartAccountInfo = + paymasterServiceData?.smartAccountInfo ?? smartAccountInfo try { const response: JsonRpcResponse = await sendRequest( @@ -177,67 +215,78 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD ...(expiryDuration !== null && { expiryDuration }), tokenInfo: { tokenList: feeTokensArray, - ...(preferredToken !== null && { preferredToken }), + ...(preferredToken !== null && { preferredToken }) }, sponsorshipInfo: { ...(webhookData !== null && { webhookData }), - smartAccountInfo: smartAccountInfo, - }, - }, + smartAccountInfo: smartAccountInfo + } + } ], // As per current API id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Paymaster", - ); - - if (response && response.result) { - if (response.result.mode == PaymasterMode.ERC20) { - const feeQuotesResponse: Array<PaymasterFeeQuote> = response.result.feeQuotes; - const paymasterAddress: Hex = response.result.paymasterAddress; + "Paymaster" + ) + + if (response?.result) { + if (response.result.mode === PaymasterMode.ERC20) { + const feeQuotesResponse: Array<PaymasterFeeQuote> = + response.result.feeQuotes + const paymasterAddress: Hex = response.result.paymasterAddress // check all objects iterate and populate below calculation for all tokens - return { feeQuotes: feeQuotesResponse, tokenPaymasterAddress: paymasterAddress }; - } else if (response.result.mode == PaymasterMode.SPONSORED) { - const paymasterAndData: Hex = response.result.paymasterAndData; - const preVerificationGas = response.result.preVerificationGas; - const verificationGasLimit = response.result.verificationGasLimit; - const callGasLimit = response.result.callGasLimit; + return { + feeQuotes: feeQuotesResponse, + tokenPaymasterAddress: paymasterAddress + } + } + if (response.result.mode === PaymasterMode.SPONSORED) { + const paymasterAndData: Hex = response.result.paymasterAndData + const preVerificationGas = response.result.preVerificationGas + const verificationGasLimit = response.result.verificationGasLimit + const callGasLimit = response.result.callGasLimit return { paymasterAndData: paymasterAndData, preVerificationGas: preVerificationGas, verificationGasLimit: verificationGasLimit, - callGasLimit: callGasLimit, - }; - } else { - const errorObject = { - code: 417, - message: "Expectation Failed: Invalid mode in Paymaster service response", - }; - throw errorObject; + callGasLimit: callGasLimit + } } + const errorObject = { + code: 417, + message: + "Expectation Failed: Invalid mode in Paymaster service response" + } + throw errorObject } } catch (error: any) { - Logger.error("Failed to fetch Fee Quotes or Paymaster data - reason: ", JSON.stringify(error)); + Logger.error( + "Failed to fetch Fee Quotes or Paymaster data - reason: ", + JSON.stringify(error) + ) // Note: we may not throw if we include strictMode off and return paymasterData '0x'. if ( !this.paymasterConfig.strictMode && - paymasterServiceData.mode == PaymasterMode.SPONSORED && - (error?.message.includes("Smart contract data not found") || error?.message.includes("No policies were set")) + paymasterServiceData.mode === PaymasterMode.SPONSORED && + (error?.message.includes("Smart contract data not found") || + error?.message.includes("No policies were set")) // can also check based on error.code being -32xxx ) { - Logger.warn(`Strict mode is ${this.paymasterConfig.strictMode}. sending paymasterAndData 0x`); + Logger.warn( + `Strict mode is ${this.paymasterConfig.strictMode}. sending paymasterAndData 0x` + ) return { paymasterAndData: "0x", // send below values same as userOp gasLimits preVerificationGas: userOp.preVerificationGas, verificationGasLimit: userOp.verificationGasLimit, - callGasLimit: userOp.callGasLimit, - }; + callGasLimit: userOp.callGasLimit + } } - throw error; + throw error } - throw new Error("Failed to fetch feeQuote or paymaster data"); + throw new Error("Failed to fetch feeQuote or paymaster data") } /** @@ -247,40 +296,44 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD * @returns A Promise that resolves to the paymaster and data string. */ async getPaymasterAndData( - userOp: Partial<UserOperationStruct>, - paymasterServiceData?: SponsorUserOperationDto, // mode is necessary. partial context of token paymaster or verifying + _userOp: Partial<UserOperationStruct>, + paymasterServiceData?: SponsorUserOperationDto // mode is necessary. partial context of token paymaster or verifying ): Promise<PaymasterAndDataResponse> { - userOp = await this.prepareUserOperation(userOp); + const userOp = await this.prepareUserOperation(_userOp) if (paymasterServiceData?.mode === undefined) { - throw new Error("mode is required in paymasterServiceData"); + throw new Error("mode is required in paymasterServiceData") } - const mode = paymasterServiceData.mode; + const mode = paymasterServiceData.mode - const calculateGasLimits = paymasterServiceData.calculateGasLimits ?? true; + const calculateGasLimits = paymasterServiceData.calculateGasLimits ?? true - let tokenInfo = null; - let expiryDuration = null; + let tokenInfo: Record<string, string | undefined> | null = null // could make below null let smartAccountInfo = { name: "BICONOMY", - version: "2.0.0", - }; - let webhookData = null; + version: "2.0.0" + } + let webhookData: Record<string, any> | null = null + let expiryDuration: number | null = null if (mode === PaymasterMode.ERC20) { - if (!paymasterServiceData?.feeTokenAddress && paymasterServiceData?.feeTokenAddress === ADDRESS_ZERO) { - throw new Error("feeTokenAddress is required and should be non-zero"); + if ( + !paymasterServiceData?.feeTokenAddress && + paymasterServiceData?.feeTokenAddress === ADDRESS_ZERO + ) { + throw new Error("feeTokenAddress is required and should be non-zero") } tokenInfo = { - feeTokenAddress: paymasterServiceData.feeTokenAddress, - }; + feeTokenAddress: paymasterServiceData.feeTokenAddress + } } - webhookData = paymasterServiceData?.webhookData ?? webhookData; - smartAccountInfo = paymasterServiceData?.smartAccountInfo ?? smartAccountInfo; - expiryDuration = paymasterServiceData?.expiryDuration ?? expiryDuration; + webhookData = paymasterServiceData?.webhookData ?? webhookData + smartAccountInfo = + paymasterServiceData?.smartAccountInfo ?? smartAccountInfo + expiryDuration = paymasterServiceData?.expiryDuration ?? expiryDuration // Note: The idea is before calling this below rpc, userOp values presense and types should be in accordance with how we call eth_estimateUseropGas on the bundler @@ -300,34 +353,38 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD ...(tokenInfo !== null && { tokenInfo }), sponsorshipInfo: { ...(webhookData !== null && { webhookData }), - smartAccountInfo: smartAccountInfo, - }, - }, + smartAccountInfo: smartAccountInfo + } + } ], id: getTimestampInSeconds(), - jsonrpc: "2.0", - }, + jsonrpc: "2.0" + } }, - "Paymaster", - ); - - if (response && response.result) { - const paymasterAndData = response.result.paymasterAndData; - const preVerificationGas = response.result.preVerificationGas; - const verificationGasLimit = response.result.verificationGasLimit; - const callGasLimit = response.result.callGasLimit; + "Paymaster" + ) + + if (response?.result) { + const paymasterAndData = response.result.paymasterAndData + const preVerificationGas = response.result.preVerificationGas + const verificationGasLimit = response.result.verificationGasLimit + const callGasLimit = response.result.callGasLimit return { paymasterAndData: paymasterAndData, preVerificationGas: preVerificationGas, verificationGasLimit: verificationGasLimit, - callGasLimit: callGasLimit, - }; + callGasLimit: callGasLimit + } } + // biome-ignore lint/suspicious/noExplicitAny: caught error is any } catch (error: any) { - Logger.error("Error in generating paymasterAndData - reason: ", JSON.stringify(error)); - throw error; + Logger.error( + "Error in generating paymasterAndData - reason: ", + JSON.stringify(error) + ) + throw error } - throw new Error("Error in generating paymasterAndData"); + throw new Error("Error in generating paymasterAndData") } /** @@ -338,12 +395,14 @@ export class BiconomyPaymaster implements IHybridPaymaster<SponsorUserOperationD */ async getDummyPaymasterAndData( _userOp: Partial<UserOperationStruct>, - _paymasterServiceData?: SponsorUserOperationDto, // mode is necessary. partial context of token paymaster or verifying + _paymasterServiceData?: SponsorUserOperationDto // mode is necessary. partial context of token paymaster or verifying ): Promise<string> { - return "0x"; + return "0x" } - public static async create(config: PaymasterConfig): Promise<BiconomyPaymaster> { - return new BiconomyPaymaster(config); + public static async create( + config: PaymasterConfig + ): Promise<BiconomyPaymaster> { + return new BiconomyPaymaster(config) } } diff --git a/src/paymaster/index.ts b/src/paymaster/index.ts new file mode 100644 index 000000000..2cebd53f5 --- /dev/null +++ b/src/paymaster/index.ts @@ -0,0 +1,8 @@ +import { BiconomyPaymaster } from "./BiconomyPaymaster.js" +export * from "./interfaces/IPaymaster.js" +export * from "./interfaces/IHybridPaymaster.js" +export * from "./utils/Types.js" +export * from "./BiconomyPaymaster.js" + +export const Paymaster = BiconomyPaymaster +export const createPaymaster = Paymaster.create diff --git a/src/paymaster/interfaces/IHybridPaymaster.ts b/src/paymaster/interfaces/IHybridPaymaster.ts new file mode 100644 index 000000000..104029e0a --- /dev/null +++ b/src/paymaster/interfaces/IHybridPaymaster.ts @@ -0,0 +1,29 @@ +import type { UserOperationStruct } from "../../account" +import type { + BiconomyTokenPaymasterRequest, + Transaction +} from "../../account/utils/Types.js" +import type { + FeeQuotesOrDataDto, + FeeQuotesOrDataResponse, + PaymasterAndDataResponse +} from "../utils/Types.js" +import type { IPaymaster } from "./IPaymaster.js" + +export interface IHybridPaymaster<T> extends IPaymaster { + getPaymasterAndData( + _userOp: Partial<UserOperationStruct>, + _paymasterServiceData?: T + ): Promise<PaymasterAndDataResponse> + getDummyPaymasterAndData( + _userOp: Partial<UserOperationStruct>, + _paymasterServiceData?: T + ): Promise<string> + buildTokenApprovalTransaction( + _tokenPaymasterRequest: BiconomyTokenPaymasterRequest + ): Promise<Transaction> + getPaymasterFeeQuotesOrData( + _userOp: Partial<UserOperationStruct>, + _paymasterServiceData: FeeQuotesOrDataDto + ): Promise<FeeQuotesOrDataResponse> +} diff --git a/src/paymaster/interfaces/IPaymaster.ts b/src/paymaster/interfaces/IPaymaster.ts new file mode 100644 index 000000000..3aee820b2 --- /dev/null +++ b/src/paymaster/interfaces/IPaymaster.ts @@ -0,0 +1,12 @@ +import type { UserOperationStruct } from "../../account" +import type { PaymasterAndDataResponse } from "../utils/Types.js" + +export interface IPaymaster { + // Implementing class may add extra parameter (for example paymasterServiceData with it's own type) in below function signature + getPaymasterAndData( + _userOp: Partial<UserOperationStruct> + ): Promise<PaymasterAndDataResponse> + getDummyPaymasterAndData( + _userOp: Partial<UserOperationStruct> + ): Promise<string> +} diff --git a/packages/paymaster/src/utils/Constants.ts b/src/paymaster/utils/Constants.ts similarity index 83% rename from packages/paymaster/src/utils/Constants.ts rename to src/paymaster/utils/Constants.ts index 9a534ee8f..cdf1e4837 100644 --- a/packages/paymaster/src/utils/Constants.ts +++ b/src/paymaster/utils/Constants.ts @@ -1,6 +1,7 @@ -export const MAX_UINT256 = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; -export const ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; -export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; +export const MAX_UINT256 = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +export const ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" +export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" // export const ERC20_PAYMASTER_ADDRESS = '0xE9f6Ffc87cac92bc94f704AE017e85cB83DBe4EC' // likely to be same address on all chains export const ERC20_ABI = [ @@ -8,5 +9,5 @@ export const ERC20_ABI = [ "function transferFrom(address from, address to, uint256 value) external returns (bool)", "function approve(address spender, uint256 value) external returns (bool)", "function allowance(address owner, address spender) external view returns (uint256)", - "function balanceOf(address owner) external view returns (uint256)", -]; + "function balanceOf(address owner) external view returns (uint256)" +] diff --git a/packages/paymaster/src/utils/Helpers.ts b/src/paymaster/utils/Helpers.ts similarity index 77% rename from packages/paymaster/src/utils/Helpers.ts rename to src/paymaster/utils/Helpers.ts index b6f5568d2..d9aeceea9 100644 --- a/packages/paymaster/src/utils/Helpers.ts +++ b/src/paymaster/utils/Helpers.ts @@ -3,5 +3,5 @@ * @returns Number */ export const getTimestampInSeconds = (): number => { - return Math.floor(Date.now() / 1000); -}; + return Math.floor(Date.now() / 1000) +} diff --git a/src/paymaster/utils/Types.ts b/src/paymaster/utils/Types.ts new file mode 100644 index 000000000..6115a94bb --- /dev/null +++ b/src/paymaster/utils/Types.ts @@ -0,0 +1,125 @@ +export type Hex = `0x${string}` +import type { BigNumberish } from "../../account" +import type { JsonRpcError } from "../../bundler/utils/Types" + +export type PaymasterServiceErrorResponse = { + jsonrpc: string + id: number + error: JsonRpcError +} + +export type JsonRpcResponse = { + jsonrpc: string + id: number + result?: any + error?: JsonRpcError +} + +export type PaymasterConfig = { + paymasterUrl: string + strictMode?: boolean +} + +export type SponsorUserOperationDto = { + /** mode: sponsored or erc20 */ + mode: PaymasterMode + /** Always recommended, especially when using token paymaster */ + calculateGasLimits?: boolean + /** Expiry duration in seconds */ + expiryDuration?: number + /** Webhooks to be fired after user op is sent */ + webhookData?: Record<string, any> + /** Smart account meta data */ + smartAccountInfo?: SmartAccountData + /** the fee-paying token address */ + feeTokenAddress?: string +} + +export type FeeQuotesOrDataDto = { + /** mode: sponsored or erc20 */ + mode?: PaymasterMode + /** Expiry duration in seconds */ + expiryDuration?: number + /** Always recommended, especially when using token paymaster */ + calculateGasLimits?: boolean + /** List of tokens to be used for fee quotes, if ommitted fees for all supported will be returned */ + tokenList?: string[] + /** preferredToken: Can be ommitted to return all quotes */ + preferredToken?: string + /** Webhooks to be fired after user op is sent */ + webhookData?: Record<string, any> + /** Smart account meta data */ + smartAccountInfo?: SmartAccountData +} + +export type FeeQuoteParams = { + tokenList?: string[] + preferredToken?: string +} + +export type FeeTokenInfo = { + feeTokenAddress: string +} + +export type SponsorpshipInfo = { + /** Webhooks to be fired after user op is sent */ + webhookData?: Record<string, any> + /** Smart account meta data */ + smartAccountInfo: SmartAccountData +} + +export type SmartAccountData = { + /** name: Name of the smart account */ + name: string + /** version: Version of the smart account */ + version: string +} + +export type PaymasterFeeQuote = { + /** symbol: Token symbol */ + symbol: string + /** tokenAddress: Token address */ + tokenAddress: string + /** decimal: Token decimal */ + decimal: number + logoUrl?: string + /** maxGasFee: in wei */ + maxGasFee: number + /** maxGasFee: in dollars */ + maxGasFeeUSD?: number + usdPayment?: number + /** The premium paid on the token */ + premiumPercentage: number + /** validUntil: Unix timestamp */ + validUntil?: number +} + +export type FeeQuotesOrDataResponse = { + /** Array of results from the paymaster */ + feeQuotes?: PaymasterFeeQuote[] + /** Normally set to the spender in the proceeding call to send the tx */ + tokenPaymasterAddress?: Hex + /** Relevant Data returned from the paymaster */ + paymasterAndData?: Uint8Array | Hex + /* Gas overhead of this UserOperation */ + preVerificationGas?: BigNumberish + /* Actual gas used by the validation of this UserOperation */ + verificationGasLimit?: BigNumberish + /* Value used by inner account execution */ + callGasLimit?: BigNumberish +} + +export type PaymasterAndDataResponse = { + paymasterAndData: Hex + /* Gas overhead of this UserOperation */ + preVerificationGas: number + /* Actual gas used by the validation of this UserOperation */ + verificationGasLimit: number + /* Value used by inner account execution */ + callGasLimit: number +} + +export enum PaymasterMode { + ERC20 = "ERC20", + SPONSORED = "SPONSORED" +} diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts new file mode 100644 index 000000000..9d9f9847f --- /dev/null +++ b/tests/account/read.test.ts @@ -0,0 +1,705 @@ +import { JsonRpcProvider } from "@ethersproject/providers" +import { Wallet } from "@ethersproject/wallet" +import { + http, + type Hex, + createPublicClient, + createWalletClient, + encodeAbiParameters, + hashMessage, + parseAbiParameters +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { bsc } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + type BiconomySmartAccountV2Config, + DEFAULT_ENTRYPOINT_ADDRESS, + ERROR_MESSAGES, + NATIVE_TOKEN_ALIAS, + compareChainIds, + createSmartAccountClient +} from "../../src/account" +import { type UserOperationStruct, getChain } from "../../src/account" +import { BiconomyAccountAbi } from "../../src/account/abi/SmartAccount" +import { + DEFAULT_ECDSA_OWNERSHIP_MODULE, + DEFAULT_SESSION_KEY_MANAGER_MODULE, + createECDSAOwnershipValidationModule +} from "../../src/modules" +import { Paymaster } from "../../src/paymaster" +import { checkBalance, getBundlerUrl, getConfig } from "../utils" + +describe("Account: Read", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const sender = account.address + const recipient = accountTwo.address + const publicClient = createPublicClient({ + chain, + transport: http() + }) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test.concurrent( + "should accept PrivateKeyAccount as signer and sign a message", + async () => { + const account = privateKeyToAccount(`0x${privateKey}`) + + const smartAccount = await createSmartAccountClient({ + signer: account, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + + const message = "hello world" + const signature = await smartAccount.signMessage(message) + expect(signature).toBeTruthy() + }, + 50000 + ) + + test.concurrent( + "should throw if PrivateKeyAccount is used as signer and rpcUrl is not provided", + async () => { + const account = privateKeyToAccount(`0x${privateKey}`) + + const createSmartAccount = createSmartAccountClient({ + signer: account, + bundlerUrl + }) + + await expect(createSmartAccount).rejects.toThrow( + ERROR_MESSAGES.MISSING_RPC_URL + ) + }, + 50000 + ) + + test.concurrent( + "should get all modules", + async () => { + const modules = await smartAccount.getAllModules() + expect(modules).toContain(DEFAULT_SESSION_KEY_MANAGER_MODULE) // session manager module + expect(modules).toContain(DEFAULT_ECDSA_OWNERSHIP_MODULE) // ecdsa ownership module + }, + 30000 + ) + + test.concurrent( + "should check if module is enabled on the smart account", + async () => { + const isEnabled = await smartAccount.isModuleEnabled( + DEFAULT_ECDSA_OWNERSHIP_MODULE + ) + expect(isEnabled).toBeTruthy() + }, + 30000 + ) + + test.concurrent( + "should get disabled module data", + async () => { + const disableModuleData = await smartAccount.getDisableModuleData( + DEFAULT_ECDSA_OWNERSHIP_MODULE, + DEFAULT_ECDSA_OWNERSHIP_MODULE + ) + expect(disableModuleData).toBeTruthy() + }, + 30000 + ) + + test.concurrent( + "should get setup and enable module data", + async () => { + const module = await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + const initData = await module.getInitData() + const setupAndEnableModuleData = + await smartAccount.getSetupAndEnableModuleData( + DEFAULT_ECDSA_OWNERSHIP_MODULE, + initData + ) + expect(setupAndEnableModuleData).toBeTruthy() + }, + 30000 + ) + + test.concurrent( + "should create a smartAccountClient from an ethers signer", + async () => { + const ethersProvider = new JsonRpcProvider(chain.rpcUrls.default.http[0]) + const ethersSigner = new Wallet(privateKey, ethersProvider) + + const smartAccount = await createSmartAccountClient({ + signer: ethersSigner, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + const address = await smartAccount.getAccountAddress() + expect(address).toBeTruthy() + } + ) + + test.concurrent( + "should pickup the rpcUrl from viem wallet and ethers", + async () => { + const newRpcUrl = "http://localhost:8545" + const defaultRpcUrl = chain.rpcUrls.default.http[0] //http://127.0.0.1:8545" + + const ethersProvider = new JsonRpcProvider(newRpcUrl) + const ethersSignerWithNewRpcUrl = new Wallet(privateKey, ethersProvider) + + const originalEthersProvider = new JsonRpcProvider( + chain.rpcUrls.default.http[0] + ) + const ethersSigner = new Wallet(privateKey, originalEthersProvider) + + const accountOne = privateKeyToAccount(`0x${privateKey}`) + const walletClientWithNewRpcUrl = createWalletClient({ + account: accountOne, + chain, + transport: http(newRpcUrl) + }) + const [ + smartAccountFromEthersWithNewRpc, + smartAccountFromViemWithNewRpc, + smartAccountFromEthersWithOldRpc, + smartAccountFromViemWithOldRpc + ] = await Promise.all([ + createSmartAccountClient({ + chainId, + signer: ethersSignerWithNewRpcUrl, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: newRpcUrl + }), + createSmartAccountClient({ + chainId, + signer: walletClientWithNewRpcUrl, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: newRpcUrl + }), + createSmartAccountClient({ + chainId, + signer: ethersSigner, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: chain.rpcUrls.default.http[0] + }), + createSmartAccountClient({ + chainId, + signer: walletClient, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: chain.rpcUrls.default.http[0] + }) + ]) + + const [ + smartAccountFromEthersWithNewRpcAddress, + smartAccountFromViemWithNewRpcAddress, + smartAccountFromEthersWithOldRpcAddress, + smartAccountFromViemWithOldRpcAddress + ] = await Promise.all([ + smartAccountFromEthersWithNewRpc.getAccountAddress(), + smartAccountFromViemWithNewRpc.getAccountAddress(), + smartAccountFromEthersWithOldRpc.getAccountAddress(), + smartAccountFromViemWithOldRpc.getAccountAddress() + ]) + + expect( + [ + smartAccountFromEthersWithNewRpcAddress, + smartAccountFromViemWithNewRpcAddress, + smartAccountFromEthersWithOldRpcAddress, + smartAccountFromViemWithOldRpcAddress + ].every(Boolean) + ).toBeTruthy() + + expect(smartAccountFromEthersWithNewRpc.rpcProvider.transport.url).toBe( + newRpcUrl + ) + expect(smartAccountFromViemWithNewRpc.rpcProvider.transport.url).toBe( + newRpcUrl + ) + expect(smartAccountFromEthersWithOldRpc.rpcProvider.transport.url).toBe( + defaultRpcUrl + ) + expect(smartAccountFromViemWithOldRpc.rpcProvider.transport.url).toBe( + defaultRpcUrl + ) + } + ) + + test.concurrent( + "should read estimated user op gas values", + async () => { + const tx = { + to: recipient, + data: "0x" + } + + const userOp = await smartAccount.buildUserOp([tx]) + + const estimatedGas = await smartAccount.estimateUserOpGas(userOp) + expect(estimatedGas.maxFeePerGas).toBeTruthy() + expect(estimatedGas.maxPriorityFeePerGas).toBeTruthy() + expect(estimatedGas.verificationGasLimit).toBeTruthy() + expect(estimatedGas.callGasLimit).toBeTruthy() + expect(estimatedGas.preVerificationGas).toBeTruthy() + expect(estimatedGas).toHaveProperty("paymasterAndData", "0x") + }, + 30000 + ) + + test.concurrent("should have an active validation module", async () => { + const module = smartAccount.activeValidationModule + expect(module).toBeTruthy() + }) + + test.concurrent( + "should create a smart account with paymaster by creating instance", + async () => { + const paymaster = new Paymaster({ paymasterUrl }) + + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + paymaster + }) + expect(smartAccount.paymaster).not.toBeNull() + expect(smartAccount.paymaster).not.toBeUndefined() + } + ) + test.concurrent( + "should fail to create a smartAccountClient from a walletClient without a chainId", + async () => { + const account = privateKeyToAccount(generatePrivateKey()) + const viemWalletClientNoChainId = createWalletClient({ + account, + transport: http(chain.rpcUrls.default.http[0]) + }) + + expect( + await expect( + createSmartAccountClient({ + signer: viemWalletClientNoChainId, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + ).rejects.toThrow("Cannot consume a viem wallet without a chainId") + ) + } + ) + + test.concurrent( + "should fail to create a smartAccountClient from a walletClient without an account", + async () => { + const viemWalletNoAccount = createWalletClient({ + transport: http(chain.rpcUrls.default.http[0]) + }) + + expect(async () => + createSmartAccountClient({ + signer: viemWalletNoAccount, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + ).rejects.toThrow("Cannot consume a viem wallet without an account") + } + ) + + test.concurrent("should have account addresses", async () => { + const addresses = await Promise.all([ + sender, + smartAccount.getAddress(), + recipient, + smartAccountTwo.getAddress() + ]) + /* + * addresses: [ + * '0xFA66E705cf2582cF56528386Bb9dFCA119767262', // sender + * '0xe6dBb5C8696d2E0f90B875cbb6ef26E3bBa575AC', // smartAccountSender + * '0x3079B249DFDE4692D7844aA261f8cf7D927A0DA5', // recipient + * '0x5F141ee1390D4c9d033a00CB940E509A4811a5E0' // smartAccountRecipient + * ] + */ + expect(addresses.every(Boolean)).toBeTruthy() + }) + + test.concurrent( + "should create a smart account with paymaster with an api key", + async () => { + const paymaster = smartAccount.paymaster + expect(paymaster).not.toBeNull() + expect(paymaster).not.toBeUndefined() + } + ) + + test.concurrent("should not throw and error, chain ids match", async () => { + const mockBundlerUrl = + "https://bundler.biconomy.io/api/v2/80002/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44" + const mockPaymasterUrl = + "https://paymaster.biconomy.io/api/v1/80002/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + const config: BiconomySmartAccountV2Config = { + signer: walletClient, + bundlerUrl: mockBundlerUrl, + paymasterUrl: mockPaymasterUrl + } + + await expect( + compareChainIds(walletClient, config, false) + ).resolves.not.toThrow() + }) + + test.concurrent( + "should throw and error, bundlerUrl chain id and paymaster url chain id does not match with validation module", + async () => { + const mockPaymasterUrl = + "https://paymaster.biconomy.io/api/v1/1337/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + const ecdsaModule = await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + + const config: BiconomySmartAccountV2Config = { + defaultValidationModule: ecdsaModule, + activeValidationModule: ecdsaModule, + bundlerUrl, + paymasterUrl: mockPaymasterUrl + } + + await expect( + compareChainIds(walletClient, config, false) + ).rejects.toThrow() + } + ) + + test.concurrent( + "should throw and error, signer has chain id (56) and paymasterUrl has chain id (80002)", + async () => { + const mockPaymasterUrl = + "https://paymaster.biconomy.io/api/v1/80002/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + const walletClientBsc = createWalletClient({ + account: walletClient.account, + chain: bsc, + transport: http(bsc.rpcUrls.default.http[0]) + }) + + const config: BiconomySmartAccountV2Config = { + signer: walletClientBsc, + bundlerUrl, + paymasterUrl: mockPaymasterUrl + } + + await expect( + compareChainIds(walletClientBsc, config, false) + ).rejects.toThrow() + } + ) + + test.concurrent("should return chain object for chain id 1", async () => { + const chainId = 1 + const chain = getChain(chainId) + expect(chain.id).toBe(chainId) + }) + + test.concurrent("should have correct fields", async () => { + const chainId = 1 + const chain = getChain(chainId) + ;[ + "blockExplorers", + "contracts", + "fees", + "formatters", + "id", + "name", + "nativeCurrency", + "rpcUrls", + "serializers" + ].every((field) => { + expect(chain).toHaveProperty(field) + }) + }) + + test.concurrent("should throw an error, chain id not found", async () => { + const chainId = 0 + expect(() => getChain(chainId)).toThrow(ERROR_MESSAGES.CHAIN_NOT_FOUND) + }) + + test.concurrent( + "should have matching #getUserOpHash and entryPoint.getUserOpHash", + async () => { + const userOp: UserOperationStruct = { + sender: "0x".padEnd(42, "1") as string, + nonce: 2, + initCode: "0x3333", + callData: "0x4444", + callGasLimit: 5, + verificationGasLimit: 6, + preVerificationGas: 7, + maxFeePerGas: 8, + maxPriorityFeePerGas: 9, + paymasterAndData: "0xaaaaaa", + signature: "0xbbbb" + } + + const epHash = await publicClient.readContract({ + address: DEFAULT_ENTRYPOINT_ADDRESS, + abi: [ + { + inputs: [ + { + components: [ + { internalType: "address", name: "sender", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "bytes", name: "initCode", type: "bytes" }, + { internalType: "bytes", name: "callData", type: "bytes" }, + { + internalType: "uint256", + name: "callGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "verificationGasLimit", + type: "uint256" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256" + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { internalType: "bytes", name: "signature", type: "bytes" } + ], + internalType: "struct UserOperation", + name: "userOp", + type: "tuple" + } + ], + name: "getUserOpHash", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function" + } + ], + functionName: "getUserOpHash", + // @ts-ignore + args: [userOp] + }) + + const hash = await smartAccount.getUserOpHash(userOp) + expect(hash).toBe(epHash) + }, + 30000 + ) + + test.concurrent( + "should be deployed to counterfactual address", + async () => { + const accountAddress = await smartAccount.getAccountAddress() + const byteCode = await publicClient.getBytecode({ + address: accountAddress as Hex + }) + + expect(byteCode?.length).toBeGreaterThan(2) + }, + 10000 + ) + + test.concurrent( + "should check if ecdsaOwnershipModule is enabled", + async () => { + const ecdsaOwnershipModule = "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e" + + expect(ecdsaOwnershipModule).toBe( + smartAccount.activeValidationModule.getAddress() + ) + } + ) + + test.concurrent( + "should fail to deploy a smart account if no native token balance or paymaster", + async () => { + const newPrivateKey = generatePrivateKey() + const newAccount = privateKeyToAccount(newPrivateKey) + + const newViemWallet = createWalletClient({ + account: newAccount, + chain, + transport: http() + }) + + const smartAccount = await createSmartAccountClient({ + signer: newViemWallet, + paymasterUrl, + bundlerUrl + }) + + expect(async () => smartAccount.deploy()).rejects.toThrow( + ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY + ) + } + ) + + test.concurrent( + "should fail to deploy a smart account if already deployed", + async () => { + expect(async () => smartAccount.deploy()).rejects.toThrow( + ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED + ) + }, + 60000 + ) + + test.concurrent("should fetch balances for smartAccount", async () => { + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) + const [tokenBalanceFromSmartAccount] = await smartAccount.getBalances([ + token + ]) + + expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount.amount) + }) + + test.concurrent("should error if no recipient exists", async () => { + const token: Hex = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + + const txs = [ + { address: token, amount: BigInt(1), recipient: sender }, + { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + ] + + expect(async () => smartAccount.withdraw(txs)).rejects.toThrow( + ERROR_MESSAGES.NO_RECIPIENT + ) + }) + + test.concurrent( + "should error when withdraw all of native token is attempted without an amount explicitly set", + async () => { + expect(async () => smartAccount.withdraw(null, sender)).rejects.toThrow( + ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT + ) + }, + 6000 + ) + + test.concurrent( + "should check native token balance for smartAccount", + async () => { + const [ethBalanceFromSmartAccount] = await smartAccount.getBalances() + + expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n) + expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS) + expect(ethBalanceFromSmartAccount.chainId).toBe(chainId) + expect(ethBalanceFromSmartAccount.decimals).toBe(18) + }, + 60000 + ) + + test.concurrent( + "should verify a correct signature through isValidSignature", + async () => { + const eip1271MagicValue = "0x1626ba7e" + const message = "Some message from dApp" + const messageHash = hashMessage(message) + const signature = await smartAccount.signMessage(messageHash) + + const response = await publicClient.readContract({ + address: await smartAccount.getAccountAddress(), + abi: BiconomyAccountAbi, + functionName: "isValidSignature", + args: [messageHash, signature] + }) + + expect(response).toBe(eip1271MagicValue) + } + ) + + test.concurrent("should confirm that signature is not valid", async () => { + const randomPrivKey = generatePrivateKey() + const randomWallet = privateKeyToAccount(randomPrivKey) + + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl + }) + + const eip1271MagicValue = "0xffffffff" + const message = "Some message from dApp" + const messageHash = hashMessage(message) + const signature = await randomWallet.signMessage({ message: messageHash }) + const signatureWithModuleAddress = encodeAbiParameters( + parseAbiParameters("bytes, address"), + [signature, smartAccount.defaultValidationModule.getAddress()] + ) + + const response = await publicClient.readContract({ + address: await smartAccount.getAccountAddress(), + abi: BiconomyAccountAbi, + functionName: "isValidSignature", + args: [messageHash, signatureWithModuleAddress] + }) + + expect(response).toBe(eip1271MagicValue) + }) +}) diff --git a/tests/account/write.test.ts b/tests/account/write.test.ts new file mode 100644 index 000000000..c0ddadff5 --- /dev/null +++ b/tests/account/write.test.ts @@ -0,0 +1,264 @@ +import { + http, + type Hex, + createPublicClient, + createWalletClient, + encodeFunctionData, + getContract, + parseAbi +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + ERC20_ABI, + createSmartAccountClient +} from "../../src/account" +import { PaymasterMode } from "../../src/paymaster" +import { testOnlyOnOptimism } from "../setupFiles" +import { checkBalance, getConfig, nonZeroBalance, topUp } from "../utils" + +describe("Account:Write", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const sender = account.address + const recipient = accountTwo.address + const publicClient = createPublicClient({ + chain, + transport: http() + }) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test("should deploy a smart account with native token balance", async () => { + const newPrivateKey = generatePrivateKey() + const newAccount = privateKeyToAccount(newPrivateKey) + + const newViemWallet = createWalletClient({ + account: newAccount, + chain, + transport: http() + }) + + const newSmartAccount = await createSmartAccountClient({ + signer: newViemWallet, + paymasterUrl, + bundlerUrl + }) + + const newSmartAccountAddress = await newSmartAccount.getAccountAddress() + + // Setup: + await topUp(newSmartAccountAddress, BigInt(100000000000000000)) + + const balanceCheck = await checkBalance(newSmartAccountAddress) + + // Test: + const { wait } = await newSmartAccount.deploy() + const { success } = await wait() + + const byteCode = await publicClient.getBytecode({ + address: newSmartAccountAddress + }) + expect(success).toBe("true") + expect(byteCode).toBeTruthy() + }, 60000) + + testOnlyOnOptimism( + "should send some native token to a recipient on optimism", + async () => { + const balanceOfRecipient = await checkBalance(recipient) + + const { wait } = await smartAccount.sendTransaction( + { + to: recipient, + value: BigInt(1) + }, + { + simulationType: "validation_and_execution" + } + ) + + const result = await wait() + const newBalanceOfRecipient = await checkBalance(recipient) + + expect(result?.receipt?.transactionHash).toBeTruthy() + expect(result.success).toBe("true") + expect(newBalanceOfRecipient).toBeGreaterThan(balanceOfRecipient) + }, + 50000 + ) + + testOnlyOnOptimism( + "should create a smart account with paymaster with an api key on optimism", + async () => { + const paymaster = smartAccount.paymaster + expect(paymaster).not.toBeNull() + expect(paymaster).not.toBeUndefined() + } + ) + + test("should withdraw erc20 balances", async () => { + await nonZeroBalance(smartAccountAddress, token) + + const tokenBalanceOfSABefore = await checkBalance( + smartAccountAddress, + token + ) + const tokenBalanceOfRecipientBefore = await checkBalance(sender, token) + const { wait } = await smartAccount.withdraw( + [{ address: token, amount: BigInt(1), recipient: sender }], + undefined, + { + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + } + ) + + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + expect(transactionHash).toBeTruthy() + + const tokenBalanceOfSAAfter = await checkBalance(smartAccountAddress, token) + const tokenBalanceOfRecipientAfter = await checkBalance(sender, token) + + expect(tokenBalanceOfSAAfter - tokenBalanceOfSABefore).toBe(-1n) + expect(tokenBalanceOfRecipientAfter - tokenBalanceOfRecipientBefore).toBe( + 1n + ) + }, 25000) + + test("should mint an NFT and pay with ERC20 - with token", async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: [recipient] + }) + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + const balance = await checkBalance(recipient, nftAddress) + const nativeBalanceBefore = await checkBalance(smartAccountAddress) + const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) + const { wait } = await smartAccount.sendTransaction([transaction], { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken: token + } + }) + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + expect(transactionHash).toBeTruthy() + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + const nativeBalanceAfter = await checkBalance(smartAccountAddress) + expect(nativeBalanceAfter).toEqual(nativeBalanceBefore) + const tokenBalanceAfter = await checkBalance(smartAccountAddress, token) + expect(tokenBalanceAfter).toBeLessThan(tokenBalanceBefore) + const newBalance = await checkBalance(recipient, nftAddress) + expect(newBalance - balance).toBe(1n) + }, 60000) + + test("should mint an NFT and pay with ERC20 - with token selection and no maxApproval", async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: [recipient] + }) + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + const feeQuotesResponse = await smartAccount.getTokenFees(transaction, { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken: token + } + }) + const selectedFeeQuote = feeQuotesResponse.feeQuotes?.[0] + // biome-ignore lint/style/noNonNullAssertion: <explanation> + const spender = feeQuotesResponse.tokenPaymasterAddress! + const contract = getContract({ + address: token, + abi: parseAbi(ERC20_ABI), + client: publicClient + }) + + const balance = await checkBalance(recipient, nftAddress) + const nativeBalanceBefore = await checkBalance(smartAccountAddress) + const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) + const { wait } = await smartAccount.sendTransaction(transaction, { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + feeQuote: selectedFeeQuote, + spender: feeQuotesResponse.tokenPaymasterAddress + } + }) + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + expect(transactionHash).toBeTruthy() + const nativeBalanceAfter = await checkBalance(smartAccountAddress) + expect(nativeBalanceAfter).toEqual(nativeBalanceBefore) + const tokenBalanceAfter = await checkBalance(smartAccountAddress, token) + expect(tokenBalanceAfter).toBeLessThan(tokenBalanceBefore) + const newBalance = await checkBalance(recipient, nftAddress) + expect(newBalance - balance).toBe(1n) + }, 60000) +}) diff --git a/tests/bundler/read.test.ts b/tests/bundler/read.test.ts new file mode 100644 index 000000000..16b8ecf58 --- /dev/null +++ b/tests/bundler/read.test.ts @@ -0,0 +1,202 @@ +import { http, type Chain, createWalletClient } from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + type BiconomySmartAccountV2Config, + compareChainIds, + createSmartAccountClient +} from "../../src/account" +import { createBundler } from "../../src/bundler" +import { getBundlerUrl, getConfig } from "../utils" + +describe("Bundler: Read", () => { + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const recipient = accountTwo.address + + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test.concurrent( + "Should throw and give advice", + async () => { + const randomPrivateKey = generatePrivateKey() + const unfundedAccount = privateKeyToAccount(randomPrivateKey) + + const unfundedSmartAccountClient = await createSmartAccountClient({ + signer: createWalletClient({ + account: unfundedAccount, + chain, + transport: http() + }), + paymasterUrl, + bundlerUrl + }) + + await expect( + unfundedSmartAccountClient.sendTransaction({ + to: recipient, + value: 1 + }) + ).rejects.toThrow("Send some native tokens in your smart wallet") + }, + 20000 + ) + + test.concurrent( + "should parse the rpcUrl when a custom chain and bundler are used", + async () => { + const customBlastChain = { + id: 81_457, + name: "Blast", + // network: "blast", + nativeCurrency: { + decimals: 18, + name: "Ethereum", + symbol: "ETH" + }, + rpcUrls: { + public: { http: ["https://rpc.blast.io"] }, + default: { http: ["https://rpc.blast.io"] } + }, + blockExplorers: { + etherscan: { name: "Blastscan", url: "https://blastscan.io/" }, + default: { name: "Blastscan", url: "https://blastscan.io/" } + }, + contracts: { + multicall3: { + address: "0xca11bde05977b3631167028862be2a173976ca11", + blockCreated: 88_189 + } + } + } as const satisfies Chain + + const accountOne = privateKeyToAccount(`0x${privateKey}`) + + const walletClientWithCustomChain = createWalletClient({ + account: accountOne, + chain: customBlastChain, + transport: http() + }) + + const blastBundler = await createBundler({ + bundlerUrl: getBundlerUrl(customBlastChain.id), + viemChain: customBlastChain + }) + const smartAccountFromViemWithCustomChain = + await createSmartAccountClient({ + viemChain: customBlastChain, + signer: walletClientWithCustomChain, + bundler: blastBundler, + rpcUrl: customBlastChain.rpcUrls.default.http[0] + }) + + expect( + smartAccountFromViemWithCustomChain.rpcProvider.transport.url + ).toBe("https://rpc.blast.io") + expect(blastBundler.getBundlerUrl()).toBe( + getBundlerUrl(customBlastChain.id) + ) + } + ) + + test.concurrent( + "should throw an error, bundlerUrl chain id and signer chain id does not match", + async () => { + const config: BiconomySmartAccountV2Config = { + signer: walletClient, + bundlerUrl: getBundlerUrl(1337), + paymasterUrl + } + + await expect( + compareChainIds(walletClient, config, false) + ).rejects.toThrow() + } + ) + test.concurrent( + "should throw an error, bundlerUrl chainId and paymasterUrl + chainId does not match", + async () => { + const mockPaymasterUrl = + "https://paymaster.biconomy.io/api/v1/1337/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + const config: BiconomySmartAccountV2Config = { + signer: walletClient, + bundlerUrl, + paymasterUrl: mockPaymasterUrl + } + + await expect( + compareChainIds(walletClient, config, false) + ).rejects.toThrow() + } + ) + + test.concurrent( + "should throw, chain id from signer and bundlerUrl do not match", + async () => { + const createAccount = createSmartAccountClient({ + signer: walletClient, + bundlerUrl: + "https://bundler.biconomy.io/api/v2/1/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44" // mock + }) + + await expect(createAccount).rejects.toThrow() + } + ) + + test.concurrent( + "should throw, chain id from paymasterUrl and bundlerUrl do not match", + async () => { + const createAccount = createSmartAccountClient({ + signer: walletClient, + paymasterUrl: + "https://paymaster.biconomy.io/api/v1/1/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71", + bundlerUrl: + "https://bundler.biconomy.io/api/v2/80002/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44" // mock + }) + + await expect(createAccount).rejects.toThrow() + } + ) +}) diff --git a/tests/bundler/write.test.ts b/tests/bundler/write.test.ts new file mode 100644 index 000000000..a67f25e32 --- /dev/null +++ b/tests/bundler/write.test.ts @@ -0,0 +1,119 @@ +import { http, type Hex, createPublicClient, createWalletClient } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + createSmartAccountClient +} from "../../src/account" +import { createBundler } from "../../src/bundler" +import { checkBalance, getConfig, nonZeroBalance, topUp } from "../utils" + +describe("Bundler:Write", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const recipient = accountTwo.address + const publicClient = createPublicClient({ + chain, + transport: http() + }) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test("should send some native token to a recipient", async () => { + await topUp(smartAccountAddress, BigInt(1000000000000000000)) + const balanceOfRecipient = await checkBalance(recipient) + + const { wait } = await smartAccount.sendTransaction({ + to: recipient, + value: 1n + }) + + const { + receipt: { transactionHash }, + success + } = await wait(3) + + expect(success).toBe("true") + + const newBalanceOfRecipient = await checkBalance(recipient) + + expect(transactionHash).toBeTruthy() + expect(newBalanceOfRecipient - balanceOfRecipient).toBe(1n) + }, 50000) + + test("should send some native token to a recipient with a bundler instance", async () => { + await topUp(smartAccountAddress, BigInt(1000000000000000000)) + + const balanceOfRecipient = await checkBalance(recipient) + + const smartAccountClientWithBundlerInstance = + await createSmartAccountClient({ + signer: walletClient, + bundler: await createBundler({ + bundlerUrl, + userOpReceiptMaxDurationIntervals: { + [chainId]: 50000 + } + }), + paymasterUrl + }) + + const { wait } = + await smartAccountClientWithBundlerInstance.sendTransaction({ + to: recipient, + value: 1 + }) + + const { + receipt: { transactionHash }, + success + } = await wait(3) + + expect(success).toBe("true") + + const newBalanceOfRecipient = await checkBalance(recipient) + + expect(transactionHash).toBeTruthy() + expect(newBalanceOfRecipient - balanceOfRecipient).toBe(1n) + }, 70000) +}) diff --git a/tests/chains.config.ts b/tests/chains.config.ts deleted file mode 100644 index 97e453c29..000000000 --- a/tests/chains.config.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { localhost, Chain } from "viem/chains"; -import { polygonMumbai, baseSepolia, optimism } from "viem/chains"; -import { config } from "dotenv"; - -config(); - -export type SupportedTestChain = "ganache" | "baseSepolia" | "mumbai" | "optimism"; -type BaseChainConfig = { - chainId: number; - entryPointAddress: string; - bundlerUrl: string; - paymasterUrl?: string; - viemChain: Chain; - biconomyPaymasterApiKey?: string; - deploymentCost: number; - nftAddress: string; -}; -export const CHAIN_CONFIG: Record<SupportedTestChain, BaseChainConfig> = { - ganache: { // No useful bundler or paymaster tests for ganache - chainId: 1337, - entryPointAddress: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", - bundlerUrl: "https://bundler.biconomy.io/api/v2/1/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44", - viemChain: localhost, - deploymentCost: 100000000000000000, - nftAddress: "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e", - }, - baseSepolia: { - chainId: 84532, - entryPointAddress: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", - bundlerUrl: "https://bundler.biconomy.io/api/v2/84532/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44", - paymasterUrl: "https://paymaster.biconomy.io/api/v1/84532/" + process.env.E2E_BICO_PAYMASTER_KEY_BASE!, - viemChain: baseSepolia, - biconomyPaymasterApiKey: process.env.E2E_BICO_PAYMASTER_KEY_BASE!, - deploymentCost: 100000000000000000, - nftAddress: "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e", - }, - mumbai: { - chainId: 80001, - entryPointAddress: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", - bundlerUrl: "https://bundler.biconomy.io/api/v2/80001/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44", - paymasterUrl: "https://paymaster.biconomy.io/api/v1/80001/" + process.env.E2E_BICO_PAYMASTER_KEY_MUMBAI!, - viemChain: polygonMumbai, - biconomyPaymasterApiKey: process.env.E2E_BICO_PAYMASTER_KEY_MUMBAI!, - deploymentCost: 100000000000000000, - nftAddress: "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e", - }, - optimism: { - chainId: 10, - entryPointAddress: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789", - bundlerUrl: "https://bundler.biconomy.io/api/v2/10/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44", - paymasterUrl: "https://paymaster.biconomy.io/api/v1/10/" + process.env.E2E_BICO_PAYMASTER_KEY_OP!, - viemChain: optimism, - biconomyPaymasterApiKey: process.env.E2E_BICO_PAYMASTER_KEY_OP!, - deploymentCost: 100000000000000000, - nftAddress: "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e", - } -}; -export const E2E_TEST_CHAINS = [CHAIN_CONFIG.mumbai, CHAIN_CONFIG.baseSepolia, CHAIN_CONFIG.optimism]; -export const UNIT_TEST_CHAIN = CHAIN_CONFIG.ganache; - -export default CHAIN_CONFIG; \ No newline at end of file diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts new file mode 100644 index 000000000..7b2602c67 --- /dev/null +++ b/tests/globalSetup.ts @@ -0,0 +1,5 @@ +import { getConfig } from "./utils.js" + +export default function setup({ provide: _ }) { + getConfig() +} diff --git a/tests/index.d.ts b/tests/index.d.ts deleted file mode 100644 index 25e39cf50..000000000 --- a/tests/index.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Chain, Hex, PrivateKeyAccount, PublicClient, WalletClient } from "viem"; -import { WalletClientSigner } from "@alchemy/aa-core"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { Signer } from "@ethersproject/abstract-signer"; - -interface WalletProps { - alchemyWalletClientSigner: WalletClientSigner; - viemWallet: WalletClient; - balance: bigint; - publicAddress: Hex; - account: PrivateKeyAccount; - privateKey: Hex; - ethersSigner: Signer; -} - -export type TestData = { - nftAddress: Hex; - deploymentCost: number; - whale: WalletProps; - minnow: WalletProps; - publicClient: PublicClient; - chainId: number; - bundlerUrl: string; - entryPointAddress: string; - viemChain: Chain; - paymasterUrl: string; - biconomyPaymasterApiKey: string; - ethersProvider: JsonRpcProvider; -}; diff --git a/tests/modules/read.test.ts b/tests/modules/read.test.ts new file mode 100644 index 000000000..78d72affd --- /dev/null +++ b/tests/modules/read.test.ts @@ -0,0 +1,247 @@ +import { defaultAbiCoder } from "@ethersproject/abi" +import { JsonRpcProvider } from "@ethersproject/providers" +import { Wallet } from "@ethersproject/wallet" +import { + http, + createWalletClient, + encodeAbiParameters, + parseAbiParameters +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + createSmartAccountClient +} from "../../src/account" +import { + createECDSAOwnershipValidationModule, + createMultiChainValidationModule +} from "../../src/modules" +import { getConfig } from "../utils" + +describe("Modules: Read", () => { + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test.concurrent("should encode params successfully", async () => { + const hardcodedPaddedSignature = + "0x000000000000000000000000000002fbffedd9b33f4e7156f2de8d48945e74890000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d50c68705bd6897b2d17c7de32fb519fda00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000fa66e705cf2582cf56528386bb9dfca119767262000000000000000000000000da5289fcaaf71d52a80a254da614a192b693e9770000000000000000000000003079b249dfde4692d7844aa261f8cf7d927a0da500000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000000000003ca2b0ef4564d7ca7044b8c9d75685659975c0cab591408cb20e4a2ab278ab282633eb23075a8cb9bc5b01a5a4fa367b73da76821105f67a62ed7eedd335f6c0e361e73015ce4bb83439ab0742bdfed338ec39e2e8dd0819528f02be218fc1db90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007ba4a7338d7a90dfa465cf975cc6691812c3772e00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000fa66e705cf2582cf56528386bb9dfca1197672620000000000000000000000000000000000000000000000000000000000000003b91f47666ba9b0b6b2cfbb60bf39b241d269786aa01f388021057d080863dd40633eb23075a8cb9bc5b01a5a4fa367b73da76821105f67a62ed7eedd335f6c0e361e73015ce4bb83439ab0742bdfed338ec39e2e8dd0819528f02be218fc1db90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004173c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b00000000000000000000000000000000000000000000000000000000000000" + + const sessionKeyManagerAddress = + "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489" + const mockEcdsaSessionKeySig = + "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b" + const sessionDataTupleArray = [ + [ + 0n, + 0n, + "0x000000d50c68705bd6897b2d17c7de32fb519fda", + "0x000000000000000000000000fa66e705cf2582cf56528386bb9dfca119767262000000000000000000000000da5289fcaaf71d52a80a254da614a192b693e9770000000000000000000000003079b249dfde4692d7844aa261f8cf7d927a0da50000000000000000000000000000000000000000000000000000000000989680", + [ + "0xca2b0ef4564d7ca7044b8c9d75685659975c0cab591408cb20e4a2ab278ab282", + "0x633eb23075a8cb9bc5b01a5a4fa367b73da76821105f67a62ed7eedd335f6c0e", + "0x361e73015ce4bb83439ab0742bdfed338ec39e2e8dd0819528f02be218fc1db9" + ], + "0x" + ], + [ + 0n, + 0n, + "0x7ba4a7338d7a90dfa465cf975cc6691812c3772e", + "0x000000000000000000000000fa66e705cf2582cf56528386bb9dfca119767262", + [ + "0xb91f47666ba9b0b6b2cfbb60bf39b241d269786aa01f388021057d080863dd40", + "0x633eb23075a8cb9bc5b01a5a4fa367b73da76821105f67a62ed7eedd335f6c0e", + "0x361e73015ce4bb83439ab0742bdfed338ec39e2e8dd0819528f02be218fc1db9" + ], + "0x" + ] + ] + + const paddedSignature = defaultAbiCoder.encode( + [ + "address", + "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", + "bytes" + ], + [sessionKeyManagerAddress, sessionDataTupleArray, mockEcdsaSessionKeySig] + ) + + const abiParameters = [ + { type: "address" }, + { + type: "tuple[]", + components: [ + { type: "uint48" }, + { type: "uint48" }, + { type: "address" }, + { type: "bytes" }, + { type: "bytes32[]" }, + { type: "bytes" } + ] + }, + { type: "bytes" } + ] + + const paddedSignatureWithViem = encodeAbiParameters(abiParameters, [ + sessionKeyManagerAddress, + sessionDataTupleArray, + mockEcdsaSessionKeySig + ]) + + expect(paddedSignature).toEqual(hardcodedPaddedSignature) + expect(paddedSignatureWithViem).toEqual(hardcodedPaddedSignature) + }) + + test.concurrent( + "should create a ECDSAOwnershipValidationModule with signer", + async () => { + const defaultValidationModule = + await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + // Should not require a signer or chainId + const smartAccount = await createSmartAccountClient({ + bundlerUrl, + defaultValidationModule, + signer: walletClient + }) + const address = await smartAccount.getAccountAddress() + expect(address).toBeTruthy() + expect(smartAccount.activeValidationModule).toEqual( + defaultValidationModule + ) + } + ) + + test.concurrent( + "should create a ECDSAOwnershipValidationModule without signer", + async () => { + const defaultValidationModule = + await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + // Should not require a signer or chainId + const smartAccount = await createSmartAccountClient({ + bundlerUrl, + defaultValidationModule + }) + const address = await smartAccount.getAccountAddress() + expect(address).toBeTruthy() + expect(smartAccount.activeValidationModule).toEqual( + defaultValidationModule + ) + } + ) + + test.concurrent( + "should create a ECDSAOwnershipValidationModule by default, without explicitly setting it on the smart account", + async () => { + const defaultValidationModule = + await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + const smartAccount = await createSmartAccountClient({ + bundlerUrl, + signer: walletClient + }) + const address = await smartAccount.getAccountAddress() + expect(address).toBeTruthy() + const smartAccountValidationModuleAddress = + await smartAccount.activeValidationModule.getAddress() + expect(smartAccountValidationModuleAddress).toEqual( + defaultValidationModule.moduleAddress + ) + } + ) + + test.concurrent( + "should create a MultiChainValidationModule from an ethers signer using convertSigner", + async () => { + const ethersProvider = new JsonRpcProvider(chain.rpcUrls.default.http[0]) + const ethersSigner = new Wallet(privateKey, ethersProvider) + + const defaultValidationModule = await createMultiChainValidationModule({ + signer: ethersSigner + }) + // Should not require a signer or chainId + const newSmartAccount = await createSmartAccountClient({ + bundlerUrl, + defaultValidationModule, + rpcUrl: chain.rpcUrls.default.http[0] + }) + + const address = await newSmartAccount.getAccountAddress() + expect(address).toBeTruthy() + // expect the relevant module to be set + expect(newSmartAccount.activeValidationModule).toEqual( + defaultValidationModule + ) + }, + 50000 + ) + + test.concurrent( + "should create a ECDSAOwnershipValidationModule from a viem signer using convertSigner", + async () => { + const defaultValidationModule = + await createECDSAOwnershipValidationModule({ + signer: walletClient + }) + // Should not require a signer or chainId + const smartAccount = await createSmartAccountClient({ + bundlerUrl, + defaultValidationModule, + rpcUrl: chain.rpcUrls.default.http[0] + }) + const address = await smartAccount.getAccountAddress() + expect(address).toBeTruthy() + // expect the relevant module to be set + expect(smartAccount.activeValidationModule).toEqual( + defaultValidationModule + ) + }, + 50000 + ) +}) diff --git a/tests/modules/write.test.ts b/tests/modules/write.test.ts new file mode 100644 index 000000000..37e498fe5 --- /dev/null +++ b/tests/modules/write.test.ts @@ -0,0 +1,585 @@ +import { + http, + type Hex, + createPublicClient, + createWalletClient, + encodeAbiParameters, + encodeFunctionData, + pad, + parseAbi, + parseEther, + parseUnits, + slice, + toFunctionSelector +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + type Transaction, + type WalletClientSigner, + createSmartAccountClient +} from "../../src/account" +import { Logger, getChain } from "../../src/account" +import { + DEFAULT_BATCHED_SESSION_ROUTER_MODULE, + DEFAULT_MULTICHAIN_MODULE, + DEFAULT_SESSION_KEY_MANAGER_MODULE, + createBatchedSessionRouterModule, + createMultiChainValidationModule, + createSessionKeyManagerModule +} from "../../src/modules" +import { SessionMemoryStorage } from "../../src/modules/session-storage/SessionMemoryStorage" +import { getABISVMSessionKeyData } from "../../src/modules/utils/Helper" +import { PaymasterMode } from "../../src/paymaster" +import { checkBalance, getBundlerUrl, getConfig, topUp } from "../utils" + +describe("Modules:Write", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl, + paymasterUrlTwo + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const publicClient = createPublicClient({ + chain, + transport: http() + }) + + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test("should enable session module", async () => { + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + paymasterUrl + }) + + const isSessionKeyEnabled = await smartAccount.isModuleEnabled( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + + if (!isSessionKeyEnabled) { + const tx = await smartAccount.getEnableModuleData( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + const { wait } = await smartAccount.sendTransaction(tx, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + expect(success).toBe("true") + } + }, 50000) + + test.skip("should use MultichainValidationModule to mint an NFT on two chains with sponsorship", async () => { + const nftAddress: Hex = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const recipientForBothChains = walletClient.account.address + + const chainIdBase = 84532 + const bundlerUrlBase = getBundlerUrl(chainIdBase) + + const signerBase = createWalletClient({ + account: privateKeyToAccount(`0x${privateKey}`), + chain: getChain(84532), + transport: http() + }) + + const paymasterUrlBase = paymasterUrlTwo + + const multiChainModule = await createMultiChainValidationModule({ + signer: walletClient, + moduleAddress: DEFAULT_MULTICHAIN_MODULE + }) + + const [polygonAccount, baseAccount] = await Promise.all([ + createSmartAccountClient({ + chainId, + signer: walletClient, + bundlerUrl, + defaultValidationModule: multiChainModule, + activeValidationModule: multiChainModule, + paymasterUrl + }), + createSmartAccountClient({ + chainId: chainIdBase, + signer: signerBase, + bundlerUrl: bundlerUrlBase, + defaultValidationModule: multiChainModule, + activeValidationModule: multiChainModule, + paymasterUrl: paymasterUrlBase + }) + ]) + + // Check if the smart account has been deployed + const [isPolygonDeployed, isBaseDeployed] = await Promise.all([ + polygonAccount.isAccountDeployed(), + baseAccount.isAccountDeployed() + ]) + if (!isPolygonDeployed) { + const { wait } = await polygonAccount.deploy({ + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + expect(success).toBe("true") + } + if (!isBaseDeployed) { + const { wait } = await baseAccount.deploy({ + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + expect(success).toBe("true") + } + + const moduleEnabled1 = await polygonAccount.isModuleEnabled( + DEFAULT_MULTICHAIN_MODULE + ) + const moduleActive1 = polygonAccount.activeValidationModule + expect(moduleEnabled1).toBeTruthy() + expect(moduleActive1.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE) + + const moduleEnabled2 = await baseAccount.isModuleEnabled( + DEFAULT_MULTICHAIN_MODULE + ) + const moduleActive2 = polygonAccount.activeValidationModule + expect(moduleEnabled2).toBeTruthy() + expect(moduleActive2.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE) + + const encodedCall = encodeFunctionData({ + abi: parseAbi([ + "function safeMint(address owner) view returns (uint balance)" + ]), + functionName: "safeMint", + args: [recipientForBothChains] + }) + + const transaction = { + to: nftAddress, + data: encodedCall + } + + const [partialUserOp1, partialUserOp2] = await Promise.all([ + baseAccount.buildUserOp([transaction], { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }), + polygonAccount.buildUserOp([transaction], { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + ]) + + expect(partialUserOp1.paymasterAndData).not.toBe("0x") + expect(partialUserOp2.paymasterAndData).not.toBe("0x") + + // Sign the user ops using multiChainModule + const returnedOps = await multiChainModule.signUserOps([ + { userOp: partialUserOp1, chainId: chainIdBase }, + { userOp: partialUserOp2, chainId } + ]) + + // Send the signed user ops on both chains + const userOpResponse1 = await baseAccount.sendSignedUserOp( + returnedOps[0] as any + ) + const userOpResponse2 = await polygonAccount.sendSignedUserOp( + returnedOps[1] as any + ) + + Logger.log(userOpResponse1.userOpHash, "MULTICHAIN BASE USER OP HASH") + Logger.log(userOpResponse2.userOpHash, "MULTICHAIN POLYGON USER OP HASH") + + expect(userOpResponse1.userOpHash).toBeTruthy() + expect(userOpResponse2.userOpHash).toBeTruthy() + + const { success: success1 } = await userOpResponse1.wait() + const { success: success2 } = await userOpResponse2.wait() + + expect(success1).toBe("true") + expect(success2).toBe("true") + }, 50000) + + test("should use SessionValidationModule to send a user op", async () => { + let sessionSigner: WalletClientSigner + const sessionKeyEOA = walletClient.account.address + const recipient = walletClientTwo.account.address + + // Create smart account + let smartAccount = await createSmartAccountClient({ + chainId, + signer: walletClient, + bundlerUrl, + paymasterUrl, + index: 5 // Increasing index to not conflict with other test cases and use a new smart account + }) + const accountAddress = await smartAccount.getAccountAddress() + const sessionMemoryStorage: SessionMemoryStorage = new SessionMemoryStorage( + accountAddress + ) + // First we need to check if smart account is deployed + // if not deployed, send an empty transaction to deploy it + const isDeployed = await smartAccount.isAccountDeployed() + Logger.log("session", { isDeployed }) + if (!isDeployed) { + const { wait } = await smartAccount.deploy({ + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + expect(success).toBe("true") + } + + try { + sessionSigner = await sessionMemoryStorage.getSignerByKey(sessionKeyEOA) + } catch (error) { + sessionSigner = await sessionMemoryStorage.addSigner({ + pbKey: sessionKeyEOA, + pvKey: `0x${privateKey}`, + chainId: chain + }) + } + + expect(sessionSigner).toBeTruthy() + // Create session module + const sessionModule = await createSessionKeyManagerModule({ + moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE, + smartAccountAddress: await smartAccount.getAddress(), + sessionStorageClient: sessionMemoryStorage + }) + const functionSelector = slice( + toFunctionSelector("safeMint(address)"), + 0, + 4 + ) + // Set enabled call on session + const sessionKeyData = await getABISVMSessionKeyData(sessionKeyEOA as Hex, { + destContract: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0" as Hex, // nft address + functionSelector: functionSelector, + valueLimit: parseEther("0"), + rules: [ + { + offset: 0, // offset 0 means we are checking first parameter of safeMint (recipient address) + condition: 0, // 0 = Condition.EQUAL + referenceValue: pad("0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", { + size: 32 + }) // recipient address + } + ] + }) + const abiSvmAddress = "0x000006bC2eCdAe38113929293d241Cf252D91861" + const sessionTxData = await sessionModule.createSessionData([ + { + validUntil: 0, + validAfter: 0, + sessionValidationModule: abiSvmAddress, + sessionPublicKey: sessionKeyEOA as Hex, + sessionKeyData: sessionKeyData as Hex + } + ]) + const setSessionAllowedTrx = { + to: DEFAULT_SESSION_KEY_MANAGER_MODULE, + data: sessionTxData.data + } + const txArray: any = [] + // Check if module is enabled + const isEnabled = await smartAccount.isModuleEnabled( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + if (!isEnabled) { + const enableModuleTrx = await smartAccount.getEnableModuleData( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + txArray.push(enableModuleTrx) + txArray.push(setSessionAllowedTrx) + } else { + Logger.log("MODULE ALREADY ENABLED") + txArray.push(setSessionAllowedTrx) + } + const userOp = await smartAccount.buildUserOp(txArray, { + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + }) + const userOpResponse1 = await smartAccount.sendUserOp(userOp) + const transactionDetails = await userOpResponse1.wait() + expect(transactionDetails.success).toBe("true") + Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash) + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: ["0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549"] + }) + const nftMintTx = { + to: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0", + data: encodedCall + } + smartAccount = smartAccount.setActiveValidationModule(sessionModule) + const maticBalanceBefore = await checkBalance(smartAccountAddress) + const userOpResponse2 = await smartAccount.sendTransaction(nftMintTx, { + params: { + sessionSigner: sessionSigner, + sessionValidationModule: abiSvmAddress + }, + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + }) + expect(userOpResponse2.userOpHash).toBeTruthy() + expect(userOpResponse2.userOpHash).not.toBeNull() + const maticBalanceAfter = await checkBalance(smartAccountAddress) + expect(maticBalanceAfter).toEqual(maticBalanceBefore) + Logger.log( + `Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai` + ) + }, 60000) + + test("should enable batched module", async () => { + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + paymasterUrl + }) + + const isBRMenabled = await smartAccount.isModuleEnabled( + DEFAULT_BATCHED_SESSION_ROUTER_MODULE + ) + + if (!isBRMenabled) { + const tx = await smartAccount.getEnableModuleData( + DEFAULT_BATCHED_SESSION_ROUTER_MODULE + ) + const { wait } = await smartAccount.sendTransaction(tx, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + expect(success).toBe("true") + } + }, 50000) + + test.skip("should use BatchedSessionValidationModule to send a user op", async () => { + let sessionSigner: WalletClientSigner + const sessionKeyEOA = walletClient.account.address + const recipient = walletClientTwo.account.address + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + + let smartAccount = await createSmartAccountClient({ + chainId, + signer: walletClient, + bundlerUrl, + paymasterUrl, + index: 6 // Increasing index to not conflict with other test cases and use a new smart account + }) + + // const accountAddress = await smartAccount.getAccountAddress() + const smartAccountAddress = await smartAccount.getAddress() + await topUp(smartAccountAddress, undefined, token) + await topUp(smartAccountAddress, undefined) + + const sessionMemoryStorage: SessionMemoryStorage = new SessionMemoryStorage( + smartAccountAddress + ) + + try { + sessionSigner = await sessionMemoryStorage.getSignerByKey(sessionKeyEOA) + } catch (error) { + sessionSigner = await sessionMemoryStorage.addSigner({ + pbKey: sessionKeyEOA, + pvKey: `0x${privateKey}`, + chainId: chain + }) + } + + expect(sessionSigner).toBeTruthy() + const sessionModule = await createSessionKeyManagerModule({ + moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE, + smartAccountAddress, + sessionStorageClient: sessionMemoryStorage + }) + // Create batched session module + const batchedSessionModule = await createBatchedSessionRouterModule({ + moduleAddress: DEFAULT_BATCHED_SESSION_ROUTER_MODULE, + smartAccountAddress, + sessionKeyManagerModule: sessionModule + }) + + // Set enabled call on session, only allows calling USDC contract transfer with <= 10 USDC + const sessionKeyData = encodeAbiParameters( + [ + { type: "address" }, + { type: "address" }, + { type: "address" }, + { type: "uint256" } + ], + [ + sessionKeyEOA, + token, // erc20 token address + recipient, // receiver address + parseUnits("10", 6) + ] + ) + // only requires that the caller is the session key + // can call anything using the mock session module + const sessionKeyData2 = encodeAbiParameters( + [{ type: "address" }], + [sessionKeyEOA] + ) + const erc20ModuleAddr = "0x000000D50C68705bd6897B2d17c7de32FB519fDA" + const mockSessionModuleAddr = "0x7Ba4a7338D7A90dfA465cF975Cc6691812C3772E" + const sessionTxData = await batchedSessionModule.createSessionData([ + { + validUntil: 0, + validAfter: 0, + sessionValidationModule: erc20ModuleAddr, + sessionPublicKey: sessionKeyEOA, + sessionKeyData: sessionKeyData + }, + { + validUntil: 0, + validAfter: 0, + sessionValidationModule: mockSessionModuleAddr, + sessionPublicKey: sessionKeyEOA, + sessionKeyData: sessionKeyData2 + } + ]) + + const setSessionAllowedTrx = { + to: DEFAULT_SESSION_KEY_MANAGER_MODULE, + data: sessionTxData.data + } + + const isDeployed = await smartAccount.isAccountDeployed() + if (!isDeployed) { + const { wait } = await smartAccount.deploy() + const { success } = await wait() + expect(success).toBe("true") + } + + const txArray: Transaction[] = [] + // Check if session module is enabled + const isEnabled = await smartAccount.isModuleEnabled( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + if (!isEnabled) { + const enableModuleTrx = await smartAccount.getEnableModuleData( + DEFAULT_SESSION_KEY_MANAGER_MODULE + ) + txArray.push(enableModuleTrx) + } + // Check if batched session module is enabled + const isBRMenabled = await smartAccount.isModuleEnabled( + DEFAULT_BATCHED_SESSION_ROUTER_MODULE + ) + if (!isBRMenabled) { + // -----> enableModule batched session router module + const tx2 = await smartAccount.getEnableModuleData( + DEFAULT_BATCHED_SESSION_ROUTER_MODULE + ) + txArray.push(tx2) + } + txArray.push(setSessionAllowedTrx) + const userOpResponse1 = await smartAccount.sendTransaction(txArray, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) // this user op will enable the modules and setup session allowed calls + const transactionDetails = await userOpResponse1.wait() + expect(transactionDetails.success).toBe("true") + Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash) + + const usdcBalance = await checkBalance(smartAccountAddress, token) + const nativeTokenBalance = await checkBalance(smartAccountAddress) + + console.log({ usdcBalance, nativeTokenBalance }) + + expect(usdcBalance).toBeGreaterThan(0) + smartAccount = smartAccount.setActiveValidationModule(batchedSessionModule) + // WARNING* If the smart account does not have enough USDC, user op execution will FAIL + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function transfer(address _to, uint256 _value)"]), + functionName: "transfer", + args: [recipient, parseUnits("0.001", 6)] + }) + const encodedCall2 = encodeFunctionData({ + abi: parseAbi(["function transfer(address _to, uint256 _value)"]), + functionName: "transfer", + args: [ + "0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", + parseUnits("0.001", 6) + ] + }) + const transferTx = { + to: "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a", + data: encodedCall + } + const transferTx2 = { + to: "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a", + data: encodedCall2 + } + const activeModule = smartAccount.activeValidationModule + expect(activeModule).toEqual(batchedSessionModule) + const maticBalanceBefore = await checkBalance(smartAccountAddress) + // failing with dummyTx because of invalid sessionKeyData + const userOpResponse2 = await smartAccount.sendTransaction( + [transferTx, transferTx2], + { + params: { + batchSessionParams: [ + { + sessionSigner: walletClient, + sessionValidationModule: erc20ModuleAddr + }, + { + sessionSigner: walletClient, + sessionValidationModule: mockSessionModuleAddr + } + ] + }, + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + } + ) + const receipt = await userOpResponse2.wait() + console.log(receipt.userOpHash, "Batched user op hash") + expect(receipt.success).toBe("true") + expect(userOpResponse2.userOpHash).toBeTruthy() + expect(userOpResponse2.userOpHash).not.toBeNull() + const maticBalanceAfter = await checkBalance(smartAccountAddress) + expect(maticBalanceAfter).toEqual(maticBalanceBefore) + Logger.log( + `Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai` + ) + }, 60000) +}) diff --git a/tests/paymaster/read.test.ts b/tests/paymaster/read.test.ts new file mode 100644 index 000000000..a57af2d4d --- /dev/null +++ b/tests/paymaster/read.test.ts @@ -0,0 +1,145 @@ +import { + http, + type Hex, + createPublicClient, + createWalletClient, + encodeFunctionData, + parseAbi +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + ERROR_MESSAGES, + createSmartAccountClient +} from "../../src/account" +import { + type FeeQuotesOrDataResponse, + PaymasterMode +} from "../../src/paymaster" +import { getConfig } from "../utils" + +describe.skip("Paymaster: Read", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const sender = account.address + const recipient = accountTwo.address + const publicClient = createPublicClient({ + chain, + transport: http() + }) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test.concurrent( + "should expect several feeQuotes in resonse to empty tokenInfo fields", + async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: [recipient] + }) + + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + + const feeQuotesResponse = await smartAccount.getTokenFees(transaction, { + paymasterServiceData: { mode: PaymasterMode.ERC20 } + }) + + expect(feeQuotesResponse.feeQuotes?.length).toBeGreaterThan(1) + } + ) + + test.concurrent( + "should get supported tokens from the paymaster", + async () => { + const tokens = await smartAccount.getSupportedTokens() + + expect(tokens.length).toBeGreaterThan(0) + expect(tokens[0]).toHaveProperty("tokenAddress") + expect(tokens[0]).toHaveProperty("symbol") + expect(tokens[0]).toHaveProperty("decimal") + expect(tokens[0]).toHaveProperty("premiumPercentage") + expect(tokens[0]).toHaveProperty("logoUrl") + }, + 60000 + ) + + test.concurrent( + "should throw and error if missing field for ERC20 Paymaster user op", + async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: [recipient] + }) + + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + + const feeQuotesResponse: FeeQuotesOrDataResponse = + await smartAccount.getTokenFees(transaction, { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken: "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + } + }) + + expect(async () => + smartAccount.sendTransaction(transaction, { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + feeQuote: feeQuotesResponse.feeQuotes?.[0] + }, + simulationType: "validation" + }) + ).rejects.toThrow(ERROR_MESSAGES.SPENDER_REQUIRED) + }, + 60000 + ) +}) diff --git a/tests/paymaster/write.test.ts b/tests/paymaster/write.test.ts new file mode 100644 index 000000000..cb1170318 --- /dev/null +++ b/tests/paymaster/write.test.ts @@ -0,0 +1,303 @@ +import { + http, + type Hex, + createPublicClient, + createWalletClient, + encodeFunctionData, + parseAbi +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type BiconomySmartAccountV2, + NATIVE_TOKEN_ALIAS, + createSmartAccountClient +} from "../../src/account" +import { PaymasterMode } from "../../src/paymaster" +import { testOnlyOnOptimism } from "../setupFiles" +import { checkBalance, getConfig, nonZeroBalance, topUp } from "../utils" + +describe("Paymaster:Write", () => { + const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const { + chain, + chainId, + privateKey, + privateKeyTwo, + bundlerUrl, + paymasterUrl + } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const accountTwo = privateKeyToAccount(`0x${privateKeyTwo}`) + const sender = account.address + const recipient = accountTwo.address + const publicClient = createPublicClient({ + chain, + transport: http() + }) + let [smartAccount, smartAccountTwo]: BiconomySmartAccountV2[] = [] + let [smartAccountAddress, smartAccountAddressTwo]: Hex[] = [] + + const [walletClient, walletClientTwo] = [ + createWalletClient({ + account, + chain, + transport: http() + }), + createWalletClient({ + account: accountTwo, + chain, + transport: http() + }) + ] + + beforeAll(async () => { + ;[smartAccount, smartAccountTwo] = await Promise.all( + [walletClient, walletClientTwo].map((client) => + createSmartAccountClient({ + chainId, + signer: client, + bundlerUrl, + paymasterUrl + }) + ) + ) + ;[smartAccountAddress, smartAccountAddressTwo] = await Promise.all( + [smartAccount, smartAccountTwo].map((account) => + account.getAccountAddress() + ) + ) + }) + + test("should mint an NFT with sponsorship", async () => { + await nonZeroBalance(smartAccountAddress) + + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address to) public"]), + functionName: "safeMint", + args: [recipient] + }) + + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + + const balance = await checkBalance(recipient, nftAddress) + const maticBalanceBefore = await checkBalance(smartAccountAddress) + + const response = await smartAccount.sendTransaction(transaction, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + simulationType: "validation" + }) + + const userOpReceipt = await response.wait(3) + expect(userOpReceipt.userOpHash).toBeTruthy() + expect(userOpReceipt.success).toBe("true") + + const maticBalanceAfter = await checkBalance(smartAccountAddress) + + expect(maticBalanceAfter).toEqual(maticBalanceBefore) + + const newBalance = (await checkBalance(recipient, nftAddress)) as bigint + + expect(newBalance - balance).toBe(1n) + }, 60000) + + test("should deploy a smart account with sponsorship", async () => { + const newPrivateKey = generatePrivateKey() + const newAccount = privateKeyToAccount(newPrivateKey) + + const newViemWallet = createWalletClient({ + account: newAccount, + chain, + transport: http() + }) + + const smartAccount = await createSmartAccountClient({ + signer: newViemWallet, + paymasterUrl, + bundlerUrl + }) + + const smartAccountAddress = await smartAccount.getAccountAddress() + const balance = await publicClient.getBalance({ + address: smartAccountAddress + }) + expect(balance).toBe(0n) + + const { wait } = await smartAccount.deploy({ + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + }) + const { success } = await wait() + + const byteCode = await publicClient.getBytecode({ + address: smartAccountAddress + }) + expect(success).toBe("true") + expect(byteCode).toBeTruthy() + }, 60000) + + test("should withdraw nativeToken with sponsorship", async () => { + await nonZeroBalance(smartAccountAddress) + + const balanceOfSABefore = await checkBalance(smartAccountAddress) + const balanceOfRecipientBefore = await checkBalance(sender) + + const { wait } = await smartAccount.withdraw( + [ + { + address: NATIVE_TOKEN_ALIAS, + amount: BigInt(1), + recipient: sender + } + ], + null, + { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + } + ) + + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + expect(transactionHash).toBeTruthy() + + const balanceOfSAAfter = await checkBalance(smartAccountAddress) + const balanceOfRecipientAfter = await checkBalance(sender) + + expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n) + expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n) + }, 25000) + + testOnlyOnOptimism( + "should mint an NFT on optimism with sponsorship", + async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address to) public"]), + functionName: "safeMint", + args: [recipient] + }) + + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + + const balance = await checkBalance(recipient, nftAddress) + + const maticBalanceBefore = await checkBalance(smartAccountAddress) + + const response = await smartAccount.sendTransaction(transaction, { + paymasterServiceData: { mode: PaymasterMode.SPONSORED }, + simulationType: "validation_and_execution" + }) + + const userOpReceipt = await response.wait(3) + expect(userOpReceipt.userOpHash).toBeTruthy() + expect(userOpReceipt.success).toBe("true") + + const maticBalanceAfter = await checkBalance(smartAccountAddress) + expect(maticBalanceAfter).toEqual(maticBalanceBefore) + const newBalance = (await checkBalance(recipient, nftAddress)) as bigint + + expect(newBalance - balance).toBe(1n) + }, + 50000 + ) + + test("should withdraw nativeToken and an erc20 token", async () => { + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + + await nonZeroBalance(smartAccountAddress, token) + await nonZeroBalance(smartAccountAddress) + + const balanceOfSABefore = await checkBalance(smartAccountAddress) + const balanceOfRecipientBefore = await checkBalance(sender) + const tokenBalanceOfSABefore = await checkBalance( + smartAccountAddress, + token + ) + const tokenBalanceOfRecipientBefore = await checkBalance(sender, token) + + const { wait } = await smartAccount.withdraw( + [ + { address: token, amount: BigInt(1) }, + { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + ], + sender, + { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } + } + ) + + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + expect(transactionHash).toBeTruthy() + + const balanceOfSAAfter = await checkBalance(smartAccountAddress) + const balanceOfRecipientAfter = await checkBalance(sender) + const tokenBalanceOfSAAfter = await checkBalance(smartAccountAddress, token) + const tokenBalanceOfRecipientAfter = await checkBalance(sender, token) + + expect(balanceOfSABefore - balanceOfSAAfter).toBe(1n) + expect(balanceOfRecipientAfter - balanceOfRecipientBefore).toBe(1n) + + expect(tokenBalanceOfSAAfter - tokenBalanceOfSABefore).toBe(-1n) + expect(tokenBalanceOfRecipientAfter - tokenBalanceOfRecipientBefore).toBe( + 1n + ) + }, 60000) + + test("should withdraw all native token", async () => { + await nonZeroBalance(smartAccountAddress) + const balanceOfSABefore = await checkBalance(smartAccountAddress) + const balanceOfRecipientBefore = await checkBalance(sender) + + const { wait } = await smartAccount.withdraw( + [] /* null or undefined or [] */, + sender, + { + paymasterServiceData: { mode: PaymasterMode.SPONSORED } // Will leave no dust + } + ) + + const { + receipt: { transactionHash }, + userOpHash, + success + } = await wait() + + expect(userOpHash).toBeTruthy() + expect(success).toBe("true") + expect(transactionHash).toBeTruthy() + + const balanceOfSAAfter = await checkBalance(smartAccountAddress) + const balanceOfRecipientAfter = await checkBalance(sender) + + expect(balanceOfSAAfter).toBe(0n) + expect(balanceOfRecipientAfter).toBe( + balanceOfSABefore + balanceOfRecipientBefore + ) + + // Teardown: send back the native token to the smart account + const teardownHash = await walletClient.sendTransaction({ + to: smartAccountAddress, + value: balanceOfSABefore, + account, + chain + }) + expect(teardownHash).toBeTruthy() + }, 60000) +}) diff --git a/tests/setup-e2e-tests.ts b/tests/setup-e2e-tests.ts deleted file mode 100644 index 4d3d8af77..000000000 --- a/tests/setup-e2e-tests.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { createWalletClient, http, createPublicClient } from "viem"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { Wallet } from "@ethersproject/wallet"; -import { privateKeyToAccount } from "viem/accounts"; -import { WalletClientSigner } from "@alchemy/aa-core"; -import { config } from "dotenv"; -import { E2E_TEST_CHAINS } from "./chains.config"; - -config(); - -beforeAll(async () => { - envVarCheck(); - - const privateKeyOne: `0x${string}` = `0x${process.env.E2E_PRIVATE_KEY_ONE}`; - const privateKeyTwo: `0x${string}` = `0x${process.env.E2E_PRIVATE_KEY_TWO}`; - const walletOne = privateKeyToAccount(privateKeyOne); - const walletTwo = privateKeyToAccount(privateKeyTwo); - - const promises = E2E_TEST_CHAINS.map((chain) => { - const ethersProvider = new JsonRpcProvider(chain.viemChain.rpcUrls.default.http[0]); - const ethersSignerOne = new Wallet(privateKeyOne, ethersProvider); - const ethersSignerTwo = new Wallet(privateKeyTwo, ethersProvider); - - const publicClient = createPublicClient({ - chain: chain.viemChain, - transport: http(), - }); - - const viemWalletClientOne = createWalletClient({ - account: walletOne, - chain: chain.viemChain, - transport: http(chain.viemChain.rpcUrls.default.http[0]), - }); - const viemWalletClientTwo = createWalletClient({ - account: walletTwo, - chain: chain.viemChain, - transport: http(chain.viemChain.rpcUrls.default.http[0]), - }); - const walletClientSignerOne = new WalletClientSigner(viemWalletClientOne, "viem"); - const walletClientSignerTwo = new WalletClientSigner(viemWalletClientTwo, "viem"); - - return Promise.all([ - Promise.all([ - { - ...chain, - publicClient, - account: walletOne, - publicAddress: walletOne.address, - viemWallet: viemWalletClientOne, - alchemyWalletClientSigner: walletClientSignerOne, - ethersProvider, - ethersSigner: ethersSignerOne, - privateKey: privateKeyOne, - }, - publicClient.getBalance({ - address: walletOne.address, - }), - ]), - Promise.all([ - { - ...chain, - publicClient, - account: walletTwo, - publicAddress: walletTwo.address, - viemWallet: viemWalletClientTwo, - alchemyWalletClientSigner: walletClientSignerTwo, - ethersProvider, - ethersSigner: ethersSignerTwo, - privateKey: privateKeyTwo, - }, - publicClient.getBalance({ - address: walletTwo.address, - }), - ]), - ]); - }); - const balancesPerChain = await Promise.all(promises); - - // @ts-ignore - testDataPerChain = balancesPerChain.map((dataAndBalanceArray) => { - const sortedBalances = dataAndBalanceArray - .map(([datum, balance]) => ({ - ...datum, - balance, - })) - .sort((a, b) => { - if (a.balance > b.balance) { - return -1; - } else if (a.balance > b.balance) { - return 1; - } else { - return 0; - } - }); - - const whaleBalance = sortedBalances[0]; - const minnowBalance = sortedBalances[1]; - - const commonData = { - publicClient: whaleBalance.publicClient, - chainId: whaleBalance.chainId, - bundlerUrl: whaleBalance.bundlerUrl, - deploymentCost: whaleBalance.deploymentCost, - nftAddress: whaleBalance.nftAddress, - entryPointAddress: whaleBalance.entryPointAddress, - viemChain: whaleBalance.viemChain, - ethersProvider: whaleBalance.ethersProvider, - paymasterUrl: whaleBalance.paymasterUrl, - biconomyPaymasterApiKey: whaleBalance.biconomyPaymasterApiKey, - }; - - const datum = { - ...commonData, - whale: { - balance: whaleBalance.balance, - viemWallet: whaleBalance.viemWallet, - alchemyWalletClientSigner: whaleBalance.alchemyWalletClientSigner, - publicAddress: whaleBalance.publicAddress, - account: whaleBalance.account, - ethersSigner: whaleBalance.ethersSigner, - privateKey: whaleBalance.privateKey, - }, - minnow: { - balance: minnowBalance.balance, - viemWallet: minnowBalance.viemWallet, - alchemyWalletClientSigner: minnowBalance.alchemyWalletClientSigner, - publicAddress: minnowBalance.publicAddress, - account: minnowBalance.account, - ethersSigner: whaleBalance.ethersSigner, - privateKey: minnowBalance.privateKey, - }, - }; - return datum; - }); -}); - -const envVarCheck = () => { - const REQUIRED_FIELDS = [ - "E2E_PRIVATE_KEY_ONE", - "E2E_PRIVATE_KEY_TWO", - "E2E_BICO_PAYMASTER_KEY_MUMBAI", - "E2E_BICO_PAYMASTER_KEY_BASE", - "E2E_BICO_PAYMASTER_KEY_OP", - ]; - const hasFields = REQUIRED_FIELDS.every((field) => !!process.env[field]); - if (!hasFields) { - console.error("Missing env var"); - process.exit(1); - } -}; diff --git a/tests/setup-unit-tests.ts b/tests/setup-unit-tests.ts deleted file mode 100644 index d2fdba7d3..000000000 --- a/tests/setup-unit-tests.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { createWalletClient, http, createPublicClient } from "viem"; -import { WalletClientSigner } from "@alchemy/aa-core"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { Wallet } from "@ethersproject/wallet"; -import { UNIT_TEST_CHAIN } from "./chains.config"; -import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; - -beforeAll(() => { - const { chainId, bundlerUrl, viemChain, entryPointAddress, deploymentCost, nftAddress } = UNIT_TEST_CHAIN; - const privateKeyOne = generatePrivateKey(); - const accountOne = privateKeyToAccount(privateKeyOne); - - const ethersProvider = new JsonRpcProvider(viemChain.rpcUrls.default.http[0]); - const ethersSignerOne = new Wallet(privateKeyOne, ethersProvider); - - const viemWalletClientOne = createWalletClient({ - account: accountOne, - chain: viemChain, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - - const walletClientSignerOne = new WalletClientSigner(viemWalletClientOne, "viem"); - const publicAddressOne = accountOne.address; - const publicClient = createPublicClient({ - chain: viemChain, - transport: http(), - }); - - const privateKeyTwo = generatePrivateKey(); - const accountTwo = privateKeyToAccount(privateKeyTwo); - - const ethersSignerTwo = new Wallet(privateKeyTwo, ethersProvider); - - const viemWalletClientTwo = createWalletClient({ - account: accountTwo, - chain: viemChain, - transport: http(viemChain.rpcUrls.default.http[0]), - }); - const walletClientSignerTwo = new WalletClientSigner(viemWalletClientTwo, "viem"); - const publicAddressTwo = accountTwo.address; - - const whale = { - viemWallet: viemWalletClientOne, - alchemyWalletClientSigner: walletClientSignerOne, - balance: 0, - publicAddress: publicAddressOne, - ethersSigner: ethersSignerOne, - account: accountOne, - privateKey: privateKeyOne, - }; - - const minnow = { - viemWallet: viemWalletClientTwo, - alchemyWalletClientSigner: walletClientSignerTwo, - balance: 0, - publicAddress: publicAddressTwo, - ethersSigner: ethersSignerTwo, - account: accountTwo, - privateKey: privateKeyTwo, - }; - - // @ts-ignore - testDataPerChain = [{ nftAddress, deploymentCost, whale, minnow, publicClient, chainId, bundlerUrl, entryPointAddress, viemChain, ethersProvider }]; -}); diff --git a/tests/setupFiles.ts b/tests/setupFiles.ts new file mode 100644 index 000000000..fea74d4a2 --- /dev/null +++ b/tests/setupFiles.ts @@ -0,0 +1,9 @@ +import { test } from "vitest" + +export const testOnlyOnSpecificNetwork = (chainId: number) => { + return Number(process.env.CHAIN_ID || 0) === chainId ? test : test.skip +} + +export const testOnlyOnOptimism = testOnlyOnSpecificNetwork(10) +export const testOnlyOnArbitrum = testOnlyOnSpecificNetwork(42161) +export const testOnlyOnBaseSopelia = testOnlyOnSpecificNetwork(84532) diff --git a/tests/utils.ts b/tests/utils.ts index 846278d95..69b88d31b 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,46 +1,189 @@ -import { Hex, PublicClient, parseAbi } from "viem"; +import { + http, + type Chain, + type Hex, + createPublicClient, + createWalletClient, + parseAbi +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { Logger, getChain } from "../src/account" +import { + extractChainIdFromBundlerUrl, + extractChainIdFromPaymasterUrl +} from "../src/bundler" + +export const getEnvVars = () => { + const fields = [ + "BUNDLER_URL", + "E2E_PRIVATE_KEY_ONE", + "E2E_PRIVATE_KEY_TWO", + "E2E_BICO_PAYMASTER_KEY_AMOY", + "E2E_BICO_PAYMASTER_KEY_BASE", + "CHAIN_ID" + ] + const errorFields = fields.filter((field) => !process.env[field]) + if (errorFields.length) { + throw new Error( + `Missing environment variable${ + errorFields.length > 1 ? "s" : "" + }: ${errorFields.join(", ")}` + ) + } + return { + bundlerUrl: process.env.BUNDLER_URL || "", + privateKey: process.env.E2E_PRIVATE_KEY_ONE || "", + privateKeyTwo: process.env.E2E_PRIVATE_KEY_TWO || "", + paymasterUrl: `https://paymaster.biconomy.io/api/v1/80002/${ + process.env.E2E_BICO_PAYMASTER_KEY_AMOY || "" + }`, + paymasterUrlTwo: `https://paymaster.biconomy.io/api/v1/84532/${ + process.env.E2E_BICO_PAYMASTER_KEY_BASE || "" + }`, + chainId: process.env.CHAIN_ID || "0" + } +} + +export type TestConfig = { + chain: Chain + chainId: number + paymasterUrl: string + paymasterUrlTwo: string + bundlerUrl: string + privateKey: string + privateKeyTwo: string +} +export const getConfig = (): TestConfig => { + const { + paymasterUrl, + paymasterUrlTwo, + bundlerUrl, + chainId: chainIdFromEnv, + privateKey, + privateKeyTwo + } = getEnvVars() + const chains = [Number.parseInt(chainIdFromEnv)] + const chainId = chains[0] + const chain = getChain(chainId) + + try { + const chainIdFromBundlerUrl = extractChainIdFromBundlerUrl(bundlerUrl) + chains.push(chainIdFromBundlerUrl) + } catch (e) {} + + try { + const chainIdFromPaymasterUrl = extractChainIdFromPaymasterUrl(paymasterUrl) + chains.push(chainIdFromPaymasterUrl) + } catch (e) {} + + const allChainsMatch = chains.every((chain) => chain === chains[0]) + + if (!allChainsMatch) { + throw new Error("Chain IDs do not match") + } + + return { + chain, + chainId, + paymasterUrl, + paymasterUrlTwo, + bundlerUrl, + privateKey, + privateKeyTwo + } +} + +export const checkBalance = (owner: Hex, tokenAddress?: Hex) => { + const { chain } = getConfig() + + const publicClient = createPublicClient({ + chain, + transport: http() + }) -export const checkBalance = (publicClient: PublicClient, address: Hex, tokenAddress?: Hex): Promise<bigint> => { if (!tokenAddress) { - return publicClient.getBalance({ address }); + return publicClient.getBalance({ address: owner }) } return publicClient.readContract({ address: tokenAddress, - abi: parseAbi(["function balanceOf(address owner) view returns (uint balance)"]), + abi: parseAbi([ + "function balanceOf(address owner) view returns (uint balance)" + ]), functionName: "balanceOf", - // @ts-ignore - args: [address], - }); -}; - -export const getMockBundlerUrl = (chainId: number) => `https://bundler.biconomy.io/api/v2/${chainId}/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f14`; - -// TODO(Joe): Make human readable -export const entryPointABI = [ - { - inputs: [ - { - components: [ - { internalType: "address", name: "sender", type: "address" }, - { internalType: "uint256", name: "nonce", type: "uint256" }, - { internalType: "bytes", name: "initCode", type: "bytes" }, - { internalType: "bytes", name: "callData", type: "bytes" }, - { internalType: "uint256", name: "callGasLimit", type: "uint256" }, - { internalType: "uint256", name: "verificationGasLimit", type: "uint256" }, - { internalType: "uint256", name: "preVerificationGas", type: "uint256" }, - { internalType: "uint256", name: "maxFeePerGas", type: "uint256" }, - { internalType: "uint256", name: "maxPriorityFeePerGas", type: "uint256" }, - { internalType: "bytes", name: "paymasterAndData", type: "bytes" }, - { internalType: "bytes", name: "signature", type: "bytes" }, - ], - internalType: "struct UserOperation", - name: "userOp", - type: "tuple", - }, - ], - name: "getUserOpHash", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, -]; + args: [owner] + }) +} + +export const nonZeroBalance = async (address: Hex, tokenAddress?: Hex) => { + const balance = await checkBalance(address, tokenAddress) + if (balance > BigInt(0)) return + throw new Error( + `Insufficient balance ${ + tokenAddress ? `of token ${tokenAddress}` : "of native token" + } during test setup of owner: ${address}` + ) +} + +export const topUp = async ( + recipient: Hex, + amount = BigInt(1000000), + token?: Hex +) => { + const { chain, privateKey } = getConfig() + const account = privateKeyToAccount(`0x${privateKey}`) + const sender = account.address + + const publicClient = createPublicClient({ + chain, + transport: http() + }) + + const balanceOfSender = await checkBalance(sender, token) + const balanceOfRecipient = await checkBalance(recipient, token) + + if (balanceOfRecipient > amount) { + Logger.log( + `balanceOfRecipient (${recipient}) already has enough ${ + token ?? "native token" + } (${balanceOfRecipient}) during topUp` + ) + return await Promise.resolve() + } + + if (balanceOfSender < amount) { + throw new Error( + `Insufficient ${ + token ? token : "" + }balance during test setup: ${balanceOfSender}` + ) + } + + Logger.log(`topping up (${recipient}): (${balanceOfRecipient}).`) + + const walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + if (token) { + const hash = await walletClient.writeContract({ + address: token, + abi: parseAbi([ + "function transfer(address recipient, uint256 amount) external" + ]), + functionName: "transfer", + args: [recipient, amount] + }) + await publicClient.waitForTransactionReceipt({ hash }) + } else { + const hash = await walletClient.sendTransaction({ + to: recipient, + value: amount + }) + await publicClient.waitForTransactionReceipt({ hash }) + } +} + +export const getBundlerUrl = (chainId: number) => + `https://bundler.biconomy.io/api/v2/${chainId}/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f14` diff --git a/tests/vitest.config.ts b/tests/vitest.config.ts new file mode 100644 index 000000000..d7dd2a794 --- /dev/null +++ b/tests/vitest.config.ts @@ -0,0 +1,35 @@ +import { join } from "node:path" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + test: { + coverage: { + all: false, + provider: "v8", + reporter: process.env.CI + ? ["json-summary", "json"] + : ["text", "json", "html"], + exclude: [ + "**/errors/utils.ts", + "**/_cjs/**", + "**/_esm/**", + "**/_types/**", + "**/*.test.ts", + "**/test/**" + ], + include: ["src/**/*.ts"], + thresholds: { + lines: 80, + functions: 50, + branches: 60, + statements: 80 + } + }, + environment: "node", + include: ["tests/**/*.test.ts"], + setupFiles: [join(__dirname, "./setupFiles.ts")], + globalSetup: [join(__dirname, "./globalSetup.ts")], + // hookTimeout: 20_000, + testTimeout: 20_000 + } +}) diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index e4b76f44d..000000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["packages/**/*"] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 8172cdac6..000000000 --- a/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "strict": true, - "esModuleInterop": true, - "lib": ["es2020"], - "types": ["node", "jest"] - }, - "include": ["packages/**/*"], - "references": [ - { "path": "./packages/transak" }, - { "path": "./packages/bundler" }, - { "path": "./packages/particle-auth" }, - { "path": "./packages/paymaster" }, - { "path": "./packages/account" }, - { "path": "./packages/common" }, - { "path": "./packages/modules" }, - ] -} diff --git a/tsconfig.settings.json b/tsconfig.settings.json deleted file mode 100644 index fbd122a5e..000000000 --- a/tsconfig.settings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "allowJs": false /* Allow javascript files to be compiled. */, - "declaration": true /* Generates corresponding '.d.ts' file. */, - "sourceMap": true /* Generates corresponding '.map' file. */, - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, - "strictNullChecks": true /* Enable strict null checks. */, - "strictFunctionTypes": true /* Enable strict checking of function types. */, - "strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */, - "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, - "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, - "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, - "noUnusedParameters": true /* Report errors on unused parameters. */, - "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, - "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, - "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, - "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, - "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "resolveJsonModule": true - } -} diff --git a/tsconfig/tsconfig.base.json b/tsconfig/tsconfig.base.json new file mode 100644 index 000000000..671115660 --- /dev/null +++ b/tsconfig/tsconfig.base.json @@ -0,0 +1,32 @@ +{ + "include": [], + "compilerOptions": { + "incremental": false, + "useDefineForClassFields": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "useUnknownInCatchVariables": true, + "noImplicitOverride": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "allowJs": false, + "checkJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": false, + "forceConsistentCasingInFileNames": true, + "verbatimModuleSyntax": true, + "importHelpers": true, + "moduleResolution": "NodeNext", + "module": "NodeNext", + "target": "ES2021", + "lib": ["ES2022"], + "skipLibCheck": true, + "noErrorTruncation": true, + "noEmit": true, + "strict": true + }, + "tsc-alias": { + "resolveFullPaths": true, + "verbose": false + } +} \ No newline at end of file diff --git a/tsconfig/tsconfig.cjs.json b/tsconfig/tsconfig.cjs.json new file mode 100644 index 000000000..d5607ac12 --- /dev/null +++ b/tsconfig/tsconfig.cjs.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../dist/_cjs", + "removeComments": true, + "verbatimModuleSyntax": false, + "noEmit": false + } +} diff --git a/tsconfig/tsconfig.esm.json b/tsconfig/tsconfig.esm.json new file mode 100644 index 000000000..136a81fc1 --- /dev/null +++ b/tsconfig/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "es2015", + "outDir": "../dist/_esm", + "noEmit": false + } +} diff --git a/tsconfig/tsconfig.json b/tsconfig/tsconfig.json new file mode 100644 index 000000000..2c9c1e634 --- /dev/null +++ b/tsconfig/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.base.json", + "include": [ + "../src/" + ], + "exclude": [ + "../src/**/*.test.ts", + "../src/**/*.test-d.ts", + "../src/**/*.bench.ts" + ], + "compilerOptions": { + "moduleResolution": "node", + "sourceMap": true, + "rootDir": "../src" + } +} \ No newline at end of file diff --git a/tsconfig/tsconfig.types.json b/tsconfig/tsconfig.types.json new file mode 100644 index 000000000..bb70b996d --- /dev/null +++ b/tsconfig/tsconfig.types.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "esnext", + "outDir": "../dist/_esm", + "declarationDir": "../dist/_types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "noEmit": false + } +} diff --git a/packages/account/typedoc.json b/typedoc.json similarity index 100% rename from packages/account/typedoc.json rename to typedoc.json diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 6224f5ea9..000000000 --- a/yarn.lock +++ /dev/null @@ -1,9707 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@adraffy/ens-normalize@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" - integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== - -"@alchemy/aa-core@^3.1.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@alchemy/aa-core/-/aa-core-3.6.1.tgz#af718313276458910d06030ee0aa946168e442f9" - integrity sha512-WVDacDuXcuePTHQSlKZ0nZvRHNSB48iUhh7fVSqchiStjq7BybdGg35AZf8eg5vcepkwSHekNKCp5LxKwpFCQg== - dependencies: - abitype "^0.8.3" - eventemitter3 "^5.0.1" - viem "^2.8.6" - zod "^3.22.4" - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== - dependencies: - "@babel/highlight" "^7.24.2" - picocolors "^1.0.0" - -"@babel/compat-data@^7.23.5": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.1.tgz#31c1f66435f2a9c329bb5716a6d6186c516c3742" - integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.3.tgz#568864247ea10fbd4eff04dda1e05f9e2ea985c3" - integrity sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.1" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.1" - "@babel/parser" "^7.24.1" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.24.1", "@babel/generator@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" - integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== - dependencies: - "@babel/types" "^7.24.0" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== - dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.22.15": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helpers@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.1.tgz#183e44714b9eba36c3038e442516587b1e0a1a94" - integrity sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" - -"@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" - integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" - integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/runtime@^7.21.0": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57" - integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" - integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== - dependencies: - "@babel/code-frame" "^7.24.1" - "@babel/generator" "^7.24.1" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.1" - "@babel/types" "^7.24.0" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@colors/colors@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" - integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@dabh/diagnostics@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" - integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== - dependencies: - colorspace "1.1.x" - enabled "2.0.x" - kuler "^2.0.0" - -"@esbuild/aix-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" - integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== - -"@esbuild/android-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" - integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== - -"@esbuild/android-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" - integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== - -"@esbuild/android-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" - integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== - -"@esbuild/darwin-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" - integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== - -"@esbuild/darwin-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" - integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== - -"@esbuild/freebsd-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" - integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== - -"@esbuild/freebsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" - integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== - -"@esbuild/linux-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" - integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== - -"@esbuild/linux-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" - integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== - -"@esbuild/linux-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" - integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== - -"@esbuild/linux-loong64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" - integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== - -"@esbuild/linux-mips64el@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" - integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== - -"@esbuild/linux-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" - integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== - -"@esbuild/linux-riscv64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" - integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== - -"@esbuild/linux-s390x@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" - integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== - -"@esbuild/linux-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" - integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== - -"@esbuild/netbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" - integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== - -"@esbuild/openbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" - integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== - -"@esbuild/sunos-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" - integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== - -"@esbuild/win32-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" - integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== - -"@esbuild/win32-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" - integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== - -"@esbuild/win32-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" - integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== - -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== - -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== - -"@ethereumjs/rlp@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" - integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== - -"@ethereumjs/util@^8.1.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" - integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== - dependencies: - "@ethereumjs/rlp" "^4.0.1" - ethereum-cryptography "^2.0.0" - micro-ftch "^0.3.1" - -"@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/abstract-provider@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - -"@ethersproject/abstract-signer@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/address@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - -"@ethersproject/base64@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - -"@ethersproject/basex@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/bignumber@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - -"@ethersproject/bytes@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/constants@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - -"@ethersproject/hash@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/hdnode@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/json-wallets@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - -"@ethersproject/networks@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/pbkdf2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - -"@ethersproject/properties@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/providers@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/rlp@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/sha2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/strings@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/transactions@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - -"@ethersproject/wallet@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/web@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/wordlists@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@fastify/busboy@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" - integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== - -"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" - integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== - -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== - -"@hutson/parse-repository-url@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" - integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" - integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - -"@jest/core@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" - integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== - dependencies: - "@jest/console" "^29.7.0" - "@jest/reporters" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.7.0" - jest-config "^29.7.0" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-resolve-dependencies "^29.7.0" - jest-runner "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - jest-watcher "^29.7.0" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" - integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== - dependencies: - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - -"@jest/expect-utils@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" - integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== - dependencies: - jest-get-type "^29.6.3" - -"@jest/expect@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" - integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== - dependencies: - expect "^29.7.0" - jest-snapshot "^29.7.0" - -"@jest/fake-timers@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" - integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== - dependencies: - "@jest/types" "^29.6.3" - "@sinonjs/fake-timers" "^10.0.2" - "@types/node" "*" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -"@jest/globals@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" - integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/types" "^29.6.3" - jest-mock "^29.7.0" - -"@jest/reporters@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" - integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^6.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - jest-worker "^29.7.0" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - v8-to-istanbul "^9.0.1" - -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/source-map@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" - integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" - integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== - dependencies: - "@jest/console" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" - integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== - dependencies: - "@jest/test-result" "^29.7.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - slash "^3.0.0" - -"@jest/transform@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" - integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" - integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== - dependencies: - "@jest/schemas" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@lerna/child-process@7.4.2": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.4.2.tgz#a2fd013ac2150dc288270d3e0d0b850c06bec511" - integrity sha512-je+kkrfcvPcwL5Tg8JRENRqlbzjdlZXyaR88UcnCdNW0AJ1jX9IfHRys1X7AwSroU2ug8ESNC+suoBw1vX833Q== - dependencies: - chalk "^4.1.0" - execa "^5.0.0" - strong-log-transformer "^2.1.0" - -"@lerna/create@7.4.2": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.4.2.tgz#f845fad1480e46555af98bd39af29571605dddc9" - integrity sha512-1wplFbQ52K8E/unnqB0Tq39Z4e+NEoNrpovEnl6GpsTUrC6WDp8+w0Le2uCBV0hXyemxChduCkLz4/y1H1wTeg== - dependencies: - "@lerna/child-process" "7.4.2" - "@npmcli/run-script" "6.0.2" - "@nx/devkit" ">=16.5.1 < 17" - "@octokit/plugin-enterprise-rest" "6.0.1" - "@octokit/rest" "19.0.11" - byte-size "8.1.1" - chalk "4.1.0" - clone-deep "4.0.1" - cmd-shim "6.0.1" - columnify "1.6.0" - conventional-changelog-core "5.0.1" - conventional-recommended-bump "7.0.1" - cosmiconfig "^8.2.0" - dedent "0.7.0" - execa "5.0.0" - fs-extra "^11.1.1" - get-stream "6.0.0" - git-url-parse "13.1.0" - glob-parent "5.1.2" - globby "11.1.0" - graceful-fs "4.2.11" - has-unicode "2.0.1" - ini "^1.3.8" - init-package-json "5.0.0" - inquirer "^8.2.4" - is-ci "3.0.1" - is-stream "2.0.0" - js-yaml "4.1.0" - libnpmpublish "7.3.0" - load-json-file "6.2.0" - lodash "^4.17.21" - make-dir "4.0.0" - minimatch "3.0.5" - multimatch "5.0.0" - node-fetch "2.6.7" - npm-package-arg "8.1.1" - npm-packlist "5.1.1" - npm-registry-fetch "^14.0.5" - npmlog "^6.0.2" - nx ">=16.5.1 < 17" - p-map "4.0.0" - p-map-series "2.1.0" - p-queue "6.6.2" - p-reduce "^2.1.0" - pacote "^15.2.0" - pify "5.0.0" - read-cmd-shim "4.0.0" - read-package-json "6.0.4" - resolve-from "5.0.0" - rimraf "^4.4.1" - semver "^7.3.4" - signal-exit "3.0.7" - slash "^3.0.0" - ssri "^9.0.1" - strong-log-transformer "2.1.0" - tar "6.1.11" - temp-dir "1.0.0" - upath "2.0.1" - uuid "^9.0.0" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "5.0.0" - write-file-atomic "5.0.1" - write-pkg "4.0.0" - yargs "16.2.0" - yargs-parser "20.2.4" - -"@metamask/eth-sig-util@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" - integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== - dependencies: - ethereumjs-abi "^0.6.8" - ethereumjs-util "^6.2.1" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - -"@noble/curves@1.2.0", "@noble/curves@~1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" - integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== - dependencies: - "@noble/hashes" "1.3.2" - -"@noble/curves@1.3.0", "@noble/curves@~1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" - integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== - dependencies: - "@noble/hashes" "1.3.3" - -"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== - -"@noble/hashes@1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== - -"@noble/hashes@1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" - integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== - -"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" - integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@nomicfoundation/edr-darwin-arm64@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz#0618dbdf1c832f8e61c77540e7188c13fdd5b658" - integrity sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ== - -"@nomicfoundation/edr-darwin-x64@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz#567ee0bca8d019085e8dd95330e7c03f16c66a79" - integrity sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg== - -"@nomicfoundation/edr-linux-arm64-gnu@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz#3956b4d7a0127e2259351626c92698c4ce6ecf05" - integrity sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA== - -"@nomicfoundation/edr-linux-arm64-musl@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz#139f801939ed467f1719a2ab014993838008eefb" - integrity sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q== - -"@nomicfoundation/edr-linux-x64-gnu@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz#b5994caa1a8bb4afca5f079ad7dd99edb26c6c45" - integrity sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA== - -"@nomicfoundation/edr-linux-x64-musl@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz#536c1d1dfd2fc7d7ad6ed6e14ed9a12322d88ba6" - integrity sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw== - -"@nomicfoundation/edr-win32-arm64-msvc@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz#f71609644d8585c2ec71580bf75c2fd036ee58b0" - integrity sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA== - -"@nomicfoundation/edr-win32-ia32-msvc@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz#baa5eaacb1fff107d02f0e6a33dee9521fd2bf37" - integrity sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w== - -"@nomicfoundation/edr-win32-x64-msvc@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz#7562e061b2481f87bb1ace30513a2ad38c469836" - integrity sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w== - -"@nomicfoundation/edr@^0.3.1": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.3.3.tgz#0ed8619ea2ac644bf87cdc09dd1a8f465a859bcc" - integrity sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ== - optionalDependencies: - "@nomicfoundation/edr-darwin-arm64" "0.3.3" - "@nomicfoundation/edr-darwin-x64" "0.3.3" - "@nomicfoundation/edr-linux-arm64-gnu" "0.3.3" - "@nomicfoundation/edr-linux-arm64-musl" "0.3.3" - "@nomicfoundation/edr-linux-x64-gnu" "0.3.3" - "@nomicfoundation/edr-linux-x64-musl" "0.3.3" - "@nomicfoundation/edr-win32-arm64-msvc" "0.3.3" - "@nomicfoundation/edr-win32-ia32-msvc" "0.3.3" - "@nomicfoundation/edr-win32-x64-msvc" "0.3.3" - -"@nomicfoundation/ethereumjs-common@4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" - integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== - dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.4" - -"@nomicfoundation/ethereumjs-rlp@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" - integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== - -"@nomicfoundation/ethereumjs-tx@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" - integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-util@9.0.4": - version "9.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" - integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz#4c858096b1c17fe58a474fe81b46815f93645c15" - integrity sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w== - -"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz#6e25ccdf6e2d22389c35553b64fe6f3fdaec432c" - integrity sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA== - -"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz#0a224ea50317139caeebcdedd435c28a039d169c" - integrity sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA== - -"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz#dfa085d9ffab9efb2e7b383aed3f557f7687ac2b" - integrity sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg== - -"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz#c9e06b5d513dd3ab02a7ac069c160051675889a4" - integrity sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w== - -"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz#8d328d16839e52571f72f2998c81e46bf320f893" - integrity sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA== - -"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz#9b49d0634b5976bb5ed1604a1e1b736f390959bb" - integrity sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w== - -"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz#e2867af7264ebbcc3131ef837878955dd6a3676f" - integrity sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg== - -"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz#0685f78608dd516c8cdfb4896ed451317e559585" - integrity sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ== - -"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz#c9a44f7108646f083b82e851486e0f6aeb785836" - integrity sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw== - -"@nomicfoundation/solidity-analyzer@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz#f5f4d36d3f66752f59a57e7208cd856f3ddf6f2d" - integrity sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg== - optionalDependencies: - "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.1" - "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.1" - "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.1" - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.1" - "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.1" - "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.1" - "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.1" - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.1" - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1" - "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1" - -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - -"@npmcli/fs@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" - integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ== - dependencies: - "@gar/promisify" "^1.1.3" - semver "^7.3.5" - -"@npmcli/fs@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.0.tgz#233d43a25a91d68c3a863ba0da6a3f00924a173e" - integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== - dependencies: - semver "^7.3.5" - -"@npmcli/git@^4.0.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-4.1.0.tgz#ab0ad3fd82bc4d8c1351b6c62f0fa56e8fe6afa6" - integrity sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ== - dependencies: - "@npmcli/promise-spawn" "^6.0.0" - lru-cache "^7.4.4" - npm-pick-manifest "^8.0.0" - proc-log "^3.0.0" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^3.0.0" - -"@npmcli/installed-package-contents@^2.0.1": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" - integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== - dependencies: - npm-bundled "^3.0.0" - npm-normalize-package-bin "^3.0.0" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - -"@npmcli/move-file@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4" - integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - -"@npmcli/node-gyp@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" - integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== - -"@npmcli/promise-spawn@^6.0.0", "@npmcli/promise-spawn@^6.0.1": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2" - integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg== - dependencies: - which "^3.0.0" - -"@npmcli/run-script@6.0.2", "@npmcli/run-script@^6.0.0": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.2.tgz#a25452d45ee7f7fb8c16dfaf9624423c0c0eb885" - integrity sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA== - dependencies: - "@npmcli/node-gyp" "^3.0.0" - "@npmcli/promise-spawn" "^6.0.0" - node-gyp "^9.0.0" - read-package-json-fast "^3.0.0" - which "^3.0.0" - -"@nrwl/devkit@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.10.0.tgz#ac8c5b4db00f12c4b817c937be2f7c4eb8f2593c" - integrity sha512-fRloARtsDQoQgQ7HKEy0RJiusg/HSygnmg4gX/0n/Z+SUS+4KoZzvHjXc6T5ZdEiSjvLypJ+HBM8dQzIcVACPQ== - dependencies: - "@nx/devkit" "16.10.0" - -"@nrwl/tao@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.10.0.tgz#94642a0380709b8e387e1e33705a5a9624933375" - integrity sha512-QNAanpINbr+Pod6e1xNgFbzK1x5wmZl+jMocgiEFXZ67KHvmbD6MAQQr0MMz+GPhIu7EE4QCTLTyCEMlAG+K5Q== - dependencies: - nx "16.10.0" - tslib "^2.3.0" - -"@nx/devkit@16.10.0", "@nx/devkit@>=16.5.1 < 17": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.10.0.tgz#7e466be2dee2dcb1ccaf286786ca2a0a639aa007" - integrity sha512-IvKQqRJFDDiaj33SPfGd3ckNHhHi6ceEoqCbAP4UuMXOPPVOX6H0KVk+9tknkPb48B7jWIw6/AgOeWkBxPRO5w== - dependencies: - "@nrwl/devkit" "16.10.0" - ejs "^3.1.7" - enquirer "~2.3.6" - ignore "^5.0.4" - semver "7.5.3" - tmp "~0.2.1" - tslib "^2.3.0" - -"@nx/nx-darwin-arm64@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.10.0.tgz#0c73010cac7a502549483b12bad347da9014e6f1" - integrity sha512-YF+MIpeuwFkyvM5OwgY/rTNRpgVAI/YiR0yTYCZR+X3AAvP775IVlusNgQ3oedTBRUzyRnI4Tknj1WniENFsvQ== - -"@nx/nx-darwin-x64@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.10.0.tgz#2ccf270418d552fd0a8e0d6089aee4944315adaa" - integrity sha512-ypi6YxwXgb0kg2ixKXE3pwf5myVNUgWf1CsV5OzVccCM8NzheMO51KDXTDmEpXdzUsfT0AkO1sk5GZeCjhVONg== - -"@nx/nx-freebsd-x64@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.10.0.tgz#c3ee6914256e69493fed9355b0d6661d0e86da44" - integrity sha512-UeEYFDmdbbDkTQamqvtU8ibgu5jQLgFF1ruNb/U4Ywvwutw2d4ruOMl2e0u9hiNja9NFFAnDbvzrDcMo7jYqYw== - -"@nx/nx-linux-arm-gnueabihf@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.10.0.tgz#a961eccbb38acb2da7fc125b29d1fead0b39152f" - integrity sha512-WV3XUC2DB6/+bz1sx+d1Ai9q2Cdr+kTZRN50SOkfmZUQyEBaF6DRYpx/a4ahhxH3ktpNfyY8Maa9OEYxGCBkQA== - -"@nx/nx-linux-arm64-gnu@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.10.0.tgz#795f20072549d03822b5c4639ef438e473dbb541" - integrity sha512-aWIkOUw995V3ItfpAi5FuxQ+1e9EWLS1cjWM1jmeuo+5WtaKToJn5itgQOkvSlPz+HSLgM3VfXMvOFALNk125g== - -"@nx/nx-linux-arm64-musl@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.10.0.tgz#f2428ee6dbe2b2c326e8973f76c97666def33607" - integrity sha512-uO6Gg+irqpVcCKMcEPIQcTFZ+tDI02AZkqkP7koQAjniLEappd8DnUBSQdcn53T086pHpdc264X/ZEpXFfrKWQ== - -"@nx/nx-linux-x64-gnu@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.10.0.tgz#d36c2bcf94d49eaa24e3880ddaf6f1f617de539b" - integrity sha512-134PW/u/arNFAQKpqMJniC7irbChMPz+W+qtyKPAUXE0XFKPa7c1GtlI/wK2dvP9qJDZ6bKf0KtA0U/m2HMUOA== - -"@nx/nx-linux-x64-musl@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.10.0.tgz#78bd2ab97a583b3d4ea3387b67fd7b136907493c" - integrity sha512-q8sINYLdIJxK/iUx9vRk5jWAWb/2O0PAbOJFwv4qkxBv4rLoN7y+otgCZ5v0xfx/zztFgk/oNY4lg5xYjIso2Q== - -"@nx/nx-win32-arm64-msvc@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.10.0.tgz#ef20ec8d0c83d66e73e20df12d2c788b8f866396" - integrity sha512-moJkL9kcqxUdJSRpG7dET3UeLIciwrfP08mzBQ12ewo8K8FzxU8ZUsTIVVdNrwt01CXOdXoweGfdQLjJ4qTURA== - -"@nx/nx-win32-x64-msvc@16.10.0": - version "16.10.0" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.10.0.tgz#7410a51d0f8be631eec9552f01b2e5946285927c" - integrity sha512-5iV2NKZnzxJwZZ4DM5JVbRG/nkhAbzEskKaLBB82PmYGKzaDHuMHP1lcPoD/rtYMlowZgNA/RQndfKvPBPwmXA== - -"@octokit/auth-token@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db" - integrity sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ== - -"@octokit/core@^4.2.1": - version "4.2.4" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.4.tgz#d8769ec2b43ff37cc3ea89ec4681a20ba58ef907" - integrity sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ== - dependencies: - "@octokit/auth-token" "^3.0.0" - "@octokit/graphql" "^5.0.0" - "@octokit/request" "^6.0.0" - "@octokit/request-error" "^3.0.0" - "@octokit/types" "^9.0.0" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^7.0.0": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.6.tgz#791f65d3937555141fb6c08f91d618a7d645f1e2" - integrity sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg== - dependencies: - "@octokit/types" "^9.0.0" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.6.tgz#9eac411ac4353ccc5d3fca7d76736e6888c5d248" - integrity sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw== - dependencies: - "@octokit/request" "^6.0.0" - "@octokit/types" "^9.0.0" - universal-user-agent "^6.0.0" - -"@octokit/openapi-types@^18.0.0": - version "18.1.1" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.1.1.tgz#09bdfdabfd8e16d16324326da5148010d765f009" - integrity sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw== - -"@octokit/plugin-enterprise-rest@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" - integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== - -"@octokit/plugin-paginate-rest@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz#f86456a7a1fe9e58fec6385a85cf1b34072341f8" - integrity sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ== - dependencies: - "@octokit/tsconfig" "^1.0.2" - "@octokit/types" "^9.2.3" - -"@octokit/plugin-request-log@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" - integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== - -"@octokit/plugin-rest-endpoint-methods@^7.1.2": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz#37a84b171a6cb6658816c82c4082ac3512021797" - integrity sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA== - dependencies: - "@octokit/types" "^10.0.0" - -"@octokit/request-error@^3.0.0": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69" - integrity sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ== - dependencies: - "@octokit/types" "^9.0.0" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^6.0.0": - version "6.2.8" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.8.tgz#aaf480b32ab2b210e9dadd8271d187c93171d8eb" - integrity sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw== - dependencies: - "@octokit/endpoint" "^7.0.0" - "@octokit/request-error" "^3.0.0" - "@octokit/types" "^9.0.0" - is-plain-object "^5.0.0" - node-fetch "^2.6.7" - universal-user-agent "^6.0.0" - -"@octokit/rest@19.0.11": - version "19.0.11" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.11.tgz#2ae01634fed4bd1fca5b642767205ed3fd36177c" - integrity sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw== - dependencies: - "@octokit/core" "^4.2.1" - "@octokit/plugin-paginate-rest" "^6.1.2" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^7.1.2" - -"@octokit/tsconfig@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@octokit/tsconfig/-/tsconfig-1.0.2.tgz#59b024d6f3c0ed82f00d08ead5b3750469125af7" - integrity sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA== - -"@octokit/types@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-10.0.0.tgz#7ee19c464ea4ada306c43f1a45d444000f419a4a" - integrity sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg== - dependencies: - "@octokit/openapi-types" "^18.0.0" - -"@octokit/types@^9.0.0", "@octokit/types@^9.2.3": - version "9.3.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5" - integrity sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA== - dependencies: - "@octokit/openapi-types" "^18.0.0" - -"@parcel/watcher@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.4.tgz#f300fef4cc38008ff4b8c29d92588eced3ce014b" - integrity sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg== - dependencies: - node-addon-api "^3.2.1" - node-gyp-build "^4.3.0" - -"@particle-network/analytics@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@particle-network/analytics/-/analytics-1.0.1.tgz#b3657cf7aaea57f90a7ac2c03f72b8786c298012" - integrity sha512-ApcSMo1BXQlywO+lvOpG3Y2/SVGNCpJzXO/4e3zHzE/9j+uMehsilDzPwWQwLhrCXZYwVm7mmE71Gs36yobiNw== - dependencies: - hash.js "^1.1.7" - uuidv4 "^6.2.13" - -"@particle-network/auth@^1.2.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@particle-network/auth/-/auth-1.3.1.tgz#f9ee51749e3b10e700e0d8c51a8c0769ab0b9851" - integrity sha512-hu6ie5RjjN4X+6y/vfjyCsSX3pQuS8k8ZoMb61QWwhWsnZXKzpBUVeAEk55aGfxxXY+KfBkSmZosyaZHGoHnfw== - dependencies: - "@particle-network/analytics" "^1.0.1" - "@particle-network/chains" "*" - "@particle-network/crypto" "^1.0.1" - buffer "^6.0.3" - draggabilly "^3.0.0" - -"@particle-network/biconomy@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@particle-network/biconomy/-/biconomy-1.0.0.tgz#91f79c6341db0fc9b23d3ed9c61fbb08df727c31" - integrity sha512-MvYdTGT48WJB72SqkmZbx3NI8HdjWb8EZNKIkbddcusws/Uqy4dHV2+tP7UWup+vGltCXK/55KAdvgcwFTsZrQ== - dependencies: - axios "^1.3.6" - uuid "^8.3.2" - -"@particle-network/chains@*": - version "1.3.27" - resolved "https://registry.yarnpkg.com/@particle-network/chains/-/chains-1.3.27.tgz#dca4f2714d23957cc68cb1301de1f310895658db" - integrity sha512-+my+i0jqZjUoP+mNXxsPc2D7o3Cijl6uRvvWyTT0DmpyK1P+9yFpUuhEHUVmZMriTGKXv6synner16CD8/AkpQ== - -"@particle-network/crypto@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@particle-network/crypto/-/crypto-1.0.1.tgz#26afef622a3eb906dca5c810fef8001ffee29029" - integrity sha512-GgvHmHcFiNkCLZdcJOgctSbgvs251yp+EAdUydOE3gSoIxN6KEr/Snu9DebENhd/nFb7FDk5ap0Hg49P7pj1fg== - dependencies: - crypto-js "^4.1.1" - uuidv4 "^6.2.13" - -"@particle-network/provider@^1.2.0": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@particle-network/provider/-/provider-1.3.2.tgz#68ae98cca471c7612206cb43c915719cd321fb25" - integrity sha512-3XAUMCISTMYE57LZik7PrVanLIUyyU1ufb5eHtsoQw5ORfH0IeX3E5o6x5mxtfOXKfxVQ0tsIoLRMw0jMmSDpA== - dependencies: - "@particle-network/chains" "*" - axios "^1.3.6" - uuid "^8.3.2" - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@pkgr/core@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" - integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== - -"@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.4": - version "1.1.6" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" - integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== - -"@scure/bip32@1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" - integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== - dependencies: - "@noble/hashes" "~1.2.0" - "@noble/secp256k1" "~1.7.0" - "@scure/base" "~1.1.0" - -"@scure/bip32@1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8" - integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA== - dependencies: - "@noble/curves" "~1.2.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.2" - -"@scure/bip32@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" - integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== - dependencies: - "@noble/curves" "~1.3.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - -"@scure/bip39@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" - integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== - dependencies: - "@noble/hashes" "~1.2.0" - "@scure/base" "~1.1.0" - -"@scure/bip39@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" - integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== - dependencies: - "@noble/hashes" "~1.3.0" - "@scure/base" "~1.1.0" - -"@scure/bip39@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" - integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== - dependencies: - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - -"@sentry/core@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" - integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/minimal" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - -"@sentry/hub@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" - integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== - dependencies: - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - -"@sentry/minimal@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" - integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/types" "5.30.0" - tslib "^1.9.3" - -"@sentry/node@^5.18.1": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" - integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== - dependencies: - "@sentry/core" "5.30.0" - "@sentry/hub" "5.30.0" - "@sentry/tracing" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/tracing@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" - integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/minimal" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - -"@sentry/types@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" - integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== - -"@sentry/utils@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" - integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== - dependencies: - "@sentry/types" "5.30.0" - tslib "^1.9.3" - -"@sigstore/bundle@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-1.1.0.tgz#17f8d813b09348b16eeed66a8cf1c3d6bd3d04f1" - integrity sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog== - dependencies: - "@sigstore/protobuf-specs" "^0.2.0" - -"@sigstore/protobuf-specs@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz#be9ef4f3c38052c43bd399d3f792c97ff9e2277b" - integrity sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A== - -"@sigstore/sign@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@sigstore/sign/-/sign-1.0.0.tgz#6b08ebc2f6c92aa5acb07a49784cb6738796f7b4" - integrity sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA== - dependencies: - "@sigstore/bundle" "^1.1.0" - "@sigstore/protobuf-specs" "^0.2.0" - make-fetch-happen "^11.0.1" - -"@sigstore/tuf@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@sigstore/tuf/-/tuf-1.0.3.tgz#2a65986772ede996485728f027b0514c0b70b160" - integrity sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg== - dependencies: - "@sigstore/protobuf-specs" "^0.2.0" - tuf-js "^1.1.7" - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sinonjs/commons@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" - integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== - dependencies: - "@sinonjs/commons" "^3.0.0" - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@tootallnate/once@2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" - integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== - -"@transak/transak-sdk@^1.2.3": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@transak/transak-sdk/-/transak-sdk-1.4.1.tgz#90dee041b772c71c35cfb22df9ef51970b780db4" - integrity sha512-/BKzb9orz1xDxa41oOPW+4KpjSHNEXgtaFazX/aIjQbr7LLbRqfXC/IHzpPmjR9OmFm8pFhV2Y86Rg0aZt5ZUA== - dependencies: - events "^3.3.0" - query-string "^8.1.0" - -"@trufflesuite/bigint-buffer@1.1.10": - version "1.1.10" - resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" - integrity sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw== - dependencies: - node-gyp-build "4.4.0" - -"@trufflesuite/uws-js-unofficial@20.30.0-unofficial.0": - version "20.30.0-unofficial.0" - resolved "https://registry.yarnpkg.com/@trufflesuite/uws-js-unofficial/-/uws-js-unofficial-20.30.0-unofficial.0.tgz#2fbc2f8ef7e82fbeea6abaf7e8a9d42a02b479d3" - integrity sha512-r5X0aOQcuT6pLwTRLD+mPnAM/nlKtvIK4Z+My++A8tTOR0qTjNRx8UB8jzRj3D+p9PMAp5LnpCUUGmz7/TppwA== - dependencies: - ws "8.13.0" - optionalDependencies: - bufferutil "4.0.7" - utf-8-validate "6.0.3" - -"@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@tufjs/canonical-json@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz#eade9fd1f537993bc1f0949f3aea276ecc4fab31" - integrity sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ== - -"@tufjs/models@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-1.0.4.tgz#5a689630f6b9dbda338d4b208019336562f176ef" - integrity sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A== - dependencies: - "@tufjs/canonical-json" "1.0.0" - minimatch "^9.0.0" - -"@types/babel__core@^7.1.14": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== - dependencies: - "@babel/types" "^7.20.7" - -"@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - -"@types/bn.js@^5.1.0": - version "5.1.5" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" - integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== - dependencies: - "@types/node" "*" - -"@types/debug@^4.1.9": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - -"@types/graceful-fs@^4.1.3": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" - integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" - integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^29.5.4": - version "29.5.12" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" - integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - -"@types/json-schema@^7.0.12": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/lru-cache@5.1.1", "@types/lru-cache@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" - integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== - -"@types/minimatch@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/minimist@^1.2.0": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e" - integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== - -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - -"@types/node@*", "@types/node@^20.11.10": - version "20.12.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.3.tgz#d6658c2c7776c1cad93534bb45428195ed840c65" - integrity sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw== - dependencies: - undici-types "~5.26.4" - -"@types/normalize-package-data@^2.4.0": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" - integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== - -"@types/pbkdf2@^3.0.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" - integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== - dependencies: - "@types/node" "*" - -"@types/secp256k1@^4.0.1": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" - integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== - dependencies: - "@types/node" "*" - -"@types/seedrandom@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.1.tgz#1254750a4fec4aff2ebec088ccd0bb02e91fedb4" - integrity sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw== - -"@types/semver@^7.5.0": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - -"@types/stack-utils@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" - integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== - -"@types/triple-beam@^1.3.2": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" - integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== - -"@types/uuid@8.3.4": - version "8.3.4" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" - integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@^6.7.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" - integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/type-utils" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" - natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^6.6.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" - integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== - dependencies: - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" - integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - -"@typescript-eslint/type-utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" - integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== - dependencies: - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" - integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== - -"@typescript-eslint/typescript-estree@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" - integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" - integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - semver "^7.5.4" - -"@typescript-eslint/visitor-keys@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" - integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== - dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" - -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - -"@yarnpkg/parsers@3.0.0-rc.46": - version "3.0.0-rc.46" - resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz#03f8363111efc0ea670e53b0282cd3ef62de4e01" - integrity sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q== - dependencies: - js-yaml "^3.10.0" - tslib "^2.4.0" - -"@zkochan/js-yaml@0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz#975f0b306e705e28b8068a07737fa46d3fc04826" - integrity sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg== - dependencies: - argparse "^2.0.1" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -abbrev@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abitype@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" - integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== - -abitype@^0.8.3: - version "0.8.11" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.11.tgz#66e1cf2cbf46f48d0e57132d7c1c392447536cc1" - integrity sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A== - -abstract-level@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" - integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - -abstract-leveldown@7.2.0, abstract-leveldown@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" - integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== - dependencies: - buffer "^6.0.3" - catering "^2.0.0" - is-buffer "^2.0.5" - level-concat-iterator "^3.0.0" - level-supports "^2.0.1" - queue-microtask "^1.2.3" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" - integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== - -acorn@^8.4.1, acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - -add-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" - integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== - -adm-zip@^0.4.16: - version "0.4.16" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" - integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - -agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-align@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-colors@^4.1.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-sequence-parser@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" - integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - -anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" - integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -args@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/args/-/args-5.0.3.tgz#943256db85021a85684be2f0882f25d796278702" - integrity sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA== - dependencies: - camelcase "5.0.0" - chalk "2.4.2" - leven "2.1.0" - mri "1.1.4" - -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== - -array-includes@^3.1.7: - version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.4" - is-string "^1.0.7" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== - -array.prototype.findlastindex@^1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" - integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-shim-unscopables "^1.0.2" - -array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== - -arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - -async-eventemitter@0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== - dependencies: - async "^2.4.0" - -async@^2.4.0: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - -async@^3.2.3, async@^3.2.4: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -axios@^1.0.0, axios@^1.3.6: - version "1.6.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" - integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -babel-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" - integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== - dependencies: - "@jest/transform" "^29.7.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.6.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" - integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" - integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== - dependencies: - babel-plugin-jest-hoist "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -before-after-hook@^2.2.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" - integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== - -bignumber.js@^9.0.1: - version "9.1.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" - integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== - -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - -bl@^4.0.3, bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -blakejs@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - -bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== - -bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -boxen@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" - integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserslist@^4.22.2: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== - dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== - dependencies: - base-x "^3.0.2" - -bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-reverse@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" - integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.5.tgz#da9ea8166911cc276bf677b8aed2d02d31f59028" - integrity sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A== - dependencies: - node-gyp-build "^4.3.0" - -bufferutil@4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" - integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== - dependencies: - node-gyp-build "^4.3.0" - -builtins@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ== - -builtins@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== - dependencies: - semver "^7.0.0" - -byte-size@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-8.1.1.tgz#3424608c62d59de5bfda05d31e0313c6174842ae" - integrity sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - -cacache@^16.1.0: - version "16.1.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" - integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ== - dependencies: - "@npmcli/fs" "^2.1.0" - "@npmcli/move-file" "^2.0.0" - chownr "^2.0.0" - fs-minipass "^2.1.0" - glob "^8.0.1" - infer-owner "^1.0.4" - lru-cache "^7.7.1" - minipass "^3.1.6" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - mkdirp "^1.0.4" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^9.0.0" - tar "^6.1.11" - unique-filename "^2.0.0" - -cacache@^17.0.0: - version "17.1.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.4.tgz#b3ff381580b47e85c6e64f801101508e26604b35" - integrity sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A== - dependencies: - "@npmcli/fs" "^3.1.0" - fs-minipass "^3.0.0" - glob "^10.2.2" - lru-cache "^7.7.1" - minipass "^7.0.3" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - p-map "^4.0.0" - ssri "^10.0.0" - tar "^6.1.11" - unique-filename "^3.0.0" - -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0, camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001587: - version "1.0.30001605" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz#ca12d7330dd8bcb784557eb9aa64f0037870d9d6" - integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== - -catering@^2.0.0, catering@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" - integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== - -chalk@2.4.2, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chokidar@^3.4.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0, ci-info@^3.6.1: - version "3.9.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" - integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - -cli-cursor@3.1.0, cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-highlight@^2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - -cli-spinners@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - -cli-spinners@^2.5.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" - integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -clone-deep@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== - -cmd-shim@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" - integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" - integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== - -color-convert@^1.9.0, color-convert@^1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.6.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" - integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -color@^3.1.3: - version "3.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" - integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== - dependencies: - color-convert "^1.9.3" - color-string "^1.6.0" - -colorspace@1.1.x: - version "1.1.4" - resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" - integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== - dependencies: - color "^3.1.3" - text-hex "1.0.x" - -columnify@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" - integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== - dependencies: - strip-ansi "^6.0.1" - wcwidth "^1.0.0" - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -command-exists@^1.2.8: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - -commander@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== - -commander@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" - integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== - -commander@^2.9.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== - -compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== - dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - -concurrently@^8.2.2: - version "8.2.2" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784" - integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg== - dependencies: - chalk "^4.1.2" - date-fns "^2.30.0" - lodash "^4.17.21" - rxjs "^7.8.1" - shell-quote "^1.8.1" - spawn-command "0.0.2" - supports-color "^8.1.1" - tree-kill "^1.2.2" - yargs "^17.7.2" - -confusing-browser-globals@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" - integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== - -console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - -conventional-changelog-angular@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" - integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== - dependencies: - compare-func "^2.0.0" - -conventional-changelog-core@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz#3c331b155d5b9850f47b4760aeddfc983a92ad49" - integrity sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A== - dependencies: - add-stream "^1.0.0" - conventional-changelog-writer "^6.0.0" - conventional-commits-parser "^4.0.0" - dateformat "^3.0.3" - get-pkg-repo "^4.2.1" - git-raw-commits "^3.0.0" - git-remote-origin-url "^2.0.0" - git-semver-tags "^5.0.0" - normalize-package-data "^3.0.3" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - -conventional-changelog-preset-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz#14975ef759d22515d6eabae6396c2ae721d4c105" - integrity sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA== - -conventional-changelog-writer@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz#d8d3bb5e1f6230caed969dcc762b1c368a8f7b01" - integrity sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ== - dependencies: - conventional-commits-filter "^3.0.0" - dateformat "^3.0.3" - handlebars "^4.7.7" - json-stringify-safe "^5.0.1" - meow "^8.1.2" - semver "^7.0.0" - split "^1.0.1" - -conventional-commits-filter@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz#bf1113266151dd64c49cd269e3eb7d71d7015ee2" - integrity sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q== - dependencies: - lodash.ismatch "^4.4.0" - modify-values "^1.0.1" - -conventional-commits-parser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz#02ae1178a381304839bce7cea9da5f1b549ae505" - integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg== - dependencies: - JSONStream "^1.3.5" - is-text-path "^1.0.1" - meow "^8.1.2" - split2 "^3.2.2" - -conventional-recommended-bump@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz#ec01f6c7f5d0e2491c2d89488b0d757393392424" - integrity sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^3.0.0" - conventional-commits-filter "^3.0.0" - conventional-commits-parser "^4.0.0" - git-raw-commits "^3.0.0" - git-semver-tags "^5.0.0" - meow "^8.1.2" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^8.2.0: - version "8.3.6" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" - integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== - dependencies: - import-fresh "^3.3.0" - js-yaml "^4.1.0" - parse-json "^5.2.0" - path-type "^4.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -create-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" - integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-config "^29.7.0" - jest-util "^29.7.0" - prompts "^2.0.1" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-js@^4.1.1, crypto-js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" - integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== - -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -date-fns@^2.30.0: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== - dependencies: - "@babel/runtime" "^7.21.0" - -dateformat@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== - -debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decamelize-keys@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" - integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -decode-uri-component@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5" - integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ== - -dedent@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== - -dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -defaults@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" - integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== - dependencies: - clone "^1.0.2" - -define-data-property@^1.0.1, define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -deprecation@^2.0.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -detect-file@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" - integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q== - -detect-indent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dot-prop@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dotenv-expand@~10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" - integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== - -dotenv@~16.3.1: - version "16.3.2" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f" - integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ== - -draggabilly@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/draggabilly/-/draggabilly-3.0.0.tgz#48defe10a67f346a0338caaa40c0765c4d3912d6" - integrity sha512-aEs+B6prbMZQMxc9lgTpCBfyCUhRur/VFucHhIOvlvvdARTj7TcDmX/cdOUtqbjJJUh7+agyJXR5Z6IFe1MxwQ== - dependencies: - get-size "^3.0.0" - unidragger "^3.0.0" - -duplexer@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ejs@^3.1.7: - version "3.1.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" - integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== - dependencies: - jake "^10.8.5" - -electron-to-chromium@^1.4.668: - version "1.4.724" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz#e0a86fe4d3d0e05a4d7b032549d79608078f830d" - integrity sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA== - -elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -elliptic@^6.5.2, elliptic@^6.5.4: - version "6.5.5" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" - integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -email-addresses@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-5.0.0.tgz#7ae9e7f58eef7d5e3e2c2c2d3ea49b78dc854fa6" - integrity sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw== - -emittery@0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" - integrity sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ== - -emittery@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" - integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -enabled@2.0.x: - version "2.0.0" - resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" - integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== - -encoding@^0.1.12, encoding@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enquirer@^2.3.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" - integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== - dependencies: - ansi-colors "^4.1.1" - strip-ansi "^6.0.1" - -enquirer@~2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -env-paths@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - -envinfo@7.8.1: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -err-code@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.2.1, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -esbuild-plugin-tsc@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/esbuild-plugin-tsc/-/esbuild-plugin-tsc-0.4.0.tgz#d7d516fda0e0b05c8e0b442152deebdee01ddc61" - integrity sha512-q9gWIovt1nkwchMLc2zhyksaiHOv3kDK4b0AUol8lkMCRhJ1zavgfb2fad6BKp7FT9rh/OHmEBXVjczLoi/0yw== - dependencies: - strip-comments "^2.0.1" - -esbuild@^0.19.11: - version "0.19.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" - integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== - optionalDependencies: - "@esbuild/aix-ppc64" "0.19.12" - "@esbuild/android-arm" "0.19.12" - "@esbuild/android-arm64" "0.19.12" - "@esbuild/android-x64" "0.19.12" - "@esbuild/darwin-arm64" "0.19.12" - "@esbuild/darwin-x64" "0.19.12" - "@esbuild/freebsd-arm64" "0.19.12" - "@esbuild/freebsd-x64" "0.19.12" - "@esbuild/linux-arm" "0.19.12" - "@esbuild/linux-arm64" "0.19.12" - "@esbuild/linux-ia32" "0.19.12" - "@esbuild/linux-loong64" "0.19.12" - "@esbuild/linux-mips64el" "0.19.12" - "@esbuild/linux-ppc64" "0.19.12" - "@esbuild/linux-riscv64" "0.19.12" - "@esbuild/linux-s390x" "0.19.12" - "@esbuild/linux-x64" "0.19.12" - "@esbuild/netbsd-x64" "0.19.12" - "@esbuild/openbsd-x64" "0.19.12" - "@esbuild/sunos-x64" "0.19.12" - "@esbuild/win32-arm64" "0.19.12" - "@esbuild/win32-ia32" "0.19.12" - "@esbuild/win32-x64" "0.19.12" - -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== - -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -eslint-config-airbnb-base@15.0.0, eslint-config-airbnb-base@^15.0.0: - version "15.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236" - integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.5" - semver "^6.3.0" - -eslint-config-airbnb-typescript@17.1.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz#fda960eee4a510f092a9a1c139035ac588937ddc" - integrity sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig== - dependencies: - eslint-config-airbnb-base "^15.0.0" - -eslint-config-prettier@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" - integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== - -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-module-utils@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" - integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== - dependencies: - debug "^3.2.7" - -eslint-plugin-import@^2.28.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.15.0" - -eslint-plugin-prettier@^5.0.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1" - integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.8.6" - -eslint-plugin-security@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-security/-/eslint-plugin-security-1.7.1.tgz#0e9c4a471f6e4d3ca16413c7a4a51f3966ba16e4" - integrity sha512-sMStceig8AFglhhT2LqlU5r+/fn9OwsA72O5bBuQVTssPCdQAOQzL+oMn/ZcpeUY6KcNfLJArgcrsSULNjYYdQ== - dependencies: - safe-regex "^2.1.1" - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@^8.48.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -ethereum-bloom-filters@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" - integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== - dependencies: - js-sha3 "^0.8.0" - -ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - -ethereum-cryptography@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" - integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== - dependencies: - "@noble/hashes" "1.2.0" - "@noble/secp256k1" "1.7.1" - "@scure/bip32" "1.1.5" - "@scure/bip39" "1.1.1" - -ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" - integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== - dependencies: - "@noble/curves" "1.3.0" - "@noble/hashes" "1.3.3" - "@scure/bip32" "1.3.3" - "@scure/bip39" "1.2.2" - -ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" - integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - -ethjs-unit@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== - dependencies: - bn.js "4.11.6" - number-to-bn "1.7.0" - -ethjs-util@0.1.6, ethjs-util@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -ev-emitter@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ev-emitter/-/ev-emitter-2.1.2.tgz#91737a2deae9fa95453e7e86cfae976f8c3ced38" - integrity sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q== - -eventemitter3@^4.0.4: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -eventemitter3@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" - integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expand-tilde@^2.0.0, expand-tilde@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" - integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw== - dependencies: - homedir-polyfill "^1.0.1" - -expect@^29.0.0, expect@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" - integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== - dependencies: - "@jest/expect-utils" "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - -exponential-backoff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" - integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - -fast-glob@^3.2.9: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - -fecha@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" - integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== - -figures@3.2.0, figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -filelist@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" - integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== - dependencies: - minimatch "^5.0.1" - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ== - -filenamify@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106" - integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.1" - trim-repeated "^1.0.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -filter-obj@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed" - integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng== - -find-cache-dir@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-node-modules@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/find-node-modules/-/find-node-modules-2.1.3.tgz#3c976cff2ca29ee94b4f9eafc613987fc4c0ee44" - integrity sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg== - dependencies: - findup-sync "^4.0.0" - merge "^2.1.1" - -find-up@5.0.0, find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -findup-sync@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0" - integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ== - dependencies: - detect-file "^1.0.0" - is-glob "^4.0.0" - micromatch "^4.0.2" - resolve-dir "^1.0.1" - -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== - -fn.name@1.x.x: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" - integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== - -follow-redirects@^1.12.1, follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fp-ts@1.19.3: - version "1.19.3" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" - integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== - -fp-ts@^1.0.0: - version "1.19.5" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" - integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs-extra@^11.1.0, fs-extra@^11.1.1: - version "11.2.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" - integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^2.0.0, fs-minipass@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs-minipass@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" - integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== - dependencies: - minipass "^7.0.3" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -ganache@^7.9.2: - version "7.9.2" - resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.9.2.tgz#77f506ad2735dd9109696ffa1834a9dd2f806449" - integrity sha512-7gsVVDpO9AhrFyDMWWl7SpMsPpqGcnAzjxz3k32LheIPNd64p2XsY9GYRdhWmKuryb60W1iaWPZWDkFKlbRWHA== - dependencies: - "@trufflesuite/bigint-buffer" "1.1.10" - "@trufflesuite/uws-js-unofficial" "20.30.0-unofficial.0" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "5.1.1" - "@types/seedrandom" "3.0.1" - abstract-level "1.0.3" - abstract-leveldown "7.2.0" - async-eventemitter "0.2.4" - emittery "0.10.0" - keccak "3.0.2" - leveldown "6.1.0" - secp256k1 "4.0.3" - optionalDependencies: - bufferutil "4.0.5" - utf-8-validate "5.0.7" - -gauge@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" - integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^3.0.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-pkg-repo@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" - integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== - dependencies: - "@hutson/parse-repository-url" "^3.0.0" - hosted-git-info "^4.0.0" - through2 "^2.0.0" - yargs "^16.2.0" - -get-port@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-size@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-size/-/get-size-3.0.0.tgz#00e39a8042a3de237b2fcf288eaf55d3f472417c" - integrity sha512-Y8aiXLq4leR7807UY0yuKEwif5s3kbVp1nTv+i4jBeoUzByTLKkLWu/HorS6/pB+7gsB0o7OTogC8AoOOeT0Hw== - -get-stream@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" - integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - -gh-pages@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-6.1.1.tgz#e80af927a081cb480657fde5a0b87ea2e77d6c74" - integrity sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw== - dependencies: - async "^3.2.4" - commander "^11.0.0" - email-addresses "^5.0.0" - filenamify "^4.3.0" - find-cache-dir "^3.3.1" - fs-extra "^11.1.1" - globby "^6.1.0" - -git-raw-commits@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-3.0.0.tgz#5432f053a9744f67e8db03dbc48add81252cfdeb" - integrity sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw== - dependencies: - dargs "^7.0.0" - meow "^8.1.2" - split2 "^3.2.2" - -git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw== - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - -git-semver-tags@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-5.0.1.tgz#db748aa0e43d313bf38dcd68624d8443234e1c15" - integrity sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA== - dependencies: - meow "^8.1.2" - semver "^7.0.0" - -git-up@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467" - integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ== - dependencies: - is-ssh "^1.4.0" - parse-url "^8.1.0" - -git-url-parse@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-13.1.0.tgz#07e136b5baa08d59fabdf0e33170de425adf07b4" - integrity sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA== - dependencies: - git-up "^7.0.0" - -gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ== - dependencies: - ini "^1.3.2" - -glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@8.1.0, glob@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - -glob@^10.2.2, glob@^10.3.7: - version "10.3.12" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" - integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.6" - minimatch "^9.0.1" - minipass "^7.0.4" - path-scurry "^1.10.2" - -glob@^7.0.3, glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^9.2.0: - version "9.3.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" - integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== - dependencies: - fs.realpath "^1.0.0" - minimatch "^8.0.2" - minipass "^4.2.4" - path-scurry "^1.6.1" - -global-modules@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" - integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== - dependencies: - global-prefix "^1.0.1" - is-windows "^1.0.1" - resolve-dir "^1.0.0" - -global-prefix@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" - integrity sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg== - dependencies: - expand-tilde "^2.0.2" - homedir-polyfill "^1.0.1" - ini "^1.3.4" - is-windows "^1.0.1" - which "^1.2.14" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@11.1.0, globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graceful-fs@4.2.11, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -handlebars@^4.7.7: - version "4.7.8" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" - integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.2" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - -hardhat@^2.17.3: - version "2.22.2" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.2.tgz#0cadd7ec93bf39bab09f81603e75bc5e92acea3d" - integrity sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.3.1" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - "@nomicfoundation/solidity-analyzer" "^0.1.0" - "@sentry/node" "^5.18.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - adm-zip "^0.4.16" - aggregate-error "^3.0.0" - ansi-escapes "^4.3.0" - boxen "^5.1.2" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - ethereum-cryptography "^1.0.3" - ethereumjs-abi "^0.6.8" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "7.2.0" - immutable "^4.0.0-rc.12" - io-ts "1.10.4" - keccak "^3.0.2" - lodash "^4.17.11" - mnemonist "^0.38.0" - mocha "^10.0.0" - p-map "^4.0.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - solc "0.7.3" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - tsort "0.0.1" - undici "^5.14.0" - uuid "^8.3.2" - ws "^7.4.6" - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -has-unicode@2.0.1, has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -homedir-polyfill@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" - integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== - dependencies: - parse-passwd "^1.0.0" - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^3.0.6: - version "3.0.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d" - integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw== - dependencies: - lru-cache "^6.0.0" - -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - -hosted-git-info@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-6.1.1.tgz#629442c7889a69c05de604d52996b74fe6f26d58" - integrity sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w== - dependencies: - lru-cache "^7.5.1" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -http-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" - integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== - dependencies: - "@tootallnate/once" "2" - agent-base "6" - debug "4" - -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-walk@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" - integrity sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw== - dependencies: - minimatch "^5.0.1" - -ignore-walk@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" - integrity sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw== - dependencies: - minimatch "^9.0.0" - -ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== - -immutable@^4.0.0-rc.12: - version "4.3.5" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" - integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== - -import-fresh@^3.2.1, import-fresh@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@3.1.0, import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.2, ini@^1.3.4, ini@^1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -init-package-json@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-5.0.0.tgz#030cf0ea9c84cfc1b0dc2e898b45d171393e4b40" - integrity sha512-kBhlSheBfYmq3e0L1ii+VKe3zBTLL5lDCDWR+f9dLmEGSB3MqLlMlsolubSsyI88Bg6EA+BIMlomAnQ1SwgQBw== - dependencies: - npm-package-arg "^10.0.0" - promzard "^1.0.0" - read "^2.0.0" - read-package-json "^6.0.0" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^5.0.0" - -inquirer@^8.2.4: - version "8.2.6" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562" - integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.21" - mute-stream "0.0.8" - ora "^5.4.1" - run-async "^2.4.0" - rxjs "^7.5.5" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - wrap-ansi "^6.0.1" - -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -io-ts@1.10.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" - integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== - dependencies: - fp-ts "^1.0.0" - -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" - -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-ci@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" - integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== - dependencies: - ci-info "^3.2.0" - -is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== - dependencies: - hasown "^2.0.0" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== - -is-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - -is-ssh@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" - integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== - dependencies: - protocols "^2.0.1" - -is-stream@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== - dependencies: - text-extensions "^1.0.0" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-windows@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - -isows@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" - integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" - integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== - -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz#91655936cf7380e4e473383081e38478b69993b1" - integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== - dependencies: - "@babel/core" "^7.23.9" - "@babel/parser" "^7.23.9" - "@istanbuljs/schema" "^0.1.3" - istanbul-lib-coverage "^3.2.0" - semver "^7.5.4" - -istanbul-lib-report@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" - integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jackspeak@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -jake@^10.8.5: - version "10.8.7" - resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" - integrity sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w== - dependencies: - async "^3.2.3" - chalk "^4.0.2" - filelist "^1.0.4" - minimatch "^3.1.2" - -jest-changed-files@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" - integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== - dependencies: - execa "^5.0.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - -jest-circus@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" - integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^1.0.0" - is-generator-fn "^2.0.0" - jest-each "^29.7.0" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - pretty-format "^29.7.0" - pure-rand "^6.0.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-cli@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" - integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== - dependencies: - "@jest/core" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - chalk "^4.0.0" - create-jest "^29.7.0" - exit "^0.1.2" - import-local "^3.0.2" - jest-config "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - yargs "^17.3.1" - -jest-config@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" - integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.7.0" - "@jest/types" "^29.6.3" - babel-jest "^29.7.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.7.0" - jest-environment-node "^29.7.0" - jest-get-type "^29.6.3" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-runner "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -"jest-diff@>=29.4.3 < 30", jest-diff@^29.4.1, jest-diff@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" - integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.6.3" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-docblock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" - integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== - dependencies: - detect-newline "^3.0.0" - -jest-each@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" - integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - jest-get-type "^29.6.3" - jest-util "^29.7.0" - pretty-format "^29.7.0" - -jest-environment-node@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" - integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -jest-get-type@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" - integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== - -jest-haste-map@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" - integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== - dependencies: - "@jest/types" "^29.6.3" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - jest-worker "^29.7.0" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" - integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== - dependencies: - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-matcher-utils@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" - integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== - dependencies: - chalk "^4.0.0" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-message-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" - integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" - integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-util "^29.7.0" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" - integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== - -jest-resolve-dependencies@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" - integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== - dependencies: - jest-regex-util "^29.6.3" - jest-snapshot "^29.7.0" - -jest-resolve@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" - integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.7.0" - jest-validate "^29.7.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" - slash "^3.0.0" - -jest-runner@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" - integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== - dependencies: - "@jest/console" "^29.7.0" - "@jest/environment" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.7.0" - jest-environment-node "^29.7.0" - jest-haste-map "^29.7.0" - jest-leak-detector "^29.7.0" - jest-message-util "^29.7.0" - jest-resolve "^29.7.0" - jest-runtime "^29.7.0" - jest-util "^29.7.0" - jest-watcher "^29.7.0" - jest-worker "^29.7.0" - p-limit "^3.1.0" - source-map-support "0.5.13" - -jest-runtime@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" - integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/globals" "^29.7.0" - "@jest/source-map" "^29.6.3" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" - integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.7.0" - graceful-fs "^4.2.9" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - natural-compare "^1.4.0" - pretty-format "^29.7.0" - semver "^7.5.3" - -jest-util@^29.0.0, jest-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" - integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" - integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== - dependencies: - "@jest/types" "^29.6.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.6.3" - leven "^3.1.0" - pretty-format "^29.7.0" - -jest-watcher@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" - integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== - dependencies: - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.13.1" - jest-util "^29.7.0" - string-length "^4.0.1" - -jest-worker@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== - dependencies: - "@types/node" "*" - jest-util "^29.7.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" - integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== - dependencies: - "@jest/core" "^29.7.0" - "@jest/types" "^29.6.3" - import-local "^3.0.2" - jest-cli "^29.7.0" - -js-sha3@0.8.0, js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -js-yaml@^3.10.0, js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-parse-even-better-errors@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz#02bb29fb5da90b5444581749c22cedd3597c6cb0" - integrity sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonc-parser@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" - integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== - -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.2.0, jsonparse@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -keccak@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - -keccak@^3.0.0, keccak@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" - integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== - optionalDependencies: - graceful-fs "^4.1.9" - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -kuler@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" - integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== - -lerna-changelog@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/lerna-changelog/-/lerna-changelog-2.2.0.tgz#c43813bba81e30cdeb20aabaef4da390f0f38e41" - integrity sha512-yjYNAHrbnw8xYFKmYWJEP52Tk4xSdlNmzpYr26+3glbSGDmpe8UMo8f9DlEntjGufL+opup421oVTXcLshwAaQ== - dependencies: - chalk "^4.0.0" - cli-highlight "^2.1.11" - execa "^5.0.0" - hosted-git-info "^4.0.0" - make-fetch-happen "^9.0.0" - p-map "^3.0.0" - progress "^2.0.0" - yargs "^17.1.0" - -lerna@^7.2.0: - version "7.4.2" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.4.2.tgz#03497125d7b7c8d463eebfe17a701b16bde2ad09" - integrity sha512-gxavfzHfJ4JL30OvMunmlm4Anw7d7Tq6tdVHzUukLdS9nWnxCN/QB21qR+VJYp5tcyXogHKbdUEGh6qmeyzxSA== - dependencies: - "@lerna/child-process" "7.4.2" - "@lerna/create" "7.4.2" - "@npmcli/run-script" "6.0.2" - "@nx/devkit" ">=16.5.1 < 17" - "@octokit/plugin-enterprise-rest" "6.0.1" - "@octokit/rest" "19.0.11" - byte-size "8.1.1" - chalk "4.1.0" - clone-deep "4.0.1" - cmd-shim "6.0.1" - columnify "1.6.0" - conventional-changelog-angular "7.0.0" - conventional-changelog-core "5.0.1" - conventional-recommended-bump "7.0.1" - cosmiconfig "^8.2.0" - dedent "0.7.0" - envinfo "7.8.1" - execa "5.0.0" - fs-extra "^11.1.1" - get-port "5.1.1" - get-stream "6.0.0" - git-url-parse "13.1.0" - glob-parent "5.1.2" - globby "11.1.0" - graceful-fs "4.2.11" - has-unicode "2.0.1" - import-local "3.1.0" - ini "^1.3.8" - init-package-json "5.0.0" - inquirer "^8.2.4" - is-ci "3.0.1" - is-stream "2.0.0" - jest-diff ">=29.4.3 < 30" - js-yaml "4.1.0" - libnpmaccess "7.0.2" - libnpmpublish "7.3.0" - load-json-file "6.2.0" - lodash "^4.17.21" - make-dir "4.0.0" - minimatch "3.0.5" - multimatch "5.0.0" - node-fetch "2.6.7" - npm-package-arg "8.1.1" - npm-packlist "5.1.1" - npm-registry-fetch "^14.0.5" - npmlog "^6.0.2" - nx ">=16.5.1 < 17" - p-map "4.0.0" - p-map-series "2.1.0" - p-pipe "3.1.0" - p-queue "6.6.2" - p-reduce "2.1.0" - p-waterfall "2.1.1" - pacote "^15.2.0" - pify "5.0.0" - read-cmd-shim "4.0.0" - read-package-json "6.0.4" - resolve-from "5.0.0" - rimraf "^4.4.1" - semver "^7.3.8" - signal-exit "3.0.7" - slash "3.0.0" - ssri "^9.0.1" - strong-log-transformer "2.1.0" - tar "6.1.11" - temp-dir "1.0.0" - typescript ">=3 < 6" - upath "2.0.1" - uuid "^9.0.0" - validate-npm-package-license "3.0.4" - validate-npm-package-name "5.0.0" - write-file-atomic "5.0.1" - write-pkg "4.0.0" - yargs "16.2.0" - yargs-parser "20.2.4" - -level-concat-iterator@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" - integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== - dependencies: - catering "^2.1.0" - -level-supports@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" - integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== - -level-supports@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" - integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== - -level-transcoder@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" - integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== - dependencies: - buffer "^6.0.3" - module-error "^1.0.1" - -leveldown@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" - integrity sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w== - dependencies: - abstract-leveldown "^7.2.0" - napi-macros "~2.0.0" - node-gyp-build "^4.3.0" - -leven@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -libnpmaccess@7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" - integrity sha512-vHBVMw1JFMTgEk15zRsJuSAg7QtGGHpUSEfnbcRL1/gTBag9iEfJbyjpDmdJmwMhvpoLoNBtdAUCdGnaP32hhw== - dependencies: - npm-package-arg "^10.1.0" - npm-registry-fetch "^14.0.3" - -libnpmpublish@7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-7.3.0.tgz#2ceb2b36866d75a6cd7b4aa748808169f4d17e37" - integrity sha512-fHUxw5VJhZCNSls0KLNEG0mCD2PN1i14gH5elGOgiVnU3VgTcRahagYP2LKI1m0tFCJ+XrAm0zVYyF5RCbXzcg== - dependencies: - ci-info "^3.6.1" - normalize-package-data "^5.0.0" - npm-package-arg "^10.1.0" - npm-registry-fetch "^14.0.3" - proc-log "^3.0.0" - semver "^7.3.7" - sigstore "^1.4.0" - ssri "^10.0.1" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -lines-and-columns@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.4.tgz#d00318855905d2660d8c0822e3f5a4715855fc42" - integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== - -load-json-file@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.ismatch@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.1.0, log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -logform@^2.3.2, logform@^2.4.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5" - integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== - dependencies: - "@colors/colors" "1.6.0" - "@types/triple-beam" "^1.3.2" - fecha "^4.2.0" - ms "^2.1.1" - safe-stable-stringify "^2.3.1" - triple-beam "^1.3.0" - -lru-cache@^10.0.1, lru-cache@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -make-dir@4.0.0, make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -make-fetch-happen@^10.0.3: - version "10.2.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" - integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== - dependencies: - agentkeepalive "^4.2.1" - cacache "^16.1.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^3.1.6" - minipass-collect "^1.0.2" - minipass-fetch "^2.0.3" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.3" - promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" - ssri "^9.0.0" - -make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f" - integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w== - dependencies: - agentkeepalive "^4.2.1" - cacache "^17.0.0" - http-cache-semantics "^4.1.1" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^5.0.0" - minipass-fetch "^3.0.0" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.3" - promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" - ssri "^10.0.0" - -make-fetch-happen@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== - -map-obj@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -marked@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" - integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== - -meow@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -merge@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-2.1.1.tgz#59ef4bf7e0b3e879186436e8481c06a6c162ca98" - integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== - -merkletreejs@^0.3.11: - version "0.3.11" - resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.3.11.tgz#e0de05c3ca1fd368de05a12cb8efb954ef6fc04f" - integrity sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ== - dependencies: - bignumber.js "^9.0.1" - buffer-reverse "^1.0.1" - crypto-js "^4.2.0" - treeify "^1.1.0" - web3-utils "^1.3.4" - -micro-ftch@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" - integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== - -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -minimatch@3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" - integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^8.0.2: - version "8.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" - integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: - version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== - dependencies: - brace-expansion "^2.0.1" - -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - -minipass-fetch@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" - integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA== - dependencies: - minipass "^3.1.6" - minipass-sized "^1.0.3" - minizlib "^2.1.2" - optionalDependencies: - encoding "^0.1.13" - -minipass-fetch@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.4.tgz#4d4d9b9f34053af6c6e597a64be8e66e42bf45b7" - integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== - dependencies: - minipass "^7.0.3" - minipass-sized "^1.0.3" - minizlib "^2.1.2" - optionalDependencies: - encoding "^0.1.13" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-json-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" - integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== - dependencies: - jsonparse "^1.3.1" - minipass "^3.0.0" - -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" - integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== - -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - -minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp@1.0.4, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mnemonist@^0.38.0: - version "0.38.5" - resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" - integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== - dependencies: - obliterator "^2.0.0" - -mocha@^10.0.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" - integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "8.1.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -modify-values@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" - integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== - -module-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" - integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== - -mri@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" - integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multimatch@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" - integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -mute-stream@^1.0.0, mute-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" - integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== - -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -negotiator@^0.6.2, negotiator@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -nock@^13.2.9: - version "13.5.4" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.4.tgz#8918f0addc70a63736170fef7106a9721e0dc479" - integrity sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw== - dependencies: - debug "^4.1.0" - json-stringify-safe "^5.0.1" - propagate "^2.0.0" - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-addon-api@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" - integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== - -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.7: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" - integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== - -node-gyp@^9.0.0, node-gyp@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.1.tgz#8a1023e0d6766ecb52764cc3a734b36ff275e185" - integrity sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ== - dependencies: - env-paths "^2.2.0" - exponential-backoff "^3.1.1" - glob "^7.1.4" - graceful-fs "^4.2.6" - make-fetch-happen "^10.0.3" - nopt "^6.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.2" - which "^2.0.2" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-machine-id@1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" - integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ== - -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -nopt@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" - integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g== - dependencies: - abbrev "^1.0.0" - -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.0, normalize-package-data@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588" - integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q== - dependencies: - hosted-git-info "^6.0.0" - is-core-module "^2.8.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-bundled@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" - integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-bundled@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" - integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ== - dependencies: - npm-normalize-package-bin "^3.0.0" - -npm-dts@^1.3.12: - version "1.3.12" - resolved "https://registry.yarnpkg.com/npm-dts/-/npm-dts-1.3.12.tgz#e422b1188fb616f41fe5c566c3d636c1aafb2ed8" - integrity sha512-3pFsz7Gf1u0cyQE2czXt8Y0hKe6kczHxlFbVrr74xWweNUit2tCDbOcL4n6KaWxyimGNJ4gzOa8KkShFA8hrdA== - dependencies: - args "5.0.3" - find-node-modules "2.1.3" - mkdirp "1.0.4" - npm-run "5.0.1" - rimraf "3.0.2" - tmp "0.2.1" - winston "3.7.2" - -npm-install-checks@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" - integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== - dependencies: - semver "^7.1.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-normalize-package-bin@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" - integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== - -npm-package-arg@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.1.tgz#00ebf16ac395c63318e67ce66780a06db6df1b04" - integrity sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg== - dependencies: - hosted-git-info "^3.0.6" - semver "^7.0.0" - validate-npm-package-name "^3.0.0" - -npm-package-arg@^10.0.0, npm-package-arg@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" - integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== - dependencies: - hosted-git-info "^6.0.0" - proc-log "^3.0.0" - semver "^7.3.5" - validate-npm-package-name "^5.0.0" - -npm-packlist@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.1.tgz#79bcaf22a26b6c30aa4dd66b976d69cc286800e0" - integrity sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw== - dependencies: - glob "^8.0.1" - ignore-walk "^5.0.1" - npm-bundled "^1.1.2" - npm-normalize-package-bin "^1.0.1" - -npm-packlist@^7.0.0: - version "7.0.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-7.0.4.tgz#033bf74110eb74daf2910dc75144411999c5ff32" - integrity sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q== - dependencies: - ignore-walk "^6.0.0" - -npm-path@^2.0.2, npm-path@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" - integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== - dependencies: - which "^1.2.10" - -npm-pick-manifest@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz#2159778d9c7360420c925c1a2287b5a884c713aa" - integrity sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg== - dependencies: - npm-install-checks "^6.0.0" - npm-normalize-package-bin "^3.0.0" - npm-package-arg "^10.0.0" - semver "^7.3.5" - -npm-registry-fetch@^14.0.0, npm-registry-fetch@^14.0.3, npm-registry-fetch@^14.0.5: - version "14.0.5" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz#fe7169957ba4986a4853a650278ee02e568d115d" - integrity sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA== - dependencies: - make-fetch-happen "^11.0.0" - minipass "^5.0.0" - minipass-fetch "^3.0.0" - minipass-json-stream "^1.0.1" - minizlib "^2.1.2" - npm-package-arg "^10.0.0" - proc-log "^3.0.0" - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npm-run@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npm-run/-/npm-run-5.0.1.tgz#1baea93389b50ae25a32382c8ca322398e50cd16" - integrity sha512-s7FyRpHUgaJfzkRgOnevX8rAWWsv1dofY1XS7hliWCF6LSQh+HtDfBvpigPS1krLvXw+Fi17CYMY8mUtblnyWw== - dependencies: - minimist "^1.2.0" - npm-path "^2.0.4" - npm-which "^3.0.1" - serializerr "^1.0.3" - -npm-which@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" - integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== - dependencies: - commander "^2.9.0" - npm-path "^2.0.2" - which "^1.2.10" - -npmlog@^6.0.0, npmlog@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== - dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" - -number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - -nx@16.10.0, "nx@>=16.5.1 < 17", nx@^16.8.1: - version "16.10.0" - resolved "https://registry.yarnpkg.com/nx/-/nx-16.10.0.tgz#b070461f7de0a3d7988bd78558ea84cda3543ace" - integrity sha512-gZl4iCC0Hx0Qe1VWmO4Bkeul2nttuXdPpfnlcDKSACGu3ZIo+uySqwOF8yBAxSTIf8xe2JRhgzJN1aFkuezEBg== - dependencies: - "@nrwl/tao" "16.10.0" - "@parcel/watcher" "2.0.4" - "@yarnpkg/lockfile" "^1.1.0" - "@yarnpkg/parsers" "3.0.0-rc.46" - "@zkochan/js-yaml" "0.0.6" - axios "^1.0.0" - chalk "^4.1.0" - cli-cursor "3.1.0" - cli-spinners "2.6.1" - cliui "^8.0.1" - dotenv "~16.3.1" - dotenv-expand "~10.0.0" - enquirer "~2.3.6" - figures "3.2.0" - flat "^5.0.2" - fs-extra "^11.1.0" - glob "7.1.4" - ignore "^5.0.4" - jest-diff "^29.4.1" - js-yaml "4.1.0" - jsonc-parser "3.2.0" - lines-and-columns "~2.0.3" - minimatch "3.0.5" - node-machine-id "1.1.12" - npm-run-path "^4.0.1" - open "^8.4.0" - semver "7.5.3" - string-width "^4.2.3" - strong-log-transformer "^2.1.0" - tar-stream "~2.2.0" - tmp "~0.2.1" - tsconfig-paths "^4.1.2" - tslib "^2.3.0" - v8-compile-cache "2.3.0" - yargs "^17.6.2" - yargs-parser "21.1.1" - optionalDependencies: - "@nx/nx-darwin-arm64" "16.10.0" - "@nx/nx-darwin-x64" "16.10.0" - "@nx/nx-freebsd-x64" "16.10.0" - "@nx/nx-linux-arm-gnueabihf" "16.10.0" - "@nx/nx-linux-arm64-gnu" "16.10.0" - "@nx/nx-linux-arm64-musl" "16.10.0" - "@nx/nx-linux-x64-gnu" "16.10.0" - "@nx/nx-linux-x64-musl" "16.10.0" - "@nx/nx-win32-arm64-msvc" "16.10.0" - "@nx/nx-win32-x64-msvc" "16.10.0" - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2, object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.5: - version "1.1.8" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" - integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -object.fromentries@^2.0.7: - version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - -object.groupby@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" - integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - -object.values@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -obliterator@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" - integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== - -once@^1.3.0, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -one-time@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" - integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== - dependencies: - fn.name "1.x.x" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^8.4.0: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== - dependencies: - p-limit "^1.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-map-series@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" - integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== - -p-map@4.0.0, p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - -p-pipe@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" - integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== - -p-queue@6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" - integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== - dependencies: - eventemitter3 "^4.0.4" - p-timeout "^3.2.0" - -p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - -p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -p-waterfall@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" - integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== - dependencies: - p-reduce "^2.0.0" - -pacote@^15.2.0: - version "15.2.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" - integrity sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA== - dependencies: - "@npmcli/git" "^4.0.0" - "@npmcli/installed-package-contents" "^2.0.1" - "@npmcli/promise-spawn" "^6.0.1" - "@npmcli/run-script" "^6.0.0" - cacache "^17.0.0" - fs-minipass "^3.0.0" - minipass "^5.0.0" - npm-package-arg "^10.0.0" - npm-packlist "^7.0.0" - npm-pick-manifest "^8.0.0" - npm-registry-fetch "^14.0.0" - proc-log "^3.0.0" - promise-retry "^2.0.1" - read-package-json "^6.0.0" - read-package-json-fast "^3.0.0" - sigstore "^1.3.0" - ssri "^10.0.0" - tar "^6.1.11" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== - -parse-path@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b" - integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog== - dependencies: - protocols "^2.0.0" - -parse-url@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d" - integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w== - dependencies: - parse-path "^7.0.0" - -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-scurry@^1.10.2, path-scurry@^1.6.1: - version "1.10.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" - integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.17: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== - -pirates@^4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pkg-dir@^4.1.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^3.0.3: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== - -pretty-format@^29.0.0, pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -proc-log@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" - integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== - -promise-retry@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -promzard@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.1.tgz#3b77251a24f988c0886f5649d4f642bcdd53e558" - integrity sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A== - dependencies: - read "^3.0.1" - -propagate@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" - integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== - -protochain@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/protochain/-/protochain-1.0.5.tgz#991c407e99de264aadf8f81504b5e7faf7bfa260" - integrity sha512-4hDwFSX50C4NE6f/6zg8EPr/WLPTkFPUtG0ulWZu6bwzV2hmb50fpdQLr0HiKBAUehapaFpItzWoCLjraLJhUA== - -protocols@^2.0.0, protocols@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" - integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -pure-rand@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" - integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== - -query-string@^8.1.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-8.2.0.tgz#f0b0ef6caa85f525dbdb745a67d3f8c08d71cc6b" - integrity sha512-tUZIw8J0CawM5wyGBiDOAp7ObdRQh4uBor/fUR9ZjmbZVvw95OD9If4w3MQxr99rg0DJZ/9CIORcpEqU5hQG7g== - dependencies: - decode-uri-component "^0.4.1" - filter-obj "^5.1.0" - split-on-first "^3.0.0" - -queue-microtask@^1.2.2, queue-microtask@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -raw-body@^2.4.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -read-cmd-shim@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" - integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== - -read-package-json-fast@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" - integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== - dependencies: - json-parse-even-better-errors "^3.0.0" - npm-normalize-package-bin "^3.0.0" - -read-package-json@6.0.4, read-package-json@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.4.tgz#90318824ec456c287437ea79595f4c2854708836" - integrity sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw== - dependencies: - glob "^10.2.2" - json-parse-even-better-errors "^3.0.0" - normalize-package-data "^5.0.0" - npm-normalize-package-bin "^3.0.0" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw== - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -read@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/read/-/read-2.1.0.tgz#69409372c54fe3381092bc363a00650b6ac37218" - integrity sha512-bvxi1QLJHcaywCAEsAk4DG3nVoqiY2Csps3qzWalhj5hFqRn1d/OixkFXtLO1PrgHUcAP0FNaSY/5GYNfENFFQ== - dependencies: - mute-stream "~1.0.0" - -read@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read/-/read-3.0.1.tgz#926808f0f7c83fa95f1ef33c0e2c09dbb28fd192" - integrity sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw== - dependencies: - mute-stream "^1.0.0" - -readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regexp-tree@~0.1.1: - version "0.1.27" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" - integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== - -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-from-string@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-dir@^1.0.0, resolve-dir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" - integrity sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg== - dependencies: - expand-tilde "^2.0.0" - global-modules "^1.0.0" - -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== - -resolve@1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - -resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rimraf@^2.2.8: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" - integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== - dependencies: - glob "^9.2.0" - -rimraf@^5.0.1: - version "5.0.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" - integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== - dependencies: - glob "^10.3.7" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rlp@^2.2.3: - version "2.2.7" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" - integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== - dependencies: - bn.js "^5.2.0" - -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^7.5.5, rxjs@^7.8.1: - version "7.8.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== - dependencies: - tslib "^2.1.0" - -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -safe-regex@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" - integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== - dependencies: - regexp-tree "~0.1.1" - -safe-stable-stringify@^2.3.1: - version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -scrypt-js@3.0.1, scrypt-js@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - -secp256k1@4.0.3, secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" - integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -serializerr@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/serializerr/-/serializerr-1.0.3.tgz#12d4c5aa1c3ffb8f6d1dc5f395aa9455569c3f91" - integrity sha512-yXUlHj0fjbndhACj2XWtIH5eJv7b/uadyl7CJA8b9wL5mIKm+g0/sL7rDzEmjC+k5y8ggcaP8i049F4FxA0U9Q== - dependencies: - protochain "^1.0.5" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" - integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== - -shiki@^0.14.7: - version "0.14.7" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" - integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== - dependencies: - ansi-sequence-parser "^1.1.0" - jsonc-parser "^3.2.0" - vscode-oniguruma "^1.7.0" - vscode-textmate "^8.0.0" - -side-channel@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -signal-exit@3.0.7, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -sigstore@^1.3.0, sigstore@^1.4.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.9.0.tgz#1e7ad8933aa99b75c6898ddd0eeebc3eb0d59875" - integrity sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A== - dependencies: - "@sigstore/bundle" "^1.1.0" - "@sigstore/protobuf-specs" "^0.2.0" - "@sigstore/sign" "^1.0.0" - "@sigstore/tuf" "^1.0.3" - make-fetch-happen "^11.0.1" - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== - dependencies: - is-arrayish "^0.3.1" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@3.0.0, slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -smart-buffer@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== - -socks-proxy-agent@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" - integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - -socks-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" - integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - -socks@^2.6.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.1.tgz#22c7d9dd7882649043cba0eafb49ae144e3457af" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== - dependencies: - ip-address "^9.0.5" - smart-buffer "^4.2.0" - -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== - dependencies: - command-exists "^1.2.8" - commander "3.0.2" - follow-redirects "^1.12.1" - fs-extra "^0.30.0" - js-sha3 "0.8.0" - memorystream "^0.3.1" - require-from-string "^2.0.0" - semver "^5.5.0" - tmp "0.0.33" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg== - dependencies: - is-plain-obj "^1.0.0" - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.5.13: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spawn-command@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" - integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" - integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.17" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" - integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== - -split-on-first@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7" - integrity sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA== - -split2@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -split@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - -sprintf-js@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" - integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -ssri@^10.0.0, ssri@^10.0.1: - version "10.0.5" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" - integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== - dependencies: - minipass "^7.0.3" - -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - -ssri@^9.0.0, ssri@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" - integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q== - dependencies: - minipass "^3.1.1" - -stack-trace@0.0.x: - version "0.0.10" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" - integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== - -stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - -stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== - dependencies: - type-fest "^0.7.1" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" - integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== - dependencies: - is-hex-prefixed "1.0.0" - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-json-comments@3.1.1, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-outer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - -strong-log-transformer@2.1.0, strong-log-transformer@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" - integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== - dependencies: - duplexer "^0.1.1" - minimist "^1.2.0" - through "^2.3.4" - -supports-color@8.1.1, supports-color@^8.0.0, supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -synckit@^0.8.6: - version "0.8.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" - integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== - dependencies: - "@pkgr/core" "^0.1.0" - tslib "^2.6.2" - -tar-stream@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@6.1.11: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" - integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^5.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -temp-dir@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== - -text-hex@1.0.x: - version "1.0.0" - resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" - integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tmp@0.0.33, tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tmp@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - -tmp@~0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" - integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - -treeify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" - integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== - -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg== - dependencies: - escape-string-regexp "^1.0.2" - -triple-beam@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" - integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== - -ts-api-utils@^1.0.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== - -ts-jest@^29.1.1: - version "29.1.2" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.2.tgz#7613d8c81c43c8cb312c6904027257e814c40e09" - integrity sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^29.0.0" - json5 "^2.2.3" - lodash.memoize "4.x" - make-error "1.x" - semver "^7.5.3" - yargs-parser "^21.0.1" - -ts-node@^10.9.1: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tsconfig-paths@^3.15.0: - version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tsconfig-paths@^4.1.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" - integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== - dependencies: - json5 "^2.2.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - -tsort@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" - integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== - -tuf-js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-1.1.7.tgz#21b7ae92a9373015be77dfe0cb282a80ec3bbe43" - integrity sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg== - dependencies: - "@tufjs/models" "1.0.4" - debug "^4.3.4" - make-fetch-happen "^11.1.1" - -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" - integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" - integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== - -typedoc@^0.25.7: - version "0.25.12" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.12.tgz#f73f0a8d3731d418cc604d4230f95a857799e27a" - integrity sha512-F+qhkK2VoTweDXd1c42GS/By2DvI2uDF4/EpG424dTexSHdtCH52C6IcAvMA6jR3DzAWZjHpUOW+E02kyPNUNw== - dependencies: - lunr "^2.3.9" - marked "^4.3.0" - minimatch "^9.0.3" - shiki "^0.14.7" - -"typescript@>=3 < 6", typescript@^5.3.3: - version "5.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" - integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== - -uglify-js@^3.1.4: - version "3.17.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" - integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -undici@^5.14.0: - version "5.28.4" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" - integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== - dependencies: - "@fastify/busboy" "^2.0.0" - -unidragger@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/unidragger/-/unidragger-3.0.1.tgz#72b2e63f2571ca6e95a884b139dfec764e08c7f3" - integrity sha512-RngbGSwBFmqGBWjkaH+yB677uzR95blSQyxq6hYbrQCejH3Mx1nm8DVOuh3M9k2fQyTstWUG5qlgCnNqV/9jVw== - dependencies: - ev-emitter "^2.0.0" - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-filename@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" - integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A== - dependencies: - unique-slug "^3.0.0" - -unique-filename@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" - integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== - dependencies: - unique-slug "^4.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -unique-slug@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" - integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w== - dependencies: - imurmurhash "^0.1.4" - -unique-slug@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" - integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== - dependencies: - imurmurhash "^0.1.4" - -universal-user-agent@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" - integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -upath@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" - integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== - -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.7.tgz#c15a19a6af1f7ad9ec7ddc425747ca28c3644922" - integrity sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q== - dependencies: - node-gyp-build "^4.3.0" - -utf-8-validate@6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-6.0.3.tgz#7d8c936d854e86b24d1d655f138ee27d2636d777" - integrity sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA== - dependencies: - node-gyp-build "^4.3.0" - -utf8@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -uuid@8.3.2, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -uuid@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - -uuidv4@^6.2.13: - version "6.2.13" - resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7" - integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ== - dependencies: - "@types/uuid" "8.3.4" - uuid "8.3.2" - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-compile-cache@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-to-istanbul@^9.0.1: - version "9.2.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" - integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^2.0.0" - -validate-npm-package-license@3.0.4, validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@5.0.0, validate-npm-package-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" - integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== - dependencies: - builtins "^5.0.0" - -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== - dependencies: - builtins "^1.0.3" - -viem@^2.7.12, viem@^2.8.6: - version "2.9.8" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.8.tgz#15288cc5332292617786d21db0aa3571db29c4c9" - integrity sha512-vetoTZ6UF2okS/1I0+1p/QYdC4yA6uf4PeWwTBp3kD5wC6eQcmeh7zP+unNdnYHGGC63x7BTGldK1ep2IFVKcQ== - dependencies: - "@adraffy/ens-normalize" "1.10.0" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@scure/bip32" "1.3.2" - "@scure/bip39" "1.2.1" - abitype "1.0.0" - isows "1.0.3" - ws "8.13.0" - -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== - -vscode-textmate@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" - integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== - -walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -wcwidth@^1.0.0, wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== - dependencies: - defaults "^1.0.3" - -web3-utils@^1.3.4: - version "1.10.4" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" - integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== - dependencies: - "@ethereumjs/util" "^8.1.0" - bn.js "^5.2.1" - ethereum-bloom-filters "^1.0.6" - ethereum-cryptography "^2.1.2" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - utf8 "3.0.0" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which@^1.2.10, which@^1.2.14: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -which@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" - integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - -winston-transport@^4.5.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.0.tgz#e302e6889e6ccb7f383b926df6936a5b781bd1f0" - integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== - dependencies: - logform "^2.3.2" - readable-stream "^3.6.0" - triple-beam "^1.3.0" - -winston@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/winston/-/winston-3.7.2.tgz#95b4eeddbec902b3db1424932ac634f887c400b1" - integrity sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng== - dependencies: - "@dabh/diagnostics" "^2.0.2" - async "^3.2.3" - is-stream "^2.0.0" - logform "^2.4.0" - one-time "^1.0.0" - readable-stream "^3.4.0" - safe-stable-stringify "^2.3.1" - stack-trace "0.0.x" - triple-beam "^1.3.0" - winston-transport "^4.5.0" - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - -workerpool@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" - integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" - integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^4.0.1" - -write-file-atomic@^2.4.2: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -write-json-file@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" - integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.15" - make-dir "^2.1.0" - pify "^4.0.1" - sort-keys "^2.0.0" - write-file-atomic "^2.4.2" - -write-pkg@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" - integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== - dependencies: - sort-keys "^2.0.0" - type-fest "^0.4.1" - write-json-file "^3.2.0" - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -ws@8.13.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== - -ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@16.2.0, yargs@^16.0.0, yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^17.1.0, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zod@^3.22.4: - version "3.22.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" - integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== From 539269e60f33790a9753644feff729902fea1349 Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Fri, 19 Apr 2024 17:10:01 +0100 Subject: [PATCH 24/33] chore: add further tests (#471) * chore: add further tests --- .../actions/install-dependencies/action.yml | 1 - .github/workflows/size-report.yml | 8 ++- .github/workflows/test-read.yml | 2 +- .github/workflows/test-write.yml | 2 + .size-limit.json | 6 +- biome.json | 3 +- bun.lockb | Bin 262560 -> 263597 bytes package.json | 1 + src/account/BiconomySmartAccountV2.ts | 16 +++-- src/account/utils/EthersSigner.ts | 3 +- src/account/utils/HttpRequests.ts | 4 +- src/account/utils/Logger.ts | 9 +-- src/account/utils/Types.ts | 3 + src/account/utils/Utils.ts | 1 + .../session-storage/SessionFileStorage.ts | 12 ++-- .../session-storage/SessionLocalStorage.ts | 5 +- .../session-storage/SessionMemoryStorage.ts | 4 +- src/paymaster/utils/Types.ts | 3 + tests/account/read.test.ts | 56 +----------------- tests/account/write.test.ts | 56 +++++++++++++++++- tests/bundler/read.test.ts | 4 +- tests/bundler/write.test.ts | 44 +++++++++++++- tests/modules/read.test.ts | 2 +- tests/modules/write.test.ts | 5 +- tests/paymaster/read.test.ts | 2 +- 25 files changed, 158 insertions(+), 94 deletions(-) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 303914370..3dbb2bd0b 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -10,5 +10,4 @@ runs: - name: Install dependencies shell: bash run: | - bun install buffer bun install --frozen-lockfile diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml index 5dabd450e..99d8cb94f 100644 --- a/.github/workflows/size-report.yml +++ b/.github/workflows/size-report.yml @@ -19,8 +19,14 @@ jobs: - name: Clone repository uses: actions/checkout@v3 + - name: Set up Bun + uses: oven-sh/setup-bun@v1 + - name: Install dependencies - uses: ./.github/actions/install-dependencies + shell: bash + run: | + bun install buffer + bun install --frozen-lockfile --production - name: Report bundle size uses: andresz1/size-limit-action@master diff --git a/.github/workflows/test-read.yml b/.github/workflows/test-read.yml index a972a2fea..4a36c8c45 100644 --- a/.github/workflows/test-read.yml +++ b/.github/workflows/test-read.yml @@ -1,4 +1,4 @@ -name: test:read +name: test-read on: workflow_dispatch: pull_request: diff --git a/.github/workflows/test-write.yml b/.github/workflows/test-write.yml index 12487e077..ee749bdbe 100644 --- a/.github/workflows/test-write.yml +++ b/.github/workflows/test-write.yml @@ -3,6 +3,8 @@ on: workflow_dispatch: pull_request_review: types: [submitted] + pull_request: + types: [opened] jobs: test-write: name: test-write diff --git a/.size-limit.json b/.size-limit.json index 86c157518..97fe21ed6 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -2,18 +2,18 @@ { "name": "core (esm)", "path": "./dist/_esm/index.js", - "limit": "10 kB", + "limit": "60 kB", "import": "*" }, { "name": "core (cjs)", "path": "./dist/_cjs/index.js", - "limit": "25 kB" + "limit": "60 kB" }, { "name": "smartAccount (tree-shaking)", "path": "./dist/_esm/index.js", - "limit": "5 kB", + "limit": "60 kB", "import": "{ createSmartAccountClient }" }, { diff --git a/biome.json b/biome.json index 20f2a72ce..dfd9300dc 100644 --- a/biome.json +++ b/biome.json @@ -12,7 +12,8 @@ "_esm", "_types", "bun.lockb", - "docs" + "docs", + "dist" ] }, "organizeImports": { diff --git a/bun.lockb b/bun.lockb index b5ff986bce2335154fdd941cc3017a64ea05c78c..d4c0bada894740cb93b5cf72198f651cd50f3078 100755 GIT binary patch delta 49611 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 delta 49259 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 diff --git a/package.json b/package.json index f8649f58c..a3d38bc83 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "commit-msg": "npx --no -- commitlint --edit ${1}" }, "dependencies": { + "buffer": "^6.0.3", "merkletreejs": "^0.3.11" } } diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index f92040cfb..981f88da9 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -714,7 +714,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { (smartAccountInfo: { factoryVersion: string currentVersion: string - deploymentIndex: { toString: () => any } + deploymentIndex: { toString: () => string } }) => smartAccountInfo.factoryVersion === "v1" && smartAccountInfo.currentVersion === "2.0.0" && @@ -887,7 +887,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { if (paymasterServiceData.mode === PaymasterMode.ERC20) { if (paymasterServiceData?.feeQuote) { const { feeQuote, spender, maxApproval = false } = paymasterServiceData - Logger.log("there is a feeQuote: ", feeQuote) + Logger.log("there is a feeQuote: ", JSON.stringify(feeQuote, null, 2)) if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED) if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH) if ( @@ -1166,7 +1166,10 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { ] this.validateUserOp(userOp, requiredFields) if (!this.bundler) throw new Error("Bundler is not provided") - Logger.warn("userOp being sent to the bundler", userOp) + Logger.warn( + "userOp being sent to the bundler", + JSON.stringify(userOp, null, 2) + ) const bundlerResponse = await this.bundler.sendUserOp( userOp, simulationType @@ -1498,7 +1501,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { let newCallData = userOp.callData Logger.warn( "Received information about fee token address and quote ", - tokenPaymasterRequest + tokenPaymasterRequest.toString() ) if (this.paymaster && this.paymaster instanceof Paymaster) { @@ -1589,7 +1592,10 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { } } catch (error) { Logger.log("Failed to update userOp. Sending back original op") - Logger.error("Failed to update callData with error", error) + Logger.error( + "Failed to update callData with error", + JSON.stringify(error) + ) return userOp } return userOp diff --git a/src/account/utils/EthersSigner.ts b/src/account/utils/EthersSigner.ts index 5019597be..8af82cb10 100644 --- a/src/account/utils/EthersSigner.ts +++ b/src/account/utils/EthersSigner.ts @@ -23,7 +23,8 @@ export class EthersSigner<T extends LightSigner> return this.#correctSignature(signature as Hex) } - async signTypedData(_notUsed: any): Promise<Hex> { + // biome-ignore lint/suspicious/noExplicitAny: <explanation> + async signTypedData(_: any): Promise<Hex> { throw new Error("signTypedData is not supported for Ethers Signer") } diff --git a/src/account/utils/HttpRequests.ts b/src/account/utils/HttpRequests.ts index 07e900225..0b641aff1 100644 --- a/src/account/utils/HttpRequests.ts +++ b/src/account/utils/HttpRequests.ts @@ -8,10 +8,10 @@ export enum HttpMethod { Delete = "delete" } -/* eslint-disable @typescript-eslint/no-explicit-any */ export interface HttpRequest { url: string method: HttpMethod + // biome-ignore lint/suspicious/noExplicitAny: <explanation> body?: Record<string, any> } @@ -28,7 +28,7 @@ export async function sendRequest<T>( body: JSON.stringify(body) }) - // biome-ignore lint/suspicious/noImplicitAnyLet: <explanation> + // biome-ignore lint/suspicious/noExplicitAny: <explanation> let jsonResponse: any try { jsonResponse = await response.json() diff --git a/src/account/utils/Logger.ts b/src/account/utils/Logger.ts index fd0aad9cb..c096cc270 100644 --- a/src/account/utils/Logger.ts +++ b/src/account/utils/Logger.ts @@ -21,8 +21,7 @@ class Logger { * warn - Magenta[time] Yellow[WARN]: Cyan[message]: [value] * error - Magenta[time] Red[ERROR]: Cyan[message]: [value] */ - /* eslint-disable @typescript-eslint/no-explicit-any */ - static log(message: string, value?: any): void { + static log(message: string, value = ""): void { const timestamp = new Date().toISOString() const logMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[36m${message}\x1b[0m:` @@ -31,8 +30,7 @@ class Logger { } } - /* eslint-disable @typescript-eslint/no-explicit-any */ - static warn(message: string, value?: any): void { + static warn(message: string, value = ""): void { const timestamp = new Date().toISOString() const warnMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[33mWARN\x1b[0m: \x1b[36m${message}\x1b[0m` @@ -41,8 +39,7 @@ class Logger { } } - /* eslint-disable @typescript-eslint/no-explicit-any */ - static error(message: string, value?: any): void { + static error(message: string, value = ""): void { const timestamp = new Date().toISOString() const errorMessage = `\x1b[35m[${timestamp}]\x1b[0m \x1b[31mERROR\x1b[0m: \x1b[36m${message}\x1b[0m` diff --git a/src/account/utils/Types.ts b/src/account/utils/Types.ts index 857e51167..305783750 100644 --- a/src/account/utils/Types.ts +++ b/src/account/utils/Types.ts @@ -239,6 +239,7 @@ export type PaymasterUserOperationDto = SponsorUserOperationDto & /** Expiry duration in seconds */ expiryDuration?: number /** Webhooks to be fired after user op is sent */ + // biome-ignore lint/suspicious/noExplicitAny: <explanation> webhookData?: Record<string, any> /** Smart account meta data */ smartAccountInfo?: SmartAccountData @@ -405,6 +406,8 @@ export interface UserOperationStruct { * @method signMessage - sign a message * @method signTypedData - sign typed data */ + +// biome-ignore lint/suspicious/noExplicitAny: <explanation> export interface SmartAccountSigner<Inner = any> { signerType: string inner: Inner diff --git a/src/account/utils/Utils.ts b/src/account/utils/Utils.ts index 979368c75..aa6c54845 100644 --- a/src/account/utils/Utils.ts +++ b/src/account/utils/Utils.ts @@ -65,6 +65,7 @@ export function packUserOp( ) } +// biome-ignore lint/suspicious/noExplicitAny: <explanation> export const isNullOrUndefined = (value: any): value is undefined => { return value === null || value === undefined } diff --git a/src/modules/session-storage/SessionFileStorage.ts b/src/modules/session-storage/SessionFileStorage.ts index 932e2d2c6..9dafc67ef 100644 --- a/src/modules/session-storage/SessionFileStorage.ts +++ b/src/modules/session-storage/SessionFileStorage.ts @@ -23,6 +23,7 @@ export class SessionFileStorage implements ISessionStorage { } // This method reads data from the file and returns it in the JSON format + // biome-ignore lint/suspicious/noExplicitAny: <explanation> private async readDataFromFile(type: "sessions" | "signers"): Promise<any> { return new Promise((resolve) => { // @ts-ignore @@ -47,6 +48,7 @@ export class SessionFileStorage implements ISessionStorage { } private async writeDataToFile( + // biome-ignore lint/suspicious/noExplicitAny: <explanation> data: any, type: "sessions" | "signers" ): Promise<void> { @@ -83,8 +85,7 @@ export class SessionFileStorage implements ISessionStorage { } // Session store is in the form of mekrleRoot and leafnodes, each object will have a root and an array of leafNodes. - private async getSessionStore(): Promise<any> { - // eslint-disable-next-line no-useless-catch + private async getSessionStore() { try { const data = await this.readDataFromFile("sessions") return data || { merkleRoot: "", leafNodes: [] } @@ -94,8 +95,7 @@ export class SessionFileStorage implements ISessionStorage { } } - private async getSignerStore(): Promise<any> { - // eslint-disable-next-line no-useless-catch + private async getSignerStore() { try { const data = await this.readDataFromFile("signers") return data || {} @@ -141,7 +141,7 @@ export class SessionFileStorage implements ISessionStorage { } async addSessionData(leaf: SessionLeafNode): Promise<void> { - Logger.log("Add session Data", leaf) + Logger.log("Add session Data") const data = await this.getSessionStore() leaf.sessionValidationModule = this.toLowercaseAddress( leaf.sessionValidationModule @@ -244,7 +244,7 @@ export class SessionFileStorage implements ISessionStorage { param: SessionSearchParam ): Promise<WalletClientSigner> { const session = await this.getSessionData(param) - Logger.log("got session", session) + Logger.log("got session") const walletClientSinger = await this.getSignerByKey( session.sessionPublicKey ) diff --git a/src/modules/session-storage/SessionLocalStorage.ts b/src/modules/session-storage/SessionLocalStorage.ts index 82fe10121..8501c2112 100644 --- a/src/modules/session-storage/SessionLocalStorage.ts +++ b/src/modules/session-storage/SessionLocalStorage.ts @@ -30,14 +30,13 @@ export class SessionLocalStorage implements ISessionStorage { "Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address." ) } - - private getSessionStore(): any { + private getSessionStore() { // @ts-ignore: LocalStorage is not available in node const data = localStorage.getItem(this.getStorageKey("sessions")) return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] } } - private getSignerStore(): any { + private getSignerStore() { // @ts-ignore: LocalStorage is not available in node const data = localStorage.getItem(this.getStorageKey("signers")) return data ? JSON.parse(data) : {} diff --git a/src/modules/session-storage/SessionMemoryStorage.ts b/src/modules/session-storage/SessionMemoryStorage.ts index b6d6e4196..b046ee4fb 100644 --- a/src/modules/session-storage/SessionMemoryStorage.ts +++ b/src/modules/session-storage/SessionMemoryStorage.ts @@ -46,12 +46,12 @@ export class SessionMemoryStorage implements ISessionStorage { ) } - private getSessionStore(): any { + private getSessionStore() { const data = memoryStorage.getItem(this.getStorageKey("sessions")) return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] } } - private getSignerStore(): any { + private getSignerStore() { const data = memoryStorage.getItem(this.getStorageKey("signers")) return data ? JSON.parse(data) : {} } diff --git a/src/paymaster/utils/Types.ts b/src/paymaster/utils/Types.ts index 6115a94bb..1d19d4773 100644 --- a/src/paymaster/utils/Types.ts +++ b/src/paymaster/utils/Types.ts @@ -11,6 +11,7 @@ export type PaymasterServiceErrorResponse = { export type JsonRpcResponse = { jsonrpc: string id: number + // biome-ignore lint/suspicious/noExplicitAny: <explanation> result?: any error?: JsonRpcError } @@ -47,6 +48,7 @@ export type FeeQuotesOrDataDto = { /** preferredToken: Can be ommitted to return all quotes */ preferredToken?: string /** Webhooks to be fired after user op is sent */ + // biome-ignore lint/suspicious/noExplicitAny: <explanation> webhookData?: Record<string, any> /** Smart account meta data */ smartAccountInfo?: SmartAccountData @@ -63,6 +65,7 @@ export type FeeTokenInfo = { export type SponsorpshipInfo = { /** Webhooks to be fired after user op is sent */ + // biome-ignore lint/suspicious/noExplicitAny: <explanation> webhookData?: Record<string, any> /** Smart account meta data */ smartAccountInfo: SmartAccountData diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index 9d9f9847f..56c4f166a 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -22,6 +22,7 @@ import { createSmartAccountClient } from "../../src/account" import { type UserOperationStruct, getChain } from "../../src/account" +import { EntryPointAbi } from "../../src/account/abi/EntryPointAbi" import { BiconomyAccountAbi } from "../../src/account/abi/SmartAccount" import { DEFAULT_ECDSA_OWNERSHIP_MODULE, @@ -31,7 +32,7 @@ import { import { Paymaster } from "../../src/paymaster" import { checkBalance, getBundlerUrl, getConfig } from "../utils" -describe("Account: Read", () => { +describe("Account:Read", () => { const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" const { chain, @@ -489,58 +490,7 @@ describe("Account: Read", () => { const epHash = await publicClient.readContract({ address: DEFAULT_ENTRYPOINT_ADDRESS, - abi: [ - { - inputs: [ - { - components: [ - { internalType: "address", name: "sender", type: "address" }, - { internalType: "uint256", name: "nonce", type: "uint256" }, - { internalType: "bytes", name: "initCode", type: "bytes" }, - { internalType: "bytes", name: "callData", type: "bytes" }, - { - internalType: "uint256", - name: "callGasLimit", - type: "uint256" - }, - { - internalType: "uint256", - name: "verificationGasLimit", - type: "uint256" - }, - { - internalType: "uint256", - name: "preVerificationGas", - type: "uint256" - }, - { - internalType: "uint256", - name: "maxFeePerGas", - type: "uint256" - }, - { - internalType: "uint256", - name: "maxPriorityFeePerGas", - type: "uint256" - }, - { - internalType: "bytes", - name: "paymasterAndData", - type: "bytes" - }, - { internalType: "bytes", name: "signature", type: "bytes" } - ], - internalType: "struct UserOperation", - name: "userOp", - type: "tuple" - } - ], - name: "getUserOpHash", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function" - } - ], + abi: EntryPointAbi, functionName: "getUserOpHash", // @ts-ignore args: [userOp] diff --git a/tests/account/write.test.ts b/tests/account/write.test.ts index c0ddadff5..2ea34e67e 100644 --- a/tests/account/write.test.ts +++ b/tests/account/write.test.ts @@ -5,15 +5,18 @@ import { createWalletClient, encodeFunctionData, getContract, - parseAbi + parseAbi, + zeroAddress } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { type BiconomySmartAccountV2, + DEFAULT_ENTRYPOINT_ADDRESS, ERC20_ABI, createSmartAccountClient } from "../../src/account" +import { EntryPointAbi } from "../../src/account/abi/EntryPointAbi" import { PaymasterMode } from "../../src/paymaster" import { testOnlyOnOptimism } from "../setupFiles" import { checkBalance, getConfig, nonZeroBalance, topUp } from "../utils" @@ -71,6 +74,57 @@ describe("Account:Write", () => { ) }) + test("should send some native token to recipient via the entrypoint", async () => { + const balanceOfRecipient = await checkBalance(recipient) + + // biome-ignore lint/style/useConst: <explanation> + let userOp = await smartAccount.buildUserOp([ + { + to: recipient, + value: 1n + } + ]) + + userOp.signature = undefined + + const signedUserOp = await smartAccount.signUserOp(userOp) + + const entrypointContract = getContract({ + address: DEFAULT_ENTRYPOINT_ADDRESS, + abi: EntryPointAbi, + client: { public: publicClient, wallet: walletClient } + }) + + const hash = await entrypointContract.write.handleOps([ + [ + { + sender: signedUserOp.sender as Hex, + nonce: BigInt(signedUserOp.nonce ?? 0), + callGasLimit: BigInt(signedUserOp.callGasLimit ?? 0), + verificationGasLimit: BigInt(signedUserOp.verificationGasLimit ?? 0), + preVerificationGas: BigInt(signedUserOp.preVerificationGas ?? 0), + maxFeePerGas: BigInt(signedUserOp.maxFeePerGas ?? 0), + maxPriorityFeePerGas: BigInt(signedUserOp.maxPriorityFeePerGas ?? 0), + initCode: signedUserOp.initCode as Hex, + callData: signedUserOp.callData as Hex, + paymasterAndData: signedUserOp.paymasterAndData as Hex, + signature: signedUserOp.signature as Hex + } + ], + sender + ]) + + const { status, transactionHash } = + await publicClient.waitForTransactionReceipt({ hash }) + + expect(status).toBe("success") + expect(transactionHash).toBeTruthy() + + const balanceOfRecipientAfter = await checkBalance(recipient) + + expect(balanceOfRecipientAfter - balanceOfRecipient).toBe(1n) + }, 50000) + test("should deploy a smart account with native token balance", async () => { const newPrivateKey = generatePrivateKey() const newAccount = privateKeyToAccount(newPrivateKey) diff --git a/tests/bundler/read.test.ts b/tests/bundler/read.test.ts index 16b8ecf58..9a0604976 100644 --- a/tests/bundler/read.test.ts +++ b/tests/bundler/read.test.ts @@ -1,4 +1,4 @@ -import { http, type Chain, createWalletClient } from "viem" +import { http, type Chain, type Hex, createWalletClient } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { @@ -10,7 +10,7 @@ import { import { createBundler } from "../../src/bundler" import { getBundlerUrl, getConfig } from "../utils" -describe("Bundler: Read", () => { +describe("Bundler:Read", () => { const { chain, chainId, diff --git a/tests/bundler/write.test.ts b/tests/bundler/write.test.ts index a67f25e32..cc3ba35cd 100644 --- a/tests/bundler/write.test.ts +++ b/tests/bundler/write.test.ts @@ -3,10 +3,17 @@ import { privateKeyToAccount } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { type BiconomySmartAccountV2, - createSmartAccountClient + createSmartAccountClient, + getChain } from "../../src/account" import { createBundler } from "../../src/bundler" -import { checkBalance, getConfig, nonZeroBalance, topUp } from "../utils" +import { + checkBalance, + getBundlerUrl, + getConfig, + nonZeroBalance, + topUp +} from "../utils" describe("Bundler:Write", () => { const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" @@ -116,4 +123,37 @@ describe("Bundler:Write", () => { expect(transactionHash).toBeTruthy() expect(newBalanceOfRecipient - balanceOfRecipient).toBe(1n) }, 70000) + + test("should test a new network", async () => { + /* Set the network id and paymaster key */ + const NETWORK_ID = 80002 + const PAYMASTER_KEY = "<API_KEY>" + /****************************************/ + const chain = getChain(NETWORK_ID) + const bundlerUrl = getBundlerUrl(NETWORK_ID) + const paymasterUrl = `https://paymaster.biconomy.io/api/v1/${NETWORK_ID}/${PAYMASTER_KEY}` + + const newWalletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + const newSmartAccount = await createSmartAccountClient({ + signer: newWalletClient, + bundlerUrl + // paymasterUrl + }) + + expect(chain.id).toBe(NETWORK_ID) + + const { wait } = await newSmartAccount.sendTransaction({ + to: recipient, + value: 1n + }) + + const { success } = await wait() + + expect(success).toBe("true") + }, 70000) }) diff --git a/tests/modules/read.test.ts b/tests/modules/read.test.ts index 78d72affd..a5d5c1a5e 100644 --- a/tests/modules/read.test.ts +++ b/tests/modules/read.test.ts @@ -19,7 +19,7 @@ import { } from "../../src/modules" import { getConfig } from "../utils" -describe("Modules: Read", () => { +describe("Modules:Read", () => { const { chain, chainId, diff --git a/tests/modules/write.test.ts b/tests/modules/write.test.ts index 37e498fe5..5902775ba 100644 --- a/tests/modules/write.test.ts +++ b/tests/modules/write.test.ts @@ -215,9 +215,11 @@ describe("Modules:Write", () => { // Send the signed user ops on both chains const userOpResponse1 = await baseAccount.sendSignedUserOp( + // biome-ignore lint/suspicious/noExplicitAny: <explanation> returnedOps[0] as any ) const userOpResponse2 = await polygonAccount.sendSignedUserOp( + // biome-ignore lint/suspicious/noExplicitAny: <explanation> returnedOps[1] as any ) @@ -314,6 +316,7 @@ describe("Modules:Write", () => { to: DEFAULT_SESSION_KEY_MANAGER_MODULE, data: sessionTxData.data } + // biome-ignore lint/suspicious/noExplicitAny: <explanation> const txArray: any = [] // Check if module is enabled const isEnabled = await smartAccount.isModuleEnabled( @@ -521,8 +524,6 @@ describe("Modules:Write", () => { const usdcBalance = await checkBalance(smartAccountAddress, token) const nativeTokenBalance = await checkBalance(smartAccountAddress) - console.log({ usdcBalance, nativeTokenBalance }) - expect(usdcBalance).toBeGreaterThan(0) smartAccount = smartAccount.setActiveValidationModule(batchedSessionModule) // WARNING* If the smart account does not have enough USDC, user op execution will FAIL diff --git a/tests/paymaster/read.test.ts b/tests/paymaster/read.test.ts index a57af2d4d..99f060f1d 100644 --- a/tests/paymaster/read.test.ts +++ b/tests/paymaster/read.test.ts @@ -19,7 +19,7 @@ import { } from "../../src/paymaster" import { getConfig } from "../utils" -describe.skip("Paymaster: Read", () => { +describe("Paymaster:Read", () => { const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" const { chain, From facab25b36e9c3e182d68f7b58eddc988f50869d Mon Sep 17 00:00:00 2001 From: Vasile Gabriel Marian <56271768+VGabriel45@users.noreply.github.com> Date: Fri, 19 Apr 2024 18:39:40 +0200 Subject: [PATCH 25/33] chore: add 6492 signature (#468) * chore: add 6492 signature --- src/account/BiconomySmartAccountV2.ts | 69 ++++++++++++++++++++------- src/account/utils/Constants.ts | 2 + tests/account/read.test.ts | 40 ++++++++++++++++ tests/bundler/write.test.ts | 2 +- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index 981f88da9..633698265 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -16,7 +16,8 @@ import { parseAbi, parseAbiParameters, toBytes, - toHex + toHex, + concat } from "viem" import type { IBundler } from "../bundler/IBundler.js" import { @@ -62,6 +63,7 @@ import { DEFAULT_FALLBACK_HANDLER_ADDRESS, ERC20_ABI, ERROR_MESSAGES, + MAGIC_BYTES, NATIVE_TOKEN_ALIAS, PROXY_CREATION_CODE } from "./utils/Constants.js" @@ -737,17 +739,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { async getAccountInitCode(): Promise<Hex> { this.isDefaultValidationModuleDefined() + if(await this.isAccountDeployed()) return "0x"; + return concatHex([ this.factoryAddress as Hex, - encodeFunctionData({ - abi: BiconomyFactoryAbi, - functionName: "deployCounterFactualAccount", - args: [ - this.defaultValidationModule.getAddress() as Hex, - (await this.defaultValidationModule.getInitData()) as Hex, - BigInt(this.index) - ] - }) + await this.getFactoryData() ?? "0x" ]) } @@ -1695,10 +1691,29 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { ) } + async getFactoryData() { + if (await this.isAccountDeployed()) return undefined + + this.isDefaultValidationModuleDefined() + + return ( + encodeFunctionData({ + abi: BiconomyFactoryAbi, + functionName: "deployCounterFactualAccount", + args: [ + this.defaultValidationModule.getAddress() as Hex, + (await this.defaultValidationModule.getInitData()) as Hex, + BigInt(this.index) + ] + }) + ) + } + async signMessage(message: string | Uint8Array): Promise<Hex> { - this.isActiveValidationModuleDefined() - const dataHash = typeof message === "string" ? toBytes(message) : message - let signature = await this.activeValidationModule.signMessage(dataHash) + let signature: any; + this.isActiveValidationModuleDefined(); + const dataHash = typeof message === "string" ? toBytes(message) : message; + signature = await this.activeValidationModule.signMessage(dataHash); const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) if (![27, 28].includes(potentiallyIncorrectV)) { @@ -1708,11 +1723,29 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { if (signature.slice(0, 2) !== "0x") { signature = `0x${signature}` } - signature = encodeAbiParameters(parseAbiParameters("bytes, address"), [ - signature as Hex, - this.defaultValidationModule.getAddress() - ]) - return signature as Hex + signature = encodeAbiParameters([{ type: "bytes" }, { type: "address" }], [signature as Hex, this.defaultValidationModule.getAddress()]); + if (await this.isAccountDeployed()) { + return signature as Hex; + } else { + const abiEncodedMessage = encodeAbiParameters( + [ + { + type: "address", + name: "create2Factory", + }, + { + type: "bytes", + name: "factoryCalldata", + }, + { + type: "bytes", + name: "originalERC1271Signature", + }, + ], + [this.getFactoryAddress() ?? "0x", (await this.getFactoryData()) ?? "0x", signature] + ); + return concat([abiEncodedMessage, MAGIC_BYTES]); + } } async getIsValidSignatureData( diff --git a/src/account/utils/Constants.ts b/src/account/utils/Constants.ts index edd7ef64b..814b6dedf 100644 --- a/src/account/utils/Constants.ts +++ b/src/account/utils/Constants.ts @@ -10,6 +10,8 @@ import type { export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" +export const MAGIC_BYTES = "0x6492649264926492649264926492649264926492649264926492649264926492"; + // will always be latest entrypoint address export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789" diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index 56c4f166a..c2fa84b36 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -652,4 +652,44 @@ describe("Account:Read", () => { expect(response).toBe(eip1271MagicValue) }) + + test.concurrent("should verifySignature of deployed", async () => { + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + index: 1, + }); + + const message = "hello world"; + + const signature = await smartAccount.signMessage(message); + + const isVerified = await publicClient.verifyMessage({ + address: await smartAccount.getAddress(), + message, + signature, + }); + + expect(isVerified).toBeTruthy(); + }); + + test.concurrent("should verifySignature of not deployed", async () => { + const smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + index: 100, + }); + + const message = "hello world"; + + const signature = await smartAccount.signMessage(message); + + const isVerified = await publicClient.verifyMessage({ + address: await smartAccount.getAddress(), + message, + signature, + }); + + expect(isVerified).toBeTruthy(); + }); }) diff --git a/tests/bundler/write.test.ts b/tests/bundler/write.test.ts index cc3ba35cd..5fd3b3d9d 100644 --- a/tests/bundler/write.test.ts +++ b/tests/bundler/write.test.ts @@ -86,7 +86,7 @@ describe("Bundler:Write", () => { expect(transactionHash).toBeTruthy() expect(newBalanceOfRecipient - balanceOfRecipient).toBe(1n) - }, 50000) + }, 60000) test("should send some native token to a recipient with a bundler instance", async () => { await topUp(smartAccountAddress, BigInt(1000000000000000000)) From 6c6583fdfe77f6a72b59f0f27256e2279c5dc884 Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Fri, 19 Apr 2024 18:05:43 +0100 Subject: [PATCH 26/33] chore: remove buffer (#473) chore: remove buffer --- .github/workflows/size-report.yml | 3 +- bun.lockb | Bin 263597 -> 263597 bytes package.json | 6 +-- src/account/BiconomySmartAccountV2.ts | 61 ++++++++++++++------------ src/account/utils/Constants.ts | 3 +- tests/account/read.test.ts | 36 +++++++-------- 6 files changed, 57 insertions(+), 52 deletions(-) diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml index 99d8cb94f..0cbdac716 100644 --- a/.github/workflows/size-report.yml +++ b/.github/workflows/size-report.yml @@ -25,8 +25,7 @@ jobs: - name: Install dependencies shell: bash run: | - bun install buffer - bun install --frozen-lockfile --production + bun install --frozen-lockfile - name: Report bundle size uses: andresz1/size-limit-action@master diff --git a/bun.lockb b/bun.lockb index d4c0bada894740cb93b5cf72198f651cd50f3078..1784ac93e6885f3b9ebf417939f3fe7293049a23 100755 GIT binary patch delta 19487 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 bnKH7w{aN{KS9`Eb8DXzm(`~+e+|>UAVQ7J; delta 19351 zcmeHvd0bW1`u^GL0J2e3L<9t!2Sh;z;ef~i6%`Of9I@0wKskwmqA59mT}#c(VOJ~7 zF)QcFOwp^RHYpkoIplDiDoaf*vq8P7-{;wTpYYzF_x`^3{_*?c_i5|HyWVF_?|Ro- z@7iY{HXCNw-7vfEd)Z3Fu<^r(=a02m9QpbAw&)I)jqVnUYO$0*?HHF|GR|TN@vvBG zLZ1g&3-Z1;MrmBO$kSp8f;JU05HiQqQy~4Jhd?%hbc1XG`7Nq8f!qg4{%y!+kTW0~ zLl&4a&CG9W>UAL5{?9NW0P;IXG+9<&TvReHx1_|f)LSRYXTWAySUx&ubde*^V#zNV zHr`Q~XUT71vD5?K2NFfg?U3~$+nKzdsk@r_w|tE9=OJ0H5)xVEn@xQwq_5?1OZiMQ zV>~1q&M^yQLbAhnQ*Q~$2I@hw+"Wcd|Hc5oCwn7_-^H)vNx>#~~|4#rvj08XYH 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 YE~xP7YMq!S-y3LkujulUb>xKq0rh?_h5!Hn diff --git a/package.json b/package.json index a3d38bc83..dfd5d83b1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "sideEffects": false, "name": "@biconomy/account", "author": "Biconomy", - "version": "4.1.2", + "version": "4.1.3", "description": "SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.", "keywords": [ "erc-7579", @@ -94,7 +94,8 @@ "tsc-alias": "^1.8.8", "tslib": "^2.6.2", "typedoc": "^0.25.9", - "vitest": "^1.3.1" + "vitest": "^1.3.1", + "buffer": "^6.0.3" }, "peerDependencies": { "typescript": "^5", @@ -108,7 +109,6 @@ "commit-msg": "npx --no -- commitlint --edit ${1}" }, "dependencies": { - "buffer": "^6.0.3", "merkletreejs": "^0.3.11" } } diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index 633698265..6b7cd373e 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -3,6 +3,7 @@ import { type GetContractReturnType, type Hex, type PublicClient, + concat, concatHex, createPublicClient, decodeFunctionData, @@ -16,8 +17,7 @@ import { parseAbi, parseAbiParameters, toBytes, - toHex, - concat + toHex } from "viem" import type { IBundler } from "../bundler/IBundler.js" import { @@ -739,11 +739,11 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { async getAccountInitCode(): Promise<Hex> { this.isDefaultValidationModuleDefined() - if(await this.isAccountDeployed()) return "0x"; + if (await this.isAccountDeployed()) return "0x" return concatHex([ this.factoryAddress as Hex, - await this.getFactoryData() ?? "0x" + (await this.getFactoryData()) ?? "0x" ]) } @@ -1696,24 +1696,22 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { this.isDefaultValidationModuleDefined() - return ( - encodeFunctionData({ - abi: BiconomyFactoryAbi, - functionName: "deployCounterFactualAccount", - args: [ - this.defaultValidationModule.getAddress() as Hex, - (await this.defaultValidationModule.getInitData()) as Hex, - BigInt(this.index) - ] - }) - ) + return encodeFunctionData({ + abi: BiconomyFactoryAbi, + functionName: "deployCounterFactualAccount", + args: [ + this.defaultValidationModule.getAddress() as Hex, + (await this.defaultValidationModule.getInitData()) as Hex, + BigInt(this.index) + ] + }) } async signMessage(message: string | Uint8Array): Promise<Hex> { - let signature: any; - this.isActiveValidationModuleDefined(); - const dataHash = typeof message === "string" ? toBytes(message) : message; - signature = await this.activeValidationModule.signMessage(dataHash); + let signature: any + this.isActiveValidationModuleDefined() + const dataHash = typeof message === "string" ? toBytes(message) : message + signature = await this.activeValidationModule.signMessage(dataHash) const potentiallyIncorrectV = Number.parseInt(signature.slice(-2), 16) if (![27, 28].includes(potentiallyIncorrectV)) { @@ -1723,28 +1721,35 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { if (signature.slice(0, 2) !== "0x") { signature = `0x${signature}` } - signature = encodeAbiParameters([{ type: "bytes" }, { type: "address" }], [signature as Hex, this.defaultValidationModule.getAddress()]); + signature = encodeAbiParameters( + [{ type: "bytes" }, { type: "address" }], + [signature as Hex, this.defaultValidationModule.getAddress()] + ) if (await this.isAccountDeployed()) { - return signature as Hex; + return signature as Hex } else { const abiEncodedMessage = encodeAbiParameters( [ { type: "address", - name: "create2Factory", + name: "create2Factory" }, { type: "bytes", - name: "factoryCalldata", + name: "factoryCalldata" }, { type: "bytes", - name: "originalERC1271Signature", - }, + name: "originalERC1271Signature" + } ], - [this.getFactoryAddress() ?? "0x", (await this.getFactoryData()) ?? "0x", signature] - ); - return concat([abiEncodedMessage, MAGIC_BYTES]); + [ + this.getFactoryAddress() ?? "0x", + (await this.getFactoryData()) ?? "0x", + signature + ] + ) + return concat([abiEncodedMessage, MAGIC_BYTES]) } } diff --git a/src/account/utils/Constants.ts b/src/account/utils/Constants.ts index 814b6dedf..320a89ac0 100644 --- a/src/account/utils/Constants.ts +++ b/src/account/utils/Constants.ts @@ -10,7 +10,8 @@ import type { export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" -export const MAGIC_BYTES = "0x6492649264926492649264926492649264926492649264926492649264926492"; +export const MAGIC_BYTES = + "0x6492649264926492649264926492649264926492649264926492649264926492" // will always be latest entrypoint address export const DEFAULT_ENTRYPOINT_ADDRESS = diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index c2fa84b36..bff2d861b 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -657,39 +657,39 @@ describe("Account:Read", () => { const smartAccount = await createSmartAccountClient({ signer: walletClient, bundlerUrl, - index: 1, - }); + index: 1 + }) + + const message = "hello world" - const message = "hello world"; + const signature = await smartAccount.signMessage(message) - const signature = await smartAccount.signMessage(message); - const isVerified = await publicClient.verifyMessage({ address: await smartAccount.getAddress(), message, - signature, - }); + signature + }) - expect(isVerified).toBeTruthy(); - }); + expect(isVerified).toBeTruthy() + }) test.concurrent("should verifySignature of not deployed", async () => { const smartAccount = await createSmartAccountClient({ signer: walletClient, bundlerUrl, - index: 100, - }); + index: 100 + }) + + const message = "hello world" - const message = "hello world"; + const signature = await smartAccount.signMessage(message) - const signature = await smartAccount.signMessage(message); - const isVerified = await publicClient.verifyMessage({ address: await smartAccount.getAddress(), message, - signature, - }); + signature + }) - expect(isVerified).toBeTruthy(); - }); + expect(isVerified).toBeTruthy() + }) }) From e290fd15d2f2114a3678bb89bffcf5cf2371d59a Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Thu, 25 Apr 2024 13:38:57 +0100 Subject: [PATCH 27/33] chore: export abi svm helper (#476) * chore: export abi svm helper from modules * chore: smart contract -> sdk * chore: add tree-shaking for modules * fix walletClient signer --- .github/PULL_REQUEST_TEMPLATE/pull_request_template.md | 2 +- .size-limit.json | 8 +++++++- SECURITY.md | 2 +- src/account/utils/convertSigner.ts | 2 +- src/bundler/utils/Constants.ts | 2 ++ src/bundler/utils/getAAError.ts | 3 ++- src/modules/index.ts | 1 + tests/modules/write.test.ts | 4 ++-- 8 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index fca427abe..35e920656 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -1,4 +1,4 @@ -## Pull Request for Smart Contract Improvement +## Pull Request for SDK Improvement **Describe your changes:** diff --git a/.size-limit.json b/.size-limit.json index 97fe21ed6..a2bdf369c 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -11,7 +11,7 @@ "limit": "60 kB" }, { - "name": "smartAccount (tree-shaking)", + "name": "account (tree-shaking)", "path": "./dist/_esm/index.js", "limit": "60 kB", "import": "{ createSmartAccountClient }" @@ -27,5 +27,11 @@ "path": "./dist/_esm/paymaster/index.js", "limit": "5 kB", "import": "{ createPaymaster }" + }, + { + "name": "modules (tree-shaking)", + "path": "./dist/_esm/modules/index.js", + "limit": "60 kB", + "import": "{ createSessionKeyManagerModule }" } ] diff --git a/SECURITY.md b/SECURITY.md index 937edcaaf..74aa0598b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Reporting a Vulnerability -The safety and security of our smart contract platform is our top priority. If you have discovered a security vulnerability, we appreciate your help in disclosing it to us responsibly. +The safety and security of our sdk is our top priority. If you have discovered a security vulnerability, we appreciate your help in disclosing it to us responsibly. ### Contact Us Directly for Critical or High-Risk Findings diff --git a/src/account/utils/convertSigner.ts b/src/account/utils/convertSigner.ts index 191c84ebd..440d82ede 100644 --- a/src/account/utils/convertSigner.ts +++ b/src/account/utils/convertSigner.ts @@ -21,7 +21,7 @@ function isPrivateKeyAccount( } function isWalletClient(signer: SupportedSigner): signer is WalletClient { - return (signer as WalletClient).type === "walletClient" + return (signer as WalletClient).transport !== undefined } function isEthersSigner(signer: SupportedSigner): signer is Signer { diff --git a/src/bundler/utils/Constants.ts b/src/bundler/utils/Constants.ts index 7c0510526..297fff8f7 100644 --- a/src/bundler/utils/Constants.ts +++ b/src/bundler/utils/Constants.ts @@ -28,3 +28,5 @@ export const UserOpWaitForTxHashMaxDurationIntervals: { export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789" + +export const SDK_VERSION = "4.2.0" diff --git a/src/bundler/utils/getAAError.ts b/src/bundler/utils/getAAError.ts index 051d5bbd2..bda4bb792 100644 --- a/src/bundler/utils/getAAError.ts +++ b/src/bundler/utils/getAAError.ts @@ -1,6 +1,6 @@ import { BaseError } from "viem" import type { Service } from "../../account" - +import { SDK_VERSION } from "./Constants" export type KnownError = { name: string regex: string @@ -41,6 +41,7 @@ type AccountAbstractionErrorParams = { class AccountAbstractionError extends BaseError { override name = "AccountAbstractionError" + override version = `@biconomy/account@${SDK_VERSION}` constructor(title: string, params: AccountAbstractionErrorParams = {}) { super(title, params) diff --git a/src/modules/index.ts b/src/modules/index.ts index 3279ad1fa..bf655585f 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,5 +1,6 @@ export * from "./utils/Types.js" export * from "./utils/Constants.js" +export * from "./utils/Helper.js" export * from "./interfaces/IValidationModule.js" export * from "./interfaces/ISessionValidationModule.js" export * from "./BaseValidationModule.js" diff --git a/tests/modules/write.test.ts b/tests/modules/write.test.ts index 5902775ba..5d66994ab 100644 --- a/tests/modules/write.test.ts +++ b/tests/modules/write.test.ts @@ -27,10 +27,10 @@ import { DEFAULT_SESSION_KEY_MANAGER_MODULE, createBatchedSessionRouterModule, createMultiChainValidationModule, - createSessionKeyManagerModule + createSessionKeyManagerModule, + getABISVMSessionKeyData } from "../../src/modules" import { SessionMemoryStorage } from "../../src/modules/session-storage/SessionMemoryStorage" -import { getABISVMSessionKeyData } from "../../src/modules/utils/Helper" import { PaymasterMode } from "../../src/paymaster" import { checkBalance, getBundlerUrl, getConfig, topUp } from "../utils" From 8694366165208cac6bbf7e560fe2abefce0eaa3a Mon Sep 17 00:00:00 2001 From: Vasile Gabriel Marian <56271768+VGabriel45@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:17:59 +0300 Subject: [PATCH 28/33] chore: add token balances in getSupportedTokens (#470) * added fetch for token balance in getSupportedTokens * refactor for getting supported tokens balance --------- Co-authored-by: GabiDev <gv@popoo.io> Co-authored-by: Joe Pegler <joepegler123@gmail.com> --- src/account/BiconomySmartAccountV2.ts | 36 ++++++++++++++----------- src/account/utils/Types.ts | 2 +- tests/account/read.test.ts | 39 ++++++++++++++++++++++----- tests/paymaster/read.test.ts | 1 + 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index 6b7cd373e..adf18b6df 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -347,9 +347,9 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { } /** - * Returns token balances (and native token balance) of the smartAccount instance. + * Returns tokens balance and information of the tokens (for native and erc20 tokens) for the smartAccount instance. * - * This method will fetch the token balances of the smartAccount instance. + * This method will fetch tokens info given an array of token addresses for the smartAccount instance. * The balance of the native token will always be returned as the last element in the reponse array, with the address set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. * * @param addresses - Optional. Array of asset addresses to fetch the balances of. If not provided, the method will return only the balance of the native token. @@ -369,7 +369,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); - * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([token]); + * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalance([token]); * * console.log(tokenBalanceFromSmartAccount); * // { @@ -382,7 +382,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * // or to get the nativeToken balance * - * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances(); + * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalance(); * * console.log(nativeTokenBalanceFromSmartAccount); * // { @@ -394,7 +394,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * // } * */ - public async getBalances( + public async getBalance( addresses?: Array<Hex> ): Promise<Array<BalancePayload>> { const accountAddress = await this.getAccountAddress() @@ -512,7 +512,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { // Get the balances of the tokens if the amount is not present in the withdrawal requests if (shouldFetchMaxBalances) { - const balances = await this.getBalances( + const balances = await this.getBalance( tokenRequests.map(({ address }) => address) ) tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ @@ -1067,16 +1067,20 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { paymasterServiceData: { mode: PaymasterMode.ERC20 } } ) - return (feeQuotesResponse?.feeQuotes ?? []).map( - ({ - maxGasFee: _, - maxGasFeeUSD: __, - validUntil: ___, - usdPayment: ____, - ...rest - }) => rest - ) - } + + return await Promise.all( + (feeQuotesResponse?.feeQuotes ?? []).map(async (quote) => { + const [tokenBalance] = await this.getBalance([quote.tokenAddress as Hex]) + return { + symbol: quote.symbol, + tokenAddress: quote.tokenAddress, + decimal: quote.decimal, + logoUrl: quote.logoUrl, + premiumPercentage: quote.premiumPercentage, + balance: tokenBalance + }; + }) + )} /** * diff --git a/src/account/utils/Types.ts b/src/account/utils/Types.ts index 305783750..e9fc72d5f 100644 --- a/src/account/utils/Types.ts +++ b/src/account/utils/Types.ts @@ -331,7 +331,7 @@ export type Transaction = { export type SupportedToken = Omit< PaymasterFeeQuote, "maxGasFeeUSD" | "usdPayment" | "maxGasFee" | "validUntil" -> +> & { balance: BalancePayload }; export type Signer = LightSigner & { // biome-ignore lint/suspicious/noExplicitAny: any is used here to allow for the ethers provider diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index bff2d861b..24ac7ffb1 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -19,7 +19,8 @@ import { ERROR_MESSAGES, NATIVE_TOKEN_ALIAS, compareChainIds, - createSmartAccountClient + createSmartAccountClient, + isNullOrUndefined } from "../../src/account" import { type UserOperationStruct, getChain } from "../../src/account" import { EntryPointAbi } from "../../src/account/abi/EntryPointAbi" @@ -563,13 +564,25 @@ describe("Account:Read", () => { test.concurrent("should fetch balances for smartAccount", async () => { const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) - const [tokenBalanceFromSmartAccount] = await smartAccount.getBalances([ - token - ]) + const [tokenBalanceFromSmartAccount] = + await smartAccount.getBalance([token]) expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount.amount) }) + test.concurrent( + "should fetch only token balance for a smartAccount", + async () => { + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" + const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) + const tokenBalanceFromSmartAccount = + await smartAccount.getBalance([token]) + console.log(tokenBalanceFromSmartAccount); + + // expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount) + } + ) + test.concurrent("should error if no recipient exists", async () => { const token: Hex = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" @@ -594,9 +607,10 @@ describe("Account:Read", () => { ) test.concurrent( - "should check native token balance for smartAccount", + "should check native token balance and more token info for smartAccount", async () => { - const [ethBalanceFromSmartAccount] = await smartAccount.getBalances() + const [ethBalanceFromSmartAccount] = + await smartAccount.getBalance() expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n) expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS) @@ -606,6 +620,19 @@ describe("Account:Read", () => { 60000 ) + test.concurrent( + "should check balance of supported token", + async () => { + const tokens = await smartAccount.getSupportedTokens() + const [firstToken] = tokens; + + expect(tokens.length).toBeGreaterThan(0); + expect(tokens[0]).toHaveProperty("balance"); + expect(firstToken.balance.amount).toBeGreaterThanOrEqual(0n); + }, + 60000 + ) + test.concurrent( "should verify a correct signature through isValidSignature", async () => { diff --git a/tests/paymaster/read.test.ts b/tests/paymaster/read.test.ts index 99f060f1d..3b851100b 100644 --- a/tests/paymaster/read.test.ts +++ b/tests/paymaster/read.test.ts @@ -104,6 +104,7 @@ describe("Paymaster:Read", () => { expect(tokens[0]).toHaveProperty("decimal") expect(tokens[0]).toHaveProperty("premiumPercentage") expect(tokens[0]).toHaveProperty("logoUrl") + expect(tokens[0]).toHaveProperty("balance") }, 60000 ) From 950a521af63d7a719edcbae4df57259d3fe110e7 Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Thu, 25 Apr 2024 14:24:00 +0100 Subject: [PATCH 29/33] feat: gas estimates (#477) * feat: gas estimates --- src/account/BiconomySmartAccountV2.ts | 146 ++++++++++++++++++++------ src/account/utils/HttpRequests.ts | 22 ++-- src/bundler/utils/getAAError.ts | 26 ++++- tests/account/read.test.ts | 53 +++++++++- 4 files changed, 197 insertions(+), 50 deletions(-) diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index adf18b6df..d1f2c0b7f 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -228,7 +228,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const bundlerUrl = "" // Retrieve bundler url from dasboard + * const bundlerUrl = "" // Retrieve bundler url from dashboard * * const smartAccountFromStaticCreate = await BiconomySmartAccountV2.create({ signer, bundlerUrl }); * @@ -347,7 +347,81 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { } /** - * Returns tokens balance and information of the tokens (for native and erc20 tokens) for the smartAccount instance. + * Returns an upper estimate for the gas spent on a specific user operation + * + * This method will fetch an approximate gas estimate for the user operation, given the current state of the network. + * It is regularly an overestimate, and the actual gas spent will likely be lower. + * It is unlikely to be an underestimate unless the network conditions rapidly change. + * + * @param transactions Array of {@link Transaction} to be sent. + * @param buildUseropDto {@link BuildUserOpOptions}. + * @returns Promise<bigint> - The estimated gas cost in wei. + * + * @example + * import { createClient } from "viem" + * import { createSmartAccountClient } from "@biconomy/account" + * import { createWalletClient, http } from "viem"; + * import { polygonAmoy } from "viem/chains"; + * + * const signer = createWalletClient({ + * account, + * chain: polygonAmoy, + * transport: http(), + * }); + * + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, paymasterUrl }); // Retrieve bundler/paymaster url from dashboard + * const encodedCall = encodeFunctionData({ + * abi: parseAbi(["function safeMint(address to) public"]), + * functionName: "safeMint", + * args: ["0x..."], + * }); + * + * const tx = { + * to: nftAddress, + * data: encodedCall + * } + * + * const amountInWei = await smartAccount.getGasEstimates([tx, tx], { + * paymasterServiceData: { + * mode: PaymasterMode.SPONSORED, + * }, + * }); + * + * console.log(amountInWei.toString()); + * + */ + public async getGasEstimate( + transactions: Transaction[], + buildUseropDto?: BuildUserOpOptions + ): Promise<bigint> { + const { + callGasLimit, + preVerificationGas, + verificationGasLimit, + maxFeePerGas + } = await this.buildUserOp(transactions, buildUseropDto) + + const _callGasLimit = BigInt(callGasLimit || 0) + const _preVerificationGas = BigInt(preVerificationGas || 0) + const _verificationGasLimit = BigInt(verificationGasLimit || 0) + const _maxFeePerGas = BigInt(maxFeePerGas || 0) + + if (!buildUseropDto?.paymasterServiceData?.mode) { + return ( + (_callGasLimit + _preVerificationGas + _verificationGasLimit) * + _maxFeePerGas + ) + } + return ( + (_callGasLimit + + BigInt(3) * _verificationGasLimit + + _preVerificationGas) * + _maxFeePerGas + ) + } + + /** + * Returns balances for the smartAccount instance. * * This method will fetch tokens info given an array of token addresses for the smartAccount instance. * The balance of the native token will always be returned as the last element in the reponse array, with the address set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. @@ -982,7 +1056,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ * abi: parseAbi(["function safeMint(address to) public"]), * functionName: "safeMint", @@ -1042,7 +1116,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); // Retrieve bundler url from dasboard + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); // Retrieve bundler url from dashboard * const tokens = await smartAccount.getSupportedTokens(); * * // [ @@ -1067,10 +1141,12 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { paymasterServiceData: { mode: PaymasterMode.ERC20 } } ) - + return await Promise.all( (feeQuotesResponse?.feeQuotes ?? []).map(async (quote) => { - const [tokenBalance] = await this.getBalance([quote.tokenAddress as Hex]) + const [tokenBalance] = await this.getBalance([ + quote.tokenAddress as Hex + ]) return { symbol: quote.symbol, tokenAddress: quote.tokenAddress, @@ -1078,9 +1154,10 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { logoUrl: quote.logoUrl, premiumPercentage: quote.premiumPercentage, balance: tokenBalance - }; - }) - )} + } + }) + ) + } /** * @@ -1108,7 +1185,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ * abi: parseAbi(["function safeMint(address to) public"]), * functionName: "safeMint", @@ -1310,7 +1387,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ * abi: parseAbi(["function safeMint(address to) public"]), * functionName: "safeMint", @@ -1363,7 +1440,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * transport: http(), * }); * - * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard + * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ * abi: parseAbi(["function safeMint(address to) public"]), * functionName: "safeMint", @@ -1731,30 +1808,29 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { ) if (await this.isAccountDeployed()) { return signature as Hex - } else { - const abiEncodedMessage = encodeAbiParameters( - [ - { - type: "address", - name: "create2Factory" - }, - { - type: "bytes", - name: "factoryCalldata" - }, - { - type: "bytes", - name: "originalERC1271Signature" - } - ], - [ - this.getFactoryAddress() ?? "0x", - (await this.getFactoryData()) ?? "0x", - signature - ] - ) - return concat([abiEncodedMessage, MAGIC_BYTES]) } + const abiEncodedMessage = encodeAbiParameters( + [ + { + type: "address", + name: "create2Factory" + }, + { + type: "bytes", + name: "factoryCalldata" + }, + { + type: "bytes", + name: "originalERC1271Signature" + } + ], + [ + this.getFactoryAddress() ?? "0x", + (await this.getFactoryData()) ?? "0x", + signature + ] + ) + return concat([abiEncodedMessage, MAGIC_BYTES]) } async getIsValidSignatureData( diff --git a/src/account/utils/HttpRequests.ts b/src/account/utils/HttpRequests.ts index 0b641aff1..cdcbe07f4 100644 --- a/src/account/utils/HttpRequests.ts +++ b/src/account/utils/HttpRequests.ts @@ -35,7 +35,7 @@ export async function sendRequest<T>( Logger.log(`${service} RPC Response`, jsonResponse) } catch (error) { if (!response.ok) { - throw await getAAError(response.statusText, service) + throw await getAAError(response.statusText, response.status, service) } } @@ -48,25 +48,29 @@ export async function sendRequest<T>( ) } if (jsonResponse.message) { - throw await getAAError(jsonResponse.message) + throw await getAAError(jsonResponse.message, response.status, service) } if (jsonResponse.msg) { - throw await getAAError(jsonResponse.msg) + throw await getAAError(jsonResponse.msg, response.status, service) } if (jsonResponse.data) { - throw await getAAError(jsonResponse.data) + throw await getAAError(jsonResponse.data, response.status, service) } if (jsonResponse.detail) { - throw await getAAError(jsonResponse.detail) + throw await getAAError(jsonResponse.detail, response.status, service) } if (jsonResponse.message) { - throw await getAAError(jsonResponse.message) + throw await getAAError(jsonResponse.message, response.status, service) } if (jsonResponse.nonFieldErrors) { - throw await getAAError(jsonResponse.nonFieldErrors) + throw await getAAError( + jsonResponse.nonFieldErrors, + response.status, + service + ) } if (jsonResponse.delegate) { - throw await getAAError(jsonResponse.delegate) + throw await getAAError(jsonResponse.delegate, response.status, service) } - throw await getAAError(response.statusText) + throw await getAAError(response.statusText, response.status, service) } diff --git a/src/bundler/utils/getAAError.ts b/src/bundler/utils/getAAError.ts index bda4bb792..7a04be10f 100644 --- a/src/bundler/utils/getAAError.ts +++ b/src/bundler/utils/getAAError.ts @@ -12,6 +12,7 @@ export type KnownError = { export const ERRORS_URL = "https://bcnmy.github.io/aa-errors/errors.json" export const DOCS_URL = "https://docs.biconomy.io/troubleshooting/commonerrors" +const UNKOWN_ERROR_CODE = "520" const knownErrors: KnownError[] = [] @@ -21,9 +22,13 @@ const matchError = (message: string): null | KnownError => message.toLowerCase().indexOf(knownError.regex) > -1 ) ?? null -const buildErrorStrings = (error: KnownError, service?: Service): string[] => +const buildErrorStrings = ( + error: KnownError, + status: string, + service?: Service +): string[] => [ - `${error.description}\n`, + `${status}: ${error.description}\n`, error.causes?.length ? ["Potential cause(s): \n", ...error.causes, ""].join("\n") : "", @@ -48,7 +53,11 @@ class AccountAbstractionError extends BaseError { } } -export const getAAError = async (message: string, service?: Service) => { +export const getAAError = async ( + message: string, + httpStatus?: number, + service?: Service +) => { if (!knownErrors.length) { const errors = (await (await fetch(ERRORS_URL)).json()) as KnownError[] knownErrors.push(...errors) @@ -59,11 +68,18 @@ export const getAAError = async (message: string, service?: Service) => { ? message : JSON.stringify(message) const matchedError = matchError(details) + const status = + matchedError?.regex ?? (httpStatus ?? UNKOWN_ERROR_CODE).toString() + const metaMessages = matchedError - ? buildErrorStrings(matchedError, service) + ? buildErrorStrings(matchedError, status, service) : [] const title = matchedError ? matchedError.name : "Unknown Error" const docsSlug = matchedError?.docsUrl ?? DOCS_URL - return new AccountAbstractionError(title, { docsSlug, metaMessages, details }) + return new AccountAbstractionError(title, { + docsSlug, + metaMessages, + details + }) } diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index 24ac7ffb1..37c5593f9 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -6,7 +6,9 @@ import { createPublicClient, createWalletClient, encodeAbiParameters, + encodeFunctionData, hashMessage, + parseAbi, parseAbiParameters } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" @@ -30,11 +32,12 @@ import { DEFAULT_SESSION_KEY_MANAGER_MODULE, createECDSAOwnershipValidationModule } from "../../src/modules" -import { Paymaster } from "../../src/paymaster" +import { Paymaster, PaymasterMode } from "../../src/paymaster" import { checkBalance, getBundlerUrl, getConfig } from "../utils" describe("Account:Read", () => { const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e" + const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" const { chain, chainId, @@ -103,6 +106,54 @@ describe("Account:Read", () => { 50000 ) + test.concurrent( + "should estimate gas for minting an NFT", + async () => { + const encodedCall = encodeFunctionData({ + abi: parseAbi(["function safeMint(address _to)"]), + functionName: "safeMint", + args: [recipient] + }) + const transaction = { + to: nftAddress, // NFT address + data: encodedCall + } + const results = await Promise.all([ + smartAccount.getGasEstimate([transaction]), + smartAccount.getGasEstimate([transaction, transaction]), + smartAccount.getGasEstimate([transaction], { + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + }), + smartAccount.getGasEstimate([transaction, transaction], { + paymasterServiceData: { + mode: PaymasterMode.SPONSORED + } + }), + smartAccount.getGasEstimate([transaction], { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken: token + } + }), + await smartAccount.getGasEstimate([transaction, transaction], { + paymasterServiceData: { + mode: PaymasterMode.ERC20, + preferredToken: token + } + }) + ]) + + const increasingGasExpenditure = results.every( + (result, i) => result > (results[i - 1] ?? 0) + ) + + expect(increasingGasExpenditure).toBeTruthy() + }, + 60000 + ) + test.concurrent( "should throw if PrivateKeyAccount is used as signer and rpcUrl is not provided", async () => { From e39bb88aa46f282871879bb7021c627862974d81 Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Thu, 25 Apr 2024 14:46:12 +0100 Subject: [PATCH 30/33] update docs link (#480) Co-authored-by: livingrockrises <90545960+livingrockrises@users.noreply.github.com> Co-authored-by: himanshugarg06 <garg91824@gmail.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 889c0a096..986466f0f 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ For a comprehensive understanding of our project and to contribute effectively, - [**Contributing Guidelines**](./CONTRIBUTING.md): Learn how to contribute to our project, from code contributions to documentation improvements. - [**Code of Conduct**](./CODE_OF_CONDUCT.md): Our commitment to fostering an open and welcoming environment. - [**Security Policy**](./SECURITY.md): Guidelines for reporting security vulnerabilities. -- [**Changelog**](./CHANGELOG.md): Stay updated with the changes and versions. +- [**Changelog**](./CHANGELOG.md): Stay updated with the changes and versions ## 💼 Examples @@ -159,7 +159,7 @@ const { ## License -This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details. +This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details ## Connect with Biconomy 🍊 From 8d34d148862510fdb76c58852c55a48bc7c20b4c Mon Sep 17 00:00:00 2001 From: livingrockrises <90545960+livingrockrises@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:02:49 +0400 Subject: [PATCH 31/33] chore: dumy pnd override (#481) --- src/account/BiconomySmartAccountV2.ts | 1 + src/account/utils/Types.ts | 4 +++- tests/account/read.test.ts | 25 +++++++++++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index d1f2c0b7f..aff655ea6 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -1500,6 +1500,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { // for this Smart Account current validation module dummy signature will be used to estimate gas userOp.signature = signature + userOp.paymasterAndData = buildUseropDto?.dummyPndOverride ?? "0x" if ( buildUseropDto?.paymasterServiceData && diff --git a/src/account/utils/Types.ts b/src/account/utils/Types.ts index e9fc72d5f..1fb265ac3 100644 --- a/src/account/utils/Types.ts +++ b/src/account/utils/Types.ts @@ -193,6 +193,8 @@ export type BuildUserOpOptions = { paymasterServiceData?: PaymasterUserOperationDto /** simulationType: Determine which parts of the tx a bundler will simulate: "validation" | "validation_and_execution". */ simulationType?: SimulationType + /** dummy pnd override */ + dummyPndOverride?: BytesLike /** stateOverrideSet: For overriding the state */ stateOverrideSet?: StateOverrideSet /** set to true if the tx is being used *only* to deploy the smartContract, so "0x" is set as the userOp.callData */ @@ -331,7 +333,7 @@ export type Transaction = { export type SupportedToken = Omit< PaymasterFeeQuote, "maxGasFeeUSD" | "usdPayment" | "maxGasFee" | "validUntil" -> & { balance: BalancePayload }; +> & { balance: BalancePayload } export type Signer = LightSigner & { // biome-ignore lint/suspicious/noExplicitAny: any is used here to allow for the ethers provider diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index 37c5593f9..67e2346cb 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -615,8 +615,9 @@ describe("Account:Read", () => { test.concurrent("should fetch balances for smartAccount", async () => { const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) - const [tokenBalanceFromSmartAccount] = - await smartAccount.getBalance([token]) + const [tokenBalanceFromSmartAccount] = await smartAccount.getBalance([ + token + ]) expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount.amount) }) @@ -626,10 +627,11 @@ describe("Account:Read", () => { async () => { const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) - const tokenBalanceFromSmartAccount = - await smartAccount.getBalance([token]) - console.log(tokenBalanceFromSmartAccount); - + const tokenBalanceFromSmartAccount = await smartAccount.getBalance([ + token + ]) + console.log(tokenBalanceFromSmartAccount) + // expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount) } ) @@ -660,8 +662,7 @@ describe("Account:Read", () => { test.concurrent( "should check native token balance and more token info for smartAccount", async () => { - const [ethBalanceFromSmartAccount] = - await smartAccount.getBalance() + const [ethBalanceFromSmartAccount] = await smartAccount.getBalance() expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n) expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS) @@ -675,11 +676,11 @@ describe("Account:Read", () => { "should check balance of supported token", async () => { const tokens = await smartAccount.getSupportedTokens() - const [firstToken] = tokens; + const [firstToken] = tokens - expect(tokens.length).toBeGreaterThan(0); - expect(tokens[0]).toHaveProperty("balance"); - expect(firstToken.balance.amount).toBeGreaterThanOrEqual(0n); + expect(tokens.length).toBeGreaterThan(0) + expect(tokens[0]).toHaveProperty("balance") + expect(firstToken.balance.amount).toBeGreaterThanOrEqual(0n) }, 60000 ) From b44a7bfa611aa9cf1049ee5186e2519ae24c2f0e Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Fri, 26 Apr 2024 09:44:32 +0100 Subject: [PATCH 32/33] chore: update readme (#482) --- README.md | 4 +++- src/account/BiconomySmartAccountV2.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 986466f0f..8d8bd5bca 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,9 @@ const smartAccount = await createSmartAccountClient({ const oneOrManyTx = { to: "0x...", value: 1 }; const { wait } = await smartAccount.sendTransaction(oneOrManyTx, { - mode: PaymasterMode.SPONSORED, + paymasterServiceData: { + mode: PaymasterMode.SPONSORED, + }, }); const { diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index aff655ea6..517e12268 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -546,7 +546,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * { address: token }, // omit the amount to withdraw the full balance * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } * ], - * account.pubKey, // Default recipient used if no recipient is present in the withdrawal request + * account.address, // Default recipient used if no recipient is present in the withdrawal request * { * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, * } @@ -554,7 +554,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * // OR to withdraw all of the native token, leaving no dust in the smart account * - * const { wait } = await smartAccount.withdraw([], account.pubKey, { + * const { wait } = await smartAccount.withdraw([], account.address, { * paymasterServiceData: { mode: PaymasterMode.SPONSORED }, * }); * From c06a8d476d9ffeb52a24de2ac7c51ad306454df0 Mon Sep 17 00:00:00 2001 From: joepegler <joepegler123@gmail.com> Date: Mon, 29 Apr 2024 09:54:45 +0100 Subject: [PATCH 33/33] chore: version bump (#483) * chore: version bump --- CHANGELOG.md | 40 +++++++++++++++++++++++++++ package.json | 11 ++++++-- src/account/BiconomySmartAccountV2.ts | 10 +++---- tests/account/read.test.ts | 18 ++---------- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ab2aa28..96cc7c818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,45 @@ # @biconomy/account +## 4.2.0 + +### Minor Changes + +- Features: + + - Improved getBalances utility helper ([da340f](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/da340fbcc20778c9810dd8980061a6bb7b4cf097)) + - Added 1271 Signature support ([fd832fe](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/fd832fe2e286a5d3e57d3292cfa395e388b07b96)) + - Added withdrawal utility helper ([7a93d87](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7a93d871ecefbce8ed5ef63349c055072877189e)) + - Reduce bundle size ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19)) + - Integrate [AAErrors](https://github.com/bcnmy/aa-errors) ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19)) + - Added 6492 Signature support ([fd832fe](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/fd832fe2e286a5d3e57d3292cfa395e388b07b96)) + - Added Token Balances to getSupportedTokens payload ([869436](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/8694366165208cac6bbf7e560fe2abefce0eaa3a)) + - Added gas estimates utility helper ([950a521](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/950a521af63d7a719edcbae4df57259d3fe110e7)) + - Added dummy pnd override ([8d34d14](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/8d34d148862510fdb76c58852c55a48bc7c20b4c)) + + Chores: + + - Modernise tooling ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19)) + - Add changesets + - Migrate tests to Amoy + - Add pr lint + - Add size report + - Add tree shaking + - Add code of conduct + - Update README (table of contents) + - Add SECURITY.md + - Replace prettier with biome + - Replace yarn with bun + - Remove deprecated Base class + - Added "NEXT_PUBLIC_BICONOMY_SDK_DEBUG" to support NextJS debugging information + - Replace jest with vitest + - Added size threshold checks to PRs + - Added test coverage checks to PRs + - Added tsdoc auto-deploy + + Fixes: + + - Fix wrong falsy check for user op nonce ([f2567](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/f256712bbf7dc0de40b82c70ad183c59bf5f39f9)) + ## 4.1.1 (2023-07-03) - Added missing extensions ([fdbec6](https://github.com/bcnmy/biconomy-client-sdk/pull/451/commits/fdbec68625f4d7f436dc39d4c1779cdbb7c53e6d)) diff --git a/package.json b/package.json index dfd5d83b1..361af2fe7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "sideEffects": false, "name": "@biconomy/account", "author": "Biconomy", - "version": "4.1.3", + "version": "4.2.0", "description": "SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.", "keywords": [ "erc-7579", @@ -46,7 +46,10 @@ "default": "./_cjs/modules/index.js" } }, - "files": ["dist/*", "README.md"], + "files": [ + "dist/*", + "README.md" + ], "scripts": { "format": "biome format . --write", "lint": "biome check .", @@ -102,7 +105,9 @@ "viem": "^2" }, "commitlint": { - "extends": ["@commitlint/config-conventional"] + "extends": [ + "@commitlint/config-conventional" + ] }, "simple-git-hooks": { "pre-commit": "bun run format && bun run lint:fix", diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts index 517e12268..b6899f1b7 100644 --- a/src/account/BiconomySmartAccountV2.ts +++ b/src/account/BiconomySmartAccountV2.ts @@ -443,7 +443,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); - * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalance([token]); + * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([token]); * * console.log(tokenBalanceFromSmartAccount); * // { @@ -456,7 +456,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * * // or to get the nativeToken balance * - * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalance(); + * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances(); * * console.log(nativeTokenBalanceFromSmartAccount); * // { @@ -468,7 +468,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { * // } * */ - public async getBalance( + public async getBalances( addresses?: Array<Hex> ): Promise<Array<BalancePayload>> { const accountAddress = await this.getAccountAddress() @@ -586,7 +586,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { // Get the balances of the tokens if the amount is not present in the withdrawal requests if (shouldFetchMaxBalances) { - const balances = await this.getBalance( + const balances = await this.getBalances( tokenRequests.map(({ address }) => address) ) tokenRequests = tokenRequests.map(({ amount, address }, i) => ({ @@ -1144,7 +1144,7 @@ export class BiconomySmartAccountV2 extends BaseSmartContractAccount { return await Promise.all( (feeQuotesResponse?.feeQuotes ?? []).map(async (quote) => { - const [tokenBalance] = await this.getBalance([ + const [tokenBalance] = await this.getBalances([ quote.tokenAddress as Hex ]) return { diff --git a/tests/account/read.test.ts b/tests/account/read.test.ts index 67e2346cb..ca24cc709 100644 --- a/tests/account/read.test.ts +++ b/tests/account/read.test.ts @@ -615,27 +615,13 @@ describe("Account:Read", () => { test.concurrent("should fetch balances for smartAccount", async () => { const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) - const [tokenBalanceFromSmartAccount] = await smartAccount.getBalance([ + const [tokenBalanceFromSmartAccount] = await smartAccount.getBalances([ token ]) expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount.amount) }) - test.concurrent( - "should fetch only token balance for a smartAccount", - async () => { - const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" - const tokenBalanceBefore = await checkBalance(smartAccountAddress, token) - const tokenBalanceFromSmartAccount = await smartAccount.getBalance([ - token - ]) - console.log(tokenBalanceFromSmartAccount) - - // expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount) - } - ) - test.concurrent("should error if no recipient exists", async () => { const token: Hex = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a" @@ -662,7 +648,7 @@ describe("Account:Read", () => { test.concurrent( "should check native token balance and more token info for smartAccount", async () => { - const [ethBalanceFromSmartAccount] = await smartAccount.getBalance() + const [ethBalanceFromSmartAccount] = await smartAccount.getBalances() expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n) expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS)