Skip to content

Commit

Permalink
test: change zerodev e2e tests to use .env wallet (#60)
Browse files Browse the repository at this point in the history
Requirements
- change zerodev e2e tests to use .env wallet
- use `waitForUserOperationTxn` and update test timeouts to 50 seconds for tests to account for "replacement underpriced" errors from not waiting enough time for prev. tests' sendUserOperations.

Tests: 
<img width="966" alt="image" src="https://github.com/alchemyplatform/aa-sdk/assets/43521356/b562ff43-9fc2-4d96-b013-49a6c1fec111">

<!-- start pr-codex -->

---

## PR-Codex overview
### Detailed summary
- Added `API_KEY` and `OWNER_MNEMONIC` constants to `constants.ts` in `packages/accounts/src/kernel-zerodev/e2e-tests`
- Modified `AccountSigner` class in `packages/ethers/src/account-signer.ts` to include `waitForUserOperationTransaction` property
- Modified `simple-account.test.ts` in `packages/ethers/e2e-tests`, `packages/core/e2e-tests`, `packages/alchemy/e2e-tests`, and `packages/accounts/src/kernel-zerodev/e2e-tests` to use `await` with `sendUserOperation` and `waitForUserOperationTransaction` methods

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
  • Loading branch information
avasisht23 authored and rthomare committed Jul 29, 2023
1 parent 1493765 commit 5b6cbb2
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 32 deletions.
2 changes: 2 additions & 0 deletions packages/accounts/src/kernel-zerodev/e2e-tests/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const API_KEY = process.env.API_KEY!;
export const OWNER_MNEMONIC = process.env.OWNER_MNEMONIC!;
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import {
PrivateKeySigner,
type BatchUserOperationCallData,
type SmartAccountSigner,
} from "@alchemy/aa-core";
import {
encodeAbiParameters,
parseAbiParameters,
toHex,
type Address,
type Hex,
type Hash,
} from "viem";
import { generatePrivateKey } from "viem/accounts";
import { mnemonicToAccount } from "viem/accounts";
import { polygonMumbai } from "viem/chains";
import {
KernelSmartContractAccount,
Expand All @@ -17,22 +19,28 @@ import {
import { KernelAccountProvider } from "../provider.js";
import type { KernelUserOperationCallData } from "../types.js";
import { KernelBaseValidator, ValidatorMode } from "../validator/base.js";
import { API_KEY, OWNER_MNEMONIC } from "./constants.js";
import { MockSigner } from "./mocks/mock-signer.js";

describe("Kernel Account Tests", () => {
//any wallet should work
const config = {
privateKey: generatePrivateKey(),
mockWallet: "0x48D4d3536cDe7A257087206870c6B6E76e3D4ff4",
chain: polygonMumbai,
rpcProvider: `${polygonMumbai.rpcUrls.alchemy.http[0]}/demo`,
rpcProvider: `${polygonMumbai.rpcUrls.alchemy.http[0]}/${API_KEY}`,
validatorAddress: "0x180D6465F921C7E0DEA0040107D342c87455fFF5" as Address,
accountFactoryAddress:
"0x5D006d3880645ec6e254E18C1F879DAC9Dd71A39" as Address,
entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" as Address,
};

const owner = PrivateKeySigner.privateKeyToAccountSigner(config.privateKey);
const ownerAccount = mnemonicToAccount(OWNER_MNEMONIC);
const owner: SmartAccountSigner = {
signMessage: async (msg) =>
ownerAccount.signMessage({
message: { raw: toHex(msg) },
}),
getAddress: async () => ownerAccount.address,
};
const mockOwner = new MockSigner();

const validator: KernelBaseValidator = new KernelBaseValidator({
Expand Down Expand Up @@ -143,16 +151,19 @@ describe("Kernel Account Tests", () => {

// Only work if you have deposited some matic balance for counterfactual address at entrypoint
it("sendUserOperation should execute properly", async () => {
//
let signerWithProvider = connect(0n, owner);

const result = signerWithProvider.sendUserOperation({
const result = await signerWithProvider.sendUserOperation({
target: await signerWithProvider.getAddress(),
data: "0x",
value: 0n,
});
await expect(result).resolves.not.toThrowError();
}, 10000);
const txnHash = signerWithProvider.waitForUserOperationTransaction(
result.hash as Hash
);

await expect(txnHash).resolves.not.toThrowError();
}, 50000);

it("sendUserOperation batch should execute properly", async () => {
let signerWithProvider = connect(0n, owner);
Expand All @@ -167,9 +178,13 @@ describe("Kernel Account Tests", () => {
value: 200000000n,
};
const requests: BatchUserOperationCallData = [request, request2];
const result = signerWithProvider.sendUserOperation(requests);
await expect(result).resolves.not.toThrowError();
}, 20000);
const result = await signerWithProvider.sendUserOperation(requests);
const txnHash = signerWithProvider.waitForUserOperationTransaction(
result.hash as Hash
);

await expect(txnHash).resolves.not.toThrowError();
}, 50000);

//non core functions
it("should correctly identify whether account is deployed", async () => {
Expand Down
20 changes: 9 additions & 11 deletions packages/alchemy/e2e-tests/simple-account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
SimpleSmartContractAccount,
type SimpleSmartAccountOwner,
} from "@alchemy/aa-core";
import { toHex } from "viem";
import { toHex, type Hash } from "viem";
import { mnemonicToAccount } from "viem/accounts";
import { polygonMumbai } from "viem/chains";
import { AlchemyProvider } from "../src/provider.js";
Expand Down Expand Up @@ -44,13 +44,14 @@ describe("Simple Account Tests", () => {
});

it("should execute successfully", async () => {
const result = signer.sendUserOperation({
const result = await signer.sendUserOperation({
target: await signer.getAddress(),
data: "0x",
});
const txnHash = signer.waitForUserOperationTransaction(result.hash as Hash);

await expect(result).resolves.not.toThrowError();
});
await expect(txnHash).resolves.not.toThrowError();
}, 50000);

it("should fail to execute if account address is not deployed and not correct", async () => {
const accountAddress = "0xc33AbD9621834CA7c6Fc9f9CC3c47b9c17B03f9F";
Expand Down Expand Up @@ -79,21 +80,18 @@ describe("Simple Account Tests", () => {
});

it("should successfully execute with alchemy paymaster info", async () => {
// TODO: this is super hacky right now
// we have to wait for the test above to run and be confirmed so that this one submits successfully using the correct nonce
// one way we could do this is by batching the two UOs together
await new Promise((resolve) => setTimeout(resolve, 7500));
const newSigner = signer.withAlchemyGasManager({
provider: signer.rpcClient,
policyId: PAYMASTER_POLICY_ID,
entryPoint: ENTRYPOINT_ADDRESS,
});

const result = newSigner.sendUserOperation({
const result = await newSigner.sendUserOperation({
target: await newSigner.getAddress(),
data: "0x",
});
const txnHash = signer.waitForUserOperationTransaction(result.hash as Hash);

await expect(result).resolves.not.toThrowError();
}, 10000);
await expect(txnHash).resolves.not.toThrowError();
}, 50000);
});
9 changes: 5 additions & 4 deletions packages/core/e2e-tests/simple-account.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isAddress } from "viem";
import { isAddress, type Hash } from "viem";
import { generatePrivateKey } from "viem/accounts";
import { polygonMumbai } from "viem/chains";
import {
Expand Down Expand Up @@ -39,13 +39,14 @@ describe("Simple Account Tests", () => {
});

it("should execute successfully", async () => {
const result = signer.sendUserOperation({
const result = await signer.sendUserOperation({
target: await signer.getAddress(),
data: "0x",
});
const txnHash = signer.waitForUserOperationTransaction(result.hash as Hash);

await expect(result).resolves.not.toThrowError();
});
await expect(txnHash).resolves.not.toThrowError();
}, 50000);

it("should fail to execute if account address is not deployed and not correct", async () => {
const accountAddress = "0xc33AbD9621834CA7c6Fc9f9CC3c47b9c17B03f9F";
Expand Down
11 changes: 7 additions & 4 deletions packages/ethers/e2e-tests/simple-account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ describe("Simple Account Tests", async () => {
});

it("should execute successfully", async () => {
const result = signer.sendUserOperation({
const result = await signer.sendUserOperation({
target: (await signer.getAddress()) as `0x${string}`,
data: "0x",
});
const txnHash = signer.waitForUserOperationTransaction(
result.hash as `0x${string}`
);

await expect(result).resolves.not.toThrowError();
});
await expect(txnHash).resolves.not.toThrowError();
}, 50000);

it("should fail to execute if account address is not deployed and not correct", async () => {
const accountAddress = "0xc33AbD9621834CA7c6Fc9f9CC3c47b9c17B03f9F";
Expand All @@ -68,5 +71,5 @@ describe("Simple Account Tests", async () => {
});

await expect(result).rejects.toThrowError();
});
}, 20000);
});
7 changes: 7 additions & 0 deletions packages/ethers/src/account-signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,22 @@ const hexlifyOptional = (value: any): `0x${string}` | undefined => {

export class AccountSigner extends Signer {
private account?: BaseSmartContractAccount;

sendUserOperation;
waitForUserOperationTransaction;

constructor(readonly provider: EthersProviderAdapter) {
super();
this.account = this.provider.accountProvider.account;

this.sendUserOperation =
this.provider.accountProvider.sendUserOperation.bind(
this.provider.accountProvider
);
this.waitForUserOperationTransaction =
this.provider.accountProvider.waitForUserOperationTransaction.bind(
this.provider.accountProvider
);
}

getAddress(): Promise<string> {
Expand Down

0 comments on commit 5b6cbb2

Please sign in to comment.