From 9bba4248a71cad443d5e00f7ce37b26d42e3c3ff Mon Sep 17 00:00:00 2001 From: Joe Pegler Date: Fri, 23 Aug 2024 15:47:38 +0100 Subject: [PATCH] Revert "chore: workflow" This reverts commit 109b35363c164157b0931ed9ad5e415683632f0b. --- .github/workflows/build.yml | 1 - .github/workflows/docs.yml | 2 - package.json | 6 +- tests/globalSetup.ts | 8 +- tests/instances/account.test.ts | 115 +++++++++++++++++++++ tests/instances/bundler.test.ts | 111 ++++++++++++++++++++ tests/instances/hook.module.test.ts | 111 ++++++++++++++++++++ tests/instances/modules.test.ts | 111 ++++++++++++++++++++ tests/instances/playground.test.ts | 150 +++++++++++++++++++++++++++- tests/testSetup.ts | 2 +- tests/vitest.config.ts | 14 ++- 11 files changed, 610 insertions(+), 21 deletions(-) create mode 100644 tests/instances/account.test.ts create mode 100644 tests/instances/bundler.test.ts create mode 100644 tests/instances/hook.module.test.ts create mode 100644 tests/instances/modules.test.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 253b4c93..96f601a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,5 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Build uses: ./.github/actions/build diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 97b719b6..4428c2b9 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,8 +12,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - run: git config --global user.email "gh@runner.com" - run: git config --global user.name "gh-runner" diff --git a/package.json b/package.json index f355382b..19dfdf4c 100644 --- a/package.json +++ b/package.json @@ -58,10 +58,12 @@ "dev": "bun link && concurrently \"bun run esm:watch\" \"bun run cjs:watch\" \"bun run esm:watch:aliases\" \"bun run cjs:watch:aliases\"", "build": "bun run clean && bun run build:cjs && bun run build:esm && bun run build:types", "clean": "rimraf ./dist/_esm ./dist/_cjs ./dist/_types ./dist/tsconfig", - "test": "vitest -c ./tests/vitest.config.ts", - "test:watch": "bun run test dev", + "test": "vitest dev -c ./tests/vitest.config.ts", "playground": "RUN_PLAYGROUND=true bun run test -t=Playground", "playground:watch": "RUN_PLAYGROUND=true bun run test -t=Playground --watch", + "test:watch": "bun run test --watch", + "test:coverage": "CI=true vitest -c ./tests/vitest.config.ts --coverage", + "test:ci": "CI=true vitest -c ./tests/vitest.config.ts", "size": "size-limit", "docs": "typedoc --tsconfig ./tsconfig/tsconfig.esm.json", "docs:deploy": "bun run docs && gh-pages -d docs", diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts index e9840f64..28eba1b1 100644 --- a/tests/globalSetup.ts +++ b/tests/globalSetup.ts @@ -1,10 +1,4 @@ -import { type NetworkConfig, initNetwork, killAllNetworks } from "./test.utils" - -export async function setup({ provide }) { - const network = await initNetwork() - const { bundlerInstance, instance, ...serializeableConfig } = network - provide("globalNetwork", serializeableConfig) -} +import { type NetworkConfig, killAllNetworks } from "./test.utils" export async function teardown() { await killAllNetworks() diff --git a/tests/instances/account.test.ts b/tests/instances/account.test.ts new file mode 100644 index 00000000..3576eef6 --- /dev/null +++ b/tests/instances/account.test.ts @@ -0,0 +1,115 @@ +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 NexusSmartAccountConfig, + createSmartAccountClient +} from "../../src/account" +import { + fundAndDeploy, + getTestAccount, + killNetwork, + toTestClient +} from "../test.utils" +import type { + MasterClient, + NetworkConfig, + NetworkConfigWithBundler +} from "../test.utils" +import { type TestFileNetworkType, aaTest, toNetwork } from "../testSetup" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("account", () => { + let network: NetworkConfig + let chain: Chain + let bundlerUrl: string + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let walletClient: WalletClient + let recipientWalletClient: WalletClient + let smartAccount: NexusSmartAccount + let recipientSmartAccount: NexusSmartAccount + let smartAccountAddress: Hex + let recipientSmartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + const testConfig: Partial = { + factoryAddress: network.deployment.k1FactoryAddress, + k1ValidatorAddress: network.deployment.k1ValidatorAddress + } + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(2) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + recipientWalletClient = createWalletClient({ + account: recipientAccount, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount()) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain, + ...testConfig + }) + + recipientSmartAccount = await createSmartAccountClient({ + signer: recipientWalletClient, + bundlerUrl, + chain, + ...testConfig + }) + + smartAccountAddress = await smartAccount.getAddress() + recipientSmartAccountAddress = await recipientSmartAccount.getAddress() + await fundAndDeploy(testClient, [smartAccount, recipientSmartAccount]) + }) + afterAll(async () => { + await killNetwork([network.rpcPort, network.bundlerPort]) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress(), + recipientAccount.address, + recipientSmartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x2915317448Dd00158361dcBB47eacF26f774DdA8", // Sender smart account + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x89028E0fD7Af7F864878e0209118DF6A9229A9Ce" // Recipient smart account + ]) + }) + + test("should", async () => { + const counterAddress = network.deployment.counterAddress + const byteCode = await testClient.getBytecode({ address: counterAddress }) + expect(byteCode).toBeTruthy() + }) +}) diff --git a/tests/instances/bundler.test.ts b/tests/instances/bundler.test.ts new file mode 100644 index 00000000..0e4f52d7 --- /dev/null +++ b/tests/instances/bundler.test.ts @@ -0,0 +1,111 @@ +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 NexusSmartAccountConfig, + createSmartAccountClient +} from "../../src/account" +import { + fundAndDeploy, + getTestAccount, + killNetwork, + toTestClient +} from "../test.utils" +import type { MasterClient, NetworkConfig } from "../test.utils" +import { type TestFileNetworkType, toNetwork } from "../testSetup" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("bundler", () => { + let network: NetworkConfig + let chain: Chain + let bundlerUrl: string + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let walletClient: WalletClient + let recipientWalletClient: WalletClient + let smartAccount: NexusSmartAccount + let recipientSmartAccount: NexusSmartAccount + let smartAccountAddress: Hex + let recipientSmartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + const testConfig: Partial = { + factoryAddress: network.deployment.k1FactoryAddress, + k1ValidatorAddress: network.deployment.k1ValidatorAddress + } + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(2) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + recipientWalletClient = createWalletClient({ + account: recipientAccount, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount()) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain, + ...testConfig + }) + + recipientSmartAccount = await createSmartAccountClient({ + signer: recipientWalletClient, + bundlerUrl, + chain, + ...testConfig + }) + + smartAccountAddress = await smartAccount.getAddress() + recipientSmartAccountAddress = await recipientSmartAccount.getAddress() + await fundAndDeploy(testClient, [smartAccount, recipientSmartAccount]) + }) + afterAll(async () => { + await killNetwork([network.rpcPort, network.bundlerPort]) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress(), + recipientAccount.address, + recipientSmartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x2915317448Dd00158361dcBB47eacF26f774DdA8", // Sender smart account + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x89028E0fD7Af7F864878e0209118DF6A9229A9Ce" // Recipient smart account + ]) + }) + + test("should check bytecode at Counter contract", async () => { + const counterAddress = network.deployment.counterAddress + const byteCode = await testClient.getBytecode({ address: counterAddress }) + expect(byteCode).toBeTruthy() + }) +}) diff --git a/tests/instances/hook.module.test.ts b/tests/instances/hook.module.test.ts new file mode 100644 index 00000000..42a76f32 --- /dev/null +++ b/tests/instances/hook.module.test.ts @@ -0,0 +1,111 @@ +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 NexusSmartAccountConfig, + createSmartAccountClient +} from "../../src/account" +import { + fundAndDeploy, + getTestAccount, + killNetwork, + toTestClient +} from "../test.utils" +import type { MasterClient, NetworkConfig } from "../test.utils" +import { type TestFileNetworkType, toNetwork } from "../testSetup" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("hook.module", () => { + let network: NetworkConfig + let chain: Chain + let bundlerUrl: string + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let walletClient: WalletClient + let recipientWalletClient: WalletClient + let smartAccount: NexusSmartAccount + let recipientSmartAccount: NexusSmartAccount + let smartAccountAddress: Hex + let recipientSmartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + const testConfig: Partial = { + factoryAddress: network.deployment.k1FactoryAddress, + k1ValidatorAddress: network.deployment.k1ValidatorAddress + } + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(2) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + recipientWalletClient = createWalletClient({ + account: recipientAccount, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount()) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain, + ...testConfig + }) + + recipientSmartAccount = await createSmartAccountClient({ + signer: recipientWalletClient, + bundlerUrl, + chain, + ...testConfig + }) + + smartAccountAddress = await smartAccount.getAddress() + recipientSmartAccountAddress = await recipientSmartAccount.getAddress() + await fundAndDeploy(testClient, [smartAccount, recipientSmartAccount]) + }) + afterAll(async () => { + await killNetwork([network.rpcPort, network.bundlerPort]) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress(), + recipientAccount.address, + recipientSmartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x2915317448Dd00158361dcBB47eacF26f774DdA8", // Sender smart account + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x89028E0fD7Af7F864878e0209118DF6A9229A9Ce" // Recipient smart account + ]) + }) + + test("should check bytecode at Counter contract", async () => { + const counterAddress = network.deployment.counterAddress + const byteCode = await testClient.getBytecode({ address: counterAddress }) + expect(byteCode).toBeTruthy() + }) +}) diff --git a/tests/instances/modules.test.ts b/tests/instances/modules.test.ts new file mode 100644 index 00000000..d75a6a70 --- /dev/null +++ b/tests/instances/modules.test.ts @@ -0,0 +1,111 @@ +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 NexusSmartAccountConfig, + createSmartAccountClient +} from "../../src/account" +import { + fundAndDeploy, + getTestAccount, + killNetwork, + toTestClient +} from "../test.utils" +import type { MasterClient, NetworkConfig } from "../test.utils" +import { type TestFileNetworkType, toNetwork } from "../testSetup" + +const NETWORK_TYPE: TestFileNetworkType = "LOCAL" + +describe("modules", () => { + let network: NetworkConfig + let chain: Chain + let bundlerUrl: string + let testClient: MasterClient + let account: Account + let recipientAccount: Account + let walletClient: WalletClient + let recipientWalletClient: WalletClient + let smartAccount: NexusSmartAccount + let recipientSmartAccount: NexusSmartAccount + let smartAccountAddress: Hex + let recipientSmartAccountAddress: Hex + + beforeAll(async () => { + network = await toNetwork(NETWORK_TYPE) + + const testConfig: Partial = { + factoryAddress: network.deployment.k1FactoryAddress, + k1ValidatorAddress: network.deployment.k1ValidatorAddress + } + + chain = network.chain + bundlerUrl = network.bundlerUrl + + account = getTestAccount(2) + recipientAccount = getTestAccount(3) + + walletClient = createWalletClient({ + account, + chain, + transport: http() + }) + + recipientWalletClient = createWalletClient({ + account: recipientAccount, + chain, + transport: http() + }) + + testClient = toTestClient(chain, getTestAccount()) + + smartAccount = await createSmartAccountClient({ + signer: walletClient, + bundlerUrl, + chain, + ...testConfig + }) + + recipientSmartAccount = await createSmartAccountClient({ + signer: recipientWalletClient, + bundlerUrl, + chain, + ...testConfig + }) + + smartAccountAddress = await smartAccount.getAddress() + recipientSmartAccountAddress = await recipientSmartAccount.getAddress() + await fundAndDeploy(testClient, [smartAccount, recipientSmartAccount]) + }) + afterAll(async () => { + await killNetwork([network.rpcPort, network.bundlerPort]) + }) + + test("should have account addresses", async () => { + const addresses = await Promise.all([ + account.address, + smartAccount.getAddress(), + recipientAccount.address, + recipientSmartAccount.getAddress() + ]) + expect(addresses.every(Boolean)).to.be.true + expect(addresses).toStrictEqual([ + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x2915317448Dd00158361dcBB47eacF26f774DdA8", // Sender smart account + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x89028E0fD7Af7F864878e0209118DF6A9229A9Ce" // Recipient smart account + ]) + }) + + test("should check bytecode at Counter contract", async () => { + const counterAddress = network.deployment.counterAddress + const byteCode = await testClient.getBytecode({ address: counterAddress }) + expect(byteCode).toBeTruthy() + }) +}) diff --git a/tests/instances/playground.test.ts b/tests/instances/playground.test.ts index 386f3381..c03b56be 100644 --- a/tests/instances/playground.test.ts +++ b/tests/instances/playground.test.ts @@ -1,7 +1,149 @@ -import { expect, describe, it } from "vitest" +import { config } from "dotenv" +import { + http, + type Address, + type Chain, + type Hex, + type PublicClient, + type WalletClient, + createPublicClient, + createWalletClient +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + type NexusSmartAccount, + createSmartAccountClient, + getChain, + getCustomChain +} from "../../src/account" +import { createK1ValidatorModule } from "../../src/modules" +import { getBundlerUrl } from "../test.utils" +config() -describe("dummy test", () => { - it("should pass", () => { - expect(1).toBe(1) +const privateKey = process.env.E2E_PRIVATE_KEY_ONE +const chainId = process.env.CHAIN_ID +const rpcUrl = process.env.RPC_URL //Optional, taken from chain (using chainId) if not provided +const _bundlerUrl = process.env.BUNDLER_URL // Optional, taken from chain (using chainId) if not provided +const conditionalDescribe = + process.env.RUN_PLAYGROUND === "true" ? describe : describe.skip + +if (!privateKey) throw new Error("Missing env var E2E_PRIVATE_KEY_ONE") +if (!chainId) throw new Error("Missing env var CHAIN_ID") + +// Remove the following lines to use the default factory and validator addresses +// These are relevant only for now on base sopelia chain and are likely to change +const k1ValidatorAddress = "0x663E709f60477f07885230E213b8149a7027239B" +const factoryAddress = "0x887Ca6FaFD62737D0E79A2b8Da41f0B15A864778" + +conditionalDescribe("playground", () => { + let ownerAddress: Address + let walletClient: WalletClient + let smartAccount: NexusSmartAccount + let smartAccountAddress: Address + let chain: Chain + let bundlerUrl: string + let publicClient: PublicClient + + beforeAll(async () => { + try { + chain = getChain(+chainId) + } catch (e) { + if (!rpcUrl) throw new Error("Missing env var RPC_URL") + chain = getCustomChain("Custom Chain", +chainId, rpcUrl) + } + walletClient = createWalletClient({ + account: privateKeyToAccount( + (privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`) as Hex + ), + chain, + transport: http() + }) + ownerAddress = walletClient?.account?.address as Hex + publicClient = createPublicClient({ + chain, + transport: http() + }) + + bundlerUrl = _bundlerUrl ?? getBundlerUrl(+chainId) + }) + + test("should have factory and k1Validator deployed", async () => { + const byteCodes = await Promise.all([ + publicClient.getBytecode({ + address: k1ValidatorAddress + }), + publicClient.getBytecode({ + address: factoryAddress + }) + ]) + + expect(byteCodes.every(Boolean)).toBeTruthy() + }) + + test("should init the smart account", async () => { + smartAccount = await createSmartAccountClient({ + signer: walletClient, + chain, + bundlerUrl, + // Remove the following lines to use the default factory and validator addresses + // These are relevant only for now on sopelia chain and are likely to change + k1ValidatorAddress, + factoryAddress + }) + }) + + test("should log relevant addresses", async () => { + smartAccountAddress = await smartAccount.getAddress() + console.log({ ownerAddress, smartAccountAddress }) + }) + + test("should check balances of relevant addresses", async () => { + const [ownerBalance, smartAccountBalance] = await Promise.all([ + publicClient.getBalance({ + address: ownerAddress + }), + publicClient.getBalance({ + address: smartAccountAddress + }) + ]) + console.log({ ownerBalance, smartAccountBalance }) + const balancesAreOfCorrectType = [ownerBalance, smartAccountBalance].every( + (balance) => typeof balance === "bigint" + ) + expect(balancesAreOfCorrectType).toBeTruthy() + }) + + test("should send some native token", async () => { + const balanceBefore = await publicClient.getBalance({ + address: ownerAddress + }) + + const k1ValidatorModule = await createK1ValidatorModule( + smartAccount.getSigner(), + k1ValidatorAddress + ) + + smartAccount.setActiveValidationModule(k1ValidatorModule) + + const { wait } = await smartAccount.sendTransaction({ + to: ownerAddress, + data: "0x", + value: 1n + }) + + const { + success, + receipt: { transactionHash } + } = await wait() + expect(success).toBeTruthy() + + const balanceAfter = await publicClient.getBalance({ + address: ownerAddress + }) + + console.log({ transactionHash }) + + expect(balanceAfter - balanceBefore).toBe(1n) }) }) diff --git a/tests/testSetup.ts b/tests/testSetup.ts index ce9507be..2227f0bd 100644 --- a/tests/testSetup.ts +++ b/tests/testSetup.ts @@ -10,7 +10,7 @@ export type NetworkConfigWithTestClients = NetworkConfigWithBundler & { fundedTestClients: FundedTestClients } -export const scopedTest = test.extend<{ +export const aaTest = test.extend<{ config: NetworkConfigWithTestClients }>({ // biome-ignore lint/correctness/noEmptyPattern: Needed in vitest :/ diff --git a/tests/vitest.config.ts b/tests/vitest.config.ts index e3fc9a13..21b7354d 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: false, + all: true, provider: "v8", reporter: process.env.CI ? ["json-summary", "json"] @@ -25,9 +25,15 @@ export default defineConfig({ statements: 80 } }, - environment: "node", - include: ["tests/instances/*.test.ts"], + include: ["tests/**/*.test.ts"], globalSetup: [join(__dirname, "./globalSetup.ts")], - testTimeout: 20_000 + sequence: { + concurrent: false + }, + fileParallelism: true, + environment: "node", + testTimeout: 60_000, + hookTimeout: 45_000, + pool: "forks" } })