From 45b59cf932e30e39fc62eefcedd631e5692bcb8d Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Wed, 28 Aug 2024 17:59:15 +0100 Subject: [PATCH] chore: sort test folder --- bun.lockb | Bin 351841 -> 351841 bytes package.json | 2 +- scripts/fetch:deployment.ts | 14 +- src/__contracts/README.md | 1 - src/__contracts/addresses.ts | 6 +- src/account/NexusSmartAccount.ts | 99 +- src/modules/executors/OwnableExecutor.ts | 26 +- src/modules/utils/Constants.ts | 2 - src/modules/validators/K1ValidatorModule.ts | 4 +- tests/__contracts/README.md | 1 - tests/__contracts/abi/index.ts | 4 - tests/__contracts/addresses.ts | 8 - tests/__contracts/deployment.json | 23 - tests/account.read.test.ts | 898 ++++++++++++++++++ tests/account.write.test.ts | 210 ++++ tests/instances/account.test.ts | 110 --- tests/modules.k1Validator.write.test.ts | 174 ++++ ...s => modules.ownableExecutor.read.test.ts} | 64 +- tests/modules.ownableExecutor.write.test.ts | 371 ++++++++ ...les.ownableValidator.install.write.test.ts | 371 ++++++++ ...s.ownableValidator.uninstall.write.test.ts | 371 ++++++++ tests/{instances => }/playground.test.ts | 6 +- tests/{ => src}/README.md | 2 +- .../__contracts/abi/BiconomyMetaFactoryAbi.ts | 0 .../{ => src}/__contracts/abi/BootstrapAbi.ts | 0 .../__contracts/abi/BootstrapLibAbi.ts | 0 tests/src/__contracts/abi/CounterAbi.ts | 36 + tests/src/__contracts/abi/MockExecutorAbi.ts | 309 ++++++ tests/src/__contracts/abi/MockHandlerAbi.ts | 227 +++++ tests/src/__contracts/abi/MockHookAbi.ts | 133 +++ .../__contracts/abi/MockRegistryAbi.ts | 0 tests/src/__contracts/abi/MockTokenAbi.ts | 344 +++++++ tests/src/__contracts/abi/MockValidatorAbi.ts | 228 +++++ .../__contracts/abi/NexusAccountFactoryAbi.ts | 323 +++++++ tests/src/__contracts/abi/StakeableAbi.ts | 211 ++++ tests/src/__contracts/abi/index.ts | 12 + tests/src/__contracts/addresses.ts | 16 + tests/src/__contracts/mockAddresses.ts | 16 + tests/{create.config.ts => src/callDatas.ts} | 8 + .../{deploy.nexus.ts => src/deployProcess.ts} | 9 +- tests/{ => src}/globalSetup.ts | 2 +- tests/{ => src}/testSetup.ts | 2 +- tests/{test.utils.ts => src/testUtils.ts} | 37 +- tests/vitest.config.ts | 4 +- 44 files changed, 4416 insertions(+), 268 deletions(-) delete mode 100644 src/__contracts/README.md delete mode 100644 tests/__contracts/README.md delete mode 100644 tests/__contracts/abi/index.ts delete mode 100644 tests/__contracts/addresses.ts delete mode 100644 tests/__contracts/deployment.json create mode 100644 tests/account.read.test.ts create mode 100644 tests/account.write.test.ts delete mode 100644 tests/instances/account.test.ts create mode 100644 tests/modules.k1Validator.write.test.ts rename tests/{instances/bundler.test.ts => modules.ownableExecutor.read.test.ts} (58%) create mode 100644 tests/modules.ownableExecutor.write.test.ts create mode 100644 tests/modules.ownableValidator.install.write.test.ts create mode 100644 tests/modules.ownableValidator.uninstall.write.test.ts rename tests/{instances => }/playground.test.ts (97%) rename tests/{ => src}/README.md (99%) rename tests/{ => src}/__contracts/abi/BiconomyMetaFactoryAbi.ts (100%) rename tests/{ => src}/__contracts/abi/BootstrapAbi.ts (100%) rename tests/{ => src}/__contracts/abi/BootstrapLibAbi.ts (100%) create mode 100644 tests/src/__contracts/abi/CounterAbi.ts create mode 100644 tests/src/__contracts/abi/MockExecutorAbi.ts create mode 100644 tests/src/__contracts/abi/MockHandlerAbi.ts create mode 100644 tests/src/__contracts/abi/MockHookAbi.ts rename tests/{ => src}/__contracts/abi/MockRegistryAbi.ts (100%) create mode 100644 tests/src/__contracts/abi/MockTokenAbi.ts create mode 100644 tests/src/__contracts/abi/MockValidatorAbi.ts create mode 100644 tests/src/__contracts/abi/NexusAccountFactoryAbi.ts create mode 100644 tests/src/__contracts/abi/StakeableAbi.ts create mode 100644 tests/src/__contracts/abi/index.ts create mode 100644 tests/src/__contracts/addresses.ts create mode 100644 tests/src/__contracts/mockAddresses.ts rename tests/{create.config.ts => src/callDatas.ts} (75%) rename tests/{deploy.nexus.ts => src/deployProcess.ts} (55%) rename tests/{ => src}/globalSetup.ts (96%) rename tests/{ => src}/testSetup.ts (97%) rename tests/{test.utils.ts => src/testUtils.ts} (92%) diff --git a/bun.lockb b/bun.lockb index 9e7dcd78bc3de101d1e3ca1b0bdfaa85307abc4a..30d906a77ac9164722b37295d384f68bdc2d22e7 100755 GIT binary patch delta 175 zcmaF3NA%$y(FuAA%u^rzl4Uu%EoSBEV%J@t9TqIomKA>|{rHa8;p=?%ahDqXTKyPX z{g_()n78_|1o&wfnp-9tB%39t0twT!#55!0L=%Iwq%^}c%T&vhlvKmiM03NWH1qAp m{8*U$t%+5hl$@7ashgKtQCh4E)iZtlJQnfoQuA2c4*&o|%Rd$X delta 175 zcmaF3NA%$y(FuAAi&GUM9$gQe&wD1qHgJh!UH%HDmG!w(^6t$#Y { const tsAbiPath = isForCore ? `${__dirname}/../src/__contracts/abi/${name}Abi.ts` - : `${__dirname}/../tests/__contracts/abi/${name}Abi.ts` + : `${__dirname}/../tests/src/__contracts/abi/${name}Abi.ts` fs.writeFileSync(tsAbiPath, tsAbiContent) @@ -66,14 +66,15 @@ export const getDeployments = async () => { const abiIndexPath = `${__dirname}/../src/__contracts/abi/index.ts` fs.writeFileSync(abiIndexPath, abiIndexContent) - const testAbiIndexPath = `${__dirname}/../tests/__contracts/abi/index.ts` + const testAbiIndexPath = `${__dirname}/../tests/src/__contracts/abi/index.ts` fs.writeFileSync(testAbiIndexPath, testAbiIndexContent) // Write addresses to src folder const writeAddressesPath = `${__dirname}/../src/__contracts/addresses.ts` - const writeAddressesPathTest = `${__dirname}/../tests/__contracts/addresses.ts` + const writeAddressesPathTest = `${__dirname}/../tests/src/__contracts/mockAddresses.ts` - const addressesContent = `import type { Hex } from "viem"\nexport const addresses: Record = ${JSON.stringify( + const addressesContent = `// The contents of this folder is auto-generated. Please do not edit as your changes are likely to be overwritten\n + import type { Hex } from "viem"\nexport const addresses: Record = ${JSON.stringify( Object.keys(deployedContracts) .filter((key) => coreFiles.includes(key)) .reduce((acc, key) => { @@ -84,7 +85,8 @@ export const getDeployments = async () => { 2 )} as const;\nexport default addresses\n` - const testAddressesContent = `import type { Hex } from "viem"\nexport const addresses: Record = ${JSON.stringify( + const testAddressesContent = `// The contents of this folder is auto-generated. Please do not edit as your changes are likely to be overwritten\n + import type { Hex } from "viem"\nexport const mockAddresses: Record = ${JSON.stringify( Object.keys(deployedContracts) .filter((key) => testFiles.includes(key)) .reduce((acc, key) => { @@ -93,7 +95,7 @@ export const getDeployments = async () => { }, {}), null, 2 - )} as const;\nexport default addresses\n` + )} as const;\nexport default mockAddresses\n` fs.writeFileSync(writeAddressesPath, addressesContent) fs.writeFileSync(writeAddressesPathTest, testAddressesContent) diff --git a/src/__contracts/README.md b/src/__contracts/README.md deleted file mode 100644 index d3a553ab..00000000 --- a/src/__contracts/README.md +++ /dev/null @@ -1 +0,0 @@ -## The contents of this folder is auto-generated. Please do not edit as your changes are likely to be overwritten \ No newline at end of file diff --git a/src/__contracts/addresses.ts b/src/__contracts/addresses.ts index d1e1edca..de6a5599 100644 --- a/src/__contracts/addresses.ts +++ b/src/__contracts/addresses.ts @@ -1,7 +1,7 @@ import type { Hex } from "viem" export const addresses: Record = { - Nexus: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", - K1Validator: "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - K1ValidatorFactory: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" + Nexus: "0x776d63154D2aa9256D72C420416c930F3B735464", + K1Validator: "0xd98238BBAeA4f91683d250003799EAd31d7F5c55", + K1ValidatorFactory: "0x8025afaD10209b8bEF3A3C94684AaE4D309c9996" } as const export default addresses diff --git a/src/account/NexusSmartAccount.ts b/src/account/NexusSmartAccount.ts index b941a919..a258d528 100644 --- a/src/account/NexusSmartAccount.ts +++ b/src/account/NexusSmartAccount.ts @@ -54,7 +54,7 @@ import { } from "../paymaster/index.js" import { BaseSmartContractAccount, - type DeploymentState + DeploymentState } from "./BaseSmartContractAccount.js" import { Logger, @@ -168,16 +168,6 @@ export class NexusSmartAccount extends BaseSmartContractAccount { this.activeValidationModule = // biome-ignore lint/style/noNonNullAssertion: nexusSmartAccountConfig.activeValidationModule! - - // this.publicClient = createPublicClient({ - // chain, - // transport: http(rpcClient) - // }) - - // this.scanForUpgradedAccountsFromV1 = - // nexusSmartAccountConfig.scanForUpgradedAccountsFromV1 ?? false - // this.maxIndexForScan = nexusSmartAccountConfig.maxIndexForScan ?? 10n - // this.getAddress() } /** @@ -280,7 +270,9 @@ export class NexusSmartAccount extends BaseSmartContractAccount { entryPointAddress: defaultedEntryPointAddress } - return new NexusSmartAccount(config) + const smartAccount = new NexusSmartAccount(config) + await smartAccount.getDeploymentState() + return smartAccount } override async getAddress(params?: CounterFactualAddressParam): Promise { @@ -323,13 +315,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * 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", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const tx = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -591,14 +583,17 @@ export class NexusSmartAccount extends BaseSmartContractAccount { async _getAccountContract(): Promise< GetContractReturnType > { - if (this.accountContract == null) { - this.accountContract = getContract({ - address: await this.getAddress(), - abi: NexusAbi, - client: this.publicClient as PublicClient - }) + if (await this.isAccountDeployed()) { + if (!this.accountContract) { + this.accountContract = getContract({ + address: await this.getAddress(), + abi: NexusAbi, + client: this.publicClient as PublicClient + }) + } + return this.accountContract } - return this.accountContract + throw new Error(ERROR_MESSAGES.ACCOUNT_NOT_DEPLOYED) } isActiveValidationModuleDefined(): boolean { @@ -676,10 +671,6 @@ export class NexusSmartAccount extends BaseSmartContractAccount { return this } - setDeploymentState(deploymentState: DeploymentState) { - this.deploymentState = deploymentState - } - // async getV1AccountsUpgradedToV2( // params: QueryParamsForAddressResolver // ): Promise { @@ -899,13 +890,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ - * abi: parseAbi(["function safeMint(address to) public"]), - * functionName: "safeMint", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const transaction = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -1028,13 +1019,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ - * abi: parseAbi(["function safeMint(address to) public"]), - * functionName: "safeMint", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const transaction = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -1273,13 +1264,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ - * abi: parseAbi(["function safeMint(address to) public"]), - * functionName: "safeMint", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const transaction = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -1302,13 +1293,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ - * abi: parseAbi(["function safeMint(address to) public"]), - * functionName: "safeMint", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const transaction = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -1331,7 +1322,17 @@ export class NexusSmartAccount extends BaseSmartContractAccount { : [manyOrOneTransactions], buildUseropDto ) - return this.sendUserOp(userOp) + const payload = await this.sendUserOp(userOp) + this.setDeploymentState(payload) // Don't wait + return payload + } + + private async setDeploymentState({ wait }: UserOpResponse) { + if (this.deploymentState === DeploymentState.DEPLOYED) return + const { success } = await wait() + if (success) { + this.deploymentState = DeploymentState.DEPLOYED + } } async sendTransactionWithExecutor( @@ -1373,13 +1374,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { * * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard * const encodedCall = encodeFunctionData({ - * abi: parseAbi(["function safeMint(address to) public"]), - * functionName: "safeMint", + * abi: CounterAbi, + * functionName: "incrementNumber", * args: ["0x..."], * }); * * const transaction = { - * to: nftAddress, + * to: mockAddresses.Counter, * data: encodedCall * } * @@ -1413,12 +1414,13 @@ export class NexusSmartAccount extends BaseSmartContractAccount { sender: (await this.getAddress()) as Hex, nonce: nonceFromFetch, factoryData, - factory: (await this.isAccountDeployed()) - ? undefined - : this.factoryAddress, callData } + if (!(await this.isAccountDeployed())) { + userOp.factory = this.factoryAddress + } + userOp.signature = dummySignature const gasFeeValues: GetUserOperationGasPriceReturnType | undefined = @@ -1722,11 +1724,11 @@ export class NexusSmartAccount extends BaseSmartContractAccount { async isModuleInstalled(module: Module) { if (await this.isAccountDeployed()) { const accountContract = await this._getAccountContract() - return (await accountContract.read.isModuleInstalled([ + return await accountContract.read.isModuleInstalled([ BigInt(moduleTypeIds[module.type]), module.moduleAddress, module.data ?? "0x" - ])) as boolean + ]) } Logger.warn("A module cannot be installed on an undeployed account") return false @@ -2006,7 +2008,10 @@ export class NexusSmartAccount extends BaseSmartContractAccount { const executors = await this.getInstalledExecutors() const hook = await this.getActiveHook() const fallbackHandler = await this.getFallbackBySelector() + return [...validators, ...executors, hook, fallbackHandler] + .flat() + .filter(Boolean) } /** diff --git a/src/modules/executors/OwnableExecutor.ts b/src/modules/executors/OwnableExecutor.ts index 2b87fca0..76be22bb 100644 --- a/src/modules/executors/OwnableExecutor.ts +++ b/src/modules/executors/OwnableExecutor.ts @@ -11,48 +11,51 @@ import { SENTINEL_ADDRESS } from "../../account" import type { NexusSmartAccount } from "../../account/NexusSmartAccount" import type { UserOpReceipt } from "../../bundler" import { BaseExecutionModule } from "../base/BaseExecutionModule" -import { OWNABLE_EXECUTOR } from "../utils/Constants" import type { Execution, Module } from "../utils/Types" export class OwnableExecutorModule extends BaseExecutionModule { smartAccount!: NexusSmartAccount public owners: Address[] + private address: Address public constructor( module: Module, smartAccount: NexusSmartAccount, - owners: Address[] + owners: Address[], + address: Address ) { super(module, smartAccount.getSigner()) this.smartAccount = smartAccount this.owners = owners this.data = module.data ?? "0x" + this.address = address } public static async create( smartAccount: NexusSmartAccount, + address: Address, data?: Hex ): Promise { const module: Module = { - moduleAddress: OWNABLE_EXECUTOR, + moduleAddress: address, type: "executor", data: data ?? "0x", additionalContext: "0x" } const owners = await smartAccount.publicClient.readContract({ - address: OWNABLE_EXECUTOR, + address, abi: parseAbi([ "function getOwners(address account) external view returns (address[])" ]), functionName: "getOwners", args: [await smartAccount.getAddress()] }) - const instance = new OwnableExecutorModule( + return new OwnableExecutorModule( module, smartAccount, - owners as Address[] + owners as Address[], + address ) - return instance } public async execute( @@ -140,7 +143,7 @@ export class OwnableExecutorModule extends BaseExecutionModule { } public async removeOwner(ownerToRemove: Address): Promise { - const owners = await this.getOwners() + const owners = await this.getOwners(this.address) let prevOwner: Address const currentOwnerIndex = owners.findIndex( @@ -175,9 +178,12 @@ export class OwnableExecutorModule extends BaseExecutionModule { return receipt } - public async getOwners(accountAddress?: Address): Promise { + public async getOwners( + moduleAddress: Address, + accountAddress?: Address + ): Promise { const owners = await this.smartAccount.publicClient.readContract({ - address: OWNABLE_EXECUTOR, + address: moduleAddress, abi: parseAbi([ "function getOwners(address account) external view returns (address[])" ]), diff --git a/src/modules/utils/Constants.ts b/src/modules/utils/Constants.ts index d35540c5..0f1d7ba3 100644 --- a/src/modules/utils/Constants.ts +++ b/src/modules/utils/Constants.ts @@ -1,5 +1,3 @@ import type { ModuleVersion } from "./Types.js" -export const OWNABLE_EXECUTOR = "0x" -export const OWNABLE_VALIDATOR = "0x" export const DEFAULT_MODULE_VERSION: ModuleVersion = "1.0.0-beta" diff --git a/src/modules/validators/K1ValidatorModule.ts b/src/modules/validators/K1ValidatorModule.ts index 6de014ac..19b26a28 100644 --- a/src/modules/validators/K1ValidatorModule.ts +++ b/src/modules/validators/K1ValidatorModule.ts @@ -1,4 +1,4 @@ -import type { Address } from "viem" +import addresses from "../../__contracts/addresses.js" import type { SmartAccountSigner } from "../../account/index.js" import { BaseValidationModule } from "../base/BaseValidationModule.js" import type { Module } from "../utils/Types.js" @@ -10,7 +10,7 @@ export class K1ValidatorModule extends BaseValidationModule { public static async create( signer: SmartAccountSigner, - k1ValidatorAddress: Address + k1ValidatorAddress = addresses.K1Validator ): Promise { const module: Module = { moduleAddress: k1ValidatorAddress, diff --git a/tests/__contracts/README.md b/tests/__contracts/README.md deleted file mode 100644 index bc22b669..00000000 --- a/tests/__contracts/README.md +++ /dev/null @@ -1 +0,0 @@ -## The contents of this folder is auto-generated. Please do not edit as they are likely to become overwritten \ No newline at end of file diff --git a/tests/__contracts/abi/index.ts b/tests/__contracts/abi/index.ts deleted file mode 100644 index 011ff2d1..00000000 --- a/tests/__contracts/abi/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./BiconomyMetaFactoryAbi" -export * from "./BootstrapLibAbi" -export * from "./MockRegistryAbi" -export * from "./BootstrapAbi" diff --git a/tests/__contracts/addresses.ts b/tests/__contracts/addresses.ts deleted file mode 100644 index 6299bad4..00000000 --- a/tests/__contracts/addresses.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Hex } from "viem" -export const addresses: Record = { - BiconomyMetaFactory: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", - BootstrapLib: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", - MockRegistry: "0x0165878A594ca255338adfa4d48449f69242Eb8F", - Bootstrap: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" -} as const -export default addresses diff --git a/tests/__contracts/deployment.json b/tests/__contracts/deployment.json deleted file mode 100644 index 15474835..00000000 --- a/tests/__contracts/deployment.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "Nexus": { - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" - }, - "BiconomyMetaFactory": { - "address": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" - }, - "K1Validator": { - "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" - }, - "K1ValidatorFactory": { - "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" - }, - "BootstrapLib": { - "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - }, - "MockRegistry": { - "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F" - }, - "Bootstrap": { - "address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" - } -} diff --git a/tests/account.read.test.ts b/tests/account.read.test.ts new file mode 100644 index 00000000..4b803499 --- /dev/null +++ b/tests/account.read.test.ts @@ -0,0 +1,898 @@ +import { JsonRpcProvider, Wallet } from "ethers" +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + concat, + createPublicClient, + createWalletClient, + encodeAbiParameters, + encodeFunctionData, + encodePacked, + getContract, + hashMessage, + keccak256, + parseAbiParameters, + toBytes, + toHex +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { baseSepolia } from "viem/chains" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { K1ValidatorFactoryAbi, NexusAbi } from "../src/__contracts/abi" +import addresses from "../src/__contracts/addresses" +import { + ERROR_MESSAGES, + NATIVE_TOKEN_ALIAS, + type NexusSmartAccount, + type SupportedSigner, + type Transaction, + createSmartAccountClient, + eip1271MagicValue, + getChain, + makeInstallDataAndHash +} from "../src/account" +import { CounterAbi } from "./src/__contracts/abi" +import mockAddresses from "./src/__contracts/mockAddresses" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + checkBalance, + getAccountDomainStructFields, + getBundlerUrl, + getTestAccount, + killNetwork, + pKey, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "GLOBAL" + +describe("account.read", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + test.skip("should estimate gas for minting an NFT", async () => { + const encodedCall = encodeFunctionData({ + abi: CounterAbi, + functionName: "incrementNumber" + }) + const transaction = { + to: mockAddresses.Counter, + data: encodedCall + } + const results = await Promise.all([ + smartAccount.getGasEstimate([transaction]), + smartAccount.getGasEstimate([transaction, transaction]) + ]) + + const increasingGasExpenditure = results.every( + (result, i) => result > (results[i - 1] ?? 0) + ) + + expect(increasingGasExpenditure).toBeTruthy() + }, 60000) + + test.skip("should throw if PrivateKeyAccount is used as signer and rpcUrl is not provided", async () => { + const createSmartAccount = createSmartAccountClient({ + chain, + signer: account as SupportedSigner, + bundlerUrl + }) + + await expect(createSmartAccount).rejects.toThrow( + ERROR_MESSAGES.MISSING_RPC_URL + ) + }, 50000) + + test.skip("should get all modules", async () => { + const modules = smartAccount.getInstalledModules() + if (await smartAccount.isAccountDeployed()) { + expect(modules).resolves + } else { + expect(modules).rejects.toThrow("Account is not deployed") + } + }, 30000) + + test.skip("should check if module is enabled on the smart account", async () => { + const isEnabled = smartAccount.isModuleInstalled({ + type: "validator", + moduleAddress: addresses.K1Validator + }) + if (await smartAccount.isAccountDeployed()) { + expect(isEnabled).resolves.toBeTruthy() + } else { + expect(isEnabled).rejects.toThrow("Account is not deployed") + } + }, 30000) + + test.skip("enable mode", async () => { + const result = makeInstallDataAndHash(account.address, [ + { + moduleType: "validator", + config: account.address + } + ]) + expect(result).toBeTruthy() + }, 30000) + + test.skip("should create a smartAccountClient from an ethers signer", async () => { + const ethersProvider = new JsonRpcProvider(chain.rpcUrls.default.http[0]) + const ethersSigner = new Wallet(pKey, ethersProvider) + + const smartAccount = await createSmartAccountClient({ + chain, + signer: ethersSigner, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + }) + + test.skip("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(pKey, ethersProvider) + + const originalEthersProvider = new JsonRpcProvider( + chain.rpcUrls.default.http[0] + ) + const ethersSigner = new Wallet(pKey, originalEthersProvider) + + const walletClientWithNewRpcUrl = createWalletClient({ + account, + chain, + transport: http(newRpcUrl) + }) + const [ + smartAccountFromEthersWithNewRpc, + smartAccountFromViemWithNewRpc, + smartAccountFromEthersWithOldRpc, + smartAccountFromViemWithOldRpc + ] = await Promise.all([ + createSmartAccountClient({ + chain, + signer: ethersSignerWithNewRpcUrl, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: newRpcUrl + }), + createSmartAccountClient({ + chain, + signer: walletClientWithNewRpcUrl, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: newRpcUrl + }), + createSmartAccountClient({ + chain, + signer: ethersSigner, + bundlerUrl: getBundlerUrl(1337), + rpcUrl: chain.rpcUrls.default.http[0] + }), + createSmartAccountClient({ + chain, + 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.publicClient.transport.url).toBe( + newRpcUrl + ) + expect(smartAccountFromViemWithNewRpc.publicClient.transport.url).toBe( + newRpcUrl + ) + expect(smartAccountFromEthersWithOldRpc.publicClient.transport.url).toBe( + defaultRpcUrl + ) + expect(smartAccountFromViemWithOldRpc.publicClient.transport.url).toBe( + defaultRpcUrl + ) + }) + + test.skip("should read estimated user op gas values", async () => { + const tx = { + to: recipientAccount.address, + 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() + }, 30000) + + test.skip("should have an active validation module", async () => { + const module = smartAccount.activeValidationModule + expect(module).toBeTruthy() + }) + + // @note Ignored untill we implement Paymaster + // test.skip( + // "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.skip("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({ + chain, + signer: viemWalletNoAccount, + bundlerUrl, + rpcUrl: chain.rpcUrls.default.http[0] + }) + ).rejects.toThrow("Cannot consume a viem wallet without an account") + }) + + // test.skip( + // "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.skip("should not throw and error, chain ids match", async () => { + // const mockBundlerUrl = + // "https://bundler.biconomy.io/api/v2/84532/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44" + // const mockPaymasterUrl = + // "https://paymaster.biconomy.io/api/v1/84532/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + // const config: NexusSmartAccountConfig = { + // signer: walletClient, + // bundlerUrl: mockBundlerUrl, + // paymasterUrl: mockPaymasterUrl + // } + + // await expect( + // compareChainIds(walletClient, config, false) + // ).resolves.not.toThrow() + // }) + + // test.skip( + // "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 k1ValidationModule = await createK1ValidatorModule( + // smartAccount.getSigner() + // ) + + // const config: NexusSmartAccountConfig = { + // chain, + // defaultValidationModule: k1ValidationModule, + // activeValidationModule: k1ValidationModule, + // bundlerUrl, + // paymasterUrl: mockPaymasterUrl + // } + + // } + // ) + + // test.skip( + // "should throw and error, signer has chain id (56) and paymasterUrl has chain id (11155111)", + // async () => { + // const mockPaymasterUrl = + // "https://paymaster.biconomy.io/api/v1/11155111/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71" + + // const walletClientBsc = createWalletClient({ + // account: walletClient.account, + // chain: bsc, + // transport: http(bsc.rpcUrls.default.http[0]) + // }) + + // const config: NexusSmartAccountConfig = { + // chain, + // signer: walletClientBsc, + // bundlerUrl, + // paymasterUrl: mockPaymasterUrl + // } + + // } + // ) + + test.skip("should return chain object for chain id 1", async () => { + const chainId = 1 + const chain = getChain(chainId) + expect(chain.id).toBe(chainId) + }) + + test.skip("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.skip("should throw an error, chain id not found", async () => { + const chainId = 0 + expect(() => getChain(chainId)).toThrow(ERROR_MESSAGES.CHAIN_NOT_FOUND) + }) + + test.skip("should have matching counterFactual address from the contracts with smartAccount.getAddress()", async () => { + const client = createWalletClient({ + account, + chain, + transport: http() + }) + + const smartAccount = await createSmartAccountClient({ + chain, + signer: client, + bundlerUrl + }) + + const smartAccountAddressFromSDK = await smartAccount.getAccountAddress() + + const publicClient = createPublicClient({ + chain, + transport: http() + }) + + const factoryContract = getContract({ + address: addresses.K1ValidatorFactory, + abi: K1ValidatorFactoryAbi, + client: { public: publicClient, wallet: client } + }) + + const smartAccountAddressFromContracts = + await factoryContract.read.computeAccountAddress([ + await smartAccount.getSmartAccountOwner().getAddress(), + BigInt(0), + [], + 0 + ]) + + expect(smartAccountAddressFromSDK).toBe(smartAccountAddressFromContracts) + }) + + test.skip("should be deployed to counterfactual address", async () => { + const accountAddress = await smartAccount.getAccountAddress() + const byteCode = await testClient.getBytecode({ + address: accountAddress as Hex + }) + if (await smartAccount.isAccountDeployed()) { + expect(byteCode?.length).toBeGreaterThan(2) + } else { + expect(byteCode?.length).toBe(undefined) + } + }, 10000) + + test.skip("should check if ecdsaOwnershipModule is enabled", async () => { + const ecdsaOwnershipModule = addresses.K1Validator + + expect(ecdsaOwnershipModule).toBe( + smartAccount.activeValidationModule.getAddress() + ) + }) + + test.skip("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({ + chain, + signer: newViemWallet, + bundlerUrl + }) + + expect(async () => smartAccount.deploy()).rejects.toThrow( + ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY + ) + }) + + test.skip("should fail to deploy a smart account if already deployed", async () => { + if (await smartAccount.isAccountDeployed()) { + expect(async () => smartAccount.deploy()).rejects.toThrow( + ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED + ) + } else { + expect(smartAccount.deploy()).resolves + } + }, 60000) + + test.skip("should fetch balances for smartAccount", async () => { + const token = "0x69835C1f31ed0721A05d5711C1d669C10802a3E1" + const tokenBalanceBefore = await checkBalance( + testClient, + smartAccountAddress, + token + ) + const [tokenBalanceFromSmartAccount] = await smartAccount.getBalances([ + token + ]) + + expect(tokenBalanceBefore).toBe(tokenBalanceFromSmartAccount.amount) + }) + + test.skip("should error if no recipient exists", async () => { + const token: Hex = "0x69835C1f31ed0721A05d5711C1d669C10802a3E1" + + const txs = [ + { address: token, amount: BigInt(1), recipient: account.address }, + { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) } + ] + + expect(async () => smartAccount.withdraw(txs)).rejects.toThrow( + ERROR_MESSAGES.NO_RECIPIENT + ) + }) + + test.skip("should error when withdraw all of native token is attempted without an amount explicitly set", async () => { + expect(async () => + smartAccount.withdraw(null, account.address) + ).rejects.toThrow(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT) + }, 6000) + + test.skip("should check native token balance and more token info for smartAccount", async () => { + const [ethBalanceFromSmartAccount] = await smartAccount.getBalances() + + expect(ethBalanceFromSmartAccount.amount).toBeGreaterThan(0n) + expect(ethBalanceFromSmartAccount.address).toBe(NATIVE_TOKEN_ALIAS) + expect(ethBalanceFromSmartAccount.chainId).toBe(chain.id) + expect(ethBalanceFromSmartAccount.decimals).toBe(18) + }, 60000) + + // @note Skip until we implement the Paymaster + // test.skip( + // "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 + // ) + + // @note Nexus SA signature needs to contain the validator module address in the first 20 bytes + test.skip("should test isValidSignature PersonalSign to be valid", async () => { + if (await smartAccount.isAccountDeployed()) { + const data = hashMessage("0x1234") + + // Define constants as per the original Solidity function + const DOMAIN_NAME = "Nexus" + const DOMAIN_VERSION = "1.0.0-beta" + const DOMAIN_TYPEHASH = + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + const PARENT_TYPEHASH = "PersonalSign(bytes prefixed)" + const chainId = baseSepolia.id + + // Calculate the domain separator + const domainSeparator = keccak256( + encodeAbiParameters( + parseAbiParameters("bytes32, bytes32, bytes32, uint256, address"), + [ + keccak256(toBytes(DOMAIN_TYPEHASH)), + keccak256(toBytes(DOMAIN_NAME)), + keccak256(toBytes(DOMAIN_VERSION)), + BigInt(chainId), + smartAccountAddress + ] + ) + ) + + // Calculate the parent struct hash + const parentStructHash = keccak256( + encodeAbiParameters(parseAbiParameters("bytes32, bytes32"), [ + keccak256(toBytes(PARENT_TYPEHASH)), + hashMessage(data) + ]) + ) + + // Calculate the final hash + const resultHash: Hex = keccak256( + concat(["0x1901", domainSeparator, parentStructHash]) + ) + + const signature = await smartAccount.signMessage(resultHash) + + const contractResponse = await testClient.readContract({ + address: await smartAccount.getAddress(), + abi: NexusAbi, + functionName: "isValidSignature", + args: [hashMessage(data), signature] + }) + + const viemResponse = await testClient.verifyMessage({ + address: smartAccountAddress, + message: data, + signature + }) + + expect(contractResponse).toBe(eip1271MagicValue) + expect(viemResponse).toBe(true) + } + }) + + test.skip("should test isValidSignature EIP712Sign to be valid", async () => { + if (await smartAccount.isAccountDeployed()) { + const data = keccak256("0x1234") + + // Define constants as per the original Solidity function + const DOMAIN_NAME = "Nexus" + const DOMAIN_VERSION = "1.0.0-beta" + const DOMAIN_TYPEHASH = + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + const PARENT_TYPEHASH = + "TypedDataSign(Contents contents,bytes1 fields,string name,string version,uint256 chainId,address verifyingContract,bytes32 salt,uint256[] extensions) Contents(bytes32 stuff)" + const chainId = baseSepolia.id + + // Calculate the domain separator + const domainSeparator = keccak256( + encodeAbiParameters( + parseAbiParameters("bytes32, bytes32, bytes32, uint256, address"), + [ + keccak256(toBytes(DOMAIN_TYPEHASH)), + keccak256(toBytes(DOMAIN_NAME)), + keccak256(toBytes(DOMAIN_VERSION)), + BigInt(chainId), + smartAccountAddress + ] + ) + ) + + const encodedAccountDomainStructFields = + await getAccountDomainStructFields(testClient, smartAccountAddress) + + // Calculate the parent struct hash + const parentStructHash = keccak256( + encodePacked( + ["bytes", "bytes"], + [ + encodeAbiParameters(parseAbiParameters("bytes32, bytes32"), [ + keccak256(toBytes(PARENT_TYPEHASH)), + hashMessage(data) + ]), + encodedAccountDomainStructFields + ] + ) + ) + + const dataToSign: Hex = keccak256( + concat(["0x1901" as Hex, domainSeparator, parentStructHash]) + ) + + let signature = await smartAccount.signMessage(dataToSign) + const contentsType: Hex = toHex("Contents(bytes32 stuff)") + signature = encodePacked( + ["bytes", "bytes", "bytes", "bytes", "uint"], + [ + signature, + domainSeparator, + hashMessage(data), + contentsType, + BigInt(contentsType.length) + ] + ) + + const finalSignature = encodePacked( + ["address", "bytes"], + [smartAccount.activeValidationModule.moduleAddress, signature] + ) + + const contents = keccak256( + encodePacked( + ["bytes", "bytes", "bytes"], + ["0x1901", domainSeparator, hashMessage(data)] + ) + ) + + const contractResponse = await testClient.readContract({ + address: await smartAccount.getAddress(), + abi: NexusAbi, + functionName: "isValidSignature", + args: [contents, finalSignature] + }) + + const viemResponse = await testClient.verifyMessage({ + address: smartAccountAddress, + message: data, + signature: finalSignature + }) + + expect(contractResponse).toBe(eip1271MagicValue) + expect(viemResponse).toBe(true) + } + }) + + // test.skip("should call isValidSignature for deployed smart account", async () => { + // const smartAccount = await createSmartAccountClient({ + // signer: walletClient, + // bundlerUrl + // }) + + // const message = "hello world" + // const signature = await smartAccount.signMessage(message) + + // const isVerified = await publicClient.readContract({ + // address: await smartAccount.getAddress(), + // abi: NexusAccountAbi, + // functionName: "isValidSignature", + // args: [hashMessage(message), signature] + // }) + + // expect(isVerified).toBe(eip1271MagicValue) + // }) + + // test.skip("should verifySignature of not deployed", async () => { + // const undeployedSmartAccount = await createSmartAccountClient({ + // signer: walletClient, + // bundlerUrl, + // index: 99n + // }) + // const isDeployed = await undeployedSmartAccount.isAccountDeployed() + // if (!isDeployed) { + // const message = "hello world" + + // const signature = await smartAccount.signMessage(message) + // // OR + // // const signature = await smartAccount.signMessageWith6492(message) + + // const isVerified = await publicClient.readContract({ + // address: await smartAccount.getAddress(), + // abi: NexusAccountAbi, + // functionName: "isValidSignature", + // args: [hashMessage(message), signature] + // }) + + // expect(isVerified).toBe(eip1271MagicValue) + // } + // }) + + // test.skip("should verifySignature using viem", async () => { + // const isDeployed = await smartAccount.isAccountDeployed() + // if (isDeployed) { + // const message = "0x123" + + // const signature = await smartAccount.signMessage(message) + + // console.log(signature, 'signature'); + // console.log(hashMessage(message), 'hashMessage(message)'); + + // // const isVerified = await verifyMessage(publicClient, { + // // address: await smartAccount.getAddress(), + // // message, + // // signature, + // // }) + + // const isVerified = await publicClient.readContract({ + // address: await smartAccount.getAddress(), + // abi: NexusAccountAbi, + // functionName: "isValidSignature", + // args: [hashMessage(message), signature] + // }) + + // console.log(isVerified, "isVerified"); + + // expect(isVerified).toBe(eip1271MagicValue) + // } + // }) + + // @note Removed untill we implement the Bundler (Pimlico's bundler does no behave as expected in this test) + // test.skip( + // "should simulate a user operation execution, expecting to fail", + // async () => { + // const smartAccount = await createSmartAccountClient({ + // signer: walletClient, + // bundlerUrl + // }) + + // const balances = await smartAccount.getBalances() + // expect(balances[0].amount).toBeGreaterThan(0n) + + // const encodedCall = encodeFunctionData({ + // abi: parseAbi(["function deposit()"]), + // functionName: "deposit" + // }) + + // const amoyTestContract = "0x59Dbe91FBa486CA10E4ad589688Fe547a48bd62A" + + // // fail if value is not bigger than 1 + // // the contract call requires a deposit of at least 1 wei + // const tx1 = { + // to: amoyTestContract as Hex, + // data: encodedCall, + // value: 0 + // } + // const tx2 = { + // to: amoyTestContract as Hex, + // data: encodedCall, + // value: 2 + // } + + // await expect(smartAccount.buildUserOp([tx1, tx2])).rejects.toThrow() + // } + // ) + + // @note Removed untill we implement the Bundler (Pimlico's bundler does no behave as expected in this test) + // test.skip( + // "should simulate a user operation execution, expecting to pass execution", + // async () => { + // const smartAccount = await createSmartAccountClient({ + // signer: walletClient, + // bundlerUrl + // }) + + // const balances = await smartAccount.getBalances() + // expect(balances[0].amount).toBeGreaterThan(0n) + + // const encodedCall = encodeFunctionData({ + // abi: parseAbi(["function deposit()"]), + // functionName: "deposit" + // }) + + // const amoyTestContract = "0x59Dbe91FBa486CA10E4ad589688Fe547a48bd62A" + + // // fail if value is not bigger than 1 + // // the contract call requires a deposit of at least 1 wei + // const tx1 = { + // to: amoyTestContract as Hex, + // data: encodedCall, + // value: 2 + // } + // const tx2 = { + // to: amoyTestContract as Hex, + // data: encodedCall, + // value: 2 + // } + + // await expect(smartAccount.buildUserOp([tx1, tx2])).resolves.toBeTruthy() + // } + // ) + + // test.skip("Should verify supported modes", async () => { + // expect( + // await smartAccount.supportsExecutionMode(ACCOUNT_MODES.DEFAULT_SINGLE) + // ).to.be.true + // expect( + // await smartAccount.supportsExecutionMode(ACCOUNT_MODES.DEFAULT_BATCH) + // ).to.be.true + // expect(await smartAccount.supportsExecutionMode(ACCOUNT_MODES.TRY_BATCH)).to + // .be.true + // expect(await smartAccount.supportsExecutionMode(ACCOUNT_MODES.TRY_SINGLE)) + // .to.be.true + + // expect( + // await smartAccount.supportsExecutionMode(ACCOUNT_MODES.DELEGATE_SINGLE) + // ).to.be.false + // }) +}) diff --git a/tests/account.write.test.ts b/tests/account.write.test.ts new file mode 100644 index 00000000..537e2612 --- /dev/null +++ b/tests/account.write.test.ts @@ -0,0 +1,210 @@ +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + createWalletClient +} from "viem" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { + type NexusSmartAccount, + type Transaction, + createSmartAccountClient +} from "../src/account" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("account.write", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + // test("install a mock Hook module", async () => { + // const isSupported = await smartAccount.supportsModule(ModuleType.Hook) + // console.log(isSupported, "is supported") + + // const isInstalledBefore = await smartAccount.isModuleInstalled( + // ModuleType.Hook, + // MOCK_HOOK + // ) + // console.log(isInstalledBefore, "is installed before") + + // const userOpReceipt = await smartAccount.installModule(MOCK_HOOK, ModuleType.Hook) + // console.log(userOpReceipt, "user op receipt") + + // const isInstalled = await smartAccount.isModuleInstalled( + // ModuleType.Hook, + // MOCK_HOOK + // ) + + // expect(userOpReceipt.success).toBe(true) + // expect(isInstalled).toBeTruthy() + // }, 60000) + + // test("get active hook", async () => { + // const activeHook: Address = await smartAccount.getActiveHook() + // console.log(activeHook, "active hook") + // expect(activeHook).toBe(MOCK_HOOK) + // }, 60000) + + // test("uninstall hook module", async () => { + // const prevAddress: Hex = "0x0000000000000000000000000000000000000001" + // const deInitData = encodeAbiParameters( + // [ + // { name: "prev", type: "address" }, + // { name: "disableModuleData", type: "bytes" } + // ], + // [prevAddress, toHex(stringToBytes(""))] + // ) + // const userOpReceipt = await smartAccount.uninstallModule(MOCK_HOOK, ModuleType.Hook, deInitData) + + // const isInstalled = await smartAccount.isModuleInstalled( + // ModuleType.Hook, + // MOCK_HOOK + // ) + + // expect(userOpReceipt.success).toBe(true) + // expect(isInstalled).toBeFalsy() + // expect(userOpReceipt).toBeTruthy() + // }, 60000) + + // test("install a fallback handler Hook module", async () => { + // const isSupported = await smartAccount.supportsModule(ModuleType.Fallback) + // console.log(isSupported, "is supported") + + // const isInstalledBefore = await smartAccount.isModuleInstalled( + // ModuleType.Fallback, + // MOCK_FALLBACK_HANDLER, + // ethers.AbiCoder.defaultAbiCoder().encode( + // ["bytes4"], + // [GENERIC_FALLBACK_SELECTOR as Hex] + // ) as Hex + // ) + // console.log(isInstalledBefore, "is installed before") + + // const userOpReceipt = await smartAccount.installModule(MOCK_FALLBACK_HANDLER, ModuleType.Fallback, ethers.AbiCoder.defaultAbiCoder().encode( + // ["bytes4"], + // [GENERIC_FALLBACK_SELECTOR as Hex] + // ) as Hex) + + // const isInstalled = await smartAccount.isModuleInstalled( + // ModuleType.Fallback, + // MOCK_FALLBACK_HANDLER, + // ethers.AbiCoder.defaultAbiCoder().encode( + // ["bytes4"], + // [GENERIC_FALLBACK_SELECTOR as Hex] + // ) as Hex + // ) + + // expect(userOpReceipt.success).toBe(true) + // expect(isInstalled).toBeTruthy() + // }, 60000) + + // test("uninstall handler module", async () => { + // const prevAddress: Hex = "0x0000000000000000000000000000000000000001" + // const deInitData = ethers.AbiCoder.defaultAbiCoder().encode( + // ["bytes4"], + // [GENERIC_FALLBACK_SELECTOR as Hex] + // ) as Hex + // const userOpReceipt = await smartAccount.uninstallModule( + // MOCK_FALLBACK_HANDLER, + // ModuleType.Fallback, + // deInitData + // ) + + // const isInstalled = await smartAccount.isModuleInstalled( + // ModuleType.Fallback, + // MOCK_FALLBACK_HANDLER, + // ethers.AbiCoder.defaultAbiCoder().encode( + // ["bytes4"], + // [GENERIC_FALLBACK_SELECTOR as Hex] + // ) as Hex + // ) + + // expect(userOpReceipt.success).toBe(true) + // expect(isInstalled).toBeFalsy() + // expect(userOpReceipt).toBeTruthy() + // }, 60000) +}) diff --git a/tests/instances/account.test.ts b/tests/instances/account.test.ts deleted file mode 100644 index 5d4946c3..00000000 --- a/tests/instances/account.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { - http, - type Account, - type Chain, - type Hex, - type WalletClient, - createWalletClient -} from "viem" -import { afterAll, beforeAll, describe, expect, test } from "vitest" -import contracts from "../../src/__contracts" -import { - type NexusSmartAccount, - type Transaction, - createSmartAccountClient -} from "../../src/account" -import { getTestAccount, killNetwork, toTestClient, topUp } from "../test.utils" -import type { MasterClient, NetworkConfig } from "../test.utils" -import { type TestFileNetworkType, toNetwork } from "../testSetup" - -const NETWORK_TYPE: TestFileNetworkType = "GLOBAL" - -describe("account", () => { - let network: NetworkConfig - - // Nexus Config - let chain: Chain - let bundlerUrl: string - let factoryAddress: Hex - let k1ValidatorAddress: Hex - let walletClient: WalletClient - - // Test utils - let testClient: MasterClient - let account: Account - let recipientAccount: Account - let smartAccount: NexusSmartAccount - let smartAccountAddress: Hex - - beforeAll(async () => { - network = await toNetwork(NETWORK_TYPE) - - chain = network.chain - bundlerUrl = network.bundlerUrl - - account = getTestAccount(0) - recipientAccount = getTestAccount(3) - - walletClient = createWalletClient({ - account, - chain, - transport: http() - }) - - testClient = toTestClient(chain, getTestAccount(0)) - - smartAccount = await createSmartAccountClient({ - signer: walletClient, - bundlerUrl, - chain - }) - - smartAccountAddress = await smartAccount.getAddress() - // await fundAndDeploy(testClient, smartAccount) - }) - afterAll(async () => { - await killNetwork([network.rpcPort, network.bundlerPort]) - }) - - test("byteCodes", async () => { - const byteCodes = await Promise.all([ - testClient.getBytecode({ address: contracts.k1ValidatorFactory.address }), - testClient.getBytecode({ address: contracts.k1Validator.address }) - ]) - expect(byteCodes.every(Boolean)).toBe(true) - }) - - test("topUp", async () => { - const total = await testClient.getBalance({ - address: testClient.account.address - }) - await topUp(testClient, smartAccountAddress) - const [balance] = await smartAccount.getBalances() - expect(balance.amount > 0) - }) - - test("should have account addresses", async () => { - const addresses = await Promise.all([ - account.address, - smartAccount.getAddress() - ]) - expect(addresses.every(Boolean)).to.be.true - expect(addresses).toStrictEqual([ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "0x473AecE3DE762252a9d47F5032133282c9615e28" // Sender smart account - ]) - }) - - test("send eth", async () => { - const tx: Transaction = { - to: account.address, - value: 1n - } - - const { wait } = await smartAccount.sendTransaction(tx) - - const { success, receipt } = await wait() - - expect(success).toBe(true) - }) -}) diff --git a/tests/modules.k1Validator.write.test.ts b/tests/modules.k1Validator.write.test.ts new file mode 100644 index 00000000..88365714 --- /dev/null +++ b/tests/modules.k1Validator.write.test.ts @@ -0,0 +1,174 @@ +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + createWalletClient, + encodeFunctionData, + encodePacked +} from "viem" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { createK1ValidatorModule, getRandomSigner } from "../src" +import addresses from "../src/__contracts/addresses" +import { + type NexusSmartAccount, + type Transaction, + createSmartAccountClient +} from "../src/account" +import { CounterAbi } from "./src/__contracts/abi" +import { mockAddresses } from "./src/__contracts/mockAddresses" +import { OWNABLE_VALIDATOR } from "./src/callDatas" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("modules.k1Validator.write", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + test("should install k1 Validator with 1 owner", async () => { + // console.log(smartAccount.activeValidationModule, addresses.K1Validator) + const isInstalledBefore = await smartAccount.isModuleInstalled({ + type: "validator", + moduleAddress: addresses.K1Validator + }) + + if (!isInstalledBefore) { + const { wait } = await smartAccount.installModule({ + moduleAddress: addresses.K1Validator, + type: "validator", + data: encodePacked(["address"], [await smartAccount.getAddress()]) + }) + + console.log("waiting....") + const { success: installSuccess } = await wait() + console.log({ installSuccess }) + + expect(installSuccess).toBe(true) + + const k1ValidationModule = await createK1ValidatorModule( + smartAccount.getSigner() + ) + + const { wait: waitUninstall } = await smartAccount.uninstallModule({ + moduleAddress: addresses.K1Validator, + type: "validator", + data: encodePacked(["address"], [await smartAccount.getAddress()]) + }) + console.log("waiting....") + const { success: successUninstall } = await waitUninstall() + console.log({ successUninstall }) + + smartAccount.setActiveValidationModule(k1ValidationModule) + expect(successUninstall).toBe(true) + } + }, 60000) + + test.skip("should have the Ownable Validator Module installed", async () => { + const isInstalled = await smartAccount.isModuleInstalled({ + type: "validator", + moduleAddress: OWNABLE_VALIDATOR + }) + expect(isInstalled).toBeTruthy() + }, 60000) + + test("should perform a contract interaction", async () => { + const encodedCall = encodeFunctionData({ + abi: CounterAbi, + functionName: "incrementNumber" + }) + + const transaction = { + to: mockAddresses.Counter, + data: encodedCall + } + + const response = await smartAccount.sendTransaction([transaction]) + const receipt = await response.wait() + + expect(receipt.success).toBe(true) + }, 60000) +}) diff --git a/tests/instances/bundler.test.ts b/tests/modules.ownableExecutor.read.test.ts similarity index 58% rename from tests/instances/bundler.test.ts rename to tests/modules.ownableExecutor.read.test.ts index 2f091410..63dbcc09 100644 --- a/tests/instances/bundler.test.ts +++ b/tests/modules.ownableExecutor.read.test.ts @@ -7,26 +7,29 @@ import { createWalletClient } from "viem" import { afterAll, beforeAll, describe, expect, test } from "vitest" -import contracts from "../../src/__contracts" import { type NexusSmartAccount, type Transaction, createSmartAccountClient -} from "../../src/account" -import { getTestAccount, killNetwork, toTestClient, topUp } from "../test.utils" -import type { MasterClient, NetworkConfig } from "../test.utils" -import { type TestFileNetworkType, toNetwork } from "../testSetup" +} from "../src/account" +import { createOwnableExecutorModule } from "../src/modules" +import { OWNABLE_EXECUTOR } from "./src/callDatas" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" const NETWORK_TYPE: TestFileNetworkType = "LOCAL" -describe("bundler", () => { +describe("modules.ownable.executor.read", () => { let network: NetworkConfig - // Nexus Config let chain: Chain let bundlerUrl: string - let factoryAddress: Hex - let k1ValidatorAddress: Hex let walletClient: WalletClient // Test utils @@ -60,24 +63,12 @@ describe("bundler", () => { }) smartAccountAddress = await smartAccount.getAddress() - // await fundAndDeploy(testClient, smartAccount) }) afterAll(async () => { - await killNetwork([network.rpcPort, network.bundlerPort]) + await killNetwork([network?.rpcPort, network?.bundlerPort]) }) - test("byteCodes", async () => { - const byteCodes = await Promise.all([ - testClient.getBytecode({ address: contracts.k1ValidatorFactory.address }), - testClient.getBytecode({ address: contracts.k1Validator.address }) - ]) - expect(byteCodes.every(Boolean)).toBe(true) - }) - - test("topUp", async () => { - const total = await testClient.getBalance({ - address: testClient.account.address - }) + test("should fund the smart account", async () => { await topUp(testClient, smartAccountAddress) const [balance] = await smartAccount.getBalances() expect(balance.amount > 0) @@ -91,20 +82,33 @@ describe("bundler", () => { expect(addresses.every(Boolean)).to.be.true expect(addresses).toStrictEqual([ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "0x473AecE3DE762252a9d47F5032133282c9615e28" // Sender smart account + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account ]) }) - test("send eth", async () => { + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) const tx: Transaction = { - to: account.address, + to: recipientAccount.address, value: 1n } - const { wait } = await smartAccount.sendTransaction(tx) - - const { success, receipt } = await wait() - + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + test.skip("should initialize Ownable Executor Module with correct owners", async () => { + const ownableExecutorModule = await createOwnableExecutorModule( + smartAccount, + OWNABLE_EXECUTOR + ) + const owners = await ownableExecutorModule.getOwners() + expect(owners).toStrictEqual(ownableExecutorModule.owners) }) }) diff --git a/tests/modules.ownableExecutor.write.test.ts b/tests/modules.ownableExecutor.write.test.ts new file mode 100644 index 00000000..0543a92f --- /dev/null +++ b/tests/modules.ownableExecutor.write.test.ts @@ -0,0 +1,371 @@ +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + createWalletClient +} from "viem" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { + type NexusSmartAccount, + type Transaction, + createSmartAccountClient +} from "../src/account" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("modules.ownable.executor.write", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + // test.skip("install Ownable Executor", async () => { + // let isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // const receipt = await smartAccount.installModule({ + // moduleAddress: ownableExecutorModule.moduleAddress, + // type: ownableExecutorModule.type, + // data: ownableExecutorModule.data + // }) + + // smartAccount.setActiveExecutionModule(ownableExecutorModule) + + // expect(receipt.success).toBe(true) + // } + // }, 60000) + + // test.skip("uninstall Ownable Executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR) + + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (isInstalled) { + // await smartAccount2.uninstallModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // }, 60000) + + // test.skip("Ownable Executor Module should be installed", async () => { + // const isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + // console.log(isInstalled, "isInstalled") + // expect(isInstalled).toBeTruthy() + // }, 60000) + + // test.skip("should add an owner to the module", async () => { + // const ownersBefore = await ownableExecutorModule.getOwners() + // const isOwnerBefore = ownersBefore.includes(accountTwo.address) + + // if (isOwnerBefore) { + // console.log("Owner already exists in list, skipping test case ...") + // return + // } + + // const userOpReceipt = await ownableExecutorModule.addOwner( + // accountTwo.address + // ) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeTruthy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("EOA 2 can execute actions on behalf of SA 1", async () => { + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + // expect(isOwner).toBeTruthy() + + // const balanceBefore = await smartAccount.getBalances([token]) + // console.log("balanceBefore", balanceBefore) + + // const calldata = encodeFunctionData({ + // abi: parseAbi([ + // "function executeOnOwnedAccount(address ownedAccount, bytes callData)" + // ]), + // functionName: "executeOnOwnedAccount", + // args: [ + // await smartAccount.getAddress(), + // encodePacked( + // ["address", "uint256", "bytes"], + // [token, BigInt(Number(0)), transferEncodedCall] + // ) + // ] + // }) + + // // EOA 2 (walletClientTwo) executes an action on behalf of SA 1 which is owned by EOA 1 (walletClientOne) + // const txHash = await walletClientTwo.sendTransaction({ + // account: accountTwo, // Called by delegated EOA owner + // to: ownableExecutorModule.moduleAddress, + // data: calldata, + // value: 0n + // }) + + // const balanceAfter = await smartAccount.getBalances([token]) + // console.log("balanceAfter", balanceAfter) + + // expect(txHash).toBeTruthy() + // }, 60000) + + // test("SA 2 can execute actions on behalf of SA 1", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // to: token, + // data: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + // const receipt = await smartAccount2.sendTransactionWithExecutor([transferTransaction], await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("SA 2 can execute actions on behalf of SA 1 using module instance instead of smart account instance", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR, initData) + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule2.getOwners() + + // // check if SA 2 is as an owner of SA 1 + // const isOwner = owners.includes(await smartAccount2.getAddress()) + // if(!isOwner) { + // const userOpReceipt = await ownableExecutorModule2.addOwner( + // await smartAccount2.getAddress() + // ) + // expect(userOpReceipt.success).toBeTruthy() + // } + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule2) + // // SA 2 will execute the transferTransaction on behalf of SA 1 (smartAccount) + // const receipt = await ownableExecutorModule2.execute(transferTransaction, await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("should remove an owner from the module", async () => { + // const userOpReceipt = await ownableExecutorModule.removeOwner( + // accountTwo.address + // ) + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeFalsy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("should use rhinestone to call ownable executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + + // const ownableExecutorModule2 = getOwnableExecuter({ + // owner: await smartAccount2.getAddress(), + // }); + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // module: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // module: ownableExecutorModule2.module, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.initData + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // const execution = getExecuteOnOwnedAccountAction({ownedAccount: await smartAccount.getAddress(), execution: transferTransaction}) + // const receipt = await smartAccount2.sendTransaction([{to: execution.target, data: execution.callData, value: 0n}]); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // }, 60000) +}) diff --git a/tests/modules.ownableValidator.install.write.test.ts b/tests/modules.ownableValidator.install.write.test.ts new file mode 100644 index 00000000..c40a508d --- /dev/null +++ b/tests/modules.ownableValidator.install.write.test.ts @@ -0,0 +1,371 @@ +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + createWalletClient +} from "viem" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { + type NexusSmartAccount, + type Transaction, + createSmartAccountClient +} from "../src/account" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("modules.ownable.validator.install.write", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + // test.skip("install Ownable Executor", async () => { + // let isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // const receipt = await smartAccount.installModule({ + // moduleAddress: ownableExecutorModule.moduleAddress, + // type: ownableExecutorModule.type, + // data: ownableExecutorModule.data + // }) + + // smartAccount.setActiveExecutionModule(ownableExecutorModule) + + // expect(receipt.success).toBe(true) + // } + // }, 60000) + + // test.skip("uninstall Ownable Executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR) + + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (isInstalled) { + // await smartAccount2.uninstallModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // }, 60000) + + // test.skip("Ownable Executor Module should be installed", async () => { + // const isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + // console.log(isInstalled, "isInstalled") + // expect(isInstalled).toBeTruthy() + // }, 60000) + + // test.skip("should add an owner to the module", async () => { + // const ownersBefore = await ownableExecutorModule.getOwners() + // const isOwnerBefore = ownersBefore.includes(accountTwo.address) + + // if (isOwnerBefore) { + // console.log("Owner already exists in list, skipping test case ...") + // return + // } + + // const userOpReceipt = await ownableExecutorModule.addOwner( + // accountTwo.address + // ) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeTruthy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("EOA 2 can execute actions on behalf of SA 1", async () => { + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + // expect(isOwner).toBeTruthy() + + // const balanceBefore = await smartAccount.getBalances([token]) + // console.log("balanceBefore", balanceBefore) + + // const calldata = encodeFunctionData({ + // abi: parseAbi([ + // "function executeOnOwnedAccount(address ownedAccount, bytes callData)" + // ]), + // functionName: "executeOnOwnedAccount", + // args: [ + // await smartAccount.getAddress(), + // encodePacked( + // ["address", "uint256", "bytes"], + // [token, BigInt(Number(0)), transferEncodedCall] + // ) + // ] + // }) + + // // EOA 2 (walletClientTwo) executes an action on behalf of SA 1 which is owned by EOA 1 (walletClientOne) + // const txHash = await walletClientTwo.sendTransaction({ + // account: accountTwo, // Called by delegated EOA owner + // to: ownableExecutorModule.moduleAddress, + // data: calldata, + // value: 0n + // }) + + // const balanceAfter = await smartAccount.getBalances([token]) + // console.log("balanceAfter", balanceAfter) + + // expect(txHash).toBeTruthy() + // }, 60000) + + // test("SA 2 can execute actions on behalf of SA 1", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // to: token, + // data: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + // const receipt = await smartAccount2.sendTransactionWithExecutor([transferTransaction], await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("SA 2 can execute actions on behalf of SA 1 using module instance instead of smart account instance", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR, initData) + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule2.getOwners() + + // // check if SA 2 is as an owner of SA 1 + // const isOwner = owners.includes(await smartAccount2.getAddress()) + // if(!isOwner) { + // const userOpReceipt = await ownableExecutorModule2.addOwner( + // await smartAccount2.getAddress() + // ) + // expect(userOpReceipt.success).toBeTruthy() + // } + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule2) + // // SA 2 will execute the transferTransaction on behalf of SA 1 (smartAccount) + // const receipt = await ownableExecutorModule2.execute(transferTransaction, await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("should remove an owner from the module", async () => { + // const userOpReceipt = await ownableExecutorModule.removeOwner( + // accountTwo.address + // ) + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeFalsy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("should use rhinestone to call ownable executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + + // const ownableExecutorModule2 = getOwnableExecuter({ + // owner: await smartAccount2.getAddress(), + // }); + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // module: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // module: ownableExecutorModule2.module, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.initData + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // const execution = getExecuteOnOwnedAccountAction({ownedAccount: await smartAccount.getAddress(), execution: transferTransaction}) + // const receipt = await smartAccount2.sendTransaction([{to: execution.target, data: execution.callData, value: 0n}]); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // }, 60000) +}) diff --git a/tests/modules.ownableValidator.uninstall.write.test.ts b/tests/modules.ownableValidator.uninstall.write.test.ts new file mode 100644 index 00000000..8b29b3b1 --- /dev/null +++ b/tests/modules.ownableValidator.uninstall.write.test.ts @@ -0,0 +1,371 @@ +import { + http, + type Account, + type Chain, + type Hex, + type WalletClient, + createWalletClient +} from "viem" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { + type NexusSmartAccount, + type Transaction, + createSmartAccountClient +} from "../src/account" +import { type TestFileNetworkType, toNetwork } from "./src/testSetup" +import { + getTestAccount, + killNetwork, + toTestClient, + topUp +} from "./src/testUtils" +import type { MasterClient, NetworkConfig } from "./src/testUtils" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("modules.ownable.validator.uninstall.write", () => { + let network: NetworkConfig + // Nexus Config + let chain: Chain + let bundlerUrl: string + let walletClient: WalletClient + + // Test utils + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let smartAccount: NexusSmartAccount + let smartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(0) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount(0)) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain + }) + + smartAccountAddress = await smartAccount.getAddress() + }) + afterAll(async () => { + await killNetwork([network?.rpcPort, network?.bundlerPort]) + }) + + test("should fund the smart account", async () => { + await topUp(testClient, smartAccountAddress) + const [balance] = await smartAccount.getBalances() + expect(balance.amount > 0) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0xa3962DB24D3cAb711e18d5A508591C6dB82a0f54" // Sender smart account + ]) + }) + + test("should send eth", async () => { + const balanceBefore = await testClient.getBalance({ + address: recipientAccount.address + }) + const tx: Transaction = { + to: recipientAccount.address, + value: 1n + } + const { wait } = await smartAccount.sendTransaction(tx) + const { success } = await wait() + const balanceAfter = await testClient.getBalance({ + address: recipientAccount.address + }) + expect(success).toBe(true) + expect(balanceAfter - balanceBefore).toBe(1n) + }) + + // test.skip("install Ownable Executor", async () => { + // let isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // const receipt = await smartAccount.installModule({ + // moduleAddress: ownableExecutorModule.moduleAddress, + // type: ownableExecutorModule.type, + // data: ownableExecutorModule.data + // }) + + // smartAccount.setActiveExecutionModule(ownableExecutorModule) + + // expect(receipt.success).toBe(true) + // } + // }, 60000) + + // test.skip("uninstall Ownable Executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR) + + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (isInstalled) { + // await smartAccount2.uninstallModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // }, 60000) + + // test.skip("Ownable Executor Module should be installed", async () => { + // const isInstalled = await smartAccount.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + // console.log(isInstalled, "isInstalled") + // expect(isInstalled).toBeTruthy() + // }, 60000) + + // test.skip("should add an owner to the module", async () => { + // const ownersBefore = await ownableExecutorModule.getOwners() + // const isOwnerBefore = ownersBefore.includes(accountTwo.address) + + // if (isOwnerBefore) { + // console.log("Owner already exists in list, skipping test case ...") + // return + // } + + // const userOpReceipt = await ownableExecutorModule.addOwner( + // accountTwo.address + // ) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeTruthy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("EOA 2 can execute actions on behalf of SA 1", async () => { + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + // expect(isOwner).toBeTruthy() + + // const balanceBefore = await smartAccount.getBalances([token]) + // console.log("balanceBefore", balanceBefore) + + // const calldata = encodeFunctionData({ + // abi: parseAbi([ + // "function executeOnOwnedAccount(address ownedAccount, bytes callData)" + // ]), + // functionName: "executeOnOwnedAccount", + // args: [ + // await smartAccount.getAddress(), + // encodePacked( + // ["address", "uint256", "bytes"], + // [token, BigInt(Number(0)), transferEncodedCall] + // ) + // ] + // }) + + // // EOA 2 (walletClientTwo) executes an action on behalf of SA 1 which is owned by EOA 1 (walletClientOne) + // const txHash = await walletClientTwo.sendTransaction({ + // account: accountTwo, // Called by delegated EOA owner + // to: ownableExecutorModule.moduleAddress, + // data: calldata, + // value: 0n + // }) + + // const balanceAfter = await smartAccount.getBalances([token]) + // console.log("balanceAfter", balanceAfter) + + // expect(txHash).toBeTruthy() + // }, 60000) + + // test("SA 2 can execute actions on behalf of SA 1", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // to: token, + // data: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + // const receipt = await smartAccount2.sendTransactionWithExecutor([transferTransaction], await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("SA 2 can execute actions on behalf of SA 1 using module instance instead of smart account instance", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + // const ownableExecutorModule2 = await createOwnableExecutorModule(smartAccount2, OWNABLE_EXECUTOR, initData) + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // moduleAddress: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // moduleAddress: ownableExecutorModule2.moduleAddress, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.data + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const owners = await ownableExecutorModule2.getOwners() + + // // check if SA 2 is as an owner of SA 1 + // const isOwner = owners.includes(await smartAccount2.getAddress()) + // if(!isOwner) { + // const userOpReceipt = await ownableExecutorModule2.addOwner( + // await smartAccount2.getAddress() + // ) + // expect(userOpReceipt.success).toBeTruthy() + // } + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule2) + // // SA 2 will execute the transferTransaction on behalf of SA 1 (smartAccount) + // const receipt = await ownableExecutorModule2.execute(transferTransaction, await smartAccount.getAddress()); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // expect(receipt.success).toBe(true) + // }, 60000) + + // test.skip("should remove an owner from the module", async () => { + // const userOpReceipt = await ownableExecutorModule.removeOwner( + // accountTwo.address + // ) + // const owners = await ownableExecutorModule.getOwners() + // const isOwner = owners.includes(accountTwo.address) + + // expect(isOwner).toBeFalsy() + // expect(userOpReceipt.success).toBeTruthy() + // }, 60000) + + // test.skip("should use rhinestone to call ownable executor", async () => { + // const smartAccount2: NexusSmartAccount = await createSmartAccountClient({ + // signer: walletClientTwo, + // bundlerUrl + // }) + + // const initData = encodePacked( + // ["address"], + // [await smartAccount2.getAddress()] + // ) + + // const ownableExecutorModule2 = getOwnableExecuter({ + // owner: await smartAccount2.getAddress(), + // }); + + // // First, we need to install the OwnableExecutor module on SA 2 + // let isInstalled = await smartAccount2.isModuleInstalled({ + // type: 'executor', + // module: OWNABLE_EXECUTOR + // }) + + // if (!isInstalled) { + // await smartAccount2.installModule({ + // module: ownableExecutorModule2.module, + // type: ownableExecutorModule2.type, + // data: ownableExecutorModule2.initData + // }) + // } + + // smartAccount2.setActiveExecutionModule(ownableExecutorModule) + + // const valueToTransfer = parseEther("0.1") + // const recipient = accountTwo.address + // const transferEncodedCall = encodeFunctionData({ + // abi: parseAbi(["function transfer(address to, uint256 value)"]), + // functionName: "transfer", + // args: [recipient, valueToTransfer] + // }) + + // const transferTransaction = { + // target: token as `0x${string}`, + // callData: transferEncodedCall, + // value: 0n + // } + + // const execution = getExecuteOnOwnedAccountAction({ownedAccount: await smartAccount.getAddress(), execution: transferTransaction}) + // const receipt = await smartAccount2.sendTransaction([{to: execution.target, data: execution.callData, value: 0n}]); + // console.log(receipt, "receipt"); + + // expect(receipt.userOpHash).toBeTruthy() + // }, 60000) +}) diff --git a/tests/instances/playground.test.ts b/tests/playground.test.ts similarity index 97% rename from tests/instances/playground.test.ts rename to tests/playground.test.ts index ffc479dd..86c74c34 100644 --- a/tests/instances/playground.test.ts +++ b/tests/playground.test.ts @@ -16,9 +16,9 @@ import { createSmartAccountClient, getChain, getCustomChain -} from "../../src/account" -import { createK1ValidatorModule } from "../../src/modules" -import { getBundlerUrl } from "../test.utils" +} from "../src/account" +import { createK1ValidatorModule } from "../src/modules" +import { getBundlerUrl } from "./src/testUtils" config() const privateKey = process.env.E2E_PRIVATE_KEY_ONE diff --git a/tests/README.md b/tests/src/README.md similarity index 99% rename from tests/README.md rename to tests/src/README.md index b1e45e10..d120de99 100644 --- a/tests/README.md +++ b/tests/src/README.md @@ -46,7 +46,7 @@ scopedTest("should be used in the following way", async({ config: { bundlerUrl, > **Note:** > Please avoid using multiple nested describe() blocks in a single test file, as it is unnecessary and can lead to confusion regarding network scope. -> Using *many* test files is preferable, as describe blocks run in parallel. +> Using *many* test files is preferable, as describe blocks run in parallel. ## Testing Custom/New Chains - There is one area where SDK tests can be run against a remote testnet: the playground. diff --git a/tests/__contracts/abi/BiconomyMetaFactoryAbi.ts b/tests/src/__contracts/abi/BiconomyMetaFactoryAbi.ts similarity index 100% rename from tests/__contracts/abi/BiconomyMetaFactoryAbi.ts rename to tests/src/__contracts/abi/BiconomyMetaFactoryAbi.ts diff --git a/tests/__contracts/abi/BootstrapAbi.ts b/tests/src/__contracts/abi/BootstrapAbi.ts similarity index 100% rename from tests/__contracts/abi/BootstrapAbi.ts rename to tests/src/__contracts/abi/BootstrapAbi.ts diff --git a/tests/__contracts/abi/BootstrapLibAbi.ts b/tests/src/__contracts/abi/BootstrapLibAbi.ts similarity index 100% rename from tests/__contracts/abi/BootstrapLibAbi.ts rename to tests/src/__contracts/abi/BootstrapLibAbi.ts diff --git a/tests/src/__contracts/abi/CounterAbi.ts b/tests/src/__contracts/abi/CounterAbi.ts new file mode 100644 index 00000000..93c3650e --- /dev/null +++ b/tests/src/__contracts/abi/CounterAbi.ts @@ -0,0 +1,36 @@ +export const CounterAbi = [ + { + inputs: [], + name: "decrementNumber", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "getNumber", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "incrementNumber", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "revertOperation", + outputs: [], + stateMutability: "pure", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/MockExecutorAbi.ts b/tests/src/__contracts/abi/MockExecutorAbi.ts new file mode 100644 index 00000000..ec9f7ba1 --- /dev/null +++ b/tests/src/__contracts/abi/MockExecutorAbi.ts @@ -0,0 +1,309 @@ +export const MockExecutorAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bytes32", + name: "dataFirstWord", + type: "bytes32" + } + ], + name: "ExecutorOnInstallCalled", + type: "event" + }, + { + inputs: [ + { + internalType: "ExecutionMode", + name: "mode", + type: "bytes32" + }, + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + name: "customExecuteViaAccount", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + name: "execDelegatecall", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + internalType: "struct Execution[]", + name: "execs", + type: "tuple[]" + } + ], + name: "executeBatchViaAccount", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + name: "executeViaAccount", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "getModuleTypes", + outputs: [ + { + internalType: "EncodedModuleTypes", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "isInitialized", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "moduleTypeId", + type: "uint256" + } + ], + name: "isModuleType", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onInstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onUninstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + internalType: "struct Execution[]", + name: "execs", + type: "tuple[]" + } + ], + name: "tryExecuteBatchViaAccount", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "contract INexus", + name: "account", + type: "address" + }, + { + internalType: "address", + name: "target", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "callData", + type: "bytes" + } + ], + name: "tryExecuteViaAccount", + outputs: [ + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + stateMutability: "payable", + type: "receive" + } +] as const diff --git a/tests/src/__contracts/abi/MockHandlerAbi.ts b/tests/src/__contracts/abi/MockHandlerAbi.ts new file mode 100644 index 00000000..0daeaab6 --- /dev/null +++ b/tests/src/__contracts/abi/MockHandlerAbi.ts @@ -0,0 +1,227 @@ +export const MockHandlerAbi = [ + { + inputs: [ + { + internalType: "bytes4", + name: "selector", + type: "bytes4" + } + ], + name: "NonExistingMethodCalled", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "sender", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + indexed: false, + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "GenericFallbackCalled", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bytes32", + name: "dataFirstWord", + type: "bytes32" + } + ], + name: "HandlerOnInstallCalled", + type: "event" + }, + { + stateMutability: "nonpayable", + type: "fallback" + }, + { + inputs: [], + name: "NAME", + outputs: [ + { + internalType: "string", + name: "", + type: "string" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "VERSION", + outputs: [ + { + internalType: "string", + name: "", + type: "string" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "count", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "getState", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "isInitialized", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "moduleTypeId", + type: "uint256" + } + ], + name: "isModuleType", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onGenericFallback", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onInstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onUninstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "revertingFunction", + outputs: [], + stateMutability: "pure", + type: "function" + }, + { + inputs: [], + name: "stateChangingFunction", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "successFunction", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32" + } + ], + stateMutability: "pure", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/MockHookAbi.ts b/tests/src/__contracts/abi/MockHookAbi.ts new file mode 100644 index 00000000..11b57fab --- /dev/null +++ b/tests/src/__contracts/abi/MockHookAbi.ts @@ -0,0 +1,133 @@ +export const MockHookAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "bytes32", + name: "dataFirstWord", + type: "bytes32" + } + ], + name: "HookOnInstallCalled", + type: "event" + }, + { + anonymous: false, + inputs: [], + name: "PostCheckCalled", + type: "event" + }, + { + anonymous: false, + inputs: [], + name: "PreCheckCalled", + type: "event" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "isInitialized", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "moduleTypeId", + type: "uint256" + } + ], + name: "isModuleType", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onInstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "", + type: "bytes" + } + ], + name: "onUninstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "hookData", + type: "bytes" + } + ], + name: "postCheck", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + }, + { + internalType: "uint256", + name: "", + type: "uint256" + }, + { + internalType: "bytes", + name: "", + type: "bytes" + } + ], + name: "preCheck", + outputs: [ + { + internalType: "bytes", + name: "", + type: "bytes" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] as const diff --git a/tests/__contracts/abi/MockRegistryAbi.ts b/tests/src/__contracts/abi/MockRegistryAbi.ts similarity index 100% rename from tests/__contracts/abi/MockRegistryAbi.ts rename to tests/src/__contracts/abi/MockRegistryAbi.ts diff --git a/tests/src/__contracts/abi/MockTokenAbi.ts b/tests/src/__contracts/abi/MockTokenAbi.ts new file mode 100644 index 00000000..213ee0cf --- /dev/null +++ b/tests/src/__contracts/abi/MockTokenAbi.ts @@ -0,0 +1,344 @@ +export const MockTokenAbi = [ + { + inputs: [ + { + internalType: "string", + name: "name", + type: "string" + }, + { + internalType: "string", + name: "symbol", + type: "string" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address" + }, + { + internalType: "uint256", + name: "allowance", + type: "uint256" + }, + { + internalType: "uint256", + name: "needed", + type: "uint256" + } + ], + name: "ERC20InsufficientAllowance", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "balance", + type: "uint256" + }, + { + internalType: "uint256", + name: "needed", + type: "uint256" + } + ], + name: "ERC20InsufficientBalance", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "approver", + type: "address" + } + ], + name: "ERC20InvalidApprover", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "receiver", + type: "address" + } + ], + name: "ERC20InvalidReceiver", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + } + ], + name: "ERC20InvalidSender", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address" + } + ], + name: "ERC20InvalidSpender", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "Approval", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address" + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "Transfer", + type: "event" + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address" + }, + { + internalType: "address", + name: "spender", + type: "address" + } + ], + name: "allowance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "decimals", + outputs: [ + { + internalType: "uint8", + name: "", + type: "uint8" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address" + }, + { + internalType: "uint256", + name: "amount", + type: "uint256" + } + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "totalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "transfer", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address" + }, + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "transferFrom", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/MockValidatorAbi.ts b/tests/src/__contracts/abi/MockValidatorAbi.ts new file mode 100644 index 00000000..d3ae3504 --- /dev/null +++ b/tests/src/__contracts/abi/MockValidatorAbi.ts @@ -0,0 +1,228 @@ +export const MockValidatorAbi = [ + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "getOwner", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "isInitialized", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "uint256", + name: "moduleTypeId", + type: "uint256" + } + ], + name: "isModuleType", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "pure", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + }, + { + internalType: "address", + name: "owner", + type: "address" + } + ], + name: "isOwner", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + }, + { + internalType: "bytes32", + name: "hash", + type: "bytes32" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + name: "isValidSignatureWithSender", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onInstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + name: "onUninstall", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "smartAccountOwners", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + 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: "bytes32", + name: "accountGasLimits", + type: "bytes32" + }, + { + internalType: "uint256", + name: "preVerificationGas", + type: "uint256" + }, + { + internalType: "bytes32", + name: "gasFees", + type: "bytes32" + }, + { + internalType: "bytes", + name: "paymasterAndData", + type: "bytes" + }, + { + internalType: "bytes", + name: "signature", + type: "bytes" + } + ], + internalType: "struct PackedUserOperation", + name: "userOp", + type: "tuple" + }, + { + internalType: "bytes32", + name: "userOpHash", + type: "bytes32" + } + ], + name: "validateUserOp", + outputs: [ + { + internalType: "uint256", + name: "validation", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/NexusAccountFactoryAbi.ts b/tests/src/__contracts/abi/NexusAccountFactoryAbi.ts new file mode 100644 index 00000000..0e0c48d3 --- /dev/null +++ b/tests/src/__contracts/abi/NexusAccountFactoryAbi.ts @@ -0,0 +1,323 @@ +export const NexusAccountFactoryAbi = [ + { + inputs: [ + { + internalType: "address", + name: "implementation_", + type: "address" + }, + { + internalType: "address", + name: "owner_", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "AccountAlreadyDeployed", + type: "error" + }, + { + inputs: [], + name: "AlreadyInitialized", + type: "error" + }, + { + inputs: [], + name: "ImplementationAddressCanNotBeZero", + type: "error" + }, + { + inputs: [], + name: "InvalidEntryPointAddress", + type: "error" + }, + { + inputs: [], + name: "NewOwnerIsZeroAddress", + type: "error" + }, + { + inputs: [], + name: "NoHandoverRequest", + type: "error" + }, + { + inputs: [], + name: "Unauthorized", + type: "error" + }, + { + inputs: [], + name: "ZeroAddressNotAllowed", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "account", + type: "address" + }, + { + indexed: true, + internalType: "bytes", + name: "initData", + type: "bytes" + }, + { + indexed: true, + internalType: "bytes32", + name: "salt", + type: "bytes32" + } + ], + name: "AccountCreated", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "OwnershipHandoverCanceled", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "OwnershipHandoverRequested", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldOwner", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + inputs: [], + name: "ACCOUNT_IMPLEMENTATION", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + }, + { + internalType: "uint32", + name: "unstakeDelaySec", + type: "uint32" + } + ], + name: "addStake", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "cancelOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "completeOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "initData", + type: "bytes" + }, + { + internalType: "bytes32", + name: "salt", + type: "bytes32" + } + ], + name: "computeAccountAddress", + outputs: [ + { + internalType: "address payable", + name: "expectedAddress", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes", + name: "initData", + type: "bytes" + }, + { + internalType: "bytes32", + name: "salt", + type: "bytes32" + } + ], + name: "createAccount", + outputs: [ + { + internalType: "address payable", + name: "", + type: "address" + } + ], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "result", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "ownershipHandoverExpiresAt", + outputs: [ + { + internalType: "uint256", + name: "result", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "requestOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "transferOwnership", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + } + ], + name: "unlockStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + }, + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + } + ], + name: "withdrawStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/StakeableAbi.ts b/tests/src/__contracts/abi/StakeableAbi.ts new file mode 100644 index 00000000..9dc5da90 --- /dev/null +++ b/tests/src/__contracts/abi/StakeableAbi.ts @@ -0,0 +1,211 @@ +export const StakeableAbi = [ + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [], + name: "AlreadyInitialized", + type: "error" + }, + { + inputs: [], + name: "InvalidEntryPointAddress", + type: "error" + }, + { + inputs: [], + name: "NewOwnerIsZeroAddress", + type: "error" + }, + { + inputs: [], + name: "NoHandoverRequest", + type: "error" + }, + { + inputs: [], + name: "Unauthorized", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "OwnershipHandoverCanceled", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "OwnershipHandoverRequested", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldOwner", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + }, + { + internalType: "uint32", + name: "unstakeDelaySec", + type: "uint32" + } + ], + name: "addStake", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "cancelOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "completeOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "result", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "pendingOwner", + type: "address" + } + ], + name: "ownershipHandoverExpiresAt", + outputs: [ + { + internalType: "uint256", + name: "result", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [], + name: "requestOwnershipHandover", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "transferOwnership", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + } + ], + name: "unlockStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "epAddress", + type: "address" + }, + { + internalType: "address payable", + name: "withdrawAddress", + type: "address" + } + ], + name: "withdrawStake", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const diff --git a/tests/src/__contracts/abi/index.ts b/tests/src/__contracts/abi/index.ts new file mode 100644 index 00000000..0b57abb4 --- /dev/null +++ b/tests/src/__contracts/abi/index.ts @@ -0,0 +1,12 @@ +export * from "./MockHookAbi" +export * from "./StakeableAbi" +export * from "./NexusAccountFactoryAbi" +export * from "./BiconomyMetaFactoryAbi" +export * from "./CounterAbi" +export * from "./MockValidatorAbi" +export * from "./MockTokenAbi" +export * from "./BootstrapLibAbi" +export * from "./MockRegistryAbi" +export * from "./MockHandlerAbi" +export * from "./BootstrapAbi" +export * from "./MockExecutorAbi" diff --git a/tests/src/__contracts/addresses.ts b/tests/src/__contracts/addresses.ts new file mode 100644 index 00000000..a2f4227d --- /dev/null +++ b/tests/src/__contracts/addresses.ts @@ -0,0 +1,16 @@ +import type { Hex } from "viem" +export const addresses: Record = { + MockHook: "0xAB9733982E5b98bdDc4f00314E8EA4911A9D1BA5", + Stakeable: "0xc60F4C65a698C0FE5eddACfB71661B580D15BDaa", + NexusAccountFactory: "0x609e47C5404758D83102AB4fe58dbeD4AC39Ae78", + BiconomyMetaFactory: "0x98C8792cf50A93900d575842eDAFf3Ccc2C2902b", + Counter: "0x36023f0abe27eC68fD2c6a489A3e21772A08E120", + MockValidator: "0xa5ab9E06eB79805e6b20586e16285f10cA3274fB", + MockToken: "0x56623d18E54cBbCae340EC449E3c5D1DC0bF60cd", + BootstrapLib: "0x0c66e850AB4aB7e748bf48698a257aaB87d9a899", + MockRegistry: "0x25D55884BFA6380B0fCDc9E924c495C44Aa46415", + MockHandler: "0xBE52B87DA68EC967e977191bE125584b98c1Ea04", + Bootstrap: "0xC952c381C006D14395047A8aeE7F67fB59D38A10", + MockExecutor: "0x940C64D0c650615d3Af0053a4CD32AbAbD3F04e7" +} as const +export default addresses diff --git a/tests/src/__contracts/mockAddresses.ts b/tests/src/__contracts/mockAddresses.ts new file mode 100644 index 00000000..48c56377 --- /dev/null +++ b/tests/src/__contracts/mockAddresses.ts @@ -0,0 +1,16 @@ +import type { Hex } from "viem" +export const mockAddresses: Record = { + MockHook: "0xAB9733982E5b98bdDc4f00314E8EA4911A9D1BA5", + Stakeable: "0xc60F4C65a698C0FE5eddACfB71661B580D15BDaa", + NexusAccountFactory: "0x609e47C5404758D83102AB4fe58dbeD4AC39Ae78", + BiconomyMetaFactory: "0x98C8792cf50A93900d575842eDAFf3Ccc2C2902b", + Counter: "0x36023f0abe27eC68fD2c6a489A3e21772A08E120", + MockValidator: "0xa5ab9E06eB79805e6b20586e16285f10cA3274fB", + MockToken: "0x56623d18E54cBbCae340EC449E3c5D1DC0bF60cd", + BootstrapLib: "0x0c66e850AB4aB7e748bf48698a257aaB87d9a899", + MockRegistry: "0x25D55884BFA6380B0fCDc9E924c495C44Aa46415", + MockHandler: "0xBE52B87DA68EC967e977191bE125584b98c1Ea04", + Bootstrap: "0xC952c381C006D14395047A8aeE7F67fB59D38A10", + MockExecutor: "0x940C64D0c650615d3Af0053a4CD32AbAbD3F04e7" +} as const +export default mockAddresses diff --git a/tests/create.config.ts b/tests/src/callDatas.ts similarity index 75% rename from tests/create.config.ts rename to tests/src/callDatas.ts index 52d7c0bd..5af88824 100644 --- a/tests/create.config.ts +++ b/tests/src/callDatas.ts @@ -4,3 +4,11 @@ export const ENTRY_POINT_SIMULATIONS_CREATECALL: Hex = export const ENTRY_POINT_V07_CREATECALL: Hex = "0x90d8084deab30c2a37c45e8d47f49f2f7965183cb6990a98943ef94940681de360a08060405234620000825760016002556101df8181016001600160401b038111838210176200006c57829162003f2b833903906000f080156200006057608052604051613ea39081620000888239608051818181610d22015261324b0152f35b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fdfe60806040526004361015610024575b361561001957600080fd5b61002233612748565b005b60003560e01c806242dc5314611b0057806301ffc9a7146119ae5780630396cb60146116765780630bd28e3b146115fa5780631b2e01b814611566578063205c2878146113d157806322cdde4c1461136b57806335567e1a146112b35780635287ce12146111a557806370a0823114611140578063765e827f14610e82578063850aaf6214610dc35780639b249f6914610c74578063b760faf914610c3a578063bb9fe6bf14610a68578063c23a5cea146107c4578063dbed18e0146101a15763fc7e286d0361000e573461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5773ffffffffffffffffffffffffffffffffffffffff61013a61229f565b16600052600060205260a0604060002065ffffffffffff6001825492015460405192835260ff8116151560208401526dffffffffffffffffffffffffffff8160081c16604084015263ffffffff8160781c16606084015260981c166080820152f35b600080fd5b3461019c576101af36612317565b906101b86129bd565b60009160005b82811061056f57506101d08493612588565b6000805b8481106102fc5750507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972600080a16000809360005b81811061024757610240868660007f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d8180a2613ba7565b6001600255005b6102a261025582848a612796565b73ffffffffffffffffffffffffffffffffffffffff6102766020830161282a565b167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d600080a2806127d6565b906000915b8083106102b957505050600101610209565b909194976102f36102ed6001926102e78c8b6102e0826102da8e8b8d61269d565b9261265a565b5191613597565b90612409565b99612416565b950191906102a7565b6020610309828789612796565b61031f61031682806127d6565b9390920161282a565b9160009273ffffffffffffffffffffffffffffffffffffffff8091165b8285106103505750505050506001016101d4565b909192939561037f83610378610366848c61265a565b516103728b898b61269d565b856129f6565b9290613dd7565b9116840361050a576104a5576103958491613dd7565b9116610440576103b5576103aa600191612416565b96019392919061033c565b60a487604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152602160448201527f41413332207061796d61737465722065787069726564206f72206e6f7420647560648201527f65000000000000000000000000000000000000000000000000000000000000006084820152fd5b608488604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601460448201527f41413334207369676e6174757265206572726f720000000000000000000000006064820152fd5b608488604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601760448201527f414132322065787069726564206f72206e6f74206475650000000000000000006064820152fd5b608489604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601460448201527f41413234207369676e6174757265206572726f720000000000000000000000006064820152fd5b61057a818487612796565b9361058585806127d6565b919095602073ffffffffffffffffffffffffffffffffffffffff6105aa82840161282a565b1697600192838a1461076657896105da575b5050505060019293949550906105d191612409565b939291016101be565b8060406105e892019061284b565b918a3b1561019c57929391906040519485937f2dd8113300000000000000000000000000000000000000000000000000000000855288604486016040600488015252606490818601918a60051b8701019680936000915b8c83106106e657505050505050838392610684927ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8560009803016024860152612709565b03818a5afa90816106d7575b506106c657602486604051907f86a9f7500000000000000000000000000000000000000000000000000000000082526004820152fd5b93945084936105d1600189806105bc565b6106e0906121bd565b88610690565b91939596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c908a9294969a0301865288357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18336030181121561019c57836107538793858394016128ec565b9a0196019301909189979695949261063f565b606483604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601760248201527f4141393620696e76616c69642061676772656761746f720000000000000000006044820152fd5b3461019c576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c576107fc61229f565b33600052600082526001604060002001908154916dffffffffffffffffffffffffffff8360081c16928315610a0a5765ffffffffffff8160981c1680156109ac57421061094e5760009373ffffffffffffffffffffffffffffffffffffffff859485947fffffffffffffff000000000000000000000000000000000000000000000000ff86951690556040517fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda33391806108da8786836020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b0390a2165af16108e8612450565b50156108f057005b606490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601860248201527f6661696c656420746f207769746864726177207374616b6500000000000000006044820152fd5b606485604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601b60248201527f5374616b65207769746864726177616c206973206e6f742064756500000000006044820152fd5b606486604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601d60248201527f6d7573742063616c6c20756e6c6f636b5374616b6528292066697273740000006044820152fd5b606485604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601460248201527f4e6f207374616b6520746f2077697468647261770000000000000000000000006044820152fd5b3461019c5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c573360005260006020526001604060002001805463ffffffff8160781c16908115610bdc5760ff1615610b7e5765ffffffffffff908142160191818311610b4f5780547fffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff001678ffffffffffff00000000000000000000000000000000000000609885901b161790556040519116815233907ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a90602090a2005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f616c726561647920756e7374616b696e670000000000000000000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f6e6f74207374616b6564000000000000000000000000000000000000000000006044820152fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c57610022610c6f61229f565b612748565b3461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5760043567ffffffffffffffff811161019c576020610cc8610d1b9236906004016122c2565b919073ffffffffffffffffffffffffffffffffffffffff9260405194859283927f570e1a360000000000000000000000000000000000000000000000000000000084528560048501526024840191612709565b03816000857f0000000000000000000000000000000000000000000000000000000000000000165af1908115610db757602492600092610d86575b50604051917f6ca7b806000000000000000000000000000000000000000000000000000000008352166004820152fd5b610da991925060203d602011610db0575b610da181836121ed565b8101906126dd565b9083610d56565b503d610d97565b6040513d6000823e3d90fd5b3461019c5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c57610dfa61229f565b60243567ffffffffffffffff811161019c57600091610e1e839236906004016122c2565b90816040519283928337810184815203915af4610e39612450565b90610e7e6040519283927f99410554000000000000000000000000000000000000000000000000000000008452151560048401526040602484015260448301906123c6565b0390fd5b3461019c57610e9036612317565b610e9b9291926129bd565b610ea483612588565b60005b848110610f1c57506000927fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972600080a16000915b858310610eec576102408585613ba7565b909193600190610f12610f0087898761269d565b610f0a888661265a565b519088613597565b0194019190610edb565b610f47610f40610f2e8385979561265a565b51610f3a84898761269d565b846129f6565b9190613dd7565b73ffffffffffffffffffffffffffffffffffffffff929183166110db5761107657610f7190613dd7565b911661101157610f8657600101929092610ea7565b60a490604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152602160448201527f41413332207061796d61737465722065787069726564206f72206e6f7420647560648201527f65000000000000000000000000000000000000000000000000000000000000006084820152fd5b608482604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601460448201527f41413334207369676e6174757265206572726f720000000000000000000000006064820152fd5b608483604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601760448201527f414132322065787069726564206f72206e6f74206475650000000000000000006064820152fd5b608484604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601460448201527f41413234207369676e6174757265206572726f720000000000000000000000006064820152fd5b3461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5773ffffffffffffffffffffffffffffffffffffffff61118c61229f565b1660005260006020526020604060002054604051908152f35b3461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5773ffffffffffffffffffffffffffffffffffffffff6111f161229f565b6000608060405161120181612155565b828152826020820152826040820152826060820152015216600052600060205260a06040600020608060405161123681612155565b6001835493848352015490602081019060ff8316151582526dffffffffffffffffffffffffffff60408201818560081c16815263ffffffff936060840193858760781c16855265ffffffffffff978891019660981c1686526040519788525115156020880152511660408601525116606084015251166080820152f35b3461019c5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5760206112ec61229f565b73ffffffffffffffffffffffffffffffffffffffff6113096122f0565b911660005260018252604060002077ffffffffffffffffffffffffffffffffffffffffffffffff821660005282526040600020547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006040519260401b16178152f35b3461019c577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60208136011261019c576004359067ffffffffffffffff821161019c5761012090823603011261019c576113c9602091600401612480565b604051908152f35b3461019c5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5761140861229f565b60243590336000526000602052604060002090815491828411611508576000808573ffffffffffffffffffffffffffffffffffffffff8295839561144c848a612443565b90556040805173ffffffffffffffffffffffffffffffffffffffff831681526020810185905233917fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb91a2165af16114a2612450565b50156114aa57005b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6661696c656420746f20776974686472617700000000000000000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f576974686472617720616d6f756e7420746f6f206c61726765000000000000006044820152fd5b3461019c5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5761159d61229f565b73ffffffffffffffffffffffffffffffffffffffff6115ba6122f0565b9116600052600160205277ffffffffffffffffffffffffffffffffffffffffffffffff604060002091166000526020526020604060002054604051908152f35b3461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5760043577ffffffffffffffffffffffffffffffffffffffffffffffff811680910361019c5733600052600160205260406000209060005260205260406000206116728154612416565b9055005b6020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5760043563ffffffff9182821680920361019c5733600052600081526040600020928215611950576001840154908160781c1683106118f2576116f86dffffffffffffffffffffffffffff9182349160081c16612409565b93841561189457818511611836579065ffffffffffff61180592546040519061172082612155565b8152848101926001845260408201908816815260608201878152600160808401936000855233600052600089526040600020905181550194511515917fffffffffffffffffffffffffff0000000000000000000000000000000000000060ff72ffffffff0000000000000000000000000000006effffffffffffffffffffffffffff008954945160081b16945160781b1694169116171717835551167fffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffff78ffffffffffff0000000000000000000000000000000000000083549260981b169116179055565b6040519283528201527fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c0160403392a2005b606483604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152600e60248201527f7374616b65206f766572666c6f770000000000000000000000000000000000006044820152fd5b606483604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601260248201527f6e6f207374616b652073706563696669656400000000000000000000000000006044820152fd5b606482604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601c60248201527f63616e6e6f7420646563726561736520756e7374616b652074696d65000000006044820152fd5b606482604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601a60248201527f6d757374207370656369667920756e7374616b652064656c61790000000000006044820152fd5b3461019c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361019c57807f60fc6b6e0000000000000000000000000000000000000000000000000000000060209214908115611ad6575b8115611aac575b8115611a82575b8115611a58575b506040519015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501482611a4d565b7f3e84f0210000000000000000000000000000000000000000000000000000000081149150611a46565b7fcf28ef970000000000000000000000000000000000000000000000000000000081149150611a3f565b7f915074d80000000000000000000000000000000000000000000000000000000081149150611a38565b3461019c576102007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019c5767ffffffffffffffff60043581811161019c573660238201121561019c57611b62903690602481600401359101612268565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36016101c0811261019c5761014060405191611b9e83612155565b1261019c5760405192611bb0846121a0565b60243573ffffffffffffffffffffffffffffffffffffffff8116810361019c578452602093604435858201526064356040820152608435606082015260a435608082015260c43560a082015260e43560c08201526101043573ffffffffffffffffffffffffffffffffffffffff8116810361019c5760e08201526101243561010082015261014435610120820152825261016435848301526101843560408301526101a43560608301526101c43560808301526101e43590811161019c57611c7c9036906004016122c2565b905a3033036120f7578351606081015195603f5a0260061c61271060a0840151890101116120ce5760009681519182611ff0575b5050505090611cca915a9003608085015101923691612268565b925a90600094845193611cdc85613ccc565b9173ffffffffffffffffffffffffffffffffffffffff60e0870151168015600014611ea957505073ffffffffffffffffffffffffffffffffffffffff855116935b5a9003019360a06060820151910151016080860151850390818111611e95575b50508302604085015192818410600014611dce5750506003811015611da157600203611d79576113c99293508093611d7481613d65565b613cf6565b5050507fdeadaa51000000000000000000000000000000000000000000000000000000008152fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b81611dde92979396940390613c98565b506003841015611e6857507f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f60808683015192519473ffffffffffffffffffffffffffffffffffffffff865116948873ffffffffffffffffffffffffffffffffffffffff60e0890151169701519160405192835215898301528760408301526060820152a46113c9565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526021600452fd5b6064919003600a0204909301928780611d3d565b8095918051611eba575b5050611d1d565b6003861015611fc1576002860315611eb35760a088015190823b1561019c57600091611f2491836040519586809581947f7c627b210000000000000000000000000000000000000000000000000000000083528d60048401526080602484015260848301906123c6565b8b8b0260448301528b60648301520393f19081611fad575b50611fa65787893d610800808211611f9e575b506040519282828501016040528184528284013e610e7e6040519283927fad7954bc000000000000000000000000000000000000000000000000000000008452600484015260248301906123c6565b905083611f4f565b8980611eb3565b611fb89199506121bd565b6000978a611f3c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91600092918380938c73ffffffffffffffffffffffffffffffffffffffff885116910192f115612023575b808080611cb0565b611cca929195503d6108008082116120c6575b5060405190888183010160405280825260008983013e805161205f575b5050600194909161201b565b7f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20188870151918973ffffffffffffffffffffffffffffffffffffffff8551169401516120bc604051928392835260408d84015260408301906123c6565b0390a38680612053565b905088612036565b877fdeaddead000000000000000000000000000000000000000000000000000000006000526000fd5b606486604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601760248201527f4141393220696e7465726e616c2063616c6c206f6e6c790000000000000000006044820152fd5b60a0810190811067ffffffffffffffff82111761217157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610140810190811067ffffffffffffffff82111761217157604052565b67ffffffffffffffff811161217157604052565b6060810190811067ffffffffffffffff82111761217157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761217157604052565b67ffffffffffffffff811161217157601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926122748261222e565b9161228260405193846121ed565b82948184528183011161019c578281602093846000960137010152565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361019c57565b9181601f8401121561019c5782359167ffffffffffffffff831161019c576020838186019501011161019c57565b6024359077ffffffffffffffffffffffffffffffffffffffffffffffff8216820361019c57565b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261019c5760043567ffffffffffffffff9283821161019c578060238301121561019c57816004013593841161019c5760248460051b8301011161019c57602401919060243573ffffffffffffffffffffffffffffffffffffffff8116810361019c5790565b60005b8381106123b65750506000910152565b81810151838201526020016123a6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612402815180928187528780880191016123a3565b0116010190565b91908201809211610b4f57565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b4f5760010190565b91908203918211610b4f57565b3d1561247b573d906124618261222e565b9161246f60405193846121ed565b82523d6000602084013e565b606090565b604061248e8183018361284b565b90818351918237206124a3606084018461284b565b90818451918237209260c06124bb60e083018361284b565b908186519182372091845195602087019473ffffffffffffffffffffffffffffffffffffffff833516865260208301358789015260608801526080870152608081013560a087015260a081013582870152013560e08501526101009081850152835261012083019167ffffffffffffffff918484108385111761217157838252845190206101408501908152306101608601524661018086015260608452936101a00191821183831017612171575251902090565b67ffffffffffffffff81116121715760051b60200190565b9061259282612570565b6040906125a260405191826121ed565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06125d08295612570565b019160005b8381106125e25750505050565b60209082516125f081612155565b83516125fb816121a0565b600081526000849181838201528187820152816060818184015260809282848201528260a08201528260c08201528260e082015282610100820152826101208201528652818587015281898701528501528301528286010152016125d5565b805182101561266e5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919081101561266e5760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18136030182121561019c570190565b9081602091031261019c575173ffffffffffffffffffffffffffffffffffffffff8116810361019c5790565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b7f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4602073ffffffffffffffffffffffffffffffffffffffff61278a3485613c98565b936040519485521692a2565b919081101561266e5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18136030182121561019c570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561019c570180359067ffffffffffffffff821161019c57602001918160051b3603831361019c57565b3573ffffffffffffffffffffffffffffffffffffffff8116810361019c5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561019c570180359067ffffffffffffffff821161019c5760200191813603831361019c57565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561019c57016020813591019167ffffffffffffffff821161019c57813603831361019c57565b61012091813573ffffffffffffffffffffffffffffffffffffffff811680910361019c576129626129476129ba9561299b93855260208601356020860152612937604087018761289c565b9091806040880152860191612709565b612954606086018661289c565b908583036060870152612709565b6080840135608084015260a084013560a084015260c084013560c084015261298d60e085018561289c565b9084830360e0860152612709565b916129ac610100918281019061289c565b929091818503910152612709565b90565b60028054146129cc5760028055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b926000905a93805194843573ffffffffffffffffffffffffffffffffffffffff811680910361019c5786526020850135602087015260808501356fffffffffffffffffffffffffffffffff90818116606089015260801c604088015260a086013560c088015260c086013590811661010088015260801c610120870152612a8060e086018661284b565b801561357b576034811061351d578060141161019c578060241161019c5760341161019c57602481013560801c60a0880152601481013560801c60808801523560601c60e08701525b612ad285612480565b60208301526040860151946effffffffffffffffffffffffffffff8660c08901511760608901511760808901511760a0890151176101008901511761012089015117116134bf57604087015160608801510160808801510160a08801510160c0880151016101008801510296835173ffffffffffffffffffffffffffffffffffffffff81511690612b66604085018561284b565b806131e4575b505060e0015173ffffffffffffffffffffffffffffffffffffffff1690600082156131ac575b6020612bd7918b828a01516000868a604051978896879586937f19822f7c00000000000000000000000000000000000000000000000000000000855260048501613db5565b0393f160009181613178575b50612c8b573d8c610800808311612c83575b50604051916020818401016040528083526000602084013e610e7e6040519283927f65c8fd4d000000000000000000000000000000000000000000000000000000008452600484015260606024840152600d60648401527f4141323320726576657274656400000000000000000000000000000000000000608484015260a0604484015260a48301906123c6565b915082612bf5565b9a92939495969798999a91156130f2575b509773ffffffffffffffffffffffffffffffffffffffff835116602084015190600052600160205260406000208160401c60005260205267ffffffffffffffff604060002091825492612cee84612416565b9055160361308d575a8503116130285773ffffffffffffffffffffffffffffffffffffffff60e0606093015116612d42575b509060a09184959697986040608096015260608601520135905a900301910152565b969550505a9683519773ffffffffffffffffffffffffffffffffffffffff60e08a01511680600052600060205260406000208054848110612fc3576080612dcd9a9b9c600093878094039055015192602089015183604051809d819582947f52b7512c0000000000000000000000000000000000000000000000000000000084528c60048501613db5565b039286f1978860009160009a612f36575b50612e86573d8b610800808311612e7e575b50604051916020818401016040528083526000602084013e610e7e6040519283927f65c8fd4d000000000000000000000000000000000000000000000000000000008452600484015260606024840152600d60648401527f4141333320726576657274656400000000000000000000000000000000000000608484015260a0604484015260a48301906123c6565b915082612df0565b9991929394959697989998925a900311612eab57509096959094939291906080612d20565b60a490604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152602760448201527f41413336206f766572207061796d6173746572566572696669636174696f6e4760648201527f61734c696d6974000000000000000000000000000000000000000000000000006084820152fd5b915098503d90816000823e612f4b82826121ed565b604081838101031261019c5780519067ffffffffffffffff821161019c57828101601f83830101121561019c578181015191612f868361222e565b93612f9460405195866121ed565b838552820160208483850101011161019c57602092612fba9184808701918501016123a3565b01519838612dde565b60848b604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601e60448201527f41413331207061796d6173746572206465706f73697420746f6f206c6f7700006064820152fd5b608490604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601e60448201527f41413236206f76657220766572696669636174696f6e4761734c696d697400006064820152fd5b608482604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601a60448201527f4141323520696e76616c6964206163636f756e74206e6f6e63650000000000006064820152fd5b600052600060205260406000208054808c11613113578b9003905538612c9c565b608484604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601760448201527f41413231206469646e2774207061792070726566756e640000000000000000006064820152fd5b9091506020813d6020116131a4575b81613194602093836121ed565b8101031261019c57519038612be3565b3d9150613187565b508060005260006020526040600020548a81116000146131d75750612bd7602060005b915050612b92565b6020612bd7918c036131cf565b833b61345a57604088510151602060405180927f570e1a360000000000000000000000000000000000000000000000000000000082528260048301528160008161323260248201898b612709565b039273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f1908115610db75760009161343b575b5073ffffffffffffffffffffffffffffffffffffffff811680156133d6578503613371573b1561330c5760141161019c5773ffffffffffffffffffffffffffffffffffffffff9183887fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d604060e0958787602086015195510151168251913560601c82526020820152a391612b6c565b60848d604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152602060448201527f4141313520696e6974436f6465206d757374206372656174652073656e6465726064820152fd5b60848e604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152602060448201527f4141313420696e6974436f6465206d7573742072657475726e2073656e6465726064820152fd5b60848f604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601b60448201527f4141313320696e6974436f6465206661696c6564206f72204f4f4700000000006064820152fd5b613454915060203d602011610db057610da181836121ed565b3861327c565b60848d604051907f220266b6000000000000000000000000000000000000000000000000000000008252600482015260406024820152601f60448201527f414131302073656e64657220616c726561647920636f6e7374727563746564006064820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f41413934206761732076616c756573206f766572666c6f7700000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4141393320696e76616c6964207061796d6173746572416e64446174610000006044820152fd5b5050600060e087015260006080870152600060a0870152612ac9565b9092915a906060810151916040928351967fffffffff00000000000000000000000000000000000000000000000000000000886135d7606084018461284b565b600060038211613b9f575b7f8dd7712f0000000000000000000000000000000000000000000000000000000094168403613a445750505061379d6000926136b292602088015161363a8a5193849360208501528b602485015260648401906128ec565b90604483015203906136727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0928381018352826121ed565b61379189519485927e42dc5300000000000000000000000000000000000000000000000000000000602085015261020060248501526102248401906123c6565b613760604484018b60806101a091805173ffffffffffffffffffffffffffffffffffffffff808251168652602082015160208701526040820151604087015260608201516060870152838201518487015260a082015160a087015260c082015160c087015260e08201511660e0860152610100808201519086015261012080910151908501526020810151610140850152604081015161016085015260608101516101808501520151910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83820301610204840152876123c6565b039081018352826121ed565b6020918183809351910182305af1600051988652156137bf575b505050505050565b909192939495965060003d8214613a3a575b7fdeaddead00000000000000000000000000000000000000000000000000000000810361385b57608487878051917f220266b600000000000000000000000000000000000000000000000000000000835260048301526024820152600f60448201527f41413935206f7574206f662067617300000000000000000000000000000000006064820152fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000091929395949650146000146138c55750506138a961389e6138b8935a90612443565b608085015190612409565b9083015183611d748295613d65565b905b3880808080806137b7565b909261395290828601518651907ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f479273ffffffffffffffffffffffffffffffffffffffff9580878551169401516139483d610800808211613a32575b508a519084818301018c5280825260008583013e8a805194859485528401528a8301906123c6565b0390a35a90612443565b916139636080860193845190612409565b926000905a94829488519761397789613ccc565b948260e08b0151168015600014613a1857505050875116955b5a9003019560a06060820151910151019051860390818111613a04575b5050840290850151928184106000146139de57505080611e68575090816139d89293611d7481613d65565b906138ba565b6139ee9082849397950390613c98565b50611e68575090826139ff92613cf6565b6139d8565b6064919003600a02049094019338806139ad565b90919892509751613a2a575b50613990565b955038613a24565b905038613920565b8181803e516137d1565b613b97945082935090613a8c917e42dc53000000000000000000000000000000000000000000000000000000006020613b6b9501526102006024860152610224850191612709565b613b3a604484018860806101a091805173ffffffffffffffffffffffffffffffffffffffff808251168652602082015160208701526040820151604087015260608201516060870152838201518487015260a082015160a087015260c082015160c087015260e08201511660e0860152610100808201519086015261012080910151908501526020810151610140850152604081015161016085015260608101516101808501520151910152565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83820301610204840152846123c6565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018952886121ed565b60008761379d565b5081356135e2565b73ffffffffffffffffffffffffffffffffffffffff168015613c3a57600080809381935af1613bd4612450565b5015613bdc57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f41413931206661696c65642073656e6420746f2062656e6566696369617279006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4141393020696e76616c69642062656e656669636961727900000000000000006044820152fd5b73ffffffffffffffffffffffffffffffffffffffff166000526000602052613cc66040600020918254612409565b80915590565b610120610100820151910151808214613cf257480180821015613ced575090565b905090565b5090565b9190917f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f6080602083015192519473ffffffffffffffffffffffffffffffffffffffff946020868851169660e089015116970151916040519283526000602084015260408301526060820152a4565b60208101519051907f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e60208073ffffffffffffffffffffffffffffffffffffffff855116940151604051908152a3565b613dcd604092959493956060835260608301906128ec565b9460208201520152565b8015613e6457600060408051613dec816121d1565b828152826020820152015273ffffffffffffffffffffffffffffffffffffffff811690604065ffffffffffff91828160a01c16908115613e5c575b60d01c92825191613e37836121d1565b8583528460208401521691829101524211908115613e5457509091565b905042109091565b839150613e27565b5060009060009056fea2646970667358221220b094fd69f04977ae9458e5ba422d01cd2d20dbcfca0992ff37f19aa07deec25464736f6c6343000817003360808060405234610016576101c3908161001c8239f35b600080fdfe6080600436101561000f57600080fd5b6000803560e01c63570e1a361461002557600080fd5b3461018a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261018a576004359167ffffffffffffffff9081841161018657366023850112156101865783600401358281116101825736602482870101116101825780601411610182577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec810192808411610155577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81600b8501160116830190838210908211176101555792846024819482600c60209a968b9960405286845289840196603889018837830101525193013560601c5af1908051911561014d575b5073ffffffffffffffffffffffffffffffffffffffff60405191168152f35b90503861012e565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8380fd5b8280fd5b80fdfea26469706673582212207adef8895ad3393b02fab10a111d85ea80ff35366aa43995f4ea20e67f29200664736f6c63430008170033" + +export const OWNABLE_VALIDATOR = "0xfb11d7ca9161F1DF508787BA45951225B6C0a681" +export const OWNABLE_VALIDATOR_BYTECODE = + "0x608060405234801561000f575f80fd5b50600436106100f0575f3560e01c80639700320311610093578063ecd0596111610063578063ecd059611461024d578063f551e2ee14610261578063fbe5ce0a1461028d578063fd8b84b1146102a0575f80fd5b806397003203146101c4578063c86ec2bf146101e5578063ccfdec8c14610204578063d60b347f14610223575f80fd5b80637065cb48116100ce5780637065cb48146101685780638a91b0e31461017b578063940d38401461018e578063960bfe04146101b1575f80fd5b806306fdde03146100f457806354fd4d50146101325780636d61fe7014610153575b5f80fd5b60408051808201909152601081526f27bbb730b13632ab30b634b230ba37b960811b60208201525b604051610129919061152e565b60405180910390f35b6040805180820190915260058152640312e302e360dc1b602082015261011c565b61016661016136600461158c565b6102c0565b005b6101666101763660046115e1565b61044c565b61016661018936600461158c565b610567565b6101a161019c3660046115fa565b6105c4565b6040519015158152602001610129565b6101666101bf36600461166e565b610705565b6101d76101d2366004611685565b6107e0565b604051908152602001610129565b6101d76101f33660046115e1565b60016020525f908152604090205481565b6101d76102123660046115e1565b60026020525f908152604090205481565b6101a16102313660046115e1565b6001600160a01b03165f90815260016020526040902054151590565b6101a161025b36600461166e565b60011490565b61027461026f3660046116cc565b610823565b6040516001600160e01b03199091168152602001610129565b61016661029b366004611722565b61085e565b6102b36102ae3660046115e1565b610910565b6040516101299190611753565b5f806102ce838501856117b3565b915091506102db81610927565b6102f85760405163e719027360e01b815260040160405180910390fd5b815f03610318576040516306968de960e31b815260040160405180910390fd5b80518281101561033b5760405163aabd5a0960e01b815260040160405180910390fd5b335f81815260016020908152604090912085905582111561036f57604051632414149d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526002602052604081208390556103939082610931565b5f5b82811015610410575f8482815181106103b0576103b061187f565b602002602001015190505f6001600160a01b0316816001600160a01b0316036103fc5760405163b20f76e360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6104075f84836109aa565b50600101610395565b506040516001600160a01b038216907f27b541a16df0902e262f34789782092ab25125513b8ed73608e802951771b928905f90a2505050505050565b335f818152600160205260409020546104835760405163f91bd6f160e01b81526001600160a01b03821660048201526024016103f3565b6001600160a01b0382166104b55760405163b20f76e360e01b81526001600160a01b03831660048201526024016103f3565b6001600160a01b0381165f90815260026020908152604090912054106104ee57604051632414149d60e01b815260040160405180910390fd5b6001600160a01b0381165f908152600260205260408120805491610511836118a7565b9091555061052290505f82846109aa565b6040516001600160a01b0383811682528216907fc82bdbbf677a2462f2a7e22e4ba9abd209496b69cd7b868b3b1d28f76e09a40a906020015b60405180910390a25050565b336105725f82610a9d565b6001600160a01b0381165f8181526001602090815260408083208390556002909152808220829055517f9d00629762554452d03c3b45626436df6ca1c3795d05d04df882f6db481b1be09190a2505050565b5f80806105d3848601866117b3565b915091506105e081610927565b6105ee575f925050506106fc565b815f036105ff575f925050506106fc565b5f61066e6106318a6020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250889250610b0f915050565b905061067981610def565b61068281610dfb565b80515f90815b818110156106dd575f6106bd8583815181106106a6576106a661187f565b602002602001015187610e0490919063ffffffff16565b50905080156106d457836106d0816118a7565b9450505b50600101610688565b508482106106f3576001955050505050506106fc565b5f955050505050505b95945050505050565b335f8181526001602052604090205461073c5760405163f91bd6f160e01b81526001600160a01b03821660048201526024016103f3565b815f0361075c5760405163aabd5a0960e01b815260040160405180910390fd5b6001600160a01b0381165f908152600260205260409020548211156107945760405163aabd5a0960e01b815260040160405180910390fd5b6001600160a01b0381165f8181526001602052604090819020849055517ff7e18aa0532694077d6fc7df02e85d86b91ba964f958d1949d45c5776d36eb6e9061055b9085815260200190565b5f806108066107f260208601866115e1565b846108016101008801886118bf565b610e25565b90508015610817575f91505061081d565b60019150505b92915050565b5f8061083133868686610e25565b905080156108495750630b135d3f60e11b9050610856565b506001600160e01b031990505b949350505050565b335f818152600160209081526040808320546002909252909120540361089757604051630f368a7560e11b815260040160405180910390fd5b6108a35f828585610f4a565b6001600160a01b0381165f9081526002602052604081208054916108c683611902565b90915550506040516001600160a01b0383811682528216907fe594d081b4382713733fe631966432c9cea5199afb2db5c3c1931f9f930036799060200160405180910390a2505050565b60606109205f836001602061103f565b5092915050565b5f61081d826111ff565b60015f908152602083815260408083206001600160a01b0380861685529252909120541615610973576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b03811615806109c957506001600160a01b0381166001145b156109f257604051637c84ecfb60e01b81526001600160a01b03821660048201526024016103f3565b6001600160a01b038181165f9081526020858152604080832086851684529091529020541615610a4057604051631034f46960e21b81526001600160a01b03821660048201526024016103f3565b60015f908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b60015f908152602083815260408083206001600160a01b038581168552925290912054165b6001600160a01b03811615610b0a576001600160a01b039081165f908152602084815260408083208585168452909152902080546001600160a01b0319811690915516610ac2565b505050565b60605f610b1d836041611917565b84519091508367ffffffffffffffff811115610b3b57610b3b61179f565b604051908082528060200260200182016040528015610b64578160200160208202803683370190505b50925081811015610b8857604051638baa579f60e01b815260040160405180910390fd5b5f5b84811015610de5575f805f80610bb78a8660410201602081015160408201516060909201515f1a92909190565b9250925092508260ff165f03610d455790925082906041811015610bfe576040516338a245ff60e11b8152600481018290525f6024820181905260448201526064016103f3565b85610c0a82602061192e565b1115610c39576040516338a245ff60e11b8152600481018290525f6024820152604481018790526064016103f3565b6020818b018101519087908290610c5190859061192e565b610c5b919061192e565b1115610c8b576040516338a245ff60e11b81526004810183905260248101829052604481018890526064016103f3565b60606020838d01019050631626ba7e60e01b6001600160e01b031916866001600160a01b0316631626ba7e8f846040518363ffffffff1660e01b8152600401610cd5929190611941565b602060405180830381865afa158015610cf0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d149190611959565b6001600160e01b03191614610d3e578060405163605d348960e01b81526004016103f3919061152e565b5050610daa565b601e8360ff161115610d9b57610d94610d828c6020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b610d8d600486611980565b8484611237565b9350610daa565b610da78b848484611237565b93505b83888681518110610dbd57610dbd61187f565b6001600160a01b0390921660209283029190910190910152505060019092019150610b8a9050565b5050509392505050565b610df881611271565b50565b610df881611414565b5f80610e1a84846001600160a01b03165f61145d565b909590945092505050565b6001600160a01b0384165f90815260016020526040812054808203610e4d575f915050610856565b5f610ebc610e7f876020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042090565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250879250610b0f915050565b9050610ec781610def565b610ed081610dfb565b80515f90815b81811015610f2757610f0c8a858381518110610ef457610ef461187f565b60200260200101515f6114be9092919063ffffffff16565b15610f1f5782610f1b816118a7565b9350505b600101610ed6565b50838210610f3c576001945050505050610856565b505f98975050505050505050565b6001600160a01b0381161580610f6957506001600160a01b0381166001145b15610f9257604051637c84ecfb60e01b81526001600160a01b03831660048201526024016103f3565b6001600160a01b038281165f908152602086815260408083208785168452909152902054811690821614610fe457604051637c84ecfb60e01b81526001600160a01b03821660048201526024016103f3565b6001600160a01b039081165f908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b60605f6001600160a01b03841660011480159061106457506110628686866114be565b155b1561108d57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016103f3565b825f036110ad5760405163f725081760e01b815260040160405180910390fd5b8267ffffffffffffffff8111156110c6576110c661179f565b6040519080825280602002602001820160405280156110ef578160200160208202803683370190505b506001600160a01b038086165f908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b0382161580159061113e57506001600160a01b038216600114155b801561114957508381105b156111ad57818382815181106111615761116161187f565b6001600160a01b039283166020918202929092018101919091529281165f90815288845260408082208984168352909452929092205490911690806111a5816118a7565b91505061111c565b6001600160a01b0382166001148015906111c657505f81115b156111f257826111d7600183611999565b815181106111e7576111e761187f565b602002602001015191505b8083525094509492505050565b805160019060021161123257815160051b82016020830192505b8251602090930180519093109150808318820261121957505b919050565b5f604051855f5260ff851660205283604052826060526020604060805f60015afa505f6060523d6060185191508060405250949350505050565b601f19602082515f8452604051600282106112fe578285018260051b8601815b85810151815111828214176112a7578501611291565b8181036112b6575050506112fe565b50805b868101518151116112cb5786016112b9565b8281036112f2575b825182518452825291850191908601908183106112d3575050506112fe565b50908252838201526040015b6040515b80821461140b57604082039150815184830151610180828203116113765785820180518351106113355780518351825283525b5b860181811161136e578051888201805182811161135557505050611336565b5b818a0152890180518281116113565750880152611336565b505050611302565b81601f1681830160061c60051b018251825180821061139157905b825181811061139c57905b8083106113a557915b835283528352518190835b5b8801805182116113b157825b8a01805183106113bd579250828110156113de5780518351825283526113b0565b50508681018552818782011060061b85019450828552808786015282811160061b85019450505050611302565b50509092525050565b6002815110610df8576020810160408201600183510160051b83015b815183511461144457602083019250815183525b60208201915080820361143057505081900360051c9052565b5f805f19600186515f87870197505b81830160011c94508460051b89015187019050878114828411176114a65780881161149b57838501915061146c565b60018501925061146c565b84151597148716989290930190950295509350505050565b5f60016001600160a01b038316148015906108565750506001600160a01b039081165f9081526020938452604080822093831682529290935291205416151590565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6115406020830184611500565b9392505050565b5f8083601f840112611557575f80fd5b50813567ffffffffffffffff81111561156e575f80fd5b602083019150836020828501011115611585575f80fd5b9250929050565b5f806020838503121561159d575f80fd5b823567ffffffffffffffff8111156115b3575f80fd5b6115bf85828601611547565b90969095509350505050565b80356001600160a01b0381168114611232575f80fd5b5f602082840312156115f1575f80fd5b611540826115cb565b5f805f805f6060868803121561160e575f80fd5b85359450602086013567ffffffffffffffff8082111561162c575f80fd5b61163889838a01611547565b90965094506040880135915080821115611650575f80fd5b5061165d88828901611547565b969995985093965092949392505050565b5f6020828403121561167e575f80fd5b5035919050565b5f8060408385031215611696575f80fd5b823567ffffffffffffffff8111156116ac575f80fd5b830161012081860312156116be575f80fd5b946020939093013593505050565b5f805f80606085870312156116df575f80fd5b6116e8856115cb565b935060208501359250604085013567ffffffffffffffff81111561170a575f80fd5b61171687828801611547565b95989497509550505050565b5f8060408385031215611733575f80fd5b61173c836115cb565b915061174a602084016115cb565b90509250929050565b602080825282518282018190525f9190848201906040850190845b818110156117935783516001600160a01b03168352928401929184019160010161176e565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156117c4575f80fd5b8235915060208084013567ffffffffffffffff808211156117e3575f80fd5b818601915086601f8301126117f6575f80fd5b8135818111156118085761180861179f565b8060051b604051601f19603f8301168101818110858211171561182d5761182d61179f565b60405291825284820192508381018501918983111561184a575f80fd5b938501935b8285101561186f57611860856115cb565b8452938501939285019261184f565b8096505050505050509250929050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016118b8576118b8611893565b5060010190565b5f808335601e198436030181126118d4575f80fd5b83018035915067ffffffffffffffff8211156118ee575f80fd5b602001915036819003821315611585575f80fd5b5f8161191057611910611893565b505f190190565b808202811582820484141761081d5761081d611893565b8082018082111561081d5761081d611893565b828152604060208201525f6108566040830184611500565b5f60208284031215611969575f80fd5b81516001600160e01b031981168114611540575f80fd5b60ff828116828216039081111561081d5761081d611893565b8181038181111561081d5761081d61189356fea2646970667358221220b82bc4d2f8213c159cea19836aa442c34ed4c7abc97ebbd8d454c3f36422e16564736f6c63430008190033" + +export const OWNABLE_EXECUTOR = "0x989110e958902f619148b8171fbDF1Dca0c5AE0B" +export const OWNABLE_EXECUTOR_BYTECODE = + "0x6080604052600436106100a5575f3560e01c8063d26cdce311610062578063d26cdce3146101b7578063d60b347f146101ca578063e5086003146101f9578063ecd059611461020c578063fbe5ce0a1461022c578063fd8b84b11461024b575f80fd5b806306fdde03146100a957806354fd4d50146100f25780636d61fe701461011f5780637065cb48146101405780638a91b0e31461015f578063ccfdec8c1461017e575b5f80fd5b3480156100b4575f80fd5b5060408051808201909152600f81526e27bbb730b13632a2bc32b1baba37b960891b60208201525b6040516100e99190610b67565b60405180910390f35b3480156100fd575f80fd5b506040805180820190915260058152640312e302e360dc1b60208201526100dc565b34801561012a575f80fd5b5061013e610139366004610be1565b610277565b005b34801561014b575f80fd5b5061013e61015a366004610c3b565b61036a565b34801561016a575f80fd5b5061013e610179366004610be1565b61045c565b348015610189575f80fd5b506101a9610198366004610c3b565b60016020525f908152604090205481565b6040519081526020016100e9565b61013e6101c5366004610c54565b6104ae565b3480156101d5575f80fd5b506101e96101e4366004610c3b565b61056d565b60405190151581526020016100e9565b61013e610207366004610c54565b61059c565b348015610217575f80fd5b506101e9610226366004610ca3565b60021490565b348015610237575f80fd5b5061013e610246366004610cba565b6105f2565b348015610256575f80fd5b5061026a610265366004610c3b565b610665565b6040516100e99190610ceb565b335f6102866014828587610d37565b61028f91610d5e565b60601c9050806102c25760405163b20f76e360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6001600160a01b0382165f9081526020819052604090206102e29061069b565b6001600160a01b0382165f90815260208190526040902061030390826106f6565b6001600160a01b0382165f8181526001602081905260409182902055517f1cd4a6da6e6a6f4dc754cedd54ead3b9cd0e2f5804cda2ba60506c2899fb29df9061035c9084906001600160a01b0391909116815260200190565b60405180910390a250505050565b336103748161056d565b61039c5760405163f91bd6f160e01b81526001600160a01b03821660048201526024016102b9565b6001600160a01b0382166103ce5760405163b20f76e360e01b81526001600160a01b03831660048201526024016102b9565b6001600160a01b0381165f9081526020819052604090206103ef90836106f6565b6001600160a01b0381165f90815260016020526040812080549161041283610da7565b90915550506040516001600160a01b0383811682528216907fc82bdbbf677a2462f2a7e22e4ba9abd209496b69cd7b868b3b1d28f76e09a40a906020015b60405180910390a25050565b335f908152602081905260409020610473906107ca565b335f81815260016020526040808220829055517f9d00629762554452d03c3b45626436df6ca1c3795d05d04df882f6db481b1be09190a25050565b6001600160a01b0383165f9081526020819052604090206104cf9033610825565b6104ec57604051631a27eac360e11b815260040160405180910390fd5b826001600160a01b031663d691c9643461050461085f565b85856040518563ffffffff1660e01b815260040161052493929190610dbf565b5f6040518083038185885af115801561053f573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f191682016040526105679190810190610e39565b50505050565b6001600160a01b038181165f908152602081815260408083206001845290915281205490911615155b92915050565b6001600160a01b0383165f9081526020819052604090206105bd9033610825565b6105da57604051631a27eac360e11b815260040160405180910390fd5b826001600160a01b031663d691c96434610504610871565b335f90815260208190526040902061060b908383610882565b335f90815260016020526040812080549161062583610f47565b90915550506040516001600160a01b038216815233907fe594d081b4382713733fe631966432c9cea5199afb2db5c3c1931f9f9300367990602001610450565b6001600160a01b0381165f90815260016020818152604080842054918490529092206060926106949290610955565b5092915050565b60015f908152602082905260409020546001600160a01b0316156106d2576040516329e42f3360e11b815260040160405180910390fd5b60015f818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061071557506001600160a01b0381166001145b1561073e57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016102b9565b6001600160a01b038181165f90815260208490526040902054161561078157604051631034f46960e21b81526001600160a01b03821660048201526024016102b9565b60015f818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b60015f908152602082905260409020546001600160a01b03165b6001600160a01b03811615610821576001600160a01b039081165f90815260208390526040902080546001600160a01b03198116909155166107e4565b5050565b5f60016001600160a01b0383161480159061085857506001600160a01b038281165f908152602085905260409020541615155b9392505050565b5f61086c81808080610afd565b905090565b5f61086c600160f81b828080610afd565b6001600160a01b03811615806108a157506001600160a01b0381166001145b156108ca57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016102b9565b6001600160a01b038281165f9081526020859052604090205481169082161461091157604051637c84ecfb60e01b81526001600160a01b03821660048201526024016102b9565b6001600160a01b039081165f8181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b60605f6001600160a01b03841660011480159061097957506109778585610825565b155b156109a257604051637c84ecfb60e01b81526001600160a01b03851660048201526024016102b9565b825f036109c25760405163f725081760e01b815260040160405180910390fd5b8267ffffffffffffffff8111156109db576109db610df4565b604051908082528060200260200182016040528015610a04578160200160208202803683370190505b506001600160a01b038086165f90815260208890526040812054929450911691505b6001600160a01b03821615801590610a4857506001600160a01b038216600114155b8015610a5357508381105b15610aac5781838281518110610a6b57610a6b610f5c565b6001600160a01b039283166020918202929092018101919091529281165f908152928790526040909220549091169080610aa481610da7565b915050610a26565b6001600160a01b038216600114801590610ac557505f81115b15610af15782610ad6600183610f70565b81518110610ae657610ae6610f5c565b602002602001015191505b80835250935093915050565b604080516001600160f81b03198087166020830152851660218201525f602282018190526001600160e01b03198516602683015269ffffffffffffffffffff198416602a8301529101604051602081830303815290604052610b5e90610f83565b95945050505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f840112610bac575f80fd5b50813567ffffffffffffffff811115610bc3575f80fd5b602083019150836020828501011115610bda575f80fd5b9250929050565b5f8060208385031215610bf2575f80fd5b823567ffffffffffffffff811115610c08575f80fd5b610c1485828601610b9c565b90969095509350505050565b80356001600160a01b0381168114610c36575f80fd5b919050565b5f60208284031215610c4b575f80fd5b61085882610c20565b5f805f60408486031215610c66575f80fd5b610c6f84610c20565b9250602084013567ffffffffffffffff811115610c8a575f80fd5b610c9686828701610b9c565b9497909650939450505050565b5f60208284031215610cb3575f80fd5b5035919050565b5f8060408385031215610ccb575f80fd5b610cd483610c20565b9150610ce260208401610c20565b90509250929050565b602080825282518282018190525f9190848201906040850190845b81811015610d2b5783516001600160a01b031683529284019291840191600101610d06565b50909695505050505050565b5f8085851115610d45575f80fd5b83861115610d51575f80fd5b5050820193919092039150565b6bffffffffffffffffffffffff198135818116916014851015610d8b5780818660140360031b1b83161692505b505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f60018201610db857610db8610d93565b5060010190565b83815260406020820152816040820152818360608301375f818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610e3157610e31610df4565b604052919050565b5f6020808385031215610e4a575f80fd5b825167ffffffffffffffff80821115610e61575f80fd5b8185019150601f86601f840112610e76575f80fd5b825182811115610e8857610e88610df4565b8060051b610e97868201610e08565b918252848101860191868101908a841115610eb0575f80fd5b87870192505b83831015610f3957825186811115610ecc575f80fd5b8701603f81018c13610edc575f80fd5b88810151604088821115610ef257610ef2610df4565b610f03828901601f19168c01610e08565b8281528e82848601011115610f16575f80fd5b828285018d83015e5f9281018c0192909252508352509187019190870190610eb6565b9a9950505050505050505050565b5f81610f5557610f55610d93565b505f190190565b634e487b7160e01b5f52603260045260245ffd5b8181038181111561059657610596610d93565b80516020808301519190811015610fa3575f198160200360031b1b821691505b5091905056fea2646970667358221220b4818563abaaf2d7c9426aa3c80814b09784cce89922dfe0c778fbe635c46e0a64736f6c63430008190033" diff --git a/tests/deploy.nexus.ts b/tests/src/deployProcess.ts similarity index 55% rename from tests/deploy.nexus.ts rename to tests/src/deployProcess.ts index 9e889839..b99cbed8 100644 --- a/tests/deploy.nexus.ts +++ b/tests/src/deployProcess.ts @@ -6,8 +6,13 @@ export const deployProcess = async (rpcPort: number) => { })`yarn install` await execa({ cwd: "./node_modules/nexus" - })`rm -rf ./deployments` + })`rm -rf ./deployments/anvil-${rpcPort}` return await execa({ - cwd: "./node_modules/nexus" + cwd: "./node_modules/nexus", + env: { + HH_RPC_URL: `http://localhost:${rpcPort}`, + HH_CHAIN_NAME: `anvil-${rpcPort}`, + HH_CHAIN_ID: rpcPort.toString() + } })`yarn deploy:hardhat --network anvil-${rpcPort}` } diff --git a/tests/globalSetup.ts b/tests/src/globalSetup.ts similarity index 96% rename from tests/globalSetup.ts rename to tests/src/globalSetup.ts index 752d8b51..80dcf92a 100644 --- a/tests/globalSetup.ts +++ b/tests/src/globalSetup.ts @@ -2,7 +2,7 @@ import { type NetworkConfig, type NetworkConfigWithBundler, initNetwork -} from "./test.utils" +} from "./testUtils" let globalConfig: NetworkConfigWithBundler export const setup = async ({ provide }) => { diff --git a/tests/testSetup.ts b/tests/src/testSetup.ts similarity index 97% rename from tests/testSetup.ts rename to tests/src/testSetup.ts index ce9507be..073311aa 100644 --- a/tests/testSetup.ts +++ b/tests/src/testSetup.ts @@ -4,7 +4,7 @@ import { type NetworkConfigWithBundler, initNetwork, toFundedTestClients -} from "./test.utils" +} from "./testUtils" export type NetworkConfigWithTestClients = NetworkConfigWithBundler & { fundedTestClients: FundedTestClients diff --git a/tests/test.utils.ts b/tests/src/testUtils.ts similarity index 92% rename from tests/test.utils.ts rename to tests/src/testUtils.ts index 1d4bc7da..89d15bc6 100644 --- a/tests/test.utils.ts +++ b/tests/src/testUtils.ts @@ -21,15 +21,19 @@ import { type EIP712DomainReturn, type NexusSmartAccount, createSmartAccountClient -} from "../src" -import contracts from "../src/__contracts" -import { getCustomChain } from "../src/account/utils" -import { Logger } from "../src/account/utils/Logger" +} from "../../src" +import contracts from "../../src/__contracts" +import { getCustomChain } from "../../src/account/utils" +import { Logger } from "../../src/account/utils/Logger" import { ENTRY_POINT_SIMULATIONS_CREATECALL, - ENTRY_POINT_V07_CREATECALL -} from "./create.config" -import { deployProcess } from "./deploy.nexus" + ENTRY_POINT_V07_CREATECALL, + OWNABLE_EXECUTOR, + OWNABLE_EXECUTOR_BYTECODE, + OWNABLE_VALIDATOR, + OWNABLE_VALIDATOR_BYTECODE +} from "./callDatas" +import { deployProcess } from "./deployProcess" type AnvilInstance = ReturnType type BundlerInstance = ReturnType @@ -134,6 +138,7 @@ export const toConfiguredAnvil = async ({ }) await instance.start() await deployContracts(rpcPort) + await deployProcess(rpcPort) // hh deploy from nexus in node_modules return instance } @@ -366,15 +371,27 @@ const deployContracts = async (rpcPort: number): Promise => { data: ENTRY_POINT_SIMULATIONS_CREATECALL, gas: 15_000_000n }) - await testClient.waitForTransactionReceipt({ hash: entrypointSimulationHash }) const entrypointHash = await testClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: ENTRY_POINT_V07_CREATECALL, gas: 15_000_000n }) - await testClient.waitForTransactionReceipt({ hash: entrypointHash }) - await deployProcess(rpcPort) // hh deploy from nexus in node_modules + + await Promise.all([ + testClient.waitForTransactionReceipt({ hash: entrypointSimulationHash }), + testClient.waitForTransactionReceipt({ hash: entrypointHash }) + ]) + + await testClient.setCode({ + bytecode: OWNABLE_EXECUTOR_BYTECODE, + address: OWNABLE_EXECUTOR + }) + + await testClient.setCode({ + bytecode: OWNABLE_VALIDATOR_BYTECODE, + address: OWNABLE_VALIDATOR + }) } export const sleep = (ms: number) => diff --git a/tests/vitest.config.ts b/tests/vitest.config.ts index 8ab6b860..ef719a81 100644 --- a/tests/vitest.config.ts +++ b/tests/vitest.config.ts @@ -4,7 +4,7 @@ import { defineConfig } from "vitest/config" export default defineConfig({ test: { coverage: { - all: true, + all: false, provider: "v8", reporter: process.env.CI ? ["json-summary", "json"] @@ -26,7 +26,7 @@ export default defineConfig({ } }, include: ["tests/**/*.test.ts"], - globalSetup: join(__dirname, "globalSetup.ts"), + globalSetup: join(__dirname, "src/globalSetup.ts"), environment: "node", testTimeout: 60_000, hookTimeout: 60_000