Skip to content

Commit fb4ff21

Browse files
committed
chore: add testing framework
1 parent 01b49cf commit fb4ff21

21 files changed

+649
-209
lines changed

.env.example

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
TEST_PRIVATE_KEY=
1+
TEST_PRIVATE_KEY=
2+
RUN_PAID_TESTS=false

.github/workflows/funded-tests.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: funded-tests
2+
on:
3+
workflow_dispatch:
4+
pull_request_review:
5+
types: [submitted]
6+
jobs:
7+
funded-tests:
8+
name: funded-tests
9+
permissions: write-all
10+
runs-on: ubuntu-latest
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}-funded-tests
13+
cancel-in-progress: true
14+
steps:
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: 22
18+
19+
- uses: actions/checkout@v4
20+
21+
- name: Install dependencies
22+
uses: ./.github/actions/install-dependencies
23+
24+
- name: Run the tests
25+
run: bun run test
26+
env:
27+
TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }}
28+
RUN_PAID_TESTS: true
29+
CI: true

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Then in your linked project, update your package.json dependencies to point to t
2121
"@biconomy/abstractjs": "file:../../abstractjs"
2222
}
2323
}
24+
```
2425

2526
This will run the package in watch mode, and will automatically update the package in your linked project.
2627

@@ -39,7 +40,7 @@ Currently the only tests which this project has interact with testnets, due to s
3940
- For tests to work, an `.env` file needs to contain the `TEST_PRIVATE_KEY` variable!
4041

4142
```sh
42-
bun i --frozen-lockfile && bun test
43+
bun i --frozen-lockfile && bun run test
4344
```
4445

4546

bun.lockb

49.3 KB
Binary file not shown.

package.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
},
2222
"files": ["dist"],
2323
"scripts": {
24+
"test": "vitest -c ./tests/vitest.config.ts",
2425
"dev": "bun link && bun run build:types && bun run build:watch",
2526
"changeset": "changeset",
2627
"changeset:release": "bun run build && changeset publish",
@@ -44,10 +45,16 @@
4445
"@size-limit/esbuild-why": "^11.1.6",
4546
"@size-limit/preset-small-lib": "^11.1.6",
4647
"@types/bun": "latest",
48+
"@vitest/coverage-istanbul": "^2.1.8",
49+
"dotenv": "^16.4.7",
50+
"get-port": "^7.1.0",
4751
"gh-pages": "^6.3.0",
52+
"prool": "^0.0.16",
4853
"semver": "^7.6.3",
4954
"size-limit": "^11.1.6",
50-
"tsup": "^8.3.5"
55+
"tsup": "^8.3.5",
56+
"viem-deal": "^2.0.4",
57+
"vitest": "^2.1.8"
5158
},
5259
"peerDependencies": {
5360
"typescript": "^5.0.0",

src/account-vendors/account.test.ts

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { beforeAll, describe, expect, inject, test } from "vitest"
2+
import {
3+
type Chain,
4+
zeroAddress,
5+
type LocalAccount,
6+
isHex,
7+
isAddress,
8+
http
9+
} from "viem"
10+
import { base, baseSepolia, optimism, optimismSepolia } from "viem/chains"
11+
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
12+
import { mcUSDC } from "../commons/tokens/stablecoins"
13+
import type { MultichainSmartAccount } from "./account"
14+
import { toMultichainNexusAccount } from "./nexus/multichain-nexus.account"
15+
import { toMeeCompliantNexusAccount } from "./nexus/nexus-mee-compliant"
16+
17+
describe("accounts", async () => {
18+
let eoa: LocalAccount
19+
let mcNexusTestnet: MultichainSmartAccount
20+
let mcNexusMainnet: MultichainSmartAccount
21+
22+
beforeAll(async () => {
23+
eoa = privateKeyToAccount(generatePrivateKey())
24+
25+
mcNexusTestnet = await toMultichainNexusAccount({
26+
chains: [baseSepolia, optimismSepolia],
27+
signer: eoa
28+
})
29+
30+
mcNexusMainnet = await toMultichainNexusAccount({
31+
chains: [base, optimism],
32+
signer: eoa
33+
})
34+
})
35+
36+
test("should have configured accounts correctly", async () => {
37+
expect(mcNexusMainnet.deployments.length).toEqual(2)
38+
expect(mcNexusTestnet.deployments.length).toEqual(2)
39+
expect(mcNexusTestnet.deploymentOn(baseSepolia.id).address).toEqual(
40+
mcNexusTestnet.deploymentOn(optimismSepolia.id).address
41+
)
42+
})
43+
44+
test("should sign message using MEE Compliant Nexus Account", async () => {
45+
const nexus = await toMeeCompliantNexusAccount({
46+
chain: optimism,
47+
signer: eoa,
48+
transport: http()
49+
})
50+
51+
expect(isAddress(nexus.address)).toBeTruthy()
52+
53+
const signed = await nexus.signMessage({ message: { raw: "0xABC" } })
54+
expect(isHex(signed)).toBeTruthy()
55+
})
56+
57+
test("should read usdc balance on mainnet", async () => {
58+
const readAddress = mcNexusMainnet.deploymentOn(optimism.id).address
59+
const usdcBalanceOnChains = await mcUSDC.read({
60+
account: mcNexusMainnet,
61+
functionName: "balanceOf",
62+
args: [readAddress],
63+
onChains: [base, optimism]
64+
})
65+
66+
expect(usdcBalanceOnChains.length).toEqual(2)
67+
})
68+
})

src/account-vendors/nexus/multichain-nexus.account.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import type { Signer } from "@biconomy/sdk"
2-
import { http, type Chain, type Transport } from "viem"
3-
import type { NonEmptyArray } from "../../utils/types/util.type"
2+
import { http, type Chain } from "viem"
43
import { MultichainSmartAccount } from "../account"
54
import { toMeeCompliantNexusAccount } from "./nexus-mee-compliant"
65

76
export type MeeNexusParams = {
87
signer: Signer
9-
chains: NonEmptyArray<Chain>
8+
chains: Chain[]
109
}
1110

1211
export async function toMultichainNexusAccount(

src/commons/tokens/stablecoins.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import { erc20Abi } from "viem"
2-
import { arbitrum, avalanche, base, optimism, polygon } from "viem/chains"
3-
import { address } from "../../primitives"
42
import {
5-
MultichainContract,
6-
getMultichainContract
7-
} from "../../utils/contract/getMultichainContract"
3+
anvil,
4+
arbitrum,
5+
avalanche,
6+
base,
7+
baseSepolia,
8+
optimism,
9+
polygon
10+
} from "viem/chains"
11+
import { getMultichainContract } from "../../utils/contract/getMultichainContract"
812

913
export const mcUSDC = getMultichainContract<typeof erc20Abi>({
1014
abi: erc20Abi,
1115
deployments: [
1216
["0xaf88d065e77c8cC2239327C5EDb3A432268e5831", arbitrum.id],
1317
["0x0b2c639c533813f4aa9d7837caf62653d097ff85", optimism.id],
1418
["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", base.id],
19+
["0x036CbD53842c5426634e7929541eC2318f3dCF7e", baseSepolia.id],
20+
["0x036CbD53842c5426634e7929541eC2318f3dCF7e", anvil.id],
1521
["0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", avalanche.id],
1622
["0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", polygon.id]
1723
]

src/mee.service.test.ts

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { type LocalAccount, type Chain, zeroAddress, isHex } from "viem"
2+
import { base } from "viem/chains"
3+
import { inject, describe, beforeAll, test, expect } from "vitest"
4+
import { initNetwork } from "../tests/config"
5+
import {
6+
type MultichainSmartAccount,
7+
toMultichainNexusAccount
8+
} from "./account-vendors"
9+
import { createMeeService } from "./mee.service"
10+
import {
11+
supertransaction,
12+
type SupportedFeeChainId,
13+
signMeeQuote
14+
} from "./utils"
15+
import { getExplorerTxLink } from "./utils/explorer/explorer"
16+
import { buildMeeUserOp } from "./workflow"
17+
18+
const runPaidTests = inject("runPaidTests")
19+
describe.runIf(runPaidTests)("meeService", async (args) => {
20+
let eoa: LocalAccount
21+
let paymentChain: Chain
22+
let mcNexusMainnet: MultichainSmartAccount
23+
24+
const meeService = createMeeService()
25+
26+
beforeAll(async () => {
27+
const network = await initNetwork("NETWORK_FROM_ENV")
28+
eoa = network.eoa
29+
paymentChain = network.paymentChain
30+
31+
mcNexusMainnet = await toMultichainNexusAccount({
32+
chains: [base, paymentChain],
33+
signer: eoa
34+
})
35+
})
36+
37+
test("should get a quote", async () => {
38+
const mcNexusMainnet = await toMultichainNexusAccount({
39+
chains: [base, paymentChain],
40+
signer: eoa
41+
})
42+
43+
const quote = await supertransaction()
44+
.injectAccount(mcNexusMainnet)
45+
.payGasWith("USDC", { on: paymentChain.id as SupportedFeeChainId })
46+
.addInstructions(
47+
buildMeeUserOp({
48+
calls: {
49+
to: zeroAddress,
50+
gasLimit: 50_000n,
51+
value: 0n
52+
},
53+
chainId: base.id
54+
})
55+
)
56+
.getQuote(meeService)
57+
58+
expect(quote.hash.startsWith("0x")).toBeTruthy()
59+
60+
const receipt = await meeService.execute(
61+
await signMeeQuote({
62+
executionMode: "direct-to-mee",
63+
quote: quote,
64+
signer: eoa
65+
})
66+
)
67+
68+
expect(isHex(receipt.hash)).toBeTruthy()
69+
const explorerUrl = getExplorerTxLink(receipt.hash)
70+
71+
expect(explorerUrl).toEqual(
72+
`https://meescan.biconomy.io/details/${receipt.hash}`
73+
)
74+
console.log(`Supertransaction: ${explorerUrl}`)
75+
})
76+
})

src/mee.service.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,8 @@ export function formatMeeSignature(parameters: {
243243
export function createMeeService(params?: MeeServiceInitParams) {
244244
console.warn(`
245245
--------------------------- READ ----------------------------------------------
246-
You are using the Developer Preview of the Biconomy MEE! The SDK has not been
247-
thoroughly tested and the underlying contracts are still in the auditing process.
248-
The interface, package name and developer flow might change significantly from now
249-
until the release data.
250-
251-
This Developer preview is meant only as a demonstrator of the capabilities
252-
for the MEE stack. Do not use in commercial projects!
246+
You are using the Developer Preview of the Biconomy MEE. The underlying
247+
contracts are still being audited.
253248
-------------------------------------------------------------------------------
254249
`)
255250
return new MeeService(params)

0 commit comments

Comments
 (0)