Skip to content

Commit

Permalink
Feat(SMA-675): Add optimism tests (#437)
Browse files Browse the repository at this point in the history
* Resolved SMA-675

* fix unit tests

* Fix all tests

* typo
  • Loading branch information
joepegler authored Feb 29, 2024
1 parent be9dc4d commit 5051ba5
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 62 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ E2E_PRIVATE_KEY_ONE=
E2E_PRIVATE_KEY_TWO=
E2E_BICO_PAYMASTER_KEY_MUMBAI=
E2E_BICO_PAYMASTER_KEY_BASE=
BICONOMY_SDK_DEBUG=true
E2E_BICO_PAYMASTER_KEY_OP=
BICONOMY_SDK_DEBUG=true
WITH_MAINNET_TESTS=false
32 changes: 32 additions & 0 deletions .github/workflows/mainnet_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: E2E Test workflow - with mainnet tests
on:
workflow_dispatch:
jobs:
e2e_test:
name: E2E tests - with mainnet tests
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]

steps:
- name: Checkout
uses: "actions/checkout@main"

- name: Set Node.js
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: yarn install --frozen-lockfile && yarn build

- name: Run tests
env:
E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
E2E_BICO_PAYMASTER_KEY_MUMBAI: ${{ secrets.E2E_BICO_PAYMASTER_KEY_MUMBAI }}
E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
E2E_BICO_PAYMASTER_KEY_OP: ${{ secrets.E2E_BICO_PAYMASTER_KEY_OP }}
WITH_MAINNET_TESTS: true
run: yarn test:e2e
6 changes: 6 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ const config: Config = {
// "node_modules"
// ],

workerThreads: true,
// This is experimental feature. Keep in mind that the worker threads use structured clone instead of JSON.stringify() to serialize messages.
// This means that built-in JavaScript objects as BigInt, Map or Set will get serialized properly.
// However extra properties set on Error, Map or Set will not be passed on through the serialization step.
// For more details see the article on structured clone.

// An array of file extensions your modules use
moduleFileExtensions: ["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"],

Expand Down
35 changes: 28 additions & 7 deletions packages/account/tests/account.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TestData } from "../../../tests";
import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, IHybridPaymaster, PaymasterMode } from "../src/index";
import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, PaymasterMode } from "../src/index";
import { Hex, createWalletClient, encodeFunctionData, getContract, http, parseAbi } from "viem";
import { UserOperationStruct } from "@alchemy/aa-core";
import { checkBalance, entryPointABI } from "../../../tests/utils";
Expand All @@ -9,10 +9,11 @@ import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
describe("Account Tests", () => {
let mumbai: TestData;
let baseSepolia: TestData;
let optimism: TestData;

beforeEach(() => {
// @ts-ignore: Comes from setup-e2e-tests
[mumbai, baseSepolia] = testDataPerChain;
[mumbai, baseSepolia, optimism] = testDataPerChain;
});

it("should have addresses", async () => {
Expand All @@ -28,6 +29,12 @@ describe("Account Tests", () => {
bundlerUrl: bundlerUrlBase,
} = baseSepolia;

const {
whale: { viemWallet: signerOp, publicAddress: senderOp },
minnow: { viemWallet: recipientSignerOp, publicAddress: recipientOp },
bundlerUrl: bundlerUrlOp,
} = optimism;

const smartAccount = await createSmartAccountClient({
signer,
bundlerUrl,
Expand All @@ -48,6 +55,16 @@ describe("Account Tests", () => {
bundlerUrl: bundlerUrlBase,
});

const smartAccountOp = await createSmartAccountClient({
signer: signerOp,
bundlerUrl: bundlerUrlOp,
});

const reciepientSmartAccountOp = await createSmartAccountClient({
signer: recipientSignerOp,
bundlerUrl: bundlerUrlOp,
});

const addresses = await Promise.all([
sender,
smartAccount.getAddress(),
Expand All @@ -57,6 +74,10 @@ describe("Account Tests", () => {
smartAccountBase.getAddress(),
recipientBase,
reciepientSmartAccountBase.getAddress(),
senderOp,
smartAccountOp.getAddress(),
recipientOp,
reciepientSmartAccountOp.getAddress(),
]);
expect(addresses.every(Boolean)).toBeTruthy();
});
Expand All @@ -79,7 +100,6 @@ describe("Account Tests", () => {
{
to: recipient,
value: 1,
data: "0x",
},
{
simulationType: "validation_and_execution",
Expand All @@ -90,8 +110,7 @@ describe("Account Tests", () => {
const newBalance = (await checkBalance(publicClient, recipient)) as bigint;

expect(result?.receipt?.transactionHash).toBeTruthy();
expect(result.success).toBe("true");
expect(newBalance).toBeGreaterThan(balance);
expect(newBalance - balance).toBe(1n);
}, 50000);

it("Create a smart account with paymaster with an api key", async () => {
Expand Down Expand Up @@ -175,6 +194,8 @@ describe("Account Tests", () => {
biconomyPaymasterApiKey,
});

const accountAddress = await smartAccount.getAddress();

const encodedCall = encodeFunctionData({
abi: parseAbi(["function safeMint(address _to)"]),
functionName: "safeMint",
Expand All @@ -187,8 +208,8 @@ describe("Account Tests", () => {
};

const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress());
const usdcBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress(), "0xda5289fcaaf71d52a80a254da614a192b693e977");
const maticBalanceBefore = await checkBalance(publicClient, accountAddress);
const usdcBalanceBefore = await checkBalance(publicClient, accountAddress, "0xda5289fcaaf71d52a80a254da614a192b693e977");

const { wait } = await smartAccount.sendTransaction([transaction], {
paymasterServiceData: {
Expand Down
118 changes: 118 additions & 0 deletions packages/account/tests/account.optimism.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { TestData } from "../../../tests";
import { createSmartAccountClient, PaymasterMode } from "../src/index";
import { encodeFunctionData, parseAbi } from "viem";
import { checkBalance } from "../../../tests/utils";

const maybe = process.env.WITH_MAINNET_TESTS === "true" ? describe : describe.skip;

maybe("Account Tests", () => {
let optimism: TestData;
let _: TestData;
let __: TestData;

beforeEach(() => {
// @ts-ignore: Comes from setup-e2e-tests
[_, __, optimism] = testDataPerChain;
});

it("should send some native token to a recipient on optimism", async () => {
const {
whale: { viemWallet: signer, publicAddress: sender },
minnow: { publicAddress: recipient },
bundlerUrl,
publicClient,
} = optimism;

const smartAccount = await createSmartAccountClient({
signer,
bundlerUrl,
});

const accountAddress = await smartAccount.getAddress();

const balanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint;
const smartAccountBalance = (await checkBalance(publicClient, accountAddress)) as bigint;
const { wait } = await smartAccount.sendTransaction(
{
to: recipient,
value: BigInt(1),
},
{
simulationType: "validation_and_execution",
},
);

const result = await wait();
const newBalanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint;

expect(result?.receipt?.transactionHash).toBeTruthy();
expect(result.success).toBe("true");
expect(newBalanceOfRecipient).toBeGreaterThan(balanceOfRecipient);
}, 50000);

it("Create a smart account with paymaster with an api key on optimism", async () => {
const {
whale: { viemWallet: signer },
bundlerUrl,
biconomyPaymasterApiKey,
} = optimism;

const smartAccount = await createSmartAccountClient({
signer,
biconomyPaymasterApiKey,
bundlerUrl,
});

const paymaster = smartAccount.paymaster;
expect(paymaster).not.toBeNull();
expect(paymaster).not.toBeUndefined();
});

it("Should gaslessly mint an NFT on optimism", async () => {
const {
whale: { viemWallet: signer, publicAddress: recipient },
bundlerUrl,
biconomyPaymasterApiKey,
publicClient,
nftAddress,
} = optimism;

const smartAccount = await createSmartAccountClient({
signer,
bundlerUrl,
biconomyPaymasterApiKey,
});

const encodedCall = encodeFunctionData({
abi: parseAbi(["function safeMint(address to) public"]),
functionName: "safeMint",
args: [recipient],
});

const transaction = {
to: nftAddress, // NFT address
data: encodedCall,
};

const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;

const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress());

const response = await smartAccount.sendTransaction(transaction, {
paymasterServiceData: { mode: PaymasterMode.SPONSORED },
simulationType: "validation_and_execution",
});

const userOpReceipt = await response.wait(3);
expect(userOpReceipt.userOpHash).toBeTruthy();
expect(userOpReceipt.success).toBe("true");

const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress());

expect(maticBalanceAfter).toEqual(maticBalanceBefore);

const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;

expect(newBalance - balance).toBe(1n);
}, 50000);
});
21 changes: 13 additions & 8 deletions packages/account/tests/account.read.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TestData } from "../../../tests";
import { createSmartAccountClient } from "../src/index";
import { DEFAULT_ECDSA_OWNERSHIP_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules";
import { DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules";

describe("Account Tests", () => {
let mumbai: TestData;
Expand All @@ -27,22 +27,27 @@ describe("Account Tests", () => {

it("should get all modules", async () => {
const {
whale: { viemWallet: signer },
whale: {
viemWallet: signer,
account: { address: accountAddress },
},
bundlerUrl,
biconomyPaymasterApiKey,
} = mumbai;

const smartWallet = await createSmartAccountClient({
const smartAccount = await createSmartAccountClient({
signer,
bundlerUrl,
biconomyPaymasterApiKey,
});

const modules = await smartWallet.getAllModules();
expect(modules).toContain("0x000000D50C68705bd6897B2d17c7de32FB519fDA"); // erc20 module
expect(modules).toContain("0x000002FbFfedd9B33F4E7156F2DE8D48945E7489"); // session manager module
expect(modules).toContain("0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e"); // ecdsa ownership module
const modules = await smartAccount.getAllModules();

expect(modules).toContain(DEFAULT_SESSION_KEY_MANAGER_MODULE); // session manager module
expect(modules).toContain(DEFAULT_ECDSA_OWNERSHIP_MODULE); // ecdsa ownership module
}, 30000);

it("should disabled module data", async () => {
it("should get disabled module data", async () => {
const {
whale: { viemWallet: signer },
bundlerUrl,
Expand Down
16 changes: 16 additions & 0 deletions packages/account/tests/account.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ describe("Account Tests", () => {
expect(address).toBeTruthy();
});

it("should create a whale smartAccountClient from an ethers signer", async () => {
const {
bundlerUrl,
whale: { ethersSigner: signer },
} = ganache;

const smartAccount = await createSmartAccountClient({
signer,
bundlerUrl: mockBundlerUrl,
rpcUrl: localhost.rpcUrls.default.http[0],
});
const address = await smartAccount.getAccountAddress();
console.log({ address });
expect(address).toBeTruthy();
});

it("should create a smartAccountClient from a walletClient", async () => {
const {
whale: { viemWallet: signer },
Expand Down
2 changes: 2 additions & 0 deletions packages/modules/src/utils/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION = {
V1_0_0: "0x00000D09967410f8C76752A104c9848b57ebba55",
};

export const DEFAULT_ERC20_MODULE = "0x000000D50C68705bd6897B2d17c7de32FB519fDA";

export const DEFAULT_MULTICHAIN_MODULE = "0x000000824dc138db84FD9109fc154bdad332Aa8E";

export const MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION = {
Expand Down
Loading

0 comments on commit 5051ba5

Please sign in to comment.