From dc87f3ad1f5dab045f1c635dcbe6454c8c85c993 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 03:05:56 +0530 Subject: [PATCH 01/20] Setup for tests with prool --- package.json | 6 ++- .../actions/bundler/chainId.test.ts | 41 +++++++++++++++++++ packages/permissionless/setupTests.ts | 19 +++++++++ packages/permissionless/vitest.config.ts | 27 ++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 packages/permissionless/actions/bundler/chainId.test.ts create mode 100644 packages/permissionless/setupTests.ts create mode 100644 packages/permissionless/vitest.config.ts diff --git a/package.json b/package.json index 88afb04b..1500efab 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "simple-git-hooks": "^2.9.0", "size-limit": "^9.0.0", "tslib": "^2.6.2", + "@pimlico/alto": "^0.0.4", + "prool": "^0.0.12", "typescript": "^5.2.2" }, "description": "", @@ -39,8 +41,8 @@ "format": "biome format . --write", "lint": "biome check .", "lint:fix": "bun run lint --apply", - "test": "bun run --cwd packages/permissionless-test test", - "test:ci": "bun run --cwd packages/permissionless-test test:ci", + "test": "vitest dev -c ./packages/permissionless/vitest.config.ts", + "test:ci": "CI=true && vitest -c ./packages/permissionless/vitest.config.ts --coverage --pool=forks", "wagmi-demo": "bun run --cwd packages/wagmi-demo dev", "build:wagmi:cjs": "tsc --project ./tsconfig/tsconfig.wagmi.cjs.json && tsc-alias -p ./tsconfig/tsconfig.wagmi.cjs.json && printf '{\"type\":\"commonjs\"}' > ./packages/wagmi/_cjs/package.json", "build:wagmi:esm": "tsc --project ./tsconfig/tsconfig.wagmi.esm.json && tsc-alias -p ./tsconfig/tsconfig.wagmi.esm.json && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./packages/wagmi/_esm/package.json", diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts new file mode 100644 index 00000000..febb9f8b --- /dev/null +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, test, beforeAll, afterAll } from "vitest" +import { Instance } from "prool" +import { alto } from "prool/instances" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import getPort from "get-port" +import { http } from "viem" + +const anvilPrivateKey = + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +describe("chainId", () => { + let altoInstance: Instance + let port: number + + beforeAll(async () => { + port = await getPort() + altoInstance = alto({ + entrypoints: [ENTRYPOINT_ADDRESS_V06], + rpcUrl: `http://localhost:8485/${port}`, + executorPrivateKeys: [anvilPrivateKey], + port + }) + await altoInstance.start() + }) + + test("chainId", async () => { + const bundlerClient = createBundlerClient({ + transport: http(`http://localhost:${port}`), + entryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032" + }) + + const chainId = await bundlerClient.chainId() + + expect(chainId).toBe(1) + }) + + afterAll(async () => { + await altoInstance.stop() + }) +}) diff --git a/packages/permissionless/setupTests.ts b/packages/permissionless/setupTests.ts new file mode 100644 index 00000000..bf1b5070 --- /dev/null +++ b/packages/permissionless/setupTests.ts @@ -0,0 +1,19 @@ +import { createServer } from "prool" +import { anvil } from "prool/instances" + +const anvilServer = createServer({ + instance: anvil({ + chainId: 1 + }), + limit: 5, + port: 8485 +}) + +export const setup = async () => { + await anvilServer.start() +} + +export const teardown = async () => { + console.log("teardown") + await anvilServer.stop() +} diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts new file mode 100644 index 00000000..010d402d --- /dev/null +++ b/packages/permissionless/vitest.config.ts @@ -0,0 +1,27 @@ +import { defineConfig } from "vitest/config" +import { join } from "node:path" + +export default defineConfig({ + test: { + globalSetup: [join(__dirname, "./setupTests.ts")], + coverage: { + all: false, + provider: "v8", + reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], + exclude: [ + "**/errors/utils.ts", + "**/_cjs/**", + "**/_esm/**", + "**/_types/**" + ] + }, + sequence: { + concurrent: true + }, + fileParallelism: true, + environment: "node", + testTimeout: 60_000, + hookTimeout: 45_000, + include: [join(__dirname, "./**/*.test.ts")] + } +}) From eec1779232d42193a51fb304d237e0fe190f5c05 Mon Sep 17 00:00:00 2001 From: plusminushalf Date: Mon, 10 Jun 2024 21:37:04 +0000 Subject: [PATCH 02/20] chore: format --- bun.lockb | Bin 534328 -> 600256 bytes .../actions/bundler/chainId.test.ts | 6 +++--- packages/permissionless/vitest.config.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bun.lockb b/bun.lockb index 4e96d83c2d612c9b650491b7f6026992eb6cea79..399f957d76fb08fafb59824723686ef0fe5b2ddc 100755 GIT binary patch delta 150198 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

DR>jdqkZujF98Bg^TRt$abi)tXDj}H9aa0! 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 delta 110612 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 Date: Tue, 11 Jun 2024 16:52:37 +0530 Subject: [PATCH 03/20] Add bundler tests --- bun.lockb | Bin 600256 -> 577776 bytes package.json | 11 +- packages/permissionless-test/README.md | 29 - .../mock-aa-infra/alto/.dockerignore | 2 - .../mock-aa-infra/alto/Dockerfile | 21 - .../mock-aa-infra/alto/alto-config.json | 19 - .../mock-aa-infra/alto/{src => }/constants.ts | 2 +- .../mock-aa-infra/alto/index.ts | 363 +++++++++ .../mock-aa-infra/alto/package.json | 20 - .../mock-aa-infra/alto/pnpm-lock.yaml | 324 -------- .../mock-aa-infra/alto/src/index.ts | 424 ---------- .../mock-aa-infra/mock-paymaster/Dockerfile | 21 - .../mock-paymaster/{src => }/helpers/abi.ts | 0 .../{src => }/helpers/schema.ts | 2 +- .../mock-paymaster/{src => }/helpers/utils.ts | 4 +- .../{src => }/helpers/verifyingPaymasters.ts | 29 +- .../mock-aa-infra/mock-paymaster/index.ts | 72 ++ .../mock-aa-infra/mock-paymaster/package.json | 22 - .../mock-paymaster/pnpm-lock.yaml | 765 ------------------ .../mock-paymaster/{src => }/relay.ts | 0 .../mock-aa-infra/mock-paymaster/src/index.ts | 54 -- packages/permissionless-test/package.json | 24 - packages/permissionless-test/src/types.ts | 2 + packages/permissionless-test/src/utils.ts | 91 ++- packages/permissionless-test/tsconfig.json | 17 - packages/permissionless-test/vitest.config.ts | 26 - .../kernel/signerToEcdsaKernelSmartAccount.ts | 4 +- .../actions/bundler/chainId.test.ts | 39 +- .../bundler/estimateUserOperationGas.test.ts | 104 +++ .../bundler/getUserOperationByHash.test.ts | 182 +++++ .../bundler/getUserOperationReceipt.test.ts | 134 +++ .../actions/bundler/sendUserOperation.test.ts | 134 +++ .../bundler/supportedEntryPoints.test.ts | 38 + .../waitForUserOperationReceipt.test.ts | 134 +++ .../prepareUserOperationRequest.ts | 4 - packages/permissionless/setupTests.ts | 90 ++- packages/permissionless/vitest.config.ts | 3 + 37 files changed, 1349 insertions(+), 1861 deletions(-) delete mode 100644 packages/permissionless-test/README.md delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/.dockerignore delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/Dockerfile delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/alto-config.json rename packages/permissionless-test/mock-aa-infra/alto/{src => }/constants.ts (99%) create mode 100644 packages/permissionless-test/mock-aa-infra/alto/index.ts delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/package.json delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml delete mode 100644 packages/permissionless-test/mock-aa-infra/alto/src/index.ts delete mode 100644 packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile rename packages/permissionless-test/mock-aa-infra/mock-paymaster/{src => }/helpers/abi.ts (100%) rename packages/permissionless-test/mock-aa-infra/mock-paymaster/{src => }/helpers/schema.ts (98%) rename packages/permissionless-test/mock-aa-infra/mock-paymaster/{src => }/helpers/utils.ts (84%) rename packages/permissionless-test/mock-aa-infra/mock-paymaster/{src => }/helpers/verifyingPaymasters.ts (96%) create mode 100644 packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts delete mode 100644 packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json delete mode 100644 packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml rename packages/permissionless-test/mock-aa-infra/mock-paymaster/{src => }/relay.ts (100%) delete mode 100644 packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts delete mode 100644 packages/permissionless-test/package.json delete mode 100644 packages/permissionless-test/tsconfig.json delete mode 100644 packages/permissionless-test/vitest.config.ts create mode 100644 packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts create mode 100644 packages/permissionless/actions/bundler/getUserOperationByHash.test.ts create mode 100644 packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts create mode 100644 packages/permissionless/actions/bundler/sendUserOperation.test.ts create mode 100644 packages/permissionless/actions/bundler/supportedEntryPoints.test.ts create mode 100644 packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts diff --git a/bun.lockb b/bun.lockb index 399f957d76fb08fafb59824723686ef0fe5b2ddc..201f4962924385b11c77b7717bd73d02fe4f21d7 100755 GIT binary patch delta 177431 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 M&<2rrO>N%)1E+&M82|tP delta 190934 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

<8?lQ-IO~ zC}c2uyq-HvuggZNOXo>&k&Oq6-6WV_dP2+^eA$r*qi_r#e$j`=_^@g^w951&yD*%y zu<`jQ^z^cJ=gibG?}dCdaxkv4p&w<;ehk{o!-u&TRq@wHwrm<_q4x+s42S{5_>+wN zJpmuo`0#cTXRhw|Nx0VJ?KEn6N_Lg58p0+6LcCF#)d|YEpEX^Ac*^#CV*Z0UlLVsp z9f{Y4VQMb;Y- zY}Sc~`gqUFoU;aQzSL$iAmpz8$R1tyxbd>xfK=nV^N_6ps2)H*48Wope&_!9}(OXcH!gWd98`T82(H12f#S+zQEdk$n~+6Wr~+ z`a7r5H64B&Pg#|3f~apV7;e_RVwj->agj9#1hGisKvjJB#+^NoW~DZyzas&mXd&}a z<7Bxo8jvAfnwXLj!R z{q9r^)yIDFf>`JUSrq(_0cqE8@du% zb`Oy9fV6%X?o&5&-vJ5Y`7fTV=m%rF^px#ISVBj4R$n4s|JlAO)noEK7y7tXgr&V) zT}XuE=D)rTCN(G|GImU4uq?o;qx-V%WzQ?*uR$AyjqFMoj`RMjQL%G*7Df@a6h-*R zHe}c*+gu-`No>loqQA(~1TPbVbZfawtHB z##P|Gi}`Xn9|=V*`ny8>G*qYazBBqnB?;?06k*%&12Bb1{E%-yCNMlaEOxl;9ZS1r z6=(Mj*yQiQj`qXTAq~MAmwCZsGnc21SIGVG3o$DUe@*cBRinVbGtPdc(T0w&)M^hP z@fiCoPTa}PE_e(G`IX3_Vb%D&f&ZIT8+xCP>nk(@$c05I;B1Res2Nh6dL#Kqw504o zafmc87d*LE&YO}W?~XpJeybsMjU*XK@pvpRrCD}=t$b@v;)?x7@-Dz7^{W1k#ixM3 zqQ}Lyq;QoLH}zRo3gl#M)! zwqk(twlp&w##vZ@DI@3IA5W7ke~-T7sX$f4sK%NN!yO^rgo%MQ?`8iR7sy2F{SHBr zAc=L<=>Ot3-d4QCBZtYQS(j(`V(E-^Z!k%iK3Wmcg8w6tP;3!@M+rZ|J7YP&0o@(& zH9? z0cYY)=2SN$b(&+gioq_4Vy-63;lB&rZgq=^jXSt8==N&6Dk$pzj58CkPZ|C9kKU{mRKJAX4e zKVjVwVUgB;3rbFur(KLIf5()fOHkAlxXDDRmJn#OR_XSEieZy#s&(fX|FeFIxeL_i ze@KDoj!3ls7cGmhmJ$_3d-#VO6~^yH8t7b$A~=QF4=EF%bAd$J(sy!`lDE8R(86em zu-~YOHY%hxRqcJjCXzZPn#6IO&OVg7*f^-&ez0vPXqF@DH9zIbO0PBI!Jt zx^pW<$ke9AMSCwQu!Y?hMUXh7^S7euXmMcCLfg?Mq&pgr%q5J9Cc9o@fkXphLrA*q z@b(D74)bFATcgRFF)2r-D(U`US3(-gk@UCd#-sXe$2yr*WJQYWgi3cvP;|Ac))V%y zE9NORRO>d;X+OWs^I-r@Tidn>IdOK}hnCimw#@#RMhde;a6z&~K8cnA+>2xLD@BFnYONV+ z9#Y9g&Soz{y0RhOYeIfthC{2Qp?AM`kQ#f)!U3Ud)~Q$RejdDeS4cNfW9PrWvO9~g zC8Pku7#M9w?%K6sYXX(d@?<)>tao8Xi;*Hv2L=V$U1Fad?%B`tQXz)=4j|;*&#%L- z9Jt#gMIk>g;<7|roQRi9p*uPt(SiR^;_J5^3n89ND4x2olZ#Po@y3NYECE%zQ{`d} zvA&a&teq>112R1(b>R}u*P_0g5DKQ{o^qd zyA)5>(Qz#uoRoBSqncex)jJQO9D|)hq z1h@5Mk;_q%A_@*~!=(IwSK1qz;l&jeScuQQv)?#9t|lxZF2TFVbf+_Wpbcg9o}JEF z7}L$JNFGg`{qNm(O8JO1@!QfpbV*5`p`Z71;@g&&=Da;%;MC6P6k$Oi{9DH041j@ai!Y81-d%Ubh!B_D>PZOx*F3DL^P* zQQxe7s=US0CYq8OWiuh>T~;aSSPyf@B^pR=KqzZI^USV|`_Js%Aok|u#vfENkG?oE z?EoA~*Uav^?8Kmb3|SLMB9(>6dI3U8eAmEYlH%)Wij+kNDvq;OAt4mr7dgQj&6w9Z zsKPU#Q@XCvvS}Uen4PthssLE{T3iCo^b$h$BMFOsJn-&40G&}S0!osyyx7{cTmz~P zxar06H*uzw@v-FK{Mdk;X9*iQGwXlBVZMKIDyCio;)IJV{C;5+0)7hz`7D1OS4zhN zB4`z{-5IS1cCnfV)^k1gha$zB-3L&$+*`1ZKH0syd~Vch4Q52D54uDfrnlW&&ITZN zYJC`}#K}fOzW%ZJP9mk&sB#eYL^yj?ob+aK8_?%PAktz)%p70-k?p~jJj=1S%48y! zRd<154vg?CyAtmk%wH&RxsZ7YAm9U#$S~KRRHM}GS{^tTl9*R=wIzsdhU+yK7Ixf( ztU))nw8Rmb)JEHqD}~ArVU>s&-31=H>qaVKNSft@-Pb;SGfw~?q#FT@3L2IO`87g8iTN^I{Y&bkU1@!O>f|JS8k(n8Kx zU8$aPb=G&y#-1wiL^p?Z^HHeG(KaK>W*3!y@nD?AZ4(Xvhy#V9EuEUX`YWX9{B__h_hr;yCRRj7q4;RkxzGe0CRUe=0$(S<TZ}xj{ z(h{J6#Mwy(N*Au7qPE@SUl?ycycmMVp(uoE(=eNV&p8c#^gI z>eMEztDH?31eu$Q4>p52^PvaP3mu`4d_Br5#@Cx_OT_%WR=*w>RUBnHQUjR4GxSEW zK(%{4dh{6<)lAbH+$1(2L@1}o9ZYNZkrjmEZ@*8>cM$#xwG9^jTB{fMX=$lM5J}Zq zh`_fI3K1;y;M1|cG4TYg$NxO4mP3BAd#w&G-$v`%I}g#CS#)%$0w!rc(Wc;7IMKGS zsnAVW+L*4nU#9+4Q!F5o;@J&HCSap`Z=jG9cWzgecFl&gouolY1ccV0rmdNKmAGz2 zWN9NBZ$)GIA8h$xY+PCnv&CVuf3P?#jvgF%)*uvxky=ld`H6})zSAiTOTPXep{x6x zd*0hw)DKi9ya0qwQp(qyzaVu*sn#GBElC%37x|L7+*^sbQ+HYRZxb8-#M1xp5c@wm z!{*Pzie?*%#_+o0jG`gVZ%O7O3f+;Gl&hnPiQhyQ+DN1LKvSb6c2JlvwKUn=B^c!B!7tippo_Me@}%RX$Pr$nTU z)}#@SQ9Nm+XV_QHe0p+DEVLnZ@J&6jf5OQ-*%PrcYOfu7ValdJY1@lyZI=O6+`tsu$bK-fmwdz#kS|L6oxGo@=3 zx?{d_0dh98A6ym-e8|KH8*RRXn!g5G9Viw0b9GS`#TV?B@Nz7o17l)CM#O~27#-R7 z?rUFMh=_-4gF6E~`y<4{>k+Kjo&KC_N&kqo9Dtu!V}Nl3um>-g$2%N+8bMc-_?44Y8z}VCEZ=B$of)o(U*VWx@zgA{KWD9K05CZ&hnyZh zFlugqT@O>^4O~zk<~0zW*x_JIkG%h~Pk~FmfXFa&#q|*8x02MH}Q#kh2F1X-yW8_243H@Q1)`Q@KC`@EO-qbnj!kf5{C0Lj9U@oCg+5- zWX|&`xDwg(AOyg2c~9yoX2k?i>%SX3di8mdT)Wc&9*)b>QN+`ZT#jzkF> z^v0syw5{BzeU`o_hcF0KABTBw10 zaP86QnhnDuX}c1h^KF24G}9ha-nT=*o4iMl`FN9ml9cHfR*(s8as>ueZSCsju<`7s zq-cd4Hyy}dkof^(OKlSk%k8N+0?90-Aox^Aaj7b@>yv1 z9rQ=}w-0*C-4U1Cdk7a-A;~fkgAF;$`Kd;a6%0Vz$s<4cPfWkSs}`@`6UVYEXE|U0 zsByw{`=uNEF1Vc>OBg_aw=oG2a=FY)Z)LM5e4Y;jH>u4aW z$1$VxC@n+to#R;aIVjE1ajY@@oivVZ%)%3zbPR|Hsa2eiT=G6T!mItjpz&h2fC$~1 z>p2RY(!S)_CysfcKSd#|#1A5}9*|i^77n$x;|1bG_s+go^4H$%^h5Umg>4kYJCWw0 zipCqsDHZm0Qbw(u;{ikm9$bNe!`PC|vNIAcVHdUtf4Q@!gW${Gb$9$OZsHhd(`SmsJ~eVE8u? z;^ZQW2ZT;LoCd3`pH>c9B|>0;mrP*(*?1-=I*x=a(mapvH9q@SRNQeOk+@=>d(oWq zVbJjwy|$k$w?iZK*?>@+?FsucmR8+WQ3H7l2$|ya{u`a#FV2J%NSdNQQE1clz!KjL z7h2XLNGVbxcKlW4r@9uUeimfe48qFdA)cm9PQeDcyC5K8afe_@t;ed9UWP{nv^@g$b_80MqK zWPz1;C#-O}uO4?D7!XWaGSA5@6&UIkz@TyCM{ag$+u`dvks=J-2@v9Ir%5p<+imP~ z6%f%e5N6}6y8DNq8k@T9XV&GMwuo(=@O<1qnAc5I7vUphi+MfeOwVe9Om3v9egp8#gHViHYMy3qR0SQRMv%j#trF zBt|0=zvUK0e%hQ#?56xOT09C6{FfqcECG|ryP6cn;?b7gxj}tMl#8#gaaKU6X5EBu z^nJQuz;9hEKX!HZlX2)9nngY6&k$UL1lJ|QzL$Ry0Em-tSD-u~bwJNKhn;=GJPfzc z{rZ^99MIx;KSHbL~wVK7QP}Biu;72Ds)_fuiMw0Q~gW zyPF8_t6bIBXI1YZ`{m5MZgJ*~_&2zRMa6^+42zXDW{;m_x3Lu*PyWFJRFgh9BvR(_ z@JxPCck}){+5ANY6tO$L(l^nAAhOxFIBSbhNrIq#ZnC=LwkUf89u?67J9>+A!o?sk zVH!|qLMh#EoLYTn)MgXm{2r`dki;BrgMk}>L8nL&QzywDx7)oC7>JH};{*t8p|!*F z+qSN27RtB9UV#HlKuD7>PhQb$!1R2Opeb6$vy~K4tP9Aga%ARp~}ndW;W_JOSbNOOu%byZ1CS z9X2z==T9EO6ITlmBeeNdH7R;==iL1~gtva~B4pg{j!t{ulrOS_wg!YmqUvtnMfX=K ztPU~TE1Zf0g`l1#-qbfoRT`$Jg(dv-cohB>!-R_(?Hkoa z0|^C$gA^fqD<%efDCXXy%*8CA*iUyBvuzKs)4yCS__Osoym%O&cI8Ydo(JHptke?0 zQQq_9dCx}$n+r4$+a>G=+NwN(LEGuVZ41tie06cM2BYf|=J=5O2w;#Key^dQy6f8( zQ5uYyfK&$LboHE#``4e1*FZKeVe!;93mCS*=(Y3Z^Z^wPP0?WFioK3oy}aG%9yjr> zY$>r@b}7q3+cveA3Y7WOm(@(Yc{4zR;hiejgPWEvPGw5ZrXwbbQ!wGqfEZ!CL!Fbd zV_jS76NLHaB66W;(0Ob8;@y#bsIC~ihIPG&U`x02`g|fA{S0M@E3P9p6VWYn zL`cqL!%PIP)M4GiM-Twr@rchl7JUOw;DvR}510z+d*$^k9lxv6)(gyD^5jZqu2HjiEpW;% zVHE3Abqtuaa@{TW#u*lDM%G`#l&HA0k>w$pQS0vW5&9s{>U`73KMp7ln`rv@Jv|av zq|wCh{{Kx}%TFFol&)1PjBCRX7V8Q<{%3Kmw&=Amcvbh?Brs-W`E_s3pI4vNM7_G@ zv1l-baD2{X&LUJd&Ht0|^j~RKWNu=)*$_GeavU^A&ore>FyRwzB)cC^SNnx)n1A3LybxL6Pd6r^peD2_bzX zghVzL3CxQiQ&?-ZXq%9sn9xXh#S5wM)xovv=={Vk!_$qd!Mlg0Y{5R*VG#x+NzI; z?sggreZe_bEHOKF{v9sa-g&{5@%@C3Ddc-IZ9?7cwYFVAb4o8j5lZb40+*hC@4gP~ zZ}^j+fGg$aDgr_YhA)5EM&4eMehU!ne&CnIOBC+b1eCV^#t)nJV0EXFb3;df*aBPa zVE!*5I9-52(cj+m&&i5`ZD{{QYhu6+0s*lU|hV$HE$uyz>D}ptmp; z`Pg(fEB_kp{dNnA7{4NEU4zHr2utH>J;3qbK29!Qg%#8Ks4G67fy&n7ues(mjO1hY z2(DMj2ReyEp)$E%9v(O^J`PEInzn_)b}u{lmaD7px)-iBt9XbrEz^WPf|ue$vQd$u zmYv6M6eicma=#Zj#;}#fAmM$qWAmU`c%0j|Jn%wlMM;xY`-N2*-|Aa%#RU;CK`Ho! z`l%4eB98<6 z7W8C`-rz7Z_29yM4FBgrmYt8E4 zUA8+>f7I7TtB53MFBnoLUGQ$aGde7aigp;JfiSC=oRxWX5q|3Z&+E?@?t>0m;+L|- z;7Tm6BUdJ&!3`nE7-!MwTiDdDbYRLqpVaYRv@9Nd7=e3JhHW)oUNP?k&m#Uv>B$V? zsRRFbj6eEwk(nM5)?kpV>BX0|Z}L7A=8yozsS6OLr;a^HUKlak1u+`biS%6N1qkgw z4VomEs{Zx1kO1P9r86M)0h#mH+L-iDr_%X0ymJ{32$`zr*8SsuteoSm>8&^$jpWHk z^q|SSxFrY&4i1k0^%O9JtKyg$X^G7%clANKn_nP6bj$$DUu*_F{-Y^8!a!tSMtj`N zv)XN11_Qwg6RW-eLe{e59{Gg0ChCoVP{z=S<@@6rnKZeWkig*K_F=KJP5T8NI4Hb` zOzl8NO*loZRLFxhnSy%sYu~wC=mz7_{4ji&p9TmmeaaHARol;)p>zlY@NW#s0Hh)y zF%IvXgMW2T(?E2uNN{ZI@G;RLGS5%L4a<(1&jxhk$|mR@;?z-LY1>R+TJGVo#zNf9 z=l^vNp_^kE8fjgb>~rF`@6}?v!ItnLT>_jtt)+R$q`GT=_8>3d{}Y~Rla9vN1+g2= zJ|=Ac%XTIuI~nSeV}R8pYpvzUGW2YEK!lndi-gr^OP2F-TI)r-GA9caIec5Kr3r4d zFY4e1n4w)EsGL$u1pq|JLGH-E?PRDE9i;ztTo8*}dxvf{9}~YG^B~Uw)M}|Xr%fEP z?6XU7qe{M7=B$BWt+w4clxr7T-%9F@WgNh%9&Zy-3w=V6-pzJBSAU!Gt2&S{c^Xnn zVY*1n9DjjjuMBN1%TBC;f>p4aZ=+iri$8spwR^{vaVg}}NcuSMtsejOs4;O0>>(yx282#W13Z0(8?OrX=gHuw`UVi%6_*ZtcxiTp z4aWe%@3=#%E_t2@uZhoP=a8{6im;EOmJYBI56OqbD&Wezlnezkn z_topKfdrou+H7gs$?@CrUo%Ar@^CVv-ogW-YRT8O8oQ_IJ4}#HDp2@V3i(XQ`3cHm z`Nug^Tda0TPnaBG>_0N;fwu{G;4PnXI@hRGBQ|aws?Fj_Uyv#f>LZ*;+TCu@zgB;{ zXMo@YpHws*bkHt)=+e`mjj_9@ifz!Z?q}la=#8r2r=Axqd%MFe4bFa_PEHpU*nxiw z&a*iu5vDtzfz!3>Jo7t)rK)~G&{m(Au2t6eY=k&VV(Q`xto|urYz79&&j*Lv<$kOg z_=E3|_YV$UU;)7JKMM@nO6yBKNc9Gk6QAL=v12uD)F*&f&1#CM^v|!-!Lv; zwF-#v&UQQk2A@qv38#|r&u_NrbZR7y5y_pwT)H)NsYKhAbC@J2t#5h);aZ=+)*+W>A#?3<#}| zb{nv8IcHv4JZ#!}nXNu9-s&zRNzD8!tmz5NN*YMeKMRws7|0lloIPkoIiqLGzF;6H zcHuZ@t7>{xNasx4nqxda;mtmtL%b0#)`w~XFip_M*eboEqYvDp4OFy*MKEW<J^XRonryq{k2)sRI$!1Jeb@9Vp=h7a_u zm@WOINaKvFOFdLT#*5~DTItVPJ&!nAitb9`sNPXl&64GR0bQP!%ocxD9e_#Nyu#Y? z;N=&=y)~FYmTbjmY=|R(K~Y9I^Oi4GY#Vt>gOMbTa#WVry5Itx6K#OXBw|UB*^kl{s+fGzV79Pg{+OtLH((F} z(@Jd_JfLF3(He}wV%zzRa;puQxn!CK5(fxPH1o;ajg`z>f7U=|S+T=3{%R|hi{90H zL`=1B*4|a~c8}FyYJD>hFVeUIg4>-Yc($jTOzTx8{z8Y=t4chidk)L_hOu?u5Gwxe z7$f=M93fD#oy6*Y2mR7*87du1&tU=hO??$Ov>t}@e7aVgd;@1U(l+u+gfuy6P`iu4 zDICK{5V0R*Biyw=FOv7Mfb~NhmH&%!Q?nmjXxZm2l-LGjveQ0FcKd>X6Pl z-)XsDZ#FO<7V+e}cQ4i(?Go&_3Qx{HJ!9vOWB#4iH^KKZzNYlrQ;tM2Q4XhUA$QzYRjC}QkFT8?E32`?hDu-52RX8F<&=$jQ4}|P(AdD> zsF+CmQGww@!=r)&!|kJo4vGjI6c%hBJ3J;Va!_hBc|9v?%f$nsKaYEoE8OudcF6 zA)sO5C%$Kn8P!vkV)tq)OS8%Kly*g+{`P45pdJ=j8dq$QP!m0S*H>260w~QE)KMBS zpp;hFyRt-mgBmmo6BbYtBtEUJG%^f~iBP-RN5qZ{E`m^=VYu2wI{edKSyTA>cOHhj zSV`&1)~J-`VEZAJ(wCW@$N2lql`2-+MmeDrVsR%n(?)5_yes3kg34fAx5^mzL1m>W z>s=j#|FXdx4XY^4=pO?%i~xIW!1PIkSH3d1Y-Njo8dOnMFo+0?j#aycgtIx*0bEuY zXicf)%t!el=C|T*l=GbAP zt!Lotg=$JGHYiDnXZ_Sr8VjFt2swN@egoY~<~vo{imjZkY|B3Vq3p0(dok^AmdYIfhwz)Zl!?<#ha2u-Vj`T5O+?0T6&>P8tW9oR?kRqaZZK!Zj2O9*j zfQ@qP6@5>!A|NV=!u$6=b0!n6?|b@v;p}pDS$plZ{#qc#E*0-E)^jRwmKERo*_1nlrXB321K*!#Hv|RGSoGxR+GzQbD1G*S}k;Z z7wCIO40uNhtO6>!220-%gJDE@crYD`W-F;%JX=ij;#eVFtie{Rhy#V?2yRHgcHR*K zZp$jdnCB(1Qmr688WcvsaLS3{*>rL~DDp%sCL=3fcm_|K;@Rz5@`(iYC7lSzET2qd z%V=B_gHl#sjWU`@xVv^WUc$jWXVpWDpI$MMN_h2!rps7WyCR{i}Awy=l z?6x`@`aK5qK@p3@TXQ(e4)ZkFiEo8N7vNn0FCY$0iH`+`V7lg8wi+d%Iv)Z%GVHFY=J-M5- zdWza&cGF-Zn@{aef!E$CVR;+NAszoTvVBzjB}n&a85ZDqBO69{l(B(y8P&YurI4t! zeFS*&ViHT;&fTD4CgHox?h29q~yjo8~ zgX$DYm5!T0mFTZoH%h#Pr*8O*t)>$m@Op6#n{Fue-d)4S8))}5&gj3Vq5sRjupIC8 z)7fH(u4z1nN~eO9A=BAl@8LRDz_oO=1(H1aAf(-~NU&}Rl^j9Uq8i4$qb+P;7`<~P zIFh2?;++2HO7KWpYk=T*cNgaUg@J9+);qEb_L^fUkEOjq*ho{lu~hHv&8*Ns=fYW~ zSMYRK8L_-$D$f$TH4oqImK;D67Gm!gEP%|iEMN&EovOp`bOTwLY_%Q>U`VavvU{9$ zs$w-c!0f(!ts3wbz>?ZhXYtglb1N0M9T-KcLD|VHEw57+HeBaA3XWmHwwF&s2%>Y& z>+H6|zv?PTrR(~|=sNTMHtzUtP5f@u$7yA+H;?Yw`o$Ac*9QMO0EEd)p! zwM>V2NqdZ~GI%%cV!fh3hrV>^1y<~}y~y4HqsM?J|9AmXx{UVB1`QS@L0*h{5fdD^ zpY_jdvV%eDl}0m8pll8HQXyx`#Gi8Ur!T#^pQU+s?`IVTihT=w8Qjih^IEg5*ri(M z(qaYyFn$=o(~s?F@ve5(n+hE~P09mr(n0nu!+`oz&=K|-^ux&`Y`6FOH`t9`=-C^w zM#tU;?al9CNndL~+ehC9u^)X0BIcJUNO@Vhay3}L`%!e0SPp8)DyJ?7N08$vvjWtA zew4izlmg{yuLs-)`|6L15T7MrECUxMd=5?39}D!0E-O9qs?od8G447U2~xr_9C zt?u78qtvSor&GG@66?MQTZnaWz0u`E_fPJ%7MRhvuPDtK5yH(Cl=yz2}_9|C% zT`|m3RX#METvnl6Qdz4F18;@lX5jg~|L#Q;|6Mk%ae+=V^G2A~L^b_Fe7 z%d*0OTTv$AYdINeS#G8_ZhhD&?3_Up5?Ou(e#jOj_^XKPH8F#EPI6~*RiIeXt%9E1 z$nsOJqE5M9TuwjNu>AC^ic9t4QjFC|ZHswcdgs;9D;Pxu48dUK*&+Vrq$Me=Hy|pY zXAX@|Ws0Fc&G~>WKv21aEOe}uCsD+Qte;frxV#Aw5(`l^;zQOVuX411$TmZHY4ZNA zCZ0(#-#~+H{}@Up;~Pkdr#^+AM_vzF@Cou>{}_rO>J*DlsL~GlZ6>#Qu8K9SSMggT z;>DiS@-g)0A5A=FTIWi0%}%!m5a%|CXyHn6bucm3L4*xxtx27!NF%+$VsBPdo5$+X z{Rw8<*AoHyb+^utWp%%}pkEbEDFr(wtz>1bA*9 z9h%FB(%`v#7R~txBv{(a9dtPiHr;d&fJN0D{xMZdfKy@bn-JqWJ-k;u&J`f<8I|BtJO{ab)9)(}15O=E3 z3cYihCDGv1j2T+VJ`L*$u*Ycq&%llHY4Fbg5}%)DPtv6EV1%c}^IIruGEA`7r}Esq z3MnpXO|`0}7?TAwf?|}!b+uY+?G`g6jyAl|8eT+;Zs7x|vW7>&{25upZ>FV7FtPnL z{1}~>#$Tf~<1qm5Y%tWCa3It>y6~hVA5yB)IswnX>EyOM=~n|Urf0kGUcp)swFNs>)%1V+y}tuOjn*6EzWd6OQEaePee)?MFYC=Qb8)r<7Qw2In}OW zRlbkM1iL$VCDk~2PKdC86|22&Hm#b8)%$HGe~R99WAOJmd0u{%%WSjTX1R(RgrF1- zGN(&>1MWb02o;I?g;1n>UECP!^HoXqlVvXY#D)1^=jN-l73FR|n1WoK1V4|3ClIt_K4qzzxXG4mh-E+aFc@+Fd58vV_#Pmu)TOty@G>oT zNE7d+gEd+0cL$br!cEu(2hIZ^?fMvQqG!!KzEh>=a(H5_2rj}hND-jzIr<=n-{QyG zsh7cQoBjf@84wOX_ltj`B_QfhT6h`!vZyz<9R4KG&%HpPtqSi!*Z1VLlz9OgB0io+ zQ_KbIr0MxQL(5YOcp;7c9WYc@IaZE$SM>mg$>hmgto*TScqr}5=jHyqK3XfcMt~(` zdk@8eW7{raEb_JY(|HVhfLbe@7Nj8g!$p*SkpP#-Pk-Raco74-KLITp#eih;$4Ja* zOHaM?xARb0ws%(n??qcLz)5mC3A=WNk;hRwdfWIrCXTFF8uACk_Ge{q{k+(N%coG< z{yX?7vH~ysSc!hD`6xg#mLfzI+i*;6{BL;e<3u#K>;j%X&4PXM`tNueHJFEQ6fc|^ zfZ=p405Od{u?R6;V8W)^}CPo_XNpA+L7nZcv9C%Ob( zCtqtT|~*>lvzS+ zS>faH$u(pOaV%vTQ21Xg%D+2i|Hb-5xN!IiAB$3}x=lq?@-Gll*f-Jg7mdW`0wyc2 zvzR4@q_=}1;Z_7guuc|;dyxVBf?t}B3KW*Df5Ahz$-pzwk=&m2kpTWcxorP+z-NCWW)ljNI@<4?y0|6HnzGZakUcx7r+4-_F=Ga0wr$vflsB-E2t$s zC2~e(Mx(K$Z)HCkbcL}4 zCe(n;c>Y?Rt2zE)YF`U($r;K^VMFz$$wT?0cra3zVSJt-38RtWyg;8ADyNa_TAl~w z1-GGmdl*FI@Dcng+MT2=E&RcM!e$by8m4F;>y|S0N-*zDr~U*vWV;cJkL0lCBpjd} zjAw*70jgRYaFA*1oaVj4_zhj@DaMQR5$K(8`XLhwAzgJHd0?@DSLaDC9Nr(ouA_3z zK&;>O1K~30$djzx+7En=r-Xol_1WAQklZ_*3+Il;4ZlY5J)MSzjZzg*S?;2o0nlI_ z9bu0Z!LTl)@k97_!nTVcblX#_QQZ%c@ZL+igW@Dxe=1!_1H2M(`}$M$TGf!+%6zf{NY!TuSDsvkr_ zL!6K1eQ51gtd$(ls0`4nJVU1;@=`Qu@@5L!l~Y^P7kM+w&;w)*qv|w_Yj8IH=<I#pP-uY^6gpkU80#;Ls zYcRaPRC05j=?+o*+Yo)pWip}=;&5iAL=13n!9kG?l_E6)l!1@CWX)Tv0$xlJ>SJ_3 zXV5Efbrk`?bqp(kpp9=A%BM#_O=u-!V5N52yt1uCRiDzmhxIbAt?=o zph$yip*7eUotg$7k-4FC?e72wg*l*xq!qMrdBF6br33e*RNsd?&k4$XaKIZ<>rWjH zguZ7g{8O?~V1j|2x(6nTrK}1}dRqmb8~`EQLjUQAA~K*^AdgTg$(AcC8AS>siARo< z!Di66{iFz=$ne4aIq~2UNgnLV5nU0@X2jtQclfrZHogwbgSO)R5Jlkf^aD~j3&^GSYy7e*I{@oImPQSCK4 zrDX#;F7#1f<^fYi)82txp>aLIpZ6O18?>r7gn&e$cPe}k2D~E?29L}IK<%l?hi`jv zW55UjUpGs^c<*(5Iz4v@6DiC@)4*?$bn*hwRKq18!2_3I(+x?(Tu)!eCwfO;&-(@i z8Ra>aR7k<}=nZ^28tO+OqrlGn#_|f`G>NAiUvJ0`GOKwvYD)#;I{%5@i=J1e4<@Cnun1^vB$na3RN!L0#Uw!kvqp{a0)@B7 zVhp3>Ac2t_uN6r8#b@$Sn)wlViW!BXknn?ACt#{@cBF+OE&;}`Vse;ex|{SEQ2MVh zf@VzNEK+*RG|O1m&GbhjHn_B<-@2J60Z#nS&D^Bfi4l9T_?F51Ix4uCcSq6CoB2rE zGZ}P~cH{#S@pN=DuS5}_!ZU-L5GJC!C~FD~mi1G3VW<_BqUI8z=cho=kGX~SrI&6& zi&M@rR1_w>V=CqwJC*07mCC6gg=||E-8UU9){*>aI&A-rB%K1N8*wW(pv=p^j<--V z#|p@IV`lJ7Lxs0w2A^)A{vHta=@(&noei;X8R)IE><+T4 zSj*48!|C_U=RmcR?^t}8-KI2{ZDzPS>NT5s<2m*irTl=i>Y3lM7K(lyM~uJKq21$W zSZc6MZM5UyWKlY}DD^B3D7)8VC!VSYN}W~D7kE=t{$P+iKBcUa%!$KIpyn^xG;zY2 zMrTd}j^mhffH>jIpxq*gW6osi^Ch07E!yi>Rv}hjLtKk~Wqk>A&!!y{q2~{S9yk}l zv(Hq$`&U@GM}K8;c%@W3%8H2t6AJT7?8Xoplnj$&l(6pPmdxXhws^E zB3>fgJN*ZC-as{H*j(I;V7c+aLW4WeWv;cT;P@uhRIk#(I80#Gd4_L_oChbPVhC;f z1rZKI`r>TYbRH+HV99IXl!ZwmtS{*uSusIEYt5Pa<^*0GRR>QdB!R``L5LQdlU*kA z67t@}n`qEPuG0Gx`PX#QBz~vH;NMOF%l&#I(1j$laS}jI&qp-sgbQbGG}W46?&$uQ zR8qcS*~xy2$rH>LD`LmQ*OZ-P|ALLhVoO-}`4>1v#+cK@J0ZeRoE74Kk@#nbv3Pk4 zD7fe)*3G-;Gq&GAC(L|Q2XP+`cUU})W}71AsFbtb!?SpmK@vgwk@{G8BvPf`K^FeF zAuq5#99S@1mB1`Td|B2{y;SIUDy7n12aoH>iuT~8bxpj6?rPyFfG@BMb7*@r z7D3t%L9M(70$S2=Q7f;AmLCWe0}>w!RS-ELBTl5Z_RUXN44@FK*)Kj}36Z)p5G!Br zv1sR&QJ=CwbRSv|!snsSP621iH{q(wkmj)W*;XEkQ~BGVRm6pdl5$F#$JdeJ9^T7q zxt+gb2r=2rR=Dx)HY#2TJv4VEki^X^c~;O|kLF$2wG#XFr#m6*9$(4BdLf2SxDV}C z3>G)MwFrhPD`d4DzD>2*@6>fs;T_yUk#~R#*Uo?(l?|=G10Zev42)DJcistp)JyXW z{pk2gZ0QrClAaq%ad+|xZ~9#vKdVrF7lya@Zr-16x*O8%=Z7yiZ=e>Q-@B;fr5HFqE@ZMB(7X)?>E0D@{(Psg=$~La-$4hO4=R z%69YF-UUx`GEn>D5Q0@tVusa(A)-A-3pVi~BD^M&V%7rGBQKIZ+615`#+0lDE8<*F z1T8A?59kwpcReI@$W}EGxQv;TQ3$eX*3H`3;9{F>w{(`_E7S`1+fw}v=)^xyzMFyEXpEUoST zC=>&~`UMPL_@^;;y~$dfXNpE~8f38`vQ%qKdd?s#5cw0B)8uxG5lC;EzoHqU)oBl` z=0M1-tuZhMvK@!nW`~L(L^ZI$jpL!K>Y6<6robw~yRW6mu%73}X&qbajg6`Z4-*fx zYa=VnxcVg&%6W(e5L;H_;km)ShECQ4U!9F&`KkVCsEX)Ve@8sigk+YV8Q7|Cw0b3x zq}{LZo;L@y(rK!C%}$v@hKdW0SOrN?Xw{Zh1*~Ori?mCqS(!msyey-#a~>+8(f`Pk z#}0Bc%XXAn#6pYcuoQn%#cLf2r9vL*4!U{(zP9~CKzAJ{8dZSwZk+Vt$Wbj8v3$ah znsimB=m%vgorz)vnE`~+xB{heQM44bO=bC=77nbWSHUCpE`Wb;meV_+AvtD^3-zi2 zSxPDGS;q6a$rng2bPfU|aswLB7+Zf=OJPweHFxBhZNNi^!T{H2-Ul#NHw;gY-N%=9 z!L21SZs%h|#ObxtV0Si364R#b{COI2A3*S+n;`xs-VZV4x(%}WvHQ6QF)#IAydQ@( zGKPng2Vf|>w?n<1dI0K8K4m}1ucw_4KqKP#ot}Sy7kQf=| zMz48@H%7`4nCk0+l~C$^`5`_qxXt&WOw7yogq0I_cg1ek%Rn}SMb^6z42G~Dr!rfG z9Jbiq7JI$P)l^ikHkdpXH*#ds?7}&|#|kFEK`^2%6d5t#d)Dxch$O2wIqMZu2psKT zj#})A;~^}qcSni8U^d3~ciH&5Gq$4Eh1M)81}5oX1JBP49D~1tHY6dH$@C0lX%y_n z4F9lE?LX&2dmPyQ!obYXC)`m_&q4Tt#39*H+6Tx`Lwlh1(Yzr0D*B=HDw2|E2P??> z55kLzzBQ0z7R;?F(y?n`b)Q%RY%0|p^lwf#%|RTt4iMwaTE2{W-vd=VX(u>R);YEw zPPUeN_(J-L@bd00Q1dw=_AUBeppTGUKpzj@iv#r;yLd`;6(|pQEsig6Olxw|&@`x9 zS@WySe1-SEU3`&&E^X#vVbBL+ncO&Rr3rOF;n3^hGgy>Wn?YD<(!UU_B@+ zV?jDb2GCR#A#DvU2w9J9KwNMzeZC)nY~vaj5J&c6Wvuhi$n3rRpSp=GbH~lY&~JR2 zPv{DzP)3hD&2wWBk_UvZ9d2u}%GCZew->vc6sM!kw+jQ~a!b_~+_Di@WMs&gFTk1h zJP*89^9=9B%q5jJ)S(^E2_X3l+`Qq7dAawiXLt!h6Di({i9hQAU;Vs~hk6tD@s|yn zJENc-PLY%sAktR1^JU%-pMztA652q(+*f!}qKKrEYDYjGKwD$hKoOR6>=4l6m)AgC z9Y4fxBx?&S!fB$B6ASooTK57^%BqxdNkeKbwa!u6w_dy_MiwrDUJz+Xw~b; z=nS86<_Wd zkocB~IHz>hQPmABW2!z3IZ=#Mi_FmmD#eKZbs1XbPc^Hi*WU- znBX7q-;=5nrNoPWOVGetbnqTtI7#o&za)6q|16N2c1Y*%y$Nd4pYV~*pZ3_yZro9$ z9nma3Q*YUqDQBaVyAYbHMWChYm3%FsbKjG{N|Ihh^o(-x4+;^r2K%~5FO+MFQY~!o z@7NO_L{+$MGGfFBR>UmjmsX^j6G|vSZ%R}Y7*qaB#^tdc|qCYiHC(2OK!=!|)v7xd=sq zuRs9VPHCF63$S5HBb-0~a$v+#?!ae@pT@d}XZyLl)0RgYozgUZC)!x`v`|+Ec}Wml z3&+D*_J()S-uW8H-_n=))DZbaIWa#v@G^wpC-Zr1n$MA;IkUu6HC14Psio48L%;<> z=o%Cn3Ikd`cT?P0XF7U_CyGaGvF#Jl4XPQb)C0?W`$B+*-iLTGG(dDHu#?O%E3p2nKCuA9z^KDSvM0ULfGP*($RK+;g*G(I*ynJAbP``F30S8F zMDDs;0X(g~*)#!$R7GP61T9mM60jPM6*SV3kT^*m`iWX49gUz?M*@2Sw`inW+Sj-! zYj)y7j|@^5@22Zn(sJxbXzyyez3mWJprA{{0Uu@@I>_;#+87=GO|BvW3N@Vo_nZm0 zxn>vBmoBK_9@F3imL`R~VREhpGe)#uA3A)&SY7?;8WQ??wjLQ!1+ zM&!j4&84{%^-c!C!6Ao)Ybhz(C6}2?c(^xjneZ5GeTCl&^eOHqhRg?)3thoSitCDS z!u7ztOwS4+(tR7@*p>c1>*KI{K3D-p7&{*dc~}|>epm><%;bgq9y-tjUPAC;0cEz~ z1g5SH{D;zT`ewPtRX8ba<6GeN>%Rz?43vnB#mC8f`_yi0g0@K;SEr!MEf97dkJs2KbP!t>-sMfoHzDux|Ko_!j;8zy6G^U$u9@q=Fj8; zyU80k^6oqSG>>T0sUUSbkW%kw+dw@>bB$X~x_a$(p%3blszp-41D?;YiFy+=fZziWN= zwv2uct$cRMl8KRe!yDTAT@eGC_zK mock paymaster and alto instance -src/ => test cases found here -``` - -#### Adding new tests -Add a new entry to either `src/ep-0.6/coreSmartClientActions.test.ts` and or `src/ep-0.7/coreSmartClientActions.test.ts` to ensure that the new smart account handles all core functions. diff --git a/packages/permissionless-test/mock-aa-infra/alto/.dockerignore b/packages/permissionless-test/mock-aa-infra/alto/.dockerignore deleted file mode 100644 index 31dd108b..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/* -pnpm-lock.yaml diff --git a/packages/permissionless-test/mock-aa-infra/alto/Dockerfile b/packages/permissionless-test/mock-aa-infra/alto/Dockerfile deleted file mode 100644 index ca400b66..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# production ready dockerfile that runs pnpm start -FROM node:20-alpine - -# set working directory -WORKDIR /app - -# Install additional dependencies -RUN apk add --no-cache git - -# install pnpm -RUN npm install -g pnpm@^8.15 - -# copy source code -COPY . . - -# install dependencies -RUN pnpm fetch -RUN pnpm install - -# start app -ENTRYPOINT ["pnpm", "run", "start"] diff --git a/packages/permissionless-test/mock-aa-infra/alto/alto-config.json b/packages/permissionless-test/mock-aa-infra/alto/alto-config.json deleted file mode 100644 index 11351372..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/alto-config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "network-name": "local", - "log-environment": "production", - "entrypoints": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789,0x0000000071727De22E5E9d8BAf0edAc6f37da032", - "balance-override-enabled": "true", - "entrypoint-simulation-contract": "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87", - "api-version": "v1,v2", - "rpc-url": "http://anvil:8545", - "min-balance": "0", - "utility-private-key": "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", - "executor-private-keys": "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6,0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356,0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e,0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba,0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", - "max-block-range": 10000, - "safe-mode": false, - "port": 4337, - "log-level": "fatal", - "public-client-log-level": "error", - "wallet-client-log-level": "error", - "polling-interval": 100 -} diff --git a/packages/permissionless-test/mock-aa-infra/alto/src/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts similarity index 99% rename from packages/permissionless-test/mock-aa-infra/alto/src/constants.ts rename to packages/permissionless-test/mock-aa-infra/alto/constants.ts index b53226ba..51aa248e 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/src/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -67,7 +67,7 @@ export const BICONOMY_SINGLETON_FACTORY_BYTECODE: Hex = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063bb34534c1461003b578063cdcb760a1461006a575b600080fd5b61004e61004936600461033f565b61007f565b6040516001600160a01b03909116815260200160405180910390f35b61007d610078366004610358565b610090565b005b600061008a8261010f565b92915050565b60006100d28484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101fe92505050565b6040519091506001600160a01b038216907f8ffcdc15a283d706d38281f500270d8b5a656918f555de0913d7455e3e6bc1bf90600090a250505050565b6000806101a8836040517fff0000000000000000000000000000000000000000000000000000000000000060208201526bffffffffffffffffffffffff193060601b166021820152603581018290527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f605582015260009060750160408051601f19818403018152919052805160209091012092915050565b6040516135a560f21b60208201526bffffffffffffffffffffffff19606083901b166022820152600160f81b603682015290915060370160408051601f1981840301815291905280516020909101209392505050565b600061020c83836000610213565b9392505050565b60408051808201909152601081527f67363d3d37363d34f03d5260086018f30000000000000000000000000000000060208201526000906102538561010f565b9150813b156102755760405163cd43efa160e01b815260040160405180910390fd5b6000858251602084016000f590506001600160a01b0381166102aa5760405163bbd2fe8760e01b815260040160405180910390fd5b6000816001600160a01b031685876040516102c591906103d4565b60006040518083038185875af1925050503d8060008114610302576040519150601f19603f3d011682016040523d82523d6000602084013e610307565b606091505b505090508015806103175750833b155b15610335576040516353de54b960e01b815260040160405180910390fd5b5050509392505050565b60006020828403121561035157600080fd5b5035919050565b60008060006040848603121561036d57600080fd5b83359250602084013567ffffffffffffffff8082111561038c57600080fd5b818601915086601f8301126103a057600080fd5b8135818111156103af57600080fd5b8760208285010111156103c157600080fd5b6020830194508093505050509250925092565b6000825160005b818110156103f557602081860181015185830152016103db565b50600092019182525091905056fea26469706673582212207886676dff8e9b5ec182bd3d55512921e83b71170648ce1692043a572fa2954964736f6c63430008110033" // Will deploy V0.6 BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE to 0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e -export const BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL: Hex = +export const BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL: Hex = "0xcdcb760aa141e6dec8c9b10eb36022b4f82d2ffe43a3b172ad899d71e2dd80b0ee4c5b7c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000090960808060405234610016576108ed908161001c8239f35b600080fdfe6040608081526004908136101561001557600080fd5b6000803560e01c80631626ba7e146104065780632ede3bc014610384578063715018a614610314578063a3f4df7e146102c1578063f2fde38b1461020b578063f44c339d14610183578063fa5441611461012b578063ffa1ad74146100d45763fff35b721461008357600080fd5b346100cd576003199082823601126100cd5783359167ffffffffffffffff83116100d0576101609083360301126100cd57506020926100c6916024359101610543565b9051908152f35b80fd5b5080fd5b5090346100d057816003193601126100d057610127906100f2610446565b90600582527f302e322e30000000000000000000000000000000000000000000000000000000602083015251918291826104fa565b0390f35b5082346100d05760203660031901126100d0576001600160a01b0383816101506104e4565b16938481528060205220541691821561016d576020838551908152f35b8351633d3fff5360e21b81529182015260249150fd5b5091346102075760603660031901126102075760243567ffffffffffffffff8111610203576101b5903690830161047c565b90604435936001600160a01b03851685036100cd5750926101d991602094356105d8565b90517fffffffff000000000000000000000000000000000000000000000000000000009091168152f35b8380fd5b8280fd5b50919034610207576020366003190112610207576102276104e4565b803b6102a2576001600160a01b0380911692831561029457503384528360205281842054169083208273ffffffffffffffffffffffffffffffffffffffff19825416179055337fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8480a480f35b82516307e179e960e31b8152fd5b826001600160a01b0360249351926377817ac360e01b84521690820152fd5b5090346100d057816003193601126100d057610127906102df610446565b90601f82527f4543445341204f776e657273686970205265676973747279204d6f64756c6500602083015251918291826104fa565b50809134610381578160031936011261038157338252816020526001600160a01b03818320541690822073ffffffffffffffffffffffffffffffffffffffff198154169055337fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8380a480f35b50fd5b5091346102075760203660031901126102075761039f6104e4565b338452836020526001600160a01b03908184862054166103f05716908115610294575081602093338152808552209073ffffffffffffffffffffffffffffffffffffffff1982541617905551308152f35b8351632c4dfb7d60e21b81523381850152602490fd5b50346100cd57816003193601126100cd576024359067ffffffffffffffff82116100cd575060209261043e6101d9923690830161047c565b3391356105d8565b604051906040820182811067ffffffffffffffff82111761046657604052565b634e487b7160e01b600052604160045260246000fd5b81601f820112156104df5780359067ffffffffffffffff928383116104665760405193601f8401601f19908116603f011685019081118582101761046657604052828452602083830101116104df57816000926020809301838601378301015290565b600080fd5b600435906001600160a01b03821682036104df57565b6020808252825181830181905290939260005b82811061052f57505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161050d565b610140810135601e19823603018112156104df57810167ffffffffffffffff81358181116104df57602083019080360382136104df578301906040848303126104df57359182116104df576040916020806105a293019185010161047c565b910135916001600160a01b0392838116036104df573591821682036104df576105ca92610616565b6105d357600190565b600090565b906105e39291610616565b61060b577fffffffff0000000000000000000000000000000000000000000000000000000090565b630b135d3f60e11b90565b916001600160a01b038091169160009383855284602052826040862054169384156106c4575060418251106106b2577f19457468657265756d205369676e6564204d6573736167653a0a333200000000855280601c528261068561067d84603c89206107f6565b9190916106dc565b1684146106a8576106999161067d916107f6565b16146106a25790565b50600190565b5050505050600190565b604051632bb1a9c560e11b8152600490fd5b60249060405190633d3fff5360e21b82526004820152fd5b60058110156107e057806106ed5750565b6001810361073a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036107875760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461079057565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b90604181511460001461082457610820916020820151906060604084015193015160001a9061082e565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116108ab5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa1561089e5781516001600160a01b038116156106a2579190565b50604051903d90823e3d90fd5b5050505060009060039056fea2646970667358221220d77d1372dac830175d3da0f00a91bc884b7cab72695fa25594e2902bca4a7bd964736f6c634300081100330000000000000000000000000000000000000000000000" // Will deploy V0.6 BICONOMY_ACCOUNT_V2_0_LOGIC to 0x0000002512019Dafb59528B82CB92D3c5D2423ac diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts new file mode 100644 index 00000000..3c472dfb --- /dev/null +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -0,0 +1,363 @@ +import { + http, + type Address, + type PublicClient, + createPublicClient, + createTestClient, + createWalletClient, + parseEther +} from "viem" +import { mnemonicToAccount } from "viem/accounts" +import { sendTransaction } from "viem/actions" +import { foundry } from "viem/chains" +import { + BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, + BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, + BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, + BICONOMY_FACTORY_CREATECALL, + BICONOMY_SINGLETON_FACTORY_BYTECODE, + ENTRY_POINT_SIMULATIONS_CREATECALL, + ENTRY_POINT_V06_CREATECALL, + ENTRY_POINT_V07_CREATECALL, + KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, + KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, + KERNEL_V06_FACTORY_CREATECALL, + KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, + KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, + KERNEL_V07_FACTORY_CREATECALL, + KERNEL_V07_META_FACTORY_CREATECALL, + LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, + SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, + SAFE_MULTI_SEND_CREATECALL, + SAFE_PROXY_FACTORY_CREATECALL, + SAFE_SINGLETON_CREATECALL, + SAFE_SINGLETON_FACTORY_BYTECODE, + SAFE_V06_MODULE_CREATECALL, + SAFE_V06_MODULE_SETUP_CREATECALL, + SAFE_V07_MODULE_CREATECALL, + SAFE_V07_MODULE_SETUP_CREATECALL, + SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, + SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL +} from "./constants" + +const DETERMINISTIC_DEPLOYER = "0x4e59b44847b379578588920ca78fbf26c0b4956c" +const SAFE_SINGLETON_FACTORY = "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7" +const BICONOMY_SINGLETON_FACTORY = "0x988C135a1049Ce61730724afD342fb7C56CD2776" +export const ENTRY_POINT_SIMULATIONS_ADDRESS = + "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87" + +const verifyDeployed = async (client: PublicClient, addresses: Address[]) => { + for (const address of addresses) { + const bytecode = await client.getBytecode({ + address + }) + + if (bytecode === undefined) { + console.log(`CONTRACT ${address} NOT DEPLOYED!!!`) + process.exit(1) + } + } +} + +export const setupContracts = async (rpc: string) => { + let nonce = 0 + + const walletClient = createWalletClient({ + account: mnemonicToAccount( + "test test test test test test test test test test test junk" + ), + chain: foundry, + transport: http(rpc) + }) + + const anvilClient = createTestClient({ + transport: http(rpc), + mode: "anvil" + }) + + const client = createPublicClient({ + transport: http(rpc) + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_V07_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_SIMULATIONS_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V06_MODULE_SETUP_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V06_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V07_MODULE_SETUP_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V07_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + await anvilClient.setCode({ + address: SAFE_SINGLETON_FACTORY, + bytecode: SAFE_SINGLETON_FACTORY_BYTECODE + }) + + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_PROXY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_SINGLETON_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + await anvilClient.setCode({ + address: BICONOMY_SINGLETON_FACTORY, + bytecode: BICONOMY_SINGLETON_FACTORY_BYTECODE + }) + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_META_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + let onchainNonce = 0 + do { + onchainNonce = await client.getTransactionCount({ + address: walletClient.account.address + }) + await new Promise((resolve) => setTimeout(resolve, 500)) + } while (onchainNonce !== nonce) + + // ==== SETUP KERNEL V0.6 CONTRACTS ==== // + const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" + await anvilClient.setBalance({ + address: kernelFactoryOwner, + value: parseEther("100") + }) + + await anvilClient.impersonateAccount({ + address: kernelFactoryOwner + }) + + // register 0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5 + await sendTransaction(walletClient, { + account: kernelFactoryOwner, + to: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" /* kernel factory v0.6 */, + data: "0xbb30a9740000000000000000000000000da6a956b9488ed4dd761e59f52fdc6c8068e6b50000000000000000000000000000000000000000000000000000000000000001" /* setImplementation(address _implementation,bool _allow) */ + }) + + // register 0x6723b44Abeec4E71eBE3232BD5B455805baDD22f + await sendTransaction(walletClient, { + account: kernelFactoryOwner, + to: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" /* kernel factory v0.7 */, + data: "0x6e7dbabb0000000000000000000000006723b44abeec4e71ebe3232bd5b455805badd22f0000000000000000000000000000000000000000000000000000000000000001" + }) + + await sendTransaction(walletClient, { + account: kernelFactoryOwner, + to: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" /* kernel factory v0.7 */, + data: "0xc7e55f3e0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0320000000000000000000000000000000000000000000000000000000000015180" + }) + + await anvilClient.stopImpersonatingAccount({ + address: kernelFactoryOwner + }) + + // ==== SETUP ALCHEMY LIGHT ACCOUNT CONTRACTS ==== // + const alchemyLightClientOwner = "0xDdF32240B4ca3184De7EC8f0D5Aba27dEc8B7A5C" + await anvilClient.setBalance({ + address: alchemyLightClientOwner, + value: parseEther("100") + }) + + await anvilClient.impersonateAccount({ + address: alchemyLightClientOwner + }) + + await sendTransaction(walletClient, { + account: alchemyLightClientOwner, + to: "0x0000000000400CdFef5E2714E63d8040b700BC24" /* light account v2.0.0 factory */, + data: "0xfbb1c3d40000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000016345785d8a0000", + value: parseEther("0.1") + }) + + await anvilClient.stopImpersonatingAccount({ + address: alchemyLightClientOwner + }) + + await verifyDeployed(client, [ + "0x4e59b44847b379578588920ca78fbf26c0b4956c", // Determinstic deployer + "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7", // Safe Singleton Factory + "0x988C135a1049Ce61730724afD342fb7C56CD2776", // Biconomy Singleton Factory + "0x0000000071727De22E5E9d8BAf0edAc6f37da032", // EntryPoint v0.7 + "0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985", // Simple Account Factory V0.7 + ENTRY_POINT_SIMULATIONS_ADDRESS, // EntryPoint Simulations (Needed for v0.7) + "0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47", // Safe V0.7 Module Setup + "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226", // Safe V0.7 4337 Module + "0x8EcD4ec46D4D2a6B64fE960B3D64e8B94B2234eb", // Safe V0.6 Module Setup + "0xa581c4A4DB7175302464fF3C06380BC3270b4037", // Safe V0.6 4337 Module + "0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67", // Safe Proxy Factory + "0x41675C099F32341bf84BFc5382aF534df5C7461a", // Safe Singleton + "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526", // Safe Multi Send + "0x9641d764fc13c8B624c04430C7356C1C7C8102e2", // Safe Multi Send Call Only + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // EntryPoint V0.6 + "0x9406Cc6185a346906296840746125a0E44976454", // Simple Account Factory V0.6 + "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", // Biconomy ECDSA Ownership Registry Module + "0x0000002512019Dafb59528B82CB92D3c5D2423ac", // Biconomy Account Logic V0.2 + "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5", // Biconomy Factory Address + "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1", // Biconomy Default Fallback Handler + "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", // Kernel v0.2.2 ECDSA Valdiator + "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", // Kernel v0.2.2 Account Logic + "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3", // Kernel v0.2.2 Factory + "0x8104e3Ad430EA6d354d013A6789fDFc71E671c43", // Kernel v0.3.0 ECDSA Valdiator + "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27", // Kernel v0.3.0 Account Logic + "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", // Kernel v0.3.0 Factory + "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", // Kernel v0.3.0 Meta Factory + "0x00004EC70002a32400f8ae005A26081065620D20", // LightAccountFactory v1.1.0 + "0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba" // LightAccount v1.1.0 implementation + ]) +} diff --git a/packages/permissionless-test/mock-aa-infra/alto/package.json b/packages/permissionless-test/mock-aa-infra/alto/package.json deleted file mode 100644 index 774a824d..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "alto + contract-deployer", - "private": true, - "scripts": { - "start": "pnpm run start:deploy-contracts && pnpm run install:alto && pnpm run start:alto", - "install:alto": "cd node_modules/alto && pnpm install", - "start:deploy-contracts": "wait-port anvil:8545 && ts-node src/index.ts", - "start:alto": "pnpm alto run --config ./alto-config.json" - }, - "dependencies": { - "alto": "github:pimlicolabs/alto", - "alto + contract-deployer": "link:", - "viem": "^2.9.9" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "ts-node": "^10.9.2", - "wait-port": "^1.1.0" - } -} diff --git a/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml b/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml deleted file mode 100644 index 2e528783..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml +++ /dev/null @@ -1,324 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - alto: - specifier: github:pimlicolabs/alto - version: github.com/pimlicolabs/alto/459e9a526a9859f1fd269f9b920f008255ce7bfb - alto + contract-deployer: - specifier: 'link:' - version: 'link:' - viem: - specifier: ^2.9.9 - version: 2.9.23(typescript@5.4.5) - -devDependencies: - '@types/node': - specifier: ^20.12.4 - version: 20.12.7 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.7)(typescript@5.4.5) - wait-port: - specifier: ^1.1.0 - version: 1.1.0 - -packages: - - /@adraffy/ens-normalize@1.10.0: - resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} - dev: false - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@noble/curves@1.2.0: - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - dependencies: - '@noble/hashes': 1.3.2 - dev: false - - /@noble/hashes@1.3.2: - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - dev: false - - /@scure/base@1.1.6: - resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} - dev: false - - /@scure/bip32@1.3.2: - resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} - dependencies: - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@scure/bip39@1.2.1: - resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} - dependencies: - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - - /@types/node@20.12.7: - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} - dependencies: - undici-types: 5.26.5 - dev: true - - /abitype@1.0.0(typescript@5.4.5): - resolution: {integrity: sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - dependencies: - typescript: 5.4.5 - dev: false - - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - dev: true - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /isows@1.0.3(ws@8.13.0): - resolution: {integrity: sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg==} - peerDependencies: - ws: '*' - dependencies: - ws: 8.13.0 - dev: false - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 - acorn: 8.11.3 - acorn-walk: 8.3.2 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.4.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - - /viem@2.9.23(typescript@5.4.5): - resolution: {integrity: sha512-KolNI8H8tNkOA6xkC5UnlQjoorJxk4F1F9h42pHnH9/CtrWG9Ka4xmAWwhO2xKNPA2sNsAsJLmedBsz2uvaQow==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 - abitype: 1.0.0(typescript@5.4.5) - isows: 1.0.3(ws@8.13.0) - typescript: 5.4.5 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - dev: false - - /wait-port@1.1.0: - resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} - engines: {node: '>=10'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 9.5.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - - github.com/pimlicolabs/alto/459e9a526a9859f1fd269f9b920f008255ce7bfb: - resolution: {tarball: https://codeload.github.com/pimlicolabs/alto/tar.gz/459e9a526a9859f1fd269f9b920f008255ce7bfb} - name: root - version: 0.0.1 - engines: {node: '>=18.0.0'} - hasBin: true - prepare: true - requiresBuild: true - dev: false diff --git a/packages/permissionless-test/mock-aa-infra/alto/src/index.ts b/packages/permissionless-test/mock-aa-infra/alto/src/index.ts deleted file mode 100644 index ffc058fe..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/src/index.ts +++ /dev/null @@ -1,424 +0,0 @@ -import { - http, - type Address, - createPublicClient, - createTestClient, - createWalletClient, - parseEther -} from "viem" -import { mnemonicToAccount } from "viem/accounts" -import { sendTransaction } from "viem/actions" -import { foundry } from "viem/chains" -import { - BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, - BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, - BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL, - BICONOMY_FACTORY_CREATECALL, - BICONOMY_SINGLETON_FACTORY_BYTECODE, - ENTRY_POINT_SIMULATIONS_CREATECALL, - ENTRY_POINT_V06_CREATECALL, - ENTRY_POINT_V07_CREATECALL, - KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, - KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, - KERNEL_V06_FACTORY_CREATECALL, - KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, - KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, - KERNEL_V07_FACTORY_CREATECALL, - KERNEL_V07_META_FACTORY_CREATECALL, - LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, - SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, - SAFE_MULTI_SEND_CREATECALL, - SAFE_PROXY_FACTORY_CREATECALL, - SAFE_SINGLETON_CREATECALL, - SAFE_SINGLETON_FACTORY_BYTECODE, - SAFE_V06_MODULE_CREATECALL, - SAFE_V06_MODULE_SETUP_CREATECALL, - SAFE_V07_MODULE_CREATECALL, - SAFE_V07_MODULE_SETUP_CREATECALL, - SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, - SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL -} from "./constants" - -const DETERMINISTIC_DEPLOYER = "0x4e59b44847b379578588920ca78fbf26c0b4956c" -const SAFE_SINGLETON_FACTORY = "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7" -const BICONOMY_SINGLETON_FACTORY = "0x988C135a1049Ce61730724afD342fb7C56CD2776" - -const verifyDeployed = async (addresses: Address[]) => { - for (const address of addresses) { - const bytecode = await client.getBytecode({ - address - }) - - if (bytecode === undefined) { - console.log(`CONTRACT ${address} NOT DEPLOYED!!!`) - process.exit(1) - } - } -} - -const walletClient = createWalletClient({ - account: mnemonicToAccount( - "test test test test test test test test test test test junk" - ), - chain: foundry, - transport: http(process.env.ANVIL_RPC) -}) - -const anvilClient = createTestClient({ - transport: http(process.env.ANVIL_RPC), - mode: "anvil" -}) - -const client = createPublicClient({ - transport: http(process.env.ANVIL_RPC) -}) - -const main = async () => { - let nonce = 0 - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_V07_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying EntryPoint")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying SimpleAccountFactory")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_SIMULATIONS_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying EntryPointSimulations")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_V06_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[V0.6 CORE] Deploying EntryPoint")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[V0.6 CORE] Deploying SimpleAccountFactory")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V06_MODULE_SETUP_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.6] Deploying Safe Module Setup")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V06_MODULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.6] Deploying Safe 4337 Module")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V07_MODULE_SETUP_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.7] Deploying Safe Module Setup")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V07_MODULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.7] Deploying Safe 4337 Module")) - - await anvilClient - .setCode({ - address: SAFE_SINGLETON_FACTORY, - bytecode: SAFE_SINGLETON_FACTORY_BYTECODE - }) - .then(() => - console.log("[SAFE] Etched Safe Singleton Factory Bytecode") - ) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_PROXY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Proxy Factory")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_SINGLETON_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Singleton")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Multi Send")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Multi Send Call Only")) - - await anvilClient - .setCode({ - address: BICONOMY_SINGLETON_FACTORY, - bytecode: BICONOMY_SINGLETON_FACTORY_BYTECODE - }) - .then(() => console.log("[BICONOMY] Etched Singleton Factory Bytecode")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => - console.log("[BICONOMY] Deployed ECDSA Ownership Registry Module") - ) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[BICONOMY] Deploying Account V0.2 Logic")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[BICONOMY] Deploying Factory")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => - console.log("[BICONOMY] Deploying Default Fallback Handler") - ) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 ECDSA Validator")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 Account V2 Logic")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 Factory")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 Factory")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 ECDSA VALIDATOR")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 ACCOUNT V3 LOGIC ")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_META_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 META FACTORY")) - - walletClient - .sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => - console.log("[LIGHT ACCOUNT] Deploying v1.1.0 LightAccount Factory") - ) - - let onchainNonce = 0 - do { - onchainNonce = await client.getTransactionCount({ - address: walletClient.account.address - }) - await new Promise((resolve) => setTimeout(resolve, 500)) - } while (onchainNonce !== nonce) - - // ==== SETUP KERNEL V0.6 CONTRACTS ==== // - const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" - await anvilClient.setBalance({ - address: kernelFactoryOwner, - value: parseEther("100") - }) - - await anvilClient.impersonateAccount({ - address: kernelFactoryOwner - }) - - // register 0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5 - await sendTransaction(walletClient, { - account: kernelFactoryOwner, - to: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" /* kernel factory v0.6 */, - data: "0xbb30a9740000000000000000000000000da6a956b9488ed4dd761e59f52fdc6c8068e6b50000000000000000000000000000000000000000000000000000000000000001" /* setImplementation(address _implementation,bool _allow) */ - }) - - // register 0x6723b44Abeec4E71eBE3232BD5B455805baDD22f - await sendTransaction(walletClient, { - account: kernelFactoryOwner, - to: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" /* kernel factory v0.7 */, - data: "0x6e7dbabb0000000000000000000000006723b44abeec4e71ebe3232bd5b455805badd22f0000000000000000000000000000000000000000000000000000000000000001" - }) - - await sendTransaction(walletClient, { - account: kernelFactoryOwner, - to: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" /* kernel factory v0.7 */, - data: "0xc7e55f3e0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0320000000000000000000000000000000000000000000000000000000000015180" - }) - - await anvilClient.stopImpersonatingAccount({ - address: kernelFactoryOwner - }) - - // ==== SETUP ALCHEMY LIGHT ACCOUNT CONTRACTS ==== // - const alchemyLightClientOwner = "0xDdF32240B4ca3184De7EC8f0D5Aba27dEc8B7A5C" - await anvilClient.setBalance({ - address: alchemyLightClientOwner, - value: parseEther("100") - }) - - await anvilClient.impersonateAccount({ - address: alchemyLightClientOwner - }) - - await sendTransaction(walletClient, { - account: alchemyLightClientOwner, - to: "0x0000000000400CdFef5E2714E63d8040b700BC24" /* light account v2.0.0 factory */, - data: "0xfbb1c3d40000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000016345785d8a0000", - value: parseEther("0.1") - }) - - await anvilClient.stopImpersonatingAccount({ - address: alchemyLightClientOwner - }) - - await verifyDeployed([ - "0x4e59b44847b379578588920ca78fbf26c0b4956c", // Determinstic deployer - "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7", // Safe Singleton Factory - "0x988C135a1049Ce61730724afD342fb7C56CD2776", // Biconomy Singleton Factory - "0x0000000071727De22E5E9d8BAf0edAc6f37da032", // EntryPoint v0.7 - "0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985", // Simple Account Factory V0.7 - "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87", // EntryPoint Simulations (Needed for v0.7) - "0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47", // Safe V0.7 Module Setup - "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226", // Safe V0.7 4337 Module - "0x8EcD4ec46D4D2a6B64fE960B3D64e8B94B2234eb", // Safe V0.6 Module Setup - "0xa581c4A4DB7175302464fF3C06380BC3270b4037", // Safe V0.6 4337 Module - "0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67", // Safe Proxy Factory - "0x41675C099F32341bf84BFc5382aF534df5C7461a", // Safe Singleton - "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526", // Safe Multi Send - "0x9641d764fc13c8B624c04430C7356C1C7C8102e2", // Safe Multi Send Call Only - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // EntryPoint V0.6 - "0x9406Cc6185a346906296840746125a0E44976454", // Simple Account Factory V0.6 - "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", // Biconomy ECDSA Ownership Registry Module - "0x0000002512019Dafb59528B82CB92D3c5D2423ac", // Biconomy Account Logic V0.2 - "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5", // Biconomy Factory Address - "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1", // Biconomy Default Fallback Handler - "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", // Kernel v0.2.2 ECDSA Valdiator - "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", // Kernel v0.2.2 Account Logic - "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3", // Kernel v0.2.2 Factory - "0x8104e3Ad430EA6d354d013A6789fDFc71E671c43", // Kernel v0.3.0 ECDSA Valdiator - "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27", // Kernel v0.3.0 Account Logic - "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", // Kernel v0.3.0 Factory - "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", // Kernel v0.3.0 Meta Factory - "0x00004EC70002a32400f8ae005A26081065620D20", // LightAccountFactory v1.1.0 - "0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba" // LightAccount v1.1.0 implementation - ]) -} - -main() diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile b/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile deleted file mode 100644 index 7fe17d6b..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# production ready dockerfile that runs pnpm start -FROM node:20-alpine - -# set working directory -WORKDIR /app - -# install pnpm -RUN npm install -g pnpm - -# copy package.json -COPY package.json ./ - -# copy source code -COPY ./src ./src - -# install dependencies -RUN pnpm fetch -RUN pnpm install - -# start app -ENTRYPOINT ["pnpm", "run", "start"] diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/abi.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/abi.ts similarity index 100% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/abi.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/abi.ts diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts similarity index 98% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts index 5bb14062..ca2290b8 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts @@ -1,5 +1,5 @@ import { type Hex, getAddress } from "viem" -import { type infer as zodInfer, z } from "zod" +import { z, type infer as zodInfer } from "zod" export enum ValidationErrors { InvalidFields = -32602, diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts similarity index 84% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts index 24877754..95cb8bad 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts @@ -2,7 +2,7 @@ import { http, createWalletClient } from "viem" import { mnemonicToAccount } from "viem/accounts" import { foundry } from "viem/chains" -export const getAnvilWalletClient = () => { +export const getAnvilWalletClient = (anvilRpc: string) => { const account = mnemonicToAccount( "test test test test test test test test test test test junk", { @@ -14,7 +14,7 @@ export const getAnvilWalletClient = () => { const walletClient = createWalletClient({ account, chain: foundry, - transport: http(process.env.ANVIL_RPC) + transport: http(anvilRpc) }) return walletClient diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts similarity index 96% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts index e4172d5e..85c87428 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts @@ -14,7 +14,6 @@ import { parseEther, slice } from "viem" -import { waitForTransactionReceipt } from "viem/actions" import { foundry } from "viem/chains" import { VERIFYING_PAYMASTER_V06_ABI, VERIFYING_PAYMASTER_V07_ABI } from "./abi" @@ -36,12 +35,13 @@ const VERIFYING_PAYMASTER_V06_CALL = (owner: Address): Hex => ]) export const setupVerifyingPaymasterV07 = async ( - walletClient: WalletClient + walletClient: WalletClient, + anvilRpc: string ) => { const data = VERIFYING_PAYMASTER_V07_CALL(walletClient.account.address) const publicClient = createPublicClient({ - transport: http(process.env.ANVIL_RPC), + transport: http(anvilRpc), chain: foundry }) @@ -51,7 +51,6 @@ export const setupVerifyingPaymasterV07 = async ( data }) .then((hash) => publicClient.waitForTransactionReceipt({ hash })) - .then(() => console.log("deployed VerifyingPaymaster v0.7")) const address = getContractAddress({ opcode: "CREATE2", @@ -66,22 +65,21 @@ export const setupVerifyingPaymasterV07 = async ( client: walletClient }) - await verifyingPaymaster.write - .deposit({ - value: parseEther("50") - }) - .then(() => console.log("Funded VerifyingPaymaster V0.7")) + await verifyingPaymaster.write.deposit({ + value: parseEther("50") + }) return verifyingPaymaster } export const setupVerifyingPaymasterV06 = async ( - walletClient: WalletClient + walletClient: WalletClient, + anvilRpc: string ) => { const data = VERIFYING_PAYMASTER_V06_CALL(walletClient.account.address) const publicClient = createPublicClient({ - transport: http(process.env.ANVIL_RPC), + transport: http(anvilRpc), chain: foundry }) @@ -91,7 +89,6 @@ export const setupVerifyingPaymasterV06 = async ( data }) .then((hash) => publicClient.waitForTransactionReceipt({ hash })) - .then(() => console.log("deployed VerifyingPaymaster v0.6")) const address = getContractAddress({ opcode: "CREATE2", @@ -106,11 +103,9 @@ export const setupVerifyingPaymasterV06 = async ( client: walletClient }) - await verifyingPaymaster.write - .deposit({ - value: parseEther("50") - }) - .then(() => console.log("Funded VerifyingPaymaster V0.6")) + await verifyingPaymaster.write.deposit({ + value: parseEther("50") + }) return verifyingPaymaster } diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts new file mode 100644 index 00000000..f81d7a6b --- /dev/null +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts @@ -0,0 +1,72 @@ +import cors from "@fastify/cors" +import Fastify from "fastify" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless" +import { createPimlicoBundlerClient } from "permissionless/clients/pimlico" +import { defineInstance } from "prool" +import { http } from "viem" +import { foundry } from "viem/chains" +import { getAnvilWalletClient } from "./helpers/utils" +import { + setupVerifyingPaymasterV06, + setupVerifyingPaymasterV07 +} from "./helpers/verifyingPaymasters" +import { createRpcHandler } from "./relay" + +export const paymaster = defineInstance( + ({ anvilRpc, port: _port }: { anvilRpc: string; port: number }) => { + const app = Fastify({}) + + return { + _internal: {}, + host: "localhost", + port: _port, + name: "mock-paymaster", + start: async ({ port = _port }) => { + const walletClient = getAnvilWalletClient(anvilRpc) + const verifyingPaymasterV07 = await setupVerifyingPaymasterV07( + walletClient, + anvilRpc + ) + const verifyingPaymasterV06 = await setupVerifyingPaymasterV06( + walletClient, + anvilRpc + ) + + const altoBundlerV07 = createPimlicoBundlerClient({ + chain: foundry, + transport: http(process.env.ALTO_RPC), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const altoBundlerV06 = createPimlicoBundlerClient({ + chain: foundry, + transport: http(process.env.ALTO_RPC), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + app.register(cors, { + origin: "*", + methods: ["POST", "GET", "OPTIONS"] + }) + + const rpcHandler = createRpcHandler( + altoBundlerV07, + altoBundlerV06, + verifyingPaymasterV07, + verifyingPaymasterV06, + walletClient + ) + app.post("/", {}, rpcHandler) + + app.get("/ping", async (_request, reply) => { + return reply.code(200).send({ message: "pong" }) + }) + + await app.listen({ host: "localhost", port }) + }, + stop: async () => { + app.close() + } + } + } +) diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json b/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json deleted file mode 100644 index d581be87..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "mock-paymaster", - "private": true, - "scripts": { - "start": "wait-port anvil:8545 && ts-node src/index.ts" - }, - "dependencies": { - "@fastify/cors": "^9.0.1", - "fastify": "^4.26.2", - "permissionless": "^0.1.0", - "tslib": "^2.6.2", - "typescript": "5.4.2", - "viem": "2.7.12", - "zod": "^3.22.4", - "zod-validation-error": "^3.0.3" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "ts-node": "^10.9.2", - "wait-port": "^1.0.4" - } -} diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml b/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml deleted file mode 100644 index 1eea8e33..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml +++ /dev/null @@ -1,765 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@fastify/cors': - specifier: ^9.0.1 - version: 9.0.1 - fastify: - specifier: ^4.26.2 - version: 4.26.2 - permissionless: - specifier: ^0.1.0 - version: 0.1.16(viem@2.7.12) - tslib: - specifier: ^2.6.2 - version: 2.6.2 - typescript: - specifier: 5.4.2 - version: 5.4.2 - viem: - specifier: 2.7.12 - version: 2.7.12(typescript@5.4.2)(zod@3.22.4) - zod: - specifier: ^3.22.4 - version: 3.22.4 - zod-validation-error: - specifier: ^3.0.3 - version: 3.1.0(zod@3.22.4) - -devDependencies: - '@types/node': - specifier: ^20.12.4 - version: 20.12.7 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.7)(typescript@5.4.2) - wait-port: - specifier: ^1.0.4 - version: 1.1.0 - -packages: - - /@adraffy/ens-normalize@1.10.0: - resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} - dev: false - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - - /@fastify/ajv-compiler@3.5.0: - resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} - dependencies: - ajv: 8.12.0 - ajv-formats: 2.1.1(ajv@8.12.0) - fast-uri: 2.3.0 - dev: false - - /@fastify/cors@9.0.1: - resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==} - dependencies: - fastify-plugin: 4.5.1 - mnemonist: 0.39.6 - dev: false - - /@fastify/error@3.4.1: - resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} - dev: false - - /@fastify/fast-json-stringify-compiler@4.3.0: - resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} - dependencies: - fast-json-stringify: 5.14.1 - dev: false - - /@fastify/merge-json-schemas@0.1.1: - resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} - dependencies: - fast-deep-equal: 3.1.3 - dev: false - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@noble/curves@1.2.0: - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - dependencies: - '@noble/hashes': 1.3.2 - dev: false - - /@noble/hashes@1.3.2: - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - dev: false - - /@scure/base@1.1.6: - resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} - dev: false - - /@scure/bip32@1.3.2: - resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} - dependencies: - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@scure/bip39@1.2.1: - resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} - dependencies: - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - - /@types/node@20.12.7: - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} - dependencies: - undici-types: 5.26.5 - dev: true - - /abitype@1.0.0(typescript@5.4.2)(zod@3.22.4): - resolution: {integrity: sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - dependencies: - typescript: 5.4.2 - zod: 3.22.4 - dev: false - - /abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - dependencies: - event-target-shim: 5.0.1 - dev: false - - /abstract-logging@2.0.1: - resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - dev: false - - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ajv-formats@2.1.1(ajv@8.12.0): - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.12.0 - dev: false - - /ajv-formats@3.0.1(ajv@8.12.0): - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.12.0 - dev: false - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: false - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - dev: false - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - - /atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - dev: false - - /avvio@8.3.0: - resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==} - dependencies: - '@fastify/error': 3.4.1 - archy: 1.0.0 - debug: 4.3.4 - fastq: 1.17.1 - transitivePeerDependencies: - - supports-color - dev: false - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: false - - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: false - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - dev: true - - /cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - dev: false - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - dev: false - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: false - - /fast-content-type-parse@1.1.0: - resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} - dev: false - - /fast-decode-uri-component@1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - dev: false - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: false - - /fast-json-stringify@5.14.1: - resolution: {integrity: sha512-J1Grbf0oSXV3lKsBf3itz1AvRk43qVrx3Ac10sNvi3LZaz1by4oDdYKFrJycPhS8+Gb7y8rgV/Jqw1UZVjyNvw==} - dependencies: - '@fastify/merge-json-schemas': 0.1.1 - ajv: 8.12.0 - ajv-formats: 3.0.1(ajv@8.12.0) - fast-deep-equal: 3.1.3 - fast-uri: 2.3.0 - json-schema-ref-resolver: 1.0.1 - rfdc: 1.3.1 - dev: false - - /fast-querystring@1.1.2: - resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - dependencies: - fast-decode-uri-component: 1.0.1 - dev: false - - /fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - dev: false - - /fast-uri@2.3.0: - resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==} - dev: false - - /fastify-plugin@4.5.1: - resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} - dev: false - - /fastify@4.26.2: - resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==} - dependencies: - '@fastify/ajv-compiler': 3.5.0 - '@fastify/error': 3.4.1 - '@fastify/fast-json-stringify-compiler': 4.3.0 - abstract-logging: 2.0.1 - avvio: 8.3.0 - fast-content-type-parse: 1.1.0 - fast-json-stringify: 5.14.1 - find-my-way: 8.1.0 - light-my-request: 5.13.0 - pino: 8.20.0 - process-warning: 3.0.0 - proxy-addr: 2.0.7 - rfdc: 1.3.1 - secure-json-parse: 2.7.0 - semver: 7.6.0 - toad-cache: 3.7.0 - transitivePeerDependencies: - - supports-color - dev: false - - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - dependencies: - reusify: 1.0.4 - dev: false - - /find-my-way@8.1.0: - resolution: {integrity: sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==} - engines: {node: '>=14'} - dependencies: - fast-deep-equal: 3.1.3 - fast-querystring: 1.1.2 - safe-regex2: 2.0.0 - dev: false - - /forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - dev: false - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false - - /ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - dev: false - - /isows@1.0.3(ws@8.13.0): - resolution: {integrity: sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg==} - peerDependencies: - ws: '*' - dependencies: - ws: 8.13.0 - dev: false - - /json-schema-ref-resolver@1.0.1: - resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} - dependencies: - fast-deep-equal: 3.1.3 - dev: false - - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: false - - /light-my-request@5.13.0: - resolution: {integrity: sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==} - dependencies: - cookie: 0.6.0 - process-warning: 3.0.0 - set-cookie-parser: 2.6.0 - dev: false - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: false - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /mnemonist@0.39.6: - resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} - dependencies: - obliterator: 2.0.4 - dev: false - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - /obliterator@2.0.4: - resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - dev: false - - /on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} - dev: false - - /permissionless@0.1.16(viem@2.7.12): - resolution: {integrity: sha512-UGC3yJiGYcPHJ+LohSFJSIxQGIQ2DMREYXGwVtb0DdvTVuO+uqqEymD6LZnKdtLF2KGhBPODv37LqvRyh+ma3g==} - peerDependencies: - viem: ^2.0.0 - dependencies: - viem: 2.7.12(typescript@5.4.2)(zod@3.22.4) - dev: false - - /pino-abstract-transport@1.1.0: - resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} - dependencies: - readable-stream: 4.5.2 - split2: 4.2.0 - dev: false - - /pino-std-serializers@6.2.2: - resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} - dev: false - - /pino@8.20.0: - resolution: {integrity: sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==} - hasBin: true - dependencies: - atomic-sleep: 1.0.0 - fast-redact: 3.5.0 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.1.0 - pino-std-serializers: 6.2.2 - process-warning: 3.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.4.3 - sonic-boom: 3.8.1 - thread-stream: 2.4.1 - dev: false - - /process-warning@3.0.0: - resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} - dev: false - - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - dev: false - - /proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - dev: false - - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: false - - /quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - dev: false - - /readable-stream@4.5.2: - resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - dev: false - - /real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} - dev: false - - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: false - - /ret@0.2.2: - resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} - engines: {node: '>=4'} - dev: false - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: false - - /rfdc@1.3.1: - resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} - dev: false - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false - - /safe-regex2@2.0.0: - resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} - dependencies: - ret: 0.2.2 - dev: false - - /safe-stable-stringify@2.4.3: - resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} - engines: {node: '>=10'} - dev: false - - /secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - dev: false - - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: false - - /set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} - dev: false - - /sonic-boom@3.8.1: - resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} - dependencies: - atomic-sleep: 1.0.0 - dev: false - - /split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - dev: false - - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: false - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /thread-stream@2.4.1: - resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} - dependencies: - real-require: 0.2.0 - dev: false - - /toad-cache@3.7.0: - resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} - engines: {node: '>=12'} - dev: false - - /ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.2): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 - acorn: 8.11.3 - acorn-walk: 8.3.2 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.4.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: false - - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - dev: false - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - - /viem@2.7.12(typescript@5.4.2)(zod@3.22.4): - resolution: {integrity: sha512-NbV+Bycw0I4X8y6A04mgJ6+Imt7xXwflgnqisR3JXoJRNc77YSaQCscFN/dmwGLESTkgegJvi+j4nZY32GTpwQ==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 - abitype: 1.0.0(typescript@5.4.2)(zod@3.22.4) - isows: 1.0.3(ws@8.13.0) - typescript: 5.4.2 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - dev: false - - /wait-port@1.1.0: - resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} - engines: {node: '>=10'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 9.5.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: false - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - - /zod-validation-error@3.1.0(zod@3.22.4): - resolution: {integrity: sha512-zujS6HqJjMZCsvjfbnRs7WI3PXN39ovTcY1n8a+KTm4kOH0ZXYsNiJkH1odZf4xZKMkBDL7M2rmQ913FCS1p9w==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.18.0 - dependencies: - zod: 3.22.4 - dev: false - - /zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - dev: false diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/relay.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts similarity index 100% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/relay.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts deleted file mode 100644 index de16703a..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import cors from "@fastify/cors" -import Fastify from "fastify" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless" -import { createPimlicoBundlerClient } from "permissionless/clients/pimlico" -import { http } from "viem" -import { foundry } from "viem/chains" -import { getAnvilWalletClient } from "./helpers/utils" -import { - setupVerifyingPaymasterV06, - setupVerifyingPaymasterV07 -} from "./helpers/verifyingPaymasters" -import { createRpcHandler } from "./relay" - -const main = async () => { - const walletClient = getAnvilWalletClient() - const verifyingPaymasterV07 = await setupVerifyingPaymasterV07(walletClient) - const verifyingPaymasterV06 = await setupVerifyingPaymasterV06(walletClient) - - const altoBundlerV07 = createPimlicoBundlerClient({ - chain: foundry, - transport: http(process.env.ALTO_RPC), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - - const altoBundlerV06 = createPimlicoBundlerClient({ - chain: foundry, - transport: http(process.env.ALTO_RPC), - entryPoint: ENTRYPOINT_ADDRESS_V06 - }) - - const app = Fastify({}) - - app.register(cors, { - origin: "*", - methods: ["POST", "GET", "OPTIONS"] - }) - - const rpcHandler = createRpcHandler( - altoBundlerV07, - altoBundlerV06, - verifyingPaymasterV07, - verifyingPaymasterV06, - walletClient - ) - app.post("/", {}, rpcHandler) - - app.get("/ping", async (_request, reply) => { - return reply.code(200).send({ message: "pong" }) - }) - - await app.listen({ host: "0.0.0.0", port: 3000 }) -} - -main() diff --git a/packages/permissionless-test/package.json b/packages/permissionless-test/package.json deleted file mode 100644 index 8acbd44a..00000000 --- a/packages/permissionless-test/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "test-cases", - "version": "0.0.0", - "type": "module", - "private": true, - "scripts": { - "start": "bun run wait-for-setup && pnpm run test", - "wait-for-setup": "wait-port localhost:4337", - "test": "bun run wait-for-setup && vitest dev -c ./vitest.config.ts", - "test:ci": "CI=true && bun run wait-for-setup && vitest -c ./vitest.config.ts --coverage --pool=forks" - }, - "dependencies": { - "tslib": "^2.6.2", - "viem": "^2.9.17", - "permissionless": "workspace:packages/permissionless" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "@vitest/coverage-v8": "^1.2.0", - "ts-node": "^10.9.2", - "vitest": "^1.5.2", - "wait-port": "^1.1.0" - } -} diff --git a/packages/permissionless-test/src/types.ts b/packages/permissionless-test/src/types.ts index 80903a54..5c839076 100644 --- a/packages/permissionless-test/src/types.ts +++ b/packages/permissionless-test/src/types.ts @@ -4,6 +4,8 @@ import type { Address, Hex, PublicClient } from "viem" export type AAParamType = { entryPoint: T + anvilRpc: string + altoRpc: string paymasterClient?: PimlicoPaymasterClient privateKey?: Hex } diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 6a860850..c9b6c4d0 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -52,12 +52,13 @@ import { } from "./constants" import type { AAParamType } from "./types" -export const ALTO_RPC = "http://localhost:4337" -const ANVIL_RPC = "http://localhost:8545" export const PAYMASTER_RPC = "http://localhost:3000" -export const ensureBundlerIsReady = async () => { - const bundlerClient = getBundlerClient(ENTRYPOINT_ADDRESS_V06) +export const ensureBundlerIsReady = async (altoRpc: string) => { + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: altoRpc + }) while (true) { try { @@ -85,7 +86,10 @@ export const ensurePaymasterIsReady = async () => { } } -export const getAnvilWalletClient = (addressIndex: number) => { +export const getAnvilWalletClient = ({ + addressIndex, + anvilRpc +}: { addressIndex: number; anvilRpc: string }) => { return createWalletClient({ account: mnemonicToAccount( "test test test test test test test test test test test junk", @@ -94,7 +98,7 @@ export const getAnvilWalletClient = (addressIndex: number) => { } ), chain: foundry, - transport: http(ANVIL_RPC) + transport: http(anvilRpc) }) } @@ -108,41 +112,47 @@ export const getPimlicoPaymasterClient = ( }) } -export const getBundlerClient = ( - entryPoint: T -): BundlerClient => +export const getBundlerClient = ({ + entryPoint, + altoRpc +}: { entryPoint: T; altoRpc: string }): BundlerClient => createBundlerClient({ chain: foundry, entryPoint, - transport: http(ALTO_RPC) + transport: http(altoRpc) }) as BundlerClient -export const getPimlicoBundlerClient = ( - entryPoint: T -): PimlicoBundlerClient => +export const getPimlicoBundlerClient = ({ + entryPoint, + altoRpc +}: { entryPoint: T; altoRpc: string }): PimlicoBundlerClient => createPimlicoBundlerClient({ chain: foundry, entryPoint, - transport: http(ALTO_RPC) + transport: http(altoRpc) }) -export const getPublicClient = () => { +export const getPublicClient = (anvilRpc: string) => { return createPublicClient({ chain: foundry, - transport: http(ANVIL_RPC), + transport: http(anvilRpc), pollingInterval: 100 }) } -const publicClient = getPublicClient() -const wallets = Array.from({ length: 100 }, (_, index) => - getAnvilWalletClient(index) -) const usedWallets = new Set
() -export const fund = async (to: Address) => { +export const fund = async ({ + to, + anvilRpc +}: { to: Address; anvilRpc: string }) => { let funder: WalletClient + const wallets = Array.from({ length: 10 }, (_, index) => + getAnvilWalletClient({ addressIndex: index, anvilRpc }) + ) + const publicClient = getPublicClient(anvilRpc) + do { const availableFunders = wallets.filter( (wallet) => !usedWallets.has(wallet.account.address) @@ -182,10 +192,14 @@ export const getFactoryAddress = ( export const getSimpleAccountClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) + const smartAccount = await signerToSimpleSmartAccount( publicClient, { @@ -195,25 +209,29 @@ export const getSimpleAccountClient = async ({ } ) - // @ts-ignore return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), - middleware: { - // @ts-ignore - sponsorUserOperation: paymasterClient?.sponsorUserOperation - } + bundlerTransport: http(altoRpc), + // @ts-ignore + middleware: paymasterClient + ? { + sponsorUserOperation: paymasterClient.sponsorUserOperation + } + : undefined }) } export const getLightAccountClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const smartAccount = await signerToLightSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), @@ -223,7 +241,7 @@ export const getLightAccountClient = async ({ return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), entryPoint: entryPoint, // eip7677Client: await getEip7677Client({ entryPoint }), middleware: { @@ -236,8 +254,11 @@ export const getLightAccountClient = async ({ export const getBiconomyClient = async ({ paymasterClient, privateKey = generatePrivateKey(), + anvilRpc, + altoRpc, entryPoint = ENTRYPOINT_ADDRESS_V06 }: AAParamType) => { + const publicClient = getPublicClient(anvilRpc) const ecdsaSmartAccount = await signerToBiconomySmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey) @@ -247,7 +268,7 @@ export const getBiconomyClient = async ({ return createSmartAccountClient({ account: ecdsaSmartAccount, chain: foundry, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -258,10 +279,13 @@ export const getBiconomyClient = async ({ export const getKernelEcdsaClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const kernelEcdsaAccount = await signerToEcdsaKernelSmartAccount( publicClient, { @@ -274,7 +298,7 @@ export const getKernelEcdsaClient = async ({ return createSmartAccountClient({ chain: foundry, account: kernelEcdsaAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -286,6 +310,8 @@ export const getSafeClient = async ({ setupTransactions = [], entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: { setupTransactions?: { @@ -293,10 +319,13 @@ export const getSafeClient = async ({ data: Address value: bigint }[] + anvilRpc: string + altoRpc: string entryPoint: T paymasterClient?: PimlicoPaymasterClient privateKey?: Hex }): Promise>> => { + const publicClient = getPublicClient(anvilRpc) const safeSmartAccount = await signerToSafeSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), @@ -309,7 +338,7 @@ export const getSafeClient = async ({ return createSmartAccountClient({ chain: foundry, account: safeSmartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation diff --git a/packages/permissionless-test/tsconfig.json b/packages/permissionless-test/tsconfig.json deleted file mode 100644 index 33f68e91..00000000 --- a/packages/permissionless-test/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "CommonJS", - "strict": true, - "allowJs": true, - "moduleResolution": "node", - "skipLibCheck": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "suppressImplicitAnyIndexErrors": true, - "declaration": false - } -} diff --git a/packages/permissionless-test/vitest.config.ts b/packages/permissionless-test/vitest.config.ts deleted file mode 100644 index 9b600d04..00000000 --- a/packages/permissionless-test/vitest.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { defineConfig } from "vitest/config" - -export default defineConfig({ - test: { - coverage: { - all: false, - provider: "v8", - reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], - exclude: [ - "**/errors/utils.ts", - "**/_cjs/**", - "**/_esm/**", - "**/_types/**" - ] - }, - sequence: { - concurrent: true - }, - fileParallelism: true, - environment: "node", - testTimeout: 60_000, - hookTimeout: 45_000 - // setupFiles: [join(__dirname, "./setup.ts")], - // globalSetup: [join(__dirname, "./globalSetup.ts")] - } -}) diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index bf8b2e3c..4d0795e5 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -14,9 +14,9 @@ import { zeroAddress } from "viem" import { + signMessage as _signMessage, getChainId, - readContract, - signMessage as _signMessage + readContract } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts index 58300c13..0180262f 100644 --- a/packages/permissionless/actions/bundler/chainId.test.ts +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -1,41 +1,24 @@ -import getPort from "get-port" -import { Instance } from "prool" -import { alto } from "prool/instances" -import { http } from "viem" -import { afterAll, beforeAll, describe, expect, test } from "vitest" -import { createBundlerClient } from "../../clients/createBundlerClient" +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { getPortForTestName, startAltoInstance } from "../../setupTests" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" -const anvilPrivateKey = - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - describe("chainId", () => { - let altoInstance: Instance let port: number + let bundlerClient: BundlerClient beforeAll(async () => { - port = await getPort() - altoInstance = alto({ - entrypoints: [ENTRYPOINT_ADDRESS_V06], - rpcUrl: `http://localhost:8485/${port}`, - executorPrivateKeys: [anvilPrivateKey], - port + port = await getPortForTestName("bundlerActions") + bundlerClient = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 }) - await altoInstance.start() }) test("chainId", async () => { - const bundlerClient = createBundlerClient({ - transport: http(`http://localhost:${port}`), - entryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032" - }) - const chainId = await bundlerClient.chainId() - - expect(chainId).toBe(1) - }) - - afterAll(async () => { - await altoInstance.stop() + expect(chainId).toBe(foundry.id) }) }) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts new file mode 100644 index 00000000..1f649c18 --- /dev/null +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts @@ -0,0 +1,104 @@ +import { generatePrivateKey } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { + anvilPort, + getPortForTestName, + startAltoInstance +} from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("eth_estimateUserOperationGas", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + let anvilRpc: string + let altoRpc: string + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${port}` + altoRpc = `http://localhost:${port}` + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("eth_estimateUserOperationGas_v06", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { preVerificationGas, verificationGasLimit, callGasLimit } = + await bundlerClientV06.estimateUserOperationGas({ + userOperation + }) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + }) + + test("eth_estimateUserOperationGas_v07", async () => { + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { + preVerificationGas, + verificationGasLimit, + callGasLimit, + paymasterVerificationGasLimit, + paymasterPostOpGasLimit + } = await bundlerClientV07.estimateUserOperationGas({ + userOperation + }) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + expect(paymasterVerificationGasLimit).toBe(0n) + expect(paymasterPostOpGasLimit).toBe(0n) + }, 100000) +}) diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts new file mode 100644 index 00000000..ecee52cf --- /dev/null +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts @@ -0,0 +1,182 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + fund, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { + anvilPort, + getPortForTestName, + startAltoInstance +} from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("getUserOperationByHash", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + let anvilRpc: string + let altoRpc: string + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${port}` + altoRpc = `http://localhost:${port}` + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("getUserOperationByHash_V06", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash + }) + + const userOperationFromUserOpHash = + await bundlerClientV06.getUserOperationByHash({ hash: opHash }) + + expect(userOperationFromUserOpHash).not.toBeNull() + expect(userOperationFromUserOpHash?.entryPoint).toBe( + ENTRYPOINT_ADDRESS_V06 + ) + + for (const key in userOperationFromUserOpHash?.userOperation) { + const expected = userOperationFromUserOpHash?.userOperation[key] + const actual = userOperation[key] + + if (typeof expected === "string" && typeof actual === "string") { + expect(expected.toLowerCase()).toBe(actual.toLowerCase()) + } else { + expect(expected).toBe(actual) + } + } + }) + + test("getUserOperationByHash_V07", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + await bundlerClientV07.waitForUserOperationReceipt({ hash: opHash }) + + const userOperationFromUserOpHash = + await bundlerClientV07.getUserOperationByHash({ hash: opHash }) + + expect(userOperationFromUserOpHash).not.toBeNull() + expect(userOperationFromUserOpHash?.entryPoint).toBe( + ENTRYPOINT_ADDRESS_V07 + ) + + expect( + userOperationFromUserOpHash?.userOperation.sender.toLowerCase() + ).toBe(userOperation.sender.toLowerCase()) + expect(userOperationFromUserOpHash?.userOperation.nonce).toBe( + userOperation.nonce + ) + expect( + userOperationFromUserOpHash?.userOperation.factory?.toLowerCase() + ).toBe(userOperation.factory?.toLowerCase()) + expect( + userOperationFromUserOpHash?.userOperation.factoryData?.toLowerCase() + ).toBe(userOperation.factoryData?.toLowerCase()) + expect( + userOperationFromUserOpHash?.userOperation.callData.toLowerCase() + ).toBe(userOperation.callData.toLowerCase()) + expect(userOperationFromUserOpHash?.userOperation.callGasLimit).toBe( + userOperation.callGasLimit + ) + expect( + userOperationFromUserOpHash?.userOperation.verificationGasLimit + ).toBe(userOperation.verificationGasLimit) + expect( + userOperationFromUserOpHash?.userOperation.preVerificationGas + ).toBe(userOperation.preVerificationGas) + expect(userOperationFromUserOpHash?.userOperation.maxFeePerGas).toBe( + userOperation.maxFeePerGas + ) + expect( + userOperationFromUserOpHash?.userOperation.maxPriorityFeePerGas + ).toBe(userOperation.maxPriorityFeePerGas) + expect( + userOperationFromUserOpHash?.userOperation.signature.toLowerCase() + ).toBe(userOperation.signature.toLowerCase()) + expect( + userOperationFromUserOpHash?.userOperation.paymaster?.toLowerCase() + ).toBe(userOperation.paymaster?.toLowerCase()) + expect( + userOperationFromUserOpHash?.userOperation + .paymasterVerificationGasLimit + ).toBe(userOperation.paymasterVerificationGasLimit) + expect( + userOperationFromUserOpHash?.userOperation.paymasterPostOpGasLimit + ).toBe(undefined) + expect( + userOperationFromUserOpHash?.userOperation.paymasterData?.toLowerCase() + ).toBe(userOperation.paymasterData?.toLowerCase()) + }) +}) diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts new file mode 100644 index 00000000..94a2f885 --- /dev/null +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts @@ -0,0 +1,134 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + fund, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { + anvilPort, + getPortForTestName, + startAltoInstance +} from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("getUserOperationReceipt", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + let anvilRpc: string + let altoRpc: string + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${port}` + altoRpc = `http://localhost:${port}` + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("getUserOperationReceipt_V06", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + test("getUserOperationReceipt_V07", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/bundler/sendUserOperation.test.ts b/packages/permissionless/actions/bundler/sendUserOperation.test.ts new file mode 100644 index 00000000..569373ec --- /dev/null +++ b/packages/permissionless/actions/bundler/sendUserOperation.test.ts @@ -0,0 +1,134 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + fund, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { + anvilPort, + getPortForTestName, + startAltoInstance +} from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("sendUserOperation", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + let anvilRpc: string + let altoRpc: string + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${port}` + altoRpc = `http://localhost:${port}` + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("sendUserOperation_V06", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + test("sendUserOperation_V07", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts new file mode 100644 index 00000000..0ffdf323 --- /dev/null +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts @@ -0,0 +1,38 @@ +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { getPortForTestName, startAltoInstance } from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("supportedEntryPoints", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("supportedEntryPoints_V06", async () => { + const entryPoints = await bundlerClientV06.supportedEntryPoints() + expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V06) + }) + + test("supportedEntryPoints_V07", async () => { + const entryPoints = await bundlerClientV07.supportedEntryPoints() + expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V07) + }) +}) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts new file mode 100644 index 00000000..2f4e3010 --- /dev/null +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts @@ -0,0 +1,134 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { beforeAll, describe, expect, test } from "vitest" +import { + fund, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import type { BundlerClient } from "../../clients/createBundlerClient" +import { + anvilPort, + getPortForTestName, + startAltoInstance +} from "../../setupTests" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("waitForUserOperationReceipt", () => { + let port: number + let bundlerClientV06: BundlerClient + let bundlerClientV07: BundlerClient + let anvilRpc: string + let altoRpc: string + + beforeAll(async () => { + port = await getPortForTestName("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${port}` + altoRpc = `http://localhost:${port}` + bundlerClientV06 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + bundlerClientV07 = await startAltoInstance({ + port, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + }) + + test("waitForUserOperationReceipt_V06", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + test("waitForUserOperationReceipt_V07", async () => { + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await fund({ to: simpleAccountClient.account.address, anvilRpc }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 3220b266..16e9b20b 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -387,10 +387,6 @@ async function prepareUserOperationRequestEntryPointV07< gasParameters.verificationGasLimit userOperation.preVerificationGas = userOperation.preVerificationGas || gasParameters.preVerificationGas - - userOperation.paymasterPostOpGasLimit = - userOperation.paymasterPostOpGasLimit || - gasParameters.paymasterPostOpGasLimit userOperation.paymasterPostOpGasLimit = userOperation.paymasterPostOpGasLimit || gasParameters.paymasterPostOpGasLimit diff --git a/packages/permissionless/setupTests.ts b/packages/permissionless/setupTests.ts index bf1b5070..d4687e7c 100644 --- a/packages/permissionless/setupTests.ts +++ b/packages/permissionless/setupTests.ts @@ -1,19 +1,99 @@ -import { createServer } from "prool" -import { anvil } from "prool/instances" +import getPort from "get-port" +import { type Instance, createServer } from "prool" +import { alto, anvil } from "prool/instances" +import { http } from "viem" +import { foundry } from "viem/chains" +import { + ENTRY_POINT_SIMULATIONS_ADDRESS, + setupContracts +} from "../permissionless-test/mock-aa-infra/alto" +import { paymaster } from "../permissionless-test/mock-aa-infra/mock-paymaster" +import { createBundlerClient } from "./clients/createBundlerClient" +import type { EntryPoint } from "./types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "./utils" +export const anvilPort = 8485 const anvilServer = createServer({ instance: anvil({ - chainId: 1 + chainId: foundry.id }), limit: 5, - port: 8485 + port: anvilPort }) +const ports: Record = {} + +export const getPortForTestName = async (testName: string) => { + if (ports[testName]) { + return ports[testName] + } + + const port = await getPort() + ports[testName] = port + + return port +} + +const instances: Record = {} +const paymasterInstances: Record = {} + +export const startAltoInstance = async ({ + port, + entryPoint +}: { port: number; entryPoint: TEntryPoint }) => { + const altoRpc = `http://localhost:${port}` + const anvilRpc = `http://localhost:${anvilPort}/${port}` + + if (instances[port]) { + return createBundlerClient({ + transport: http(altoRpc), + entryPoint: entryPoint + }) + } + + const anvilPrivateKey = + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + + const instance = alto({ + entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], + rpcUrl: anvilRpc, + executorPrivateKeys: [anvilPrivateKey], + entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, + safeMode: false, + port + }) + + // instance.on("stderr", (data) => { + // console.log(data.toString()) + // }) + // instance.on("stdout", (data) => { + // console.log(data.toString()) + // }) + + instances[port] = instance + const paymasterInstance = paymaster({ + anvilRpc, + port: await getPort() + }) + paymasterInstances[port] = paymasterInstance + + await setupContracts(anvilRpc) + await instance.start() + await paymasterInstance.start() + + return createBundlerClient({ + transport: http(altoRpc), + entryPoint: entryPoint + }) +} + export const setup = async () => { await anvilServer.start() } export const teardown = async () => { - console.log("teardown") await anvilServer.stop() + await Promise.all( + Object.values(instances).map((instance) => instance.stop()) + ) } diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index fee0e197..3a8af670 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -3,6 +3,9 @@ import { defineConfig } from "vitest/config" export default defineConfig({ test: { + alias: { + permissionless: join(__dirname, "./") + }, globalSetup: [join(__dirname, "./setupTests.ts")], coverage: { all: false, From 721866f21acd8405fe2ee7348f5fbe05c19d6e38 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:29:17 +0530 Subject: [PATCH 04/20] fix build --- tsconfig/tsconfig.permissionless.json | 4 +++- tsconfig/tsconfig.wagmi.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tsconfig/tsconfig.permissionless.json b/tsconfig/tsconfig.permissionless.json index 632d24f9..cec9d51d 100644 --- a/tsconfig/tsconfig.permissionless.json +++ b/tsconfig/tsconfig.permissionless.json @@ -5,6 +5,8 @@ "../packages/permissionless" ], "exclude": [ + "../packages/permissionless-test/*", + "../packages/permissionless/**/setupTests.ts", "../packages/permissionless/**/*.test.ts", "../packages/permissionless/**/*.test-d.ts", "../packages/permissionless/**/*.bench.ts" @@ -14,4 +16,4 @@ "sourceMap": true, "rootDir": "../packages/permissionless" } -} +} \ No newline at end of file diff --git a/tsconfig/tsconfig.wagmi.json b/tsconfig/tsconfig.wagmi.json index 4770e5a4..20c976ab 100644 --- a/tsconfig/tsconfig.wagmi.json +++ b/tsconfig/tsconfig.wagmi.json @@ -5,6 +5,7 @@ "../packages/wagmi" ], "exclude": [ + "../packages/wagmi/node_modules", "../packages/wagmi/**/*.test.ts", "../packages/wagmi/**/*.test-d.ts", "../packages/wagmi/**/*.bench.ts" @@ -15,4 +16,4 @@ "rootDir": "../packages/wagmi" }, "jsx": "react-jsx", -} +} \ No newline at end of file From 858d930173737104a0a0f076eb2ec394f87f6e9f Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:39:10 +0530 Subject: [PATCH 05/20] remove wagmi build for now --- package.json | 2 +- tsconfig/tsconfig.base.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 85dbf842..bfa4fc21 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "keywords": [], "license": "MIT", "scripts": { - "build": "bun run build:permissionless && bun run build:wagmi", + "build": "bun run build:permissionless", "build:permissionless": "bun run clean:permissionless && bun run build:cjs && bun run build:esm && bun run build:types", "build:wagmi": "bun run clean:wagmi && bun run build:wagmi:cjs && bun run build:wagmi:esm && bun run build:wagmi:types", "build:cjs": "tsc --project ./tsconfig/tsconfig.permissionless.cjs.json && tsc-alias -p ./tsconfig/tsconfig.permissionless.cjs.json && printf '{\"type\":\"commonjs\"}' > ./packages/permissionless/_cjs/package.json", diff --git a/tsconfig/tsconfig.base.json b/tsconfig/tsconfig.base.json index a8ddd689..fc47f3bc 100644 --- a/tsconfig/tsconfig.base.json +++ b/tsconfig/tsconfig.base.json @@ -1,6 +1,5 @@ { // This tsconfig file contains the shared config for the build (tsconfig.build.json) and type checking (tsconfig.json) config. - "include": [], "compilerOptions": { // Incremental builds // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. @@ -42,4 +41,4 @@ "resolveFullPaths": true, "verbose": false } -} +} \ No newline at end of file From a1f1cacd55c7975e69fa4d6d5d7e12afe0aa8b36 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:44:23 +0530 Subject: [PATCH 06/20] Docker is not needed anymore for tests --- .github/workflows/on-pull-request.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 86696d0e..4bcc6cfc 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -28,16 +28,9 @@ jobs: - name: Build run: bun run build:permissionless - - name: Start Docker - run: docker compose -f "packages/permissionless-test/mock-aa-infra/docker-compose.yml" up -d - - name: Run tests & coverage run: bun run test:ci - - name: Stop containers - if: always() - run: docker compose -f "packages/permissionless-test/mock-aa-infra/docker-compose.yml" down - - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 env: From 0bbd8c994cb289bdcc430d2206144ab61abe78cf Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:46:34 +0530 Subject: [PATCH 07/20] update bun --- .github/actions/install-dependencies/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 97c27648..0d699ee8 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -7,7 +7,7 @@ runs: - name: Set up Bun uses: oven-sh/setup-bun@v1 with: - bun-version: 1.0.26 + bun-version: 1.0.30 - name: Set up foundry uses: foundry-rs/foundry-toolchain@v1 From 0842880af1f5f95432bb99ea47231e89f8296517 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:47:21 +0530 Subject: [PATCH 08/20] fix biome --- biome.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/biome.json b/biome.json index 9cc93617..b2665b47 100644 --- a/biome.json +++ b/biome.json @@ -39,7 +39,7 @@ "javascript": { "formatter": { "semicolons": "asNeeded", - "trailingComma": "none" + "trailingCommas": "none" } } } diff --git a/package.json b/package.json index bfa4fc21..20257823 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "changeset:version": "changeset version && bun install --lockfile-only", "format": "biome format . --write", "lint": "biome check .", - "lint:fix": "bun run lint --apply", + "lint:fix": "bun run lint --write", "test": "vitest dev -c ./packages/permissionless/vitest.config.ts", "test:ci": "CI=true && vitest -c ./packages/permissionless/vitest.config.ts --coverage --pool=forks", "wagmi-demo": "bun run --cwd packages/wagmi-demo dev", From 4dd7e740e91c92fd85f380547d49ee14a57c0f36 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 17:55:29 +0530 Subject: [PATCH 09/20] use node 22 with prool --- .github/workflows/on-pull-request.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 4bcc6cfc..eb171f1f 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -25,6 +25,10 @@ jobs: - name: Install dependencies uses: ./.github/actions/install-dependencies + - uses: actions/setup-node@v4 + with: + node-version: "v22.2.0" + - name: Build run: bun run build:permissionless From bda77e02510ea5338f502e635ee56b379605c1e3 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 22:57:55 +0530 Subject: [PATCH 10/20] Bundler actions test finished --- .../mock-aa-infra/mock-paymaster/index.ts | 10 +- .../mock-aa-infra/mock-paymaster/relay.ts | 2 - packages/permissionless-test/src/utils.ts | 9 +- .../actions/bundler/chainId.test.ts | 24 ++-- .../bundler/estimateUserOperationGas.test.ts | 37 +++--- .../bundler/getUserOperationByHash.test.ts | 119 +++++++----------- .../bundler/getUserOperationReceipt.test.ts | 58 +++++---- .../actions/bundler/sendUserOperation.test.ts | 58 +++++---- .../bundler/supportedEntryPoints.test.ts | 25 ++-- .../waitForUserOperationReceipt.test.ts | 55 ++++---- .../bundler/waitForUserOperationReceipt.ts | 2 +- packages/permissionless/setupTests.ts | 107 ++++++++++------ packages/permissionless/vitest.config.ts | 2 +- 13 files changed, 279 insertions(+), 229 deletions(-) diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts index f81d7a6b..01230e3e 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts @@ -13,7 +13,11 @@ import { import { createRpcHandler } from "./relay" export const paymaster = defineInstance( - ({ anvilRpc, port: _port }: { anvilRpc: string; port: number }) => { + ({ + anvilRpc, + port: _port, + altoRpc + }: { anvilRpc: string; port: number; altoRpc: string }) => { const app = Fastify({}) return { @@ -34,13 +38,13 @@ export const paymaster = defineInstance( const altoBundlerV07 = createPimlicoBundlerClient({ chain: foundry, - transport: http(process.env.ALTO_RPC), + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) const altoBundlerV06 = createPimlicoBundlerClient({ chain: foundry, - transport: http(process.env.ALTO_RPC), + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts index 849c3dc4..665a4231 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts @@ -295,8 +295,6 @@ export const createRpcHandler = ( walletClient: WalletClient ) => { return async (request: FastifyRequest, _reply: FastifyReply) => { - console.log(`received request: ${JSON.stringify(request.body)}`) - const body = request.body const parsedBody = jsonRpcSchema.safeParse(body) if (!parsedBody.success) { diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index c9b6c4d0..d80a2c59 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -102,12 +102,13 @@ export const getAnvilWalletClient = ({ }) } -export const getPimlicoPaymasterClient = ( - entryPoint: T -): PimlicoPaymasterClient => { +export const getPimlicoPaymasterClient = ({ + entryPoint, + paymasterRpc +}: { entryPoint: T; paymasterRpc: string }): PimlicoPaymasterClient => { return createPimlicoPaymasterClient({ chain: foundry, - transport: http(PAYMASTER_RPC), + transport: http(paymasterRpc), entryPoint }) } diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts index 0180262f..f66d7d8a 100644 --- a/packages/permissionless/actions/bundler/chainId.test.ts +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -1,19 +1,25 @@ +import type { Instance } from "prool" +import { http } from "viem" import { foundry } from "viem/chains" -import { beforeAll, describe, expect, test } from "vitest" -import type { BundlerClient } from "../../clients/createBundlerClient" -import { getPortForTestName, startAltoInstance } from "../../setupTests" +import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" -describe("chainId", () => { - let port: number +describe.sequential("chainId", () => { let bundlerClient: BundlerClient beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - bundlerClient = await startAltoInstance({ - port, - entryPoint: ENTRYPOINT_ADDRESS_V06 + const { altoPort } = getPortsForTest("bundlerActions") + const altoRpc = `http://localhost:${altoPort}` + const entryPoint = ENTRYPOINT_ADDRESS_V06 + bundlerClient = createBundlerClient({ + transport: http(altoRpc), + entryPoint }) }) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts index 1f649c18..cee02818 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts @@ -1,38 +1,41 @@ +import { http } from "viem" import { generatePrivateKey } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import type { BundlerClient } from "../../clients/createBundlerClient" import { - anvilPort, - getPortForTestName, - startAltoInstance -} from "../../setupTests" + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { anvilPort, getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("eth_estimateUserOperationGas", () => { - let port: number +describe.sequential("eth_estimateUserOperationGas", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient let anvilRpc: string let altoRpc: string + let paymasterRpc: string beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${port}` - altoRpc = `http://localhost:${port}` - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + altoRpc = `http://localhost:${altoPort}` + paymasterRpc = `http://localhost:${paymasterPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) @@ -42,7 +45,11 @@ describe("eth_estimateUserOperationGas", () => { entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) }) const userOperation = diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts index ecee52cf..85108a9b 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts @@ -1,39 +1,43 @@ -import { isHash, zeroAddress } from "viem" +import type { Instance } from "prool" +import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { - fund, + getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import type { BundlerClient } from "../../clients/createBundlerClient" import { - anvilPort, - getPortForTestName, - startAltoInstance -} from "../../setupTests" + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { anvilPort, getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("getUserOperationByHash", () => { - let port: number +describe.sequential("getUserOperationByHash", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient let anvilRpc: string let altoRpc: string + let paymasterRpc: string + const instances: Instance[] = [] beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${port}` - altoRpc = `http://localhost:${port}` - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + altoRpc = `http://localhost:${altoPort}` + paymasterRpc = `http://localhost:${paymasterPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) @@ -43,11 +47,13 @@ describe("getUserOperationByHash", () => { entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -69,7 +75,8 @@ describe("getUserOperationByHash", () => { expect(isHash(opHash)).toBe(true) await bundlerClientV06.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 10000 }) const userOperationFromUserOpHash = @@ -97,11 +104,13 @@ describe("getUserOperationByHash", () => { entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -122,61 +131,23 @@ describe("getUserOperationByHash", () => { expect(isHash(opHash)).toBe(true) - await bundlerClientV07.waitForUserOperationReceipt({ hash: opHash }) + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 10000 + }) const userOperationFromUserOpHash = await bundlerClientV07.getUserOperationByHash({ hash: opHash }) - expect(userOperationFromUserOpHash).not.toBeNull() - expect(userOperationFromUserOpHash?.entryPoint).toBe( - ENTRYPOINT_ADDRESS_V07 - ) + for (const key in userOperationFromUserOpHash?.userOperation) { + const expected = userOperationFromUserOpHash?.userOperation[key] + const actual = userOperation[key] - expect( - userOperationFromUserOpHash?.userOperation.sender.toLowerCase() - ).toBe(userOperation.sender.toLowerCase()) - expect(userOperationFromUserOpHash?.userOperation.nonce).toBe( - userOperation.nonce - ) - expect( - userOperationFromUserOpHash?.userOperation.factory?.toLowerCase() - ).toBe(userOperation.factory?.toLowerCase()) - expect( - userOperationFromUserOpHash?.userOperation.factoryData?.toLowerCase() - ).toBe(userOperation.factoryData?.toLowerCase()) - expect( - userOperationFromUserOpHash?.userOperation.callData.toLowerCase() - ).toBe(userOperation.callData.toLowerCase()) - expect(userOperationFromUserOpHash?.userOperation.callGasLimit).toBe( - userOperation.callGasLimit - ) - expect( - userOperationFromUserOpHash?.userOperation.verificationGasLimit - ).toBe(userOperation.verificationGasLimit) - expect( - userOperationFromUserOpHash?.userOperation.preVerificationGas - ).toBe(userOperation.preVerificationGas) - expect(userOperationFromUserOpHash?.userOperation.maxFeePerGas).toBe( - userOperation.maxFeePerGas - ) - expect( - userOperationFromUserOpHash?.userOperation.maxPriorityFeePerGas - ).toBe(userOperation.maxPriorityFeePerGas) - expect( - userOperationFromUserOpHash?.userOperation.signature.toLowerCase() - ).toBe(userOperation.signature.toLowerCase()) - expect( - userOperationFromUserOpHash?.userOperation.paymaster?.toLowerCase() - ).toBe(userOperation.paymaster?.toLowerCase()) - expect( - userOperationFromUserOpHash?.userOperation - .paymasterVerificationGasLimit - ).toBe(userOperation.paymasterVerificationGasLimit) - expect( - userOperationFromUserOpHash?.userOperation.paymasterPostOpGasLimit - ).toBe(undefined) - expect( - userOperationFromUserOpHash?.userOperation.paymasterData?.toLowerCase() - ).toBe(userOperation.paymasterData?.toLowerCase()) + if (typeof expected === "string" && typeof actual === "string") { + expect(expected.toLowerCase()).toBe(actual.toLowerCase()) + } else { + expect(expected).toBe(actual) + } + } }) }) diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts index 94a2f885..e7a66026 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts @@ -1,39 +1,43 @@ -import { isHash, zeroAddress } from "viem" +import type { Instance } from "prool" +import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { beforeAll, describe, expect, test } from "vitest" +import { afterAll, beforeAll, describe, expect, test } from "vitest" import { fund, + getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import type { BundlerClient } from "../../clients/createBundlerClient" import { - anvilPort, - getPortForTestName, - startAltoInstance -} from "../../setupTests" + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { anvilPort, getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("getUserOperationReceipt", () => { - let port: number +describe.sequential("getUserOperationReceipt", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient let anvilRpc: string let altoRpc: string + let paymasterRpc: string beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${port}` - altoRpc = `http://localhost:${port}` - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + altoRpc = `http://localhost:${altoPort}` + paymasterRpc = `http://localhost:${paymasterPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) @@ -43,11 +47,13 @@ describe("getUserOperationReceipt", () => { entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -70,7 +76,8 @@ describe("getUserOperationReceipt", () => { const userOperationReceipt = await bundlerClientV06.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) @@ -90,11 +97,13 @@ describe("getUserOperationReceipt", () => { entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -117,7 +126,8 @@ describe("getUserOperationReceipt", () => { const userOperationReceipt = await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) diff --git a/packages/permissionless/actions/bundler/sendUserOperation.test.ts b/packages/permissionless/actions/bundler/sendUserOperation.test.ts index 569373ec..f5df2a96 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.test.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.test.ts @@ -1,39 +1,43 @@ -import { isHash, zeroAddress } from "viem" +import type { Instance } from "prool" +import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { beforeAll, describe, expect, test } from "vitest" +import { afterAll, beforeAll, describe, expect, test } from "vitest" import { fund, + getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import type { BundlerClient } from "../../clients/createBundlerClient" import { - anvilPort, - getPortForTestName, - startAltoInstance -} from "../../setupTests" + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { anvilPort, getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("sendUserOperation", () => { - let port: number +describe.sequential("sendUserOperation", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient let anvilRpc: string let altoRpc: string + let paymasterRpc: string beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${port}` - altoRpc = `http://localhost:${port}` - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + altoRpc = `http://localhost:${altoPort}` + paymasterRpc = `http://localhost:${paymasterPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) @@ -43,11 +47,13 @@ describe("sendUserOperation", () => { entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -70,7 +76,8 @@ describe("sendUserOperation", () => { const userOperationReceipt = await bundlerClientV06.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) @@ -90,11 +97,13 @@ describe("sendUserOperation", () => { entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -117,7 +126,8 @@ describe("sendUserOperation", () => { const userOperationReceipt = await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts index 0ffdf323..2dbdddca 100644 --- a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts @@ -1,27 +1,32 @@ -import { foundry } from "viem/chains" +import { http } from "viem" import { beforeAll, describe, expect, test } from "vitest" -import type { BundlerClient } from "../../clients/createBundlerClient" -import { getPortForTestName, startAltoInstance } from "../../setupTests" +import { + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("supportedEntryPoints", () => { - let port: number +describe.sequential("supportedEntryPoints", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient + let altoRpc: string beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort } = getPortsForTest("bundlerActions") + altoRpc = `http://localhost:${altoPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts index 2f4e3010..b323a5fd 100644 --- a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts @@ -1,39 +1,42 @@ -import { isHash, zeroAddress } from "viem" +import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { beforeAll, describe, expect, test } from "vitest" import { fund, + getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import type { BundlerClient } from "../../clients/createBundlerClient" import { - anvilPort, - getPortForTestName, - startAltoInstance -} from "../../setupTests" + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import { anvilPort, getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe("waitForUserOperationReceipt", () => { - let port: number +describe.sequential("waitForUserOperationReceipt", () => { let bundlerClientV06: BundlerClient let bundlerClientV07: BundlerClient let anvilRpc: string let altoRpc: string + let paymasterRpc: string beforeAll(async () => { - port = await getPortForTestName("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${port}` - altoRpc = `http://localhost:${port}` - bundlerClientV06 = await startAltoInstance({ - port, + const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") + anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + altoRpc = `http://localhost:${altoPort}` + paymasterRpc = `http://localhost:${paymasterPort}` + + bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = await startAltoInstance({ - port, + + bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) }) @@ -43,11 +46,13 @@ describe("waitForUserOperationReceipt", () => { entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -70,7 +75,8 @@ describe("waitForUserOperationReceipt", () => { const userOperationReceipt = await bundlerClientV06.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) @@ -90,11 +96,13 @@ describe("waitForUserOperationReceipt", () => { entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), altoRpc: altoRpc, - anvilRpc: anvilRpc + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) }) - await fund({ to: simpleAccountClient.account.address, anvilRpc }) - const userOperation = await simpleAccountClient.prepareUserOperationRequest({ userOperation: { @@ -117,7 +125,8 @@ describe("waitForUserOperationReceipt", () => { const userOperationReceipt = await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash + hash: opHash, + timeout: 100000 }) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts index 676edd0a..8ed2a875 100644 --- a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts @@ -19,7 +19,7 @@ export class WaitForUserOperationReceiptTimeoutError extends BaseError { override name = "WaitForUserOperationReceiptTimeoutError" constructor({ hash }: { hash: Hash }) { super( - `Timed out while waiting for transaction with hash "${hash}" to be confirmed.` + `Timed out while waiting for user operation with hash "${hash}" to be confirmed.` ) } } diff --git a/packages/permissionless/setupTests.ts b/packages/permissionless/setupTests.ts index d4687e7c..eb6f9181 100644 --- a/packages/permissionless/setupTests.ts +++ b/packages/permissionless/setupTests.ts @@ -8,7 +8,6 @@ import { setupContracts } from "../permissionless-test/mock-aa-infra/alto" import { paymaster } from "../permissionless-test/mock-aa-infra/mock-paymaster" -import { createBundlerClient } from "./clients/createBundlerClient" import type { EntryPoint } from "./types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "./utils" @@ -21,35 +20,67 @@ const anvilServer = createServer({ port: anvilPort }) -const ports: Record = {} - -export const getPortForTestName = async (testName: string) => { - if (ports[testName]) { - return ports[testName] +export const getPortsForTest = (name: "bundlerActions") => { + switch (name) { + case "bundlerActions": + return { + altoPort: 43371, + paymasterPort: 43372 + } } - - const port = await getPort() - ports[testName] = port - - return port } -const instances: Record = {} -const paymasterInstances: Record = {} +// export const getAltoInstance = async ({ +// anvilPort, +// altoPort, +// paymasterPort +// }: { anvilPort: number; altoPort: number; paymasterPort: number }) => { +// const anvilRpc = `http://localhost:${anvilPort}` +// const altoRpc = `http://localhost:${altoPort}` + +// const anvilPrivateKey = +// "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +// const anvilInstance = anvil({ +// chainId: foundry.id, +// port: anvilPort +// }) + +// const instance = alto({ +// entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], +// rpcUrl: anvilRpc, +// executorPrivateKeys: [anvilPrivateKey], +// entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, +// safeMode: false, +// port: altoPort +// }) + +// // instance.on("stderr", (data) => { +// // console.error(data.toString()) +// // }) +// // instance.on("stdout", (data) => { +// // console.log(data.toString()) +// // }) + +// const paymasterInstance = paymaster({ +// anvilRpc, +// port: paymasterPort, +// altoRpc +// }) +// await anvilInstance.start() +// await setupContracts(anvilRpc) +// await instance.start() +// await paymasterInstance.start() + +// return [anvilInstance, instance, paymasterInstance] +// } export const startAltoInstance = async ({ - port, - entryPoint -}: { port: number; entryPoint: TEntryPoint }) => { - const altoRpc = `http://localhost:${port}` - const anvilRpc = `http://localhost:${anvilPort}/${port}` - - if (instances[port]) { - return createBundlerClient({ - transport: http(altoRpc), - entryPoint: entryPoint - }) - } + altoPort, + paymasterPort +}: { altoPort: number; paymasterPort: number }) => { + const anvilRpc = `http://localhost:${anvilPort}/${altoPort}` + const altoRpc = `http://localhost:${altoPort}` const anvilPrivateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" @@ -60,40 +91,38 @@ export const startAltoInstance = async ({ executorPrivateKeys: [anvilPrivateKey], entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, safeMode: false, - port + port: altoPort }) // instance.on("stderr", (data) => { - // console.log(data.toString()) + // console.error(data.toString()) // }) // instance.on("stdout", (data) => { // console.log(data.toString()) // }) - instances[port] = instance const paymasterInstance = paymaster({ anvilRpc, - port: await getPort() + port: paymasterPort, + altoRpc }) - paymasterInstances[port] = paymasterInstance - await setupContracts(anvilRpc) await instance.start() await paymasterInstance.start() - return createBundlerClient({ - transport: http(altoRpc), - entryPoint: entryPoint - }) + instances.push(instance) + instances.push(paymasterInstance) } +const instances: Instance[] = [] export const setup = async () => { await anvilServer.start() + await startAltoInstance(getPortsForTest("bundlerActions")) } export const teardown = async () => { - await anvilServer.stop() - await Promise.all( - Object.values(instances).map((instance) => instance.stop()) - ) + await Promise.all([ + ...instances.map((instance) => instance.stop()), + anvilServer.stop() + ]) } diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index 3a8af670..9340f8f5 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -21,7 +21,7 @@ export default defineConfig({ sequence: { concurrent: true }, - fileParallelism: true, + fileParallelism: false, environment: "node", testTimeout: 60_000, hookTimeout: 45_000, From 92cbd3c14afea00a22e7f3094aed4bd13fea721f Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 22:59:10 +0530 Subject: [PATCH 11/20] kint --- .../accounts/trust/privateKeyToTrustSmartAccount.ts | 2 +- packages/permissionless/package.json | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts index ab638f68..f3cfe41d 100644 --- a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts @@ -1,4 +1,4 @@ -import { type Chain, type Client, type Hex, type Transport } from "viem" +import type { Chain, Client, Hex, Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { diff --git a/packages/permissionless/package.json b/packages/permissionless/package.json index e5a62fe2..a52850e7 100644 --- a/packages/permissionless/package.json +++ b/packages/permissionless/package.json @@ -11,13 +11,7 @@ "type": "module", "sideEffects": false, "description": "A utility library for working with ERC-4337", - "keywords": [ - "ethereum", - "erc-4337", - "eip-4337", - "paymaster", - "bundler" - ], + "keywords": ["ethereum", "erc-4337", "eip-4337", "paymaster", "bundler"], "license": "MIT", "exports": { ".": { From f2171ba419532710eb0ae9e98e56d40cdda6e153 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 11 Jun 2024 23:07:43 +0530 Subject: [PATCH 12/20] fix converage --- packages/permissionless/vitest.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index 9340f8f5..d33df1bf 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -13,6 +13,8 @@ export default defineConfig({ reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], exclude: [ "**/errors/utils.ts", + "**/*.test.ts", + "**/permissionless-test/**", "**/_cjs/**", "**/_esm/**", "**/_types/**" From 00a1a14bb342e0506f4084782c84d335cfc79091 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 14:59:37 +0530 Subject: [PATCH 13/20] Run tests in parallel --- .../mock-aa-infra/alto/index.ts | 14 +- .../permissionless-test/src/testWithRpc.ts | 109 ++++++++++++ .../actions/bundler/chainId.test.ts | 25 ++- .../bundler/estimateUserOperationGas.test.ts | 159 ++++++++++++++---- .../bundler/getUserOperationByHash.test.ts | 49 ++---- .../bundler/getUserOperationReceipt.test.ts | 48 ++---- .../actions/bundler/sendUserOperation.test.ts | 49 ++---- .../bundler/supportedEntryPoints.test.ts | 41 ++--- .../waitForUserOperationReceipt.test.ts | 48 ++---- packages/permissionless/setupTests.ts | 128 -------------- packages/permissionless/vitest.config.ts | 5 +- 11 files changed, 320 insertions(+), 355 deletions(-) create mode 100644 packages/permissionless-test/src/testWithRpc.ts delete mode 100644 packages/permissionless/setupTests.ts diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index 3c472dfb..acbac6fd 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -60,8 +60,6 @@ const verifyDeployed = async (client: PublicClient, addresses: Address[]) => { } export const setupContracts = async (rpc: string) => { - let nonce = 0 - const walletClient = createWalletClient({ account: mnemonicToAccount( "test test test test test test test test test test test junk" @@ -79,6 +77,10 @@ export const setupContracts = async (rpc: string) => { transport: http(rpc) }) + let nonce = await client.getTransactionCount({ + address: walletClient.account.address + }) + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: ENTRY_POINT_V07_CREATECALL, @@ -264,14 +266,6 @@ export const setupContracts = async (rpc: string) => { nonce: nonce++ }) - let onchainNonce = 0 - do { - onchainNonce = await client.getTransactionCount({ - address: walletClient.account.address - }) - await new Promise((resolve) => setTimeout(resolve, 500)) - } while (onchainNonce !== nonce) - // ==== SETUP KERNEL V0.6 CONTRACTS ==== // const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" await anvilClient.setBalance({ diff --git a/packages/permissionless-test/src/testWithRpc.ts b/packages/permissionless-test/src/testWithRpc.ts new file mode 100644 index 00000000..d05b837e --- /dev/null +++ b/packages/permissionless-test/src/testWithRpc.ts @@ -0,0 +1,109 @@ +import getPort from "get-port" +import { alto, anvil } from "prool/instances" +import { foundry } from "viem/chains" +import { test } from "vitest" +import type { EntryPoint } from "../../permissionless/types/entrypoint" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07 +} from "../../permissionless/utils" +import { + ENTRY_POINT_SIMULATIONS_ADDRESS, + setupContracts +} from "../mock-aa-infra/alto" +import { paymaster } from "../mock-aa-infra/mock-paymaster" + +export const getAltoInstance = async ({ + anvilPort, + altoPort, + paymasterPort +}: { anvilPort: number; altoPort: number; paymasterPort: number }) => { + const anvilRpc = `http://localhost:${anvilPort}` + const altoRpc = `http://localhost:${altoPort}` + + const anvilPrivateKey = + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + + const anvilInstance = anvil({ + chainId: foundry.id, + port: anvilPort + }) + + const instance = alto({ + entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], + rpcUrl: anvilRpc, + executorPrivateKeys: [anvilPrivateKey], + entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, + safeMode: false, + port: altoPort + }) + + // instance.on("stderr", (data) => { + // console.error(data.toString()) + // }) + // instance.on("stdout", (data) => { + // console.log(data.toString()) + // }) + + const paymasterInstance = paymaster({ + anvilRpc, + port: paymasterPort, + altoRpc + }) + await anvilInstance.start() + await setupContracts(anvilRpc) + await instance.start() + await paymasterInstance.start() + + return [anvilInstance, instance, paymasterInstance] +} + +let ports: number[] = [] + +export const testWithRpc = test.extend<{ + rpc: { + anvilRpc: string + altoRpc: string + paymasterRpc: string + } +}>({ + // biome-ignore lint/correctness/noEmptyPattern: Needed in vitest :/ + rpc: async ({}, use) => { + const altoPort = await getPort({ + exclude: ports + }) + ports.push(altoPort) + const paymasterPort = await getPort({ + exclude: ports + }) + ports.push(paymasterPort) + const anvilPort = await getPort({ + exclude: ports + }) + ports.push(anvilPort) + + const anvilRpc = `http://localhost:${anvilPort}` + const altoRpc = `http://localhost:${altoPort}` + const paymasterRpc = `http://localhost:${paymasterPort}` + + const instances = await getAltoInstance({ + anvilPort, + altoPort, + paymasterPort + }) + + await use({ + anvilRpc, + altoRpc, + paymasterRpc + }) + + await Promise.all([...instances.map((instance) => instance.stop())]) + ports = ports.filter( + (port) => + port !== altoPort || + port !== anvilPort || + port !== paymasterPort + ) + } +}) diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts index f66d7d8a..c95ac010 100644 --- a/packages/permissionless/actions/bundler/chainId.test.ts +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -1,29 +1,24 @@ -import type { Instance } from "prool" import { http } from "viem" import { foundry } from "viem/chains" -import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { type BundlerClient, createBundlerClient } from "../../clients/createBundlerClient" -import { getPortsForTest } from "../../setupTests" import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" -describe.sequential("chainId", () => { - let bundlerClient: BundlerClient - - beforeAll(async () => { - const { altoPort } = getPortsForTest("bundlerActions") - const altoRpc = `http://localhost:${altoPort}` +describe("chainId", () => { + testWithRpc("chainId", async ({ rpc }) => { + const { altoRpc } = rpc const entryPoint = ENTRYPOINT_ADDRESS_V06 - bundlerClient = createBundlerClient({ - transport: http(altoRpc), - entryPoint - }) - }) - test("chainId", async () => { + const bundlerClient: BundlerClient = + createBundlerClient({ + transport: http(altoRpc), + entryPoint + }) const chainId = await bundlerClient.chainId() expect(chainId).toBe(foundry.id) }) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts index cee02818..80d81ecb 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts @@ -1,46 +1,23 @@ -import { http } from "viem" +import { http, parseEther } from "viem" import { generatePrivateKey } from "viem/accounts" -import { beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { anvilPort, getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("eth_estimateUserOperationGas", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let anvilRpc: string - let altoRpc: string - let paymasterRpc: string - - beforeAll(async () => { - const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - altoRpc = `http://localhost:${altoPort}` - paymasterRpc = `http://localhost:${paymasterPort}` +describe("eth_estimateUserOperationGas", () => { + testWithRpc("eth_estimateUserOperationGas_v06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc - bundlerClientV06 = createBundlerClient({ + const bundlerClientV06 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("eth_estimateUserOperationGas_v06", async () => { const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), @@ -64,16 +41,33 @@ describe.sequential("eth_estimateUserOperationGas", () => { }) const { preVerificationGas, verificationGasLimit, callGasLimit } = - await bundlerClientV06.estimateUserOperationGas({ - userOperation - }) + await bundlerClientV06.estimateUserOperationGas( + { + userOperation + }, + { + "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC": { + balance: parseEther("1"), + stateDiff: { + "0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0": + "0x00000000000000000000000000000000000000000000000000000000000001a4" + } + } + } + ) expect(preVerificationGas).toBeTruthy() expect(verificationGasLimit).toBeTruthy() expect(callGasLimit).toBeTruthy() }) - test("eth_estimateUserOperationGas_v07", async () => { + testWithRpc("eth_estimateUserOperationGas_v07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const smartAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), @@ -107,5 +101,98 @@ describe.sequential("eth_estimateUserOperationGas", () => { expect(callGasLimit).toBeTruthy() expect(paymasterVerificationGasLimit).toBe(0n) expect(paymasterPostOpGasLimit).toBe(0n) - }, 100000) + }) + + testWithRpc( + "eth_estimateUserOperationGas_V07_with_error", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 1000n + }) + } + }) + + await expect(() => + bundlerClientV07.estimateUserOperationGas( + { + userOperation + }, + { + [smartAccountClient.account.address]: { + balance: 0n + } + } + ) + ).rejects.toThrowError(/AA21/) + } + ) + + testWithRpc( + "eth_estimateUserOperationGas_V07_withPaymaster", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { + preVerificationGas, + verificationGasLimit, + callGasLimit, + paymasterVerificationGasLimit, + paymasterPostOpGasLimit + } = await bundlerClientV07.estimateUserOperationGas({ + userOperation + }) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + expect(paymasterVerificationGasLimit).toBeTruthy() + expect(paymasterPostOpGasLimit).toBeTruthy() + } + ) }) diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts index 85108a9b..6f1e7d5c 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts @@ -1,48 +1,22 @@ -import type { Instance } from "prool" import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { anvilPort, getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("getUserOperationByHash", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let anvilRpc: string - let altoRpc: string - let paymasterRpc: string - const instances: Instance[] = [] - - beforeAll(async () => { - const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - altoRpc = `http://localhost:${altoPort}` - paymasterRpc = `http://localhost:${paymasterPort}` - - bundlerClientV06 = createBundlerClient({ +describe("getUserOperationByHash", () => { + testWithRpc("getUserOperationByHash_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV06 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("getUserOperationByHash_V06", async () => { const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), @@ -99,7 +73,14 @@ describe.sequential("getUserOperationByHash", () => { } }) - test("getUserOperationByHash_V07", async () => { + testWithRpc("getUserOperationByHash_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts index e7a66026..6e5b3d84 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts @@ -1,48 +1,23 @@ -import type { Instance } from "prool" import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { - fund, getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { anvilPort, getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("getUserOperationReceipt", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let anvilRpc: string - let altoRpc: string - let paymasterRpc: string - - beforeAll(async () => { - const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - altoRpc = `http://localhost:${altoPort}` - paymasterRpc = `http://localhost:${paymasterPort}` +describe("getUserOperationReceipt", () => { + testWithRpc("getUserOperationReceipt_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc - bundlerClientV06 = createBundlerClient({ + const bundlerClientV06 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("getUserOperationReceipt_V06", async () => { const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), @@ -92,7 +67,14 @@ describe.sequential("getUserOperationReceipt", () => { ) }) - test("getUserOperationReceipt_V07", async () => { + testWithRpc("getUserOperationReceipt_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), diff --git a/packages/permissionless/actions/bundler/sendUserOperation.test.ts b/packages/permissionless/actions/bundler/sendUserOperation.test.ts index f5df2a96..6b9d923a 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.test.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.test.ts @@ -1,48 +1,22 @@ -import type { Instance } from "prool" import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { afterAll, beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { - fund, getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { anvilPort, getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("sendUserOperation", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let anvilRpc: string - let altoRpc: string - let paymasterRpc: string - - beforeAll(async () => { - const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - altoRpc = `http://localhost:${altoPort}` - paymasterRpc = `http://localhost:${paymasterPort}` +describe("sendUserOperation", () => { + testWithRpc("sendUserOperation_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc - bundlerClientV06 = createBundlerClient({ + const bundlerClientV06 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("sendUserOperation_V06", async () => { const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), @@ -92,7 +66,14 @@ describe.sequential("sendUserOperation", () => { ) }) - test("sendUserOperation_V07", async () => { + testWithRpc("sendUserOperation_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts index 2dbdddca..f9f8a326 100644 --- a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts @@ -1,42 +1,25 @@ import { http } from "viem" -import { beforeAll, describe, expect, test } from "vitest" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("supportedEntryPoints", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let altoRpc: string - - beforeAll(async () => { - const { altoPort } = getPortsForTest("bundlerActions") - altoRpc = `http://localhost:${altoPort}` - - bundlerClientV06 = createBundlerClient({ - transport: http(altoRpc), +describe("supportedEntryPoints", () => { + testWithRpc("supportedEntryPoints_V06", async ({ rpc }) => { + const bundlerClientV06 = createBundlerClient({ + transport: http(rpc.altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("supportedEntryPoints_V06", async () => { const entryPoints = await bundlerClientV06.supportedEntryPoints() expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V06) }) - test("supportedEntryPoints_V07", async () => { + testWithRpc("supportedEntryPoints_V07", async ({ rpc }) => { + const bundlerClientV07 = createBundlerClient({ + transport: http(rpc.altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) const entryPoints = await bundlerClientV07.supportedEntryPoints() expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V07) }) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts index b323a5fd..9ebd95ce 100644 --- a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts @@ -1,47 +1,22 @@ import { http, isHash, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" -import { beforeAll, describe, expect, test } from "vitest" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { - fund, getPimlicoPaymasterClient, getSimpleAccountClient } from "../../../permissionless-test/src/utils" -import { - type BundlerClient, - createBundlerClient -} from "../../clients/createBundlerClient" -import { anvilPort, getPortsForTest } from "../../setupTests" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE -} from "../../types/entrypoint" +import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.sequential("waitForUserOperationReceipt", () => { - let bundlerClientV06: BundlerClient - let bundlerClientV07: BundlerClient - let anvilRpc: string - let altoRpc: string - let paymasterRpc: string - - beforeAll(async () => { - const { altoPort, paymasterPort } = getPortsForTest("bundlerActions") - anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - altoRpc = `http://localhost:${altoPort}` - paymasterRpc = `http://localhost:${paymasterPort}` +describe("waitForUserOperationReceipt", () => { + testWithRpc("waitForUserOperationReceipt_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc - bundlerClientV06 = createBundlerClient({ + const bundlerClientV06 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V06 }) - - bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - }) - - test("waitForUserOperationReceipt_V06", async () => { const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V06, privateKey: generatePrivateKey(), @@ -91,7 +66,14 @@ describe.sequential("waitForUserOperationReceipt", () => { ) }) - test("waitForUserOperationReceipt_V07", async () => { + testWithRpc("waitForUserOperationReceipt_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const simpleAccountClient = await getSimpleAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), diff --git a/packages/permissionless/setupTests.ts b/packages/permissionless/setupTests.ts deleted file mode 100644 index eb6f9181..00000000 --- a/packages/permissionless/setupTests.ts +++ /dev/null @@ -1,128 +0,0 @@ -import getPort from "get-port" -import { type Instance, createServer } from "prool" -import { alto, anvil } from "prool/instances" -import { http } from "viem" -import { foundry } from "viem/chains" -import { - ENTRY_POINT_SIMULATIONS_ADDRESS, - setupContracts -} from "../permissionless-test/mock-aa-infra/alto" -import { paymaster } from "../permissionless-test/mock-aa-infra/mock-paymaster" -import type { EntryPoint } from "./types/entrypoint" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "./utils" - -export const anvilPort = 8485 -const anvilServer = createServer({ - instance: anvil({ - chainId: foundry.id - }), - limit: 5, - port: anvilPort -}) - -export const getPortsForTest = (name: "bundlerActions") => { - switch (name) { - case "bundlerActions": - return { - altoPort: 43371, - paymasterPort: 43372 - } - } -} - -// export const getAltoInstance = async ({ -// anvilPort, -// altoPort, -// paymasterPort -// }: { anvilPort: number; altoPort: number; paymasterPort: number }) => { -// const anvilRpc = `http://localhost:${anvilPort}` -// const altoRpc = `http://localhost:${altoPort}` - -// const anvilPrivateKey = -// "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - -// const anvilInstance = anvil({ -// chainId: foundry.id, -// port: anvilPort -// }) - -// const instance = alto({ -// entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], -// rpcUrl: anvilRpc, -// executorPrivateKeys: [anvilPrivateKey], -// entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, -// safeMode: false, -// port: altoPort -// }) - -// // instance.on("stderr", (data) => { -// // console.error(data.toString()) -// // }) -// // instance.on("stdout", (data) => { -// // console.log(data.toString()) -// // }) - -// const paymasterInstance = paymaster({ -// anvilRpc, -// port: paymasterPort, -// altoRpc -// }) -// await anvilInstance.start() -// await setupContracts(anvilRpc) -// await instance.start() -// await paymasterInstance.start() - -// return [anvilInstance, instance, paymasterInstance] -// } - -export const startAltoInstance = async ({ - altoPort, - paymasterPort -}: { altoPort: number; paymasterPort: number }) => { - const anvilRpc = `http://localhost:${anvilPort}/${altoPort}` - const altoRpc = `http://localhost:${altoPort}` - - const anvilPrivateKey = - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - - const instance = alto({ - entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], - rpcUrl: anvilRpc, - executorPrivateKeys: [anvilPrivateKey], - entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, - safeMode: false, - port: altoPort - }) - - // instance.on("stderr", (data) => { - // console.error(data.toString()) - // }) - // instance.on("stdout", (data) => { - // console.log(data.toString()) - // }) - - const paymasterInstance = paymaster({ - anvilRpc, - port: paymasterPort, - altoRpc - }) - await setupContracts(anvilRpc) - await instance.start() - await paymasterInstance.start() - - instances.push(instance) - instances.push(paymasterInstance) -} - -const instances: Instance[] = [] -export const setup = async () => { - await anvilServer.start() - await startAltoInstance(getPortsForTest("bundlerActions")) -} - -export const teardown = async () => { - await Promise.all([ - ...instances.map((instance) => instance.stop()), - anvilServer.stop() - ]) -} diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index d33df1bf..6a6a6671 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -6,7 +6,6 @@ export default defineConfig({ alias: { permissionless: join(__dirname, "./") }, - globalSetup: [join(__dirname, "./setupTests.ts")], coverage: { all: false, provider: "v8", @@ -21,9 +20,9 @@ export default defineConfig({ ] }, sequence: { - concurrent: true + concurrent: false }, - fileParallelism: false, + fileParallelism: true, environment: "node", testTimeout: 60_000, hookTimeout: 45_000, From 950ff6dbf46780d8f22f38fecf1e8578296ecbb5 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 15:00:12 +0530 Subject: [PATCH 14/20] Add Pimlico & public actions tests --- .../pimlico/getUserOperationGasPrice.test.ts | 32 ++++ .../pimlico/getUserOperationStatus.test.ts | 147 ++++++++++++++++++ .../pimlico/sponsorUserOperation.test.ts | 126 +++++++++++++++ .../validateSponsorshipPolicies.test.ts | 52 +++++++ .../actions/public/getAccountNonce.test.ts | 52 +++++++ .../actions/public/getSenderAddress.test.ts | 83 ++++++++++ .../smartAccount/deployContract.test.ts | 0 7 files changed, 492 insertions(+) create mode 100644 packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts create mode 100644 packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts create mode 100644 packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts create mode 100644 packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts create mode 100644 packages/permissionless/actions/public/getAccountNonce.test.ts create mode 100644 packages/permissionless/actions/public/getSenderAddress.test.ts create mode 100644 packages/permissionless/actions/smartAccount/deployContract.test.ts diff --git a/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts new file mode 100644 index 00000000..bbbcecb5 --- /dev/null +++ b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts @@ -0,0 +1,32 @@ +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getPimlicoBundlerClient } from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" + +describe("getUserOperationGasPrice", () => { + testWithRpc("getUserOperationGasPrice", async ({ rpc }) => { + const pimlicoBundlerClient = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: rpc.altoRpc + }) + + const gasPrice = await pimlicoBundlerClient.getUserOperationGasPrice() + + expect(gasPrice).toBeTruthy() + expect(gasPrice.slow).toBeTruthy() + expect(gasPrice.standard).toBeTruthy() + expect(gasPrice.fast).toBeTruthy() + expect(typeof gasPrice.slow.maxFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.slow.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxPriorityFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.standard.maxFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.standard.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxPriorityFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.fast.maxFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.fast.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxPriorityFeePerGas).toBeGreaterThan(0n) + }) +}) diff --git a/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts new file mode 100644 index 00000000..37109215 --- /dev/null +++ b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts @@ -0,0 +1,147 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoBundlerClient, + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { bundlerActions } from "../../clients/decorators/bundler" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("getUserOperationStatus", () => { + testWithRpc("getUserOperationStatus_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: altoRpc + }).extend(bundlerActions(ENTRYPOINT_ADDRESS_V06)) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + const userOperationStatus = + await bundlerClientV06.getUserOperationStatus({ + hash: opHash + }) + expect(userOperationStatus).not.toBeNull() + expect(userOperationStatus).not.toBeUndefined() + expect(userOperationStatus.status).toBe("included") + expect(userOperationStatus.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("getUserOperationStatus_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + altoRpc: altoRpc + }).extend(bundlerActions(ENTRYPOINT_ADDRESS_V07)) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + const userOperationStatus = + await bundlerClientV07.getUserOperationStatus({ + hash: opHash + }) + expect(userOperationStatus).not.toBeNull() + expect(userOperationStatus).not.toBeUndefined() + expect(userOperationStatus.status).toBe("included") + expect(userOperationStatus.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts new file mode 100644 index 00000000..1a1d4d2d --- /dev/null +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts @@ -0,0 +1,126 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("sponsorUserOperation", () => { + testWithRpc("sponsorUserOperation_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + transport: http(altoRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("sponsorUserOperation_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + transport: http(altoRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts new file mode 100644 index 00000000..c1e3dbcf --- /dev/null +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts @@ -0,0 +1,52 @@ +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" + +describe("validateSponsorshipPolicies", () => { + testWithRpc("Validating sponsorship policies", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const pimlicoPaymasterClient = getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + + const validateSponsorshipPolicies = + await pimlicoPaymasterClient.validateSponsorshipPolicies({ + userOperation: userOperation, + sponsorshipPolicyIds: ["sp_crazy_kangaroo"] + }) + + expect(validateSponsorshipPolicies).toBeTruthy() + expect(validateSponsorshipPolicies.length).toBeGreaterThan(0) + expect(Array.isArray(validateSponsorshipPolicies)).toBe(true) + expect(validateSponsorshipPolicies.length).toBe(1) + }) +}) diff --git a/packages/permissionless/actions/public/getAccountNonce.test.ts b/packages/permissionless/actions/public/getAccountNonce.test.ts new file mode 100644 index 00000000..2fe9099e --- /dev/null +++ b/packages/permissionless/actions/public/getAccountNonce.test.ts @@ -0,0 +1,52 @@ +import { http, createPublicClient } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getSimpleAccountClient } from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getAccountNonce } from "./getAccountNonce" + +describe("getAccountNonce", () => { + testWithRpc("getAccountNonce_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const nonce = await getAccountNonce(client, { + entryPoint: ENTRYPOINT_ADDRESS_V06, + sender: simpleAccountClient.account.address + }) + + expect(nonce).toBe(0n) + }) + testWithRpc("getAccountNonce_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const nonce = await getAccountNonce(client, { + entryPoint: ENTRYPOINT_ADDRESS_V07, + sender: simpleAccountClient.account.address + }) + + expect(nonce).toBe(0n) + }) +}) diff --git a/packages/permissionless/actions/public/getSenderAddress.test.ts b/packages/permissionless/actions/public/getSenderAddress.test.ts new file mode 100644 index 00000000..dc8680de --- /dev/null +++ b/packages/permissionless/actions/public/getSenderAddress.test.ts @@ -0,0 +1,83 @@ +import { http, createPublicClient } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getSimpleAccountClient } from "../../../permissionless-test/src/utils" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../_types/types" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getSenderAddress } from "./getSenderAddress" + +describe("getSenderAddress", () => { + testWithRpc("getSenderAddress_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const address = await getSenderAddress(client, { + entryPoint: ENTRYPOINT_ADDRESS_V06, + initCode: await simpleAccountClient.account.getInitCode() + }) + + expect(address).toBe(simpleAccountClient.account.address) + }) + testWithRpc("getSenderAddress_V06_error", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await expect(async () => + getSenderAddress(client, { + entryPoint: + "0x0000000000000000000000000000000000000000" as ENTRYPOINT_ADDRESS_V06_TYPE, + initCode: await simpleAccountClient.account.getInitCode() + }) + ).rejects.toThrowError(/not a valid entry point/) + }) + testWithRpc("getSenderAddress_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const factory = await simpleAccountClient.account.getFactory() + const factoryData = await simpleAccountClient.account.getFactoryData() + + if (!factory || !factoryData) { + throw new Error("Factory or factoryData not found") + } + + const address = await getSenderAddress(client, { + entryPoint: ENTRYPOINT_ADDRESS_V07, + factory, + factoryData + }) + + expect(address).toBe(simpleAccountClient.account.address) + }) +}) diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts new file mode 100644 index 00000000..e69de29b From 26fe248bb049d1673bb1a24b9b63ea58980a0f60 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 16:30:42 +0530 Subject: [PATCH 15/20] add deployContract tests --- .../mock-aa-infra/mock-paymaster/index.ts | 7 +- .../mock-aa-infra/mock-paymaster/relay.ts | 24 +-- .../src/common/utils.test.ts | 28 +-- .../src/ep-0.6/bundlerActions.test.ts | 12 +- .../src/ep-0.6/coreSmartClientActions.test.ts | 35 ++-- .../src/ep-0.6/experiments.ts | 14 +- .../src/ep-0.6/pimlicoActions.test.ts | 12 +- .../src/ep-0.6/safeSmartAccount.test.ts | 2 +- .../src/ep-0.7/bundlerActions.test.ts | 10 +- .../src/ep-0.7/coreSmartClinetActions.test.ts | 28 +-- .../src/ep-0.7/experiments.ts | 16 +- .../src/ep-0.7/pimlicoActions.test.ts | 10 +- .../src/ep-0.7/safeSmartAccount.test.ts | 2 +- packages/permissionless-test/src/types.ts | 4 +- packages/permissionless-test/src/utils.ts | 159 +++++++++++++++--- .../accounts/trust/utils/signUserOperation.ts | 2 +- .../smartAccount/deployContract.test.ts | 71 ++++++++ 17 files changed, 307 insertions(+), 129 deletions(-) diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts index 01230e3e..44321b33 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts @@ -1,10 +1,13 @@ import cors from "@fastify/cors" import Fastify from "fastify" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless" -import { createPimlicoBundlerClient } from "permissionless/clients/pimlico" import { defineInstance } from "prool" import { http } from "viem" import { foundry } from "viem/chains" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07 +} from "../../../permissionless" +import { createPimlicoBundlerClient } from "../../../permissionless/clients/pimlico" import { getAnvilWalletClient } from "./helpers/utils" import { setupVerifyingPaymasterV06, diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts index 665a4231..299687eb 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts @@ -1,17 +1,5 @@ import util from "node:util" import type { FastifyReply, FastifyRequest } from "fastify" -import { - ENTRYPOINT_ADDRESS_V07, - type EstimateUserOperationGasReturnType, - getPackedUserOperation -} from "permissionless" -import type { PimlicoBundlerClient } from "permissionless/clients/pimlico" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE, - UserOperation -} from "permissionless/types" -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless/utils" import { type Account, BaseError, @@ -27,6 +15,18 @@ import { toHex } from "viem" import { fromZodError } from "zod-validation-error" +import { + ENTRYPOINT_ADDRESS_V07, + type EstimateUserOperationGasReturnType, + getPackedUserOperation +} from "../../../permissionless" +import type { PimlicoBundlerClient } from "../../../permissionless/clients/pimlico" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, + UserOperation +} from "../../../permissionless/types" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless/utils" import type { VERIFYING_PAYMASTER_V06_ABI, VERIFYING_PAYMASTER_V07_ABI diff --git a/packages/permissionless-test/src/common/utils.test.ts b/packages/permissionless-test/src/common/utils.test.ts index 896dbba7..4b62212f 100644 --- a/packages/permissionless-test/src/common/utils.test.ts +++ b/packages/permissionless-test/src/common/utils.test.ts @@ -1,17 +1,3 @@ -import { - ENTRYPOINT_ADDRESS_V06, - ENTRYPOINT_ADDRESS_V07, - type GetSenderAddressParams, - deepHexlify, - getSenderAddress, - getUserOperationHash -} from "permissionless" -import type { PackedUserOperation } from "permissionless/types" -import { - getPackedUserOperation, - getRequiredPrefund, - signUserOperationHashWithECDSA -} from "permissionless/utils" import { type Address, type Hash, @@ -25,6 +11,20 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07, + type GetSenderAddressParams, + deepHexlify, + getSenderAddress, + getUserOperationHash +} from "../../../permissionless" +import type { PackedUserOperation } from "../../../permissionless/types" +import { + getPackedUserOperation, + getRequiredPrefund, + signUserOperationHashWithECDSA +} from "../../../permissionless/utils" import { SIMPLE_ACCOUNT_FACTORY_V06, SIMPLE_ACCOUNT_FACTORY_V07 diff --git a/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts b/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts index 52a4cb97..716a31a1 100644 --- a/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts @@ -1,18 +1,18 @@ +import { type Chain, isHash, zeroAddress } from "viem" +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" import { type BundlerClient, WaitForUserOperationReceiptTimeoutError -} from "permissionless" +} from "../../../permissionless" import type { ENTRYPOINT_ADDRESS_V06_TYPE, UserOperation -} from "permissionless/types" +} from "../../../permissionless/types" import { ENTRYPOINT_ADDRESS_V06, getUserOperationHash -} from "permissionless/utils" -import { type Chain, isHash, zeroAddress } from "viem" -import { foundry } from "viem/chains" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless/utils" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts b/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts index 28d71ef8..9b6754b7 100644 --- a/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts @@ -1,20 +1,3 @@ -import { - type BundlerClient, - ENTRYPOINT_ADDRESS_V06, - createSmartAccountClient -} from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToBiconomySmartAccount, - signerToEcdsaKernelSmartAccount, - signerToLightSmartAccount, - signerToSafeSmartAccount, - signerToSimpleSmartAccount, - signerToTrustSmartAccount -} from "permissionless/accounts" -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" -import { getUserOperationHash } from "permissionless/utils" import { http, type BaseError, @@ -32,11 +15,27 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, test } from "vitest" +import { + type BundlerClient, + ENTRYPOINT_ADDRESS_V06, + createSmartAccountClient +} from "../../../permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToBiconomySmartAccount, + signerToEcdsaKernelSmartAccount, + signerToLightSmartAccount, + signerToSafeSmartAccount, + signerToSimpleSmartAccount, + signerToTrustSmartAccount +} from "../../../permissionless/accounts" +import type { PimlicoPaymasterClient } from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" +import { getUserOperationHash } from "../../../permissionless/utils" import { ENTRYPOINT_V06_ABI } from "../../abi/entryPointV06Abi" import { SIMPLE_ACCOUNT_FACTORY_V06 } from "../constants" import type { AAParamType, ExistingSignerParamType } from "../types" import { - ALTO_RPC, ensureBundlerIsReady, ensurePaymasterIsReady, fund, diff --git a/packages/permissionless-test/src/ep-0.6/experiments.ts b/packages/permissionless-test/src/ep-0.6/experiments.ts index 811bef4b..191f88b7 100644 --- a/packages/permissionless-test/src/ep-0.6/experiments.ts +++ b/packages/permissionless-test/src/ep-0.6/experiments.ts @@ -1,14 +1,14 @@ -import { - ENTRYPOINT_ADDRESS_V06, - createSmartAccountClient -} from "permissionless" -import { privateKeyToSafeSmartAccount } from "permissionless/accounts" -import { paymasterActionsEip7677 } from "permissionless/experimental" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { http, createClient, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { foundry } from "viem/chains" import { describe, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V06, + createSmartAccountClient +} from "../../../permissionless" +import { privateKeyToSafeSmartAccount } from "../../../permissionless/accounts" +import { paymasterActionsEip7677 } from "../../../permissionless/experimental" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" import type { AAParamType } from "../types" import { PAYMASTER_RPC, diff --git a/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts b/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts index bda1718a..54cfd87f 100644 --- a/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts @@ -1,9 +1,3 @@ -import type { PimlicoBundlerClient } from "permissionless/clients/pimlico" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - UserOperation -} from "permissionless/types" -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless/utils" import { type Chain, type PublicClient, @@ -12,6 +6,12 @@ import { isHex } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import type { PimlicoBundlerClient } from "../../../permissionless/clients/pimlico" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + UserOperation +} from "../../../permissionless/types" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless/utils" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts b/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts index 4f44aa98..ea031a92 100644 --- a/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts +++ b/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts @@ -1,6 +1,6 @@ -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless" import { isHash, zeroAddress } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts b/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts index 914f3b1d..12468ff1 100644 --- a/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts @@ -1,14 +1,14 @@ +import { type Chain, isHash } from "viem" +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" import { type BundlerClient, ENTRYPOINT_ADDRESS_V07, type UserOperation, WaitForUserOperationReceiptTimeoutError, getUserOperationHash -} from "permissionless" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { type Chain, isHash } from "viem" -import { foundry } from "viem/chains" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts b/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts index cb5b693f..f4a0a7ba 100644 --- a/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts @@ -1,17 +1,3 @@ -import { - type BundlerClient, - ENTRYPOINT_ADDRESS_V07, - createSmartAccountClient -} from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToEcdsaKernelSmartAccount, - signerToSafeSmartAccount, - signerToSimpleSmartAccount -} from "permissionless/accounts" -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { getUserOperationHash } from "permissionless/utils" import { http, type BaseError, @@ -29,6 +15,20 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, test } from "vitest" +import { + type BundlerClient, + ENTRYPOINT_ADDRESS_V07, + createSmartAccountClient +} from "../../../permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToEcdsaKernelSmartAccount, + signerToSafeSmartAccount, + signerToSimpleSmartAccount +} from "../../../permissionless/accounts" +import type { PimlicoPaymasterClient } from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" +import { getUserOperationHash } from "../../../permissionless/utils" import { ENTRYPOINT_V07_ABI } from "../../abi/entryPointV07Abi" import { SIMPLE_ACCOUNT_FACTORY_V07 } from "../constants" import type { AAParamType, ExistingSignerParamType } from "../types" diff --git a/packages/permissionless-test/src/ep-0.7/experiments.ts b/packages/permissionless-test/src/ep-0.7/experiments.ts index 6d04cc39..ae3e9a79 100644 --- a/packages/permissionless-test/src/ep-0.7/experiments.ts +++ b/packages/permissionless-test/src/ep-0.7/experiments.ts @@ -1,15 +1,15 @@ -import { - ENTRYPOINT_ADDRESS_V07, - createSmartAccountClient -} from "permissionless" -import { privateKeyToSimpleSmartAccount } from "permissionless/_types/accounts" -import { privateKeyToSafeSmartAccount } from "permissionless/accounts" -import { paymasterActionsEip7677 } from "permissionless/experimental" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { http, createClient, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { foundry } from "viem/chains" import { describe, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V07, + createSmartAccountClient +} from "../../../permissionless" +import { privateKeyToSimpleSmartAccount } from "../../../permissionless/_types/accounts" +import { privateKeyToSafeSmartAccount } from "../../../permissionless/accounts" +import { paymasterActionsEip7677 } from "../../../permissionless/experimental" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" import { SIMPLE_ACCOUNT_FACTORY_V07 } from "../constants" import type { AAParamType } from "../types" import { diff --git a/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts b/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts index ea488f65..a7f815e8 100644 --- a/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts @@ -1,11 +1,11 @@ -import { ENTRYPOINT_ADDRESS_V07 } from "permissionless" +import { isAddress, isHash, zeroAddress } from "viem" +import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V07 } from "../../../permissionless" import type { PimlicoBundlerClient, PimlicoPaymasterClient -} from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { isAddress, isHash, zeroAddress } from "viem" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts b/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts index 098b5dfc..d09fc409 100644 --- a/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts +++ b/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts @@ -1,6 +1,6 @@ -import { ENTRYPOINT_ADDRESS_V07 } from "permissionless" import { isHash, zeroAddress } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V07 } from "../../../permissionless" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/types.ts b/packages/permissionless-test/src/types.ts index 5c839076..3cfd89a6 100644 --- a/packages/permissionless-test/src/types.ts +++ b/packages/permissionless-test/src/types.ts @@ -1,6 +1,6 @@ -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { EntryPoint } from "permissionless/types" import type { Address, Hex, PublicClient } from "viem" +import type { PimlicoPaymasterClient } from "../../permissionless/clients/pimlico" +import type { EntryPoint } from "../../permissionless/types" export type AAParamType = { entryPoint: T diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 14842d7b..e1840194 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -1,3 +1,22 @@ +import { + http, + type Account, + type Address, + type Chain, + type Hex, + type Transport, + type WalletClient, + createClient, + createPublicClient, + createWalletClient, + parseEther +} from "viem" +import { + generatePrivateKey, + mnemonicToAccount, + privateKeyToAccount +} from "viem/accounts" +import { foundry } from "viem/chains" import { type BundlerClient, ENTRYPOINT_ADDRESS_V06, @@ -5,7 +24,7 @@ import { createBundlerClient, createSmartAccountClient, getEntryPointVersion -} from "permissionless" +} from "../../permissionless" import { type SafeSmartAccount, type SmartAccount, @@ -15,43 +34,24 @@ import { signerToSafeSmartAccount, signerToSimpleSmartAccount, signerToTrustSmartAccount -} from "permissionless/accounts" -import type { KernelEcdsaSmartAccount } from "permissionless/accounts" +} from "../../permissionless/accounts" +import type { KernelEcdsaSmartAccount } from "../../permissionless/accounts" import { type PimlicoBundlerClient, type PimlicoPaymasterClient, createPimlicoBundlerClient, createPimlicoPaymasterClient -} from "permissionless/clients/pimlico" -import { paymasterActionsEip7677 } from "permissionless/experimental" +} from "../../permissionless/clients/pimlico" +import { paymasterActionsEip7677 } from "../../permissionless/experimental" import type { ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint -} from "permissionless/types" -import { - http, - type Account, - type Address, - type Chain, - type Hex, - type Transport, - type WalletClient, - createClient, - createPublicClient, - createWalletClient, - parseEther -} from "viem" -import { - generatePrivateKey, - mnemonicToAccount, - privateKeyToAccount -} from "viem/accounts" -import { foundry } from "viem/chains" +} from "../../permissionless/types" import { SIMPLE_ACCOUNT_FACTORY_V06, SIMPLE_ACCOUNT_FACTORY_V07 } from "./constants" -import type { AAParamType } from "./types" +import type { AAParamType, ExistingSignerParamType } from "./types" export const PAYMASTER_RPC = "http://localhost:3000" @@ -257,10 +257,13 @@ export const getLightAccountClient = async ({ export const getTrustAccountClient = async ({ entryPoint, paymasterClient, + altoRpc, + anvilRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const smartAccount = await signerToTrustSmartAccount( publicClient, { @@ -273,7 +276,7 @@ export const getTrustAccountClient = async ({ return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -387,3 +390,105 @@ export const getEip7677Client = async ({ return client } + +export const getCoreSmartAccountDescriptions = () => [ + { + name: "Trust", + getSmartAccountClient: async ( + conf: AAParamType + ) => getTrustAccountClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToTrustSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + }, + { + name: "LightAccount v1.1.0", + getSmartAccountClient: async ( + conf: AAParamType + ) => getLightAccountClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToLightSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06, + lightAccountVersion: "1.1.0" + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + }, + { + name: "Simple", + getSmartAccountClient: async ( + conf: AAParamType + ) => getSimpleAccountClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToSimpleSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: false + }, + { + name: "Kernel", + getSmartAccountClient: async ( + conf: AAParamType + ) => getKernelEcdsaClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToEcdsaKernelSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + }, + { + name: "Biconomy", + getSmartAccountClient: async ( + conf: AAParamType + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getBiconomyClient( + conf as AAParamType + ) + }, + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToBiconomySmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: false, + isEip1271Compliant: true + }, + { + name: "Safe", + getSmartAccountClient: async ( + conf: AAParamType + ) => getSafeClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToSafeSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06, + safeVersion: "1.4.1" + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + } +] diff --git a/packages/permissionless/accounts/trust/utils/signUserOperation.ts b/packages/permissionless/accounts/trust/utils/signUserOperation.ts index d499426f..0ff0393a 100644 --- a/packages/permissionless/accounts/trust/utils/signUserOperation.ts +++ b/packages/permissionless/accounts/trust/utils/signUserOperation.ts @@ -1,10 +1,10 @@ -import { getUserOperationHash } from "permissionless/utils" import type { Account, Address, Chain, Client, Transport } from "viem" import type { EntryPoint, GetEntryPointVersion, UserOperation } from "../../../types" +import { getUserOperationHash } from "../../../utils" import { signMessage } from "./signMessage" export const signUserOperation = async < diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts index e69de29b..863fc994 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.test.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.test.ts @@ -0,0 +1,71 @@ +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccountDescriptions, + getPimlicoPaymasterClient +} from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe.each(getCoreSmartAccountDescriptions())( + "deployContract", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "deployContract_V06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + await expect(async () => + smartClient.deployContract({ + abi: [], + bytecode: "0xff66" + }) + ).rejects.toThrowError( + /^.*doesn't support account deployment.*$/i + ) + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "deployContract_V07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + await expect(async () => + smartClient.deployContract({ + abi: [], + bytecode: "0xff66" + }) + ).rejects.toThrowError( + /^.*doesn't support account deployment.*$/i + ) + } + ) + } +) From f3cfbe7356463c51f06e78d44ab271bf5baa9fd4 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 17:26:45 +0530 Subject: [PATCH 16/20] Add prepareUserOperationRequest tests --- .../mock-aa-infra/alto/index.ts | 67 ++++++++- packages/permissionless-test/src/utils.ts | 19 ++- .../smartAccount/deployContract.test.ts | 4 +- .../prepareUserOperationRequest.test.ts | 136 ++++++++++++++++++ .../errors/estimateUserOperationGas.ts | 7 + 5 files changed, 224 insertions(+), 9 deletions(-) create mode 100644 packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index acbac6fd..c8f101c2 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -37,7 +37,14 @@ import { SAFE_V07_MODULE_CREATECALL, SAFE_V07_MODULE_SETUP_CREATECALL, SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, - SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL + SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, + TRUST_ACCOUNT_FACET_CREATE_CALL, + TRUST_DEFAULT_FALLBACK_HANDLER, + TRUST_DIAMOND_CUT_FACET_CREATE_CALL, + TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL, + TRUST_FACTORY_V06_CREATECALL, + TRUST_SECP256K1_VERIFICATION_FACET_CREATECALL, + TRUST_TOKEN_RECEIVER_FACET_CREATE_CALL } from "./constants" const DETERMINISTIC_DEPLOYER = "0x4e59b44847b379578588920ca78fbf26c0b4956c" @@ -266,6 +273,55 @@ export const setupContracts = async (rpc: string) => { nonce: nonce++ }) + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_FACTORY_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_SECP256K1_VERIFICATION_FACET_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_ACCOUNT_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DIAMOND_CUT_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_TOKEN_RECEIVER_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }) + + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DEFAULT_FALLBACK_HANDLER, + gas: 15_000_000n, + nonce: nonce++ + }) + // ==== SETUP KERNEL V0.6 CONTRACTS ==== // const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" await anvilClient.setBalance({ @@ -352,6 +408,13 @@ export const setupContracts = async (rpc: string) => { "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", // Kernel v0.3.0 Factory "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", // Kernel v0.3.0 Meta Factory "0x00004EC70002a32400f8ae005A26081065620D20", // LightAccountFactory v1.1.0 - "0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba" // LightAccount v1.1.0 implementation + "0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba", // LightAccount v1.1.0 implementation + "0x81b9E3689390C7e74cF526594A105Dea21a8cdD5", // Trust Secp256k1VerificationFacet + "0x729c310186a57833f622630a16d13f710b83272a", // Trust factory + "0xFde53272dcd7938d16E031A6989753c321728332", // Trust AccountFacet + "0x0B9504140771C3688Ff041917192277D2f52E1e0", // Trust DiamondCutFacet + "0x3143E1C0Af0Cdc153423863923Cf4e3818e34Daa", // Trust TokenReceiverFacet + "0xCe36b85d12D81cd619C745c7717f3396E184Ac7C", // Trust DiamondLoupeFacet + "0x2e7f1dAe1F3799d20f5c31bEFdc7A620f664728D" // Trust DefaultFallbackHandler ]) } diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index e1840194..86d6ffd2 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -254,7 +254,9 @@ export const getLightAccountClient = async ({ } // Only supports v0.6 for now -export const getTrustAccountClient = async ({ +export const getTrustAccountClient = async < + T extends ENTRYPOINT_ADDRESS_V06_TYPE +>({ entryPoint, paymasterClient, altoRpc, @@ -391,12 +393,19 @@ export const getEip7677Client = async ({ return client } -export const getCoreSmartAccountDescriptions = () => [ +export const getCoreSmartAccounts = () => [ { name: "Trust", getSmartAccountClient: async ( conf: AAParamType - ) => getTrustAccountClient(conf), + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getTrustAccountClient( + conf as AAParamType + ) + }, getSmartAccountSigner: async (conf: ExistingSignerParamType) => signerToTrustSmartAccount(conf.publicClient, { address: conf.existingAddress, // this is the field we are testing @@ -404,7 +413,7 @@ export const getCoreSmartAccountDescriptions = () => [ entryPoint: ENTRYPOINT_ADDRESS_V06 }), supportsEntryPointV06: true, - supportsEntryPointV07: true, + supportsEntryPointV07: false, isEip1271Compliant: true }, { @@ -420,7 +429,7 @@ export const getCoreSmartAccountDescriptions = () => [ lightAccountVersion: "1.1.0" }), supportsEntryPointV06: true, - supportsEntryPointV07: true, + supportsEntryPointV07: false, isEip1271Compliant: true }, { diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts index 863fc994..8dde027e 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.test.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.test.ts @@ -2,12 +2,12 @@ import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { - getCoreSmartAccountDescriptions, + getCoreSmartAccounts, getPimlicoPaymasterClient } from "../../../permissionless-test/src/utils" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -describe.each(getCoreSmartAccountDescriptions())( +describe.each(getCoreSmartAccounts())( "deployContract", ({ getSmartAccountClient, diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts new file mode 100644 index 00000000..2e1ba6e1 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts @@ -0,0 +1,136 @@ +import { zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient +} from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe.each(getCoreSmartAccounts())( + "prepareUserOperationRequest", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "prepareUserOperationRequest_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartClient.prepareUserOperationRequest({ + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + expect(userOperation).toBeTruthy() + expect(userOperation.sender).toBe(smartClient.account.address) + expect(userOperation.nonce).toBe( + await smartClient.account.getNonce() + ) + expect(userOperation.initCode).toBe( + await smartClient.account.getInitCode() + ) + expect(userOperation.callData).toBe( + await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + ) + expect(userOperation.callGasLimit).toBeTruthy() + expect(userOperation.verificationGasLimit).toBeTruthy() + expect(userOperation.maxFeePerGas).toBeTruthy() + expect(userOperation.maxPriorityFeePerGas).toBeTruthy() + expect(userOperation.paymasterAndData).toBe("0x") + expect(userOperation.signature).toBe( + await smartClient.account.getDummySignature(userOperation) + ) + + expect(userOperation.factory).toBe(undefined) + expect(userOperation.factoryData).toBe(undefined) + expect(userOperation.paymaster).toBe(undefined) + expect(userOperation.paymasterVerificationGasLimit).toBe( + undefined + ) + expect(userOperation.paymasterPostOpGasLimit).toBe(undefined) + expect(userOperation.paymasterData).toBe(undefined) + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "prepareUserOperationRequest_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartClient.prepareUserOperationRequest({ + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + expect(userOperation).toBeTruthy() + expect(userOperation.sender).toBe(smartClient.account.address) + expect(userOperation.nonce).toBe( + await smartClient.account.getNonce() + ) + expect(userOperation.factory).toBe( + await smartClient.account.getFactory() + ) + expect(userOperation.factoryData).toBe( + await smartClient.account.getFactoryData() + ) + expect(userOperation.callData).toBe( + await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + ) + expect(userOperation.callGasLimit).toBeTruthy() + expect(userOperation.verificationGasLimit).toBeTruthy() + expect(userOperation.maxFeePerGas).toBeTruthy() + expect(userOperation.maxPriorityFeePerGas).toBeTruthy() + expect(userOperation.paymaster).toBe(undefined) + expect(userOperation.paymasterVerificationGasLimit).toBe( + undefined + ) + expect(userOperation.signature).toBe( + // @ts-ignore: since tests return all smart account client, some of them don't support V07. + // The TS error is because in that case, getDummySignature would not accept the userOperation of type UserOperation + await smartClient.account.getDummySignature(userOperation) + ) + expect(userOperation.paymasterPostOpGasLimit).toBe(0n) + expect(userOperation.paymasterData).toBe(undefined) + expect(userOperation.paymasterAndData).toBe(undefined) + expect(userOperation.initCode).toBe(undefined) + } + ) + } +) diff --git a/packages/permissionless/errors/estimateUserOperationGas.ts b/packages/permissionless/errors/estimateUserOperationGas.ts index 1e3f0691..4564692b 100644 --- a/packages/permissionless/errors/estimateUserOperationGas.ts +++ b/packages/permissionless/errors/estimateUserOperationGas.ts @@ -36,6 +36,13 @@ export class EstimateUserOperationGasError< maxPriorityFeePerGas: userOperation.maxPriorityFeePerGas, paymasterAndData: userOperation.paymasterAndData, signature: userOperation.signature, + factory: userOperation.factory, + factoryData: userOperation.factoryData, + paymaster: userOperation.paymaster, + paymasterVerificationGasLimit: + userOperation.paymasterVerificationGasLimit, + paymasterPostOpGasLimit: userOperation.paymasterPostOpGasLimit, + paymasterData: userOperation.paymasterData, entryPoint }) From b62d6e386019bd72cb116fcb01c9946cf9d73098 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 17:38:47 +0530 Subject: [PATCH 17/20] await for transactions before calling from owner --- .../mock-aa-infra/alto/index.ts | 422 +++++++++--------- .../smartAccount/deployContract.test.ts | 2 +- .../prepareUserOperationRequest.test.ts | 2 +- 3 files changed, 203 insertions(+), 223 deletions(-) diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index c8f101c2..8f60913a 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -88,239 +88,219 @@ export const setupContracts = async (rpc: string) => { address: walletClient.account.address }) - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_V07_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_SIMULATIONS_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: ENTRY_POINT_V06_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V06_MODULE_SETUP_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V06_MODULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V07_MODULE_SETUP_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: SAFE_V07_MODULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) + await Promise.all([ + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_V07_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_SIMULATIONS_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ENTRY_POINT_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V06_MODULE_SETUP_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V06_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V07_MODULE_SETUP_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_V07_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V06_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: KERNEL_V07_META_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_FACTORY_V06_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_SECP256K1_VERIFICATION_FACET_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_ACCOUNT_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DIAMOND_CUT_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_TOKEN_RECEIVER_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: TRUST_DEFAULT_FALLBACK_HANDLER, + gas: 15_000_000n, + nonce: nonce++ + }) + ]) await anvilClient.setCode({ address: SAFE_SINGLETON_FACTORY, bytecode: SAFE_SINGLETON_FACTORY_BYTECODE }) - walletClient.sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_PROXY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_SINGLETON_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) + await Promise.all([ + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_PROXY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_SINGLETON_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + ]) await anvilClient.setCode({ address: BICONOMY_SINGLETON_FACTORY, bytecode: BICONOMY_SINGLETON_FACTORY_BYTECODE }) - walletClient.sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V06_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: KERNEL_V07_META_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_FACTORY_V06_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_SECP256K1_VERIFICATION_FACET_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_ACCOUNT_FACET_CREATE_CALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_DIAMOND_CUT_FACET_CREATE_CALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_TOKEN_RECEIVER_FACET_CREATE_CALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL, - gas: 15_000_000n, - nonce: nonce++ - }) - - walletClient.sendTransaction({ - to: DETERMINISTIC_DEPLOYER, - data: TRUST_DEFAULT_FALLBACK_HANDLER, - gas: 15_000_000n, - nonce: nonce++ - }) + await Promise.all([ + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + ]) // ==== SETUP KERNEL V0.6 CONTRACTS ==== // const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts index 8dde027e..b6c52fde 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.test.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.test.ts @@ -8,7 +8,7 @@ import { import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" describe.each(getCoreSmartAccounts())( - "deployContract", + "deployContract $name", ({ getSmartAccountClient, supportsEntryPointV06, diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts index 2e1ba6e1..0d84ba52 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts @@ -9,7 +9,7 @@ import { import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" describe.each(getCoreSmartAccounts())( - "prepareUserOperationRequest", + "prepareUserOperationRequest $name", ({ getSmartAccountClient, supportsEntryPointV06, From 3c1f821d6cbc6bbc75dbafe7a09b1e54eb8621a9 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 18:09:19 +0530 Subject: [PATCH 18/20] Use direct functions --- .../actions/bundler/chainId.test.ts | 5 ++-- .../bundler/estimateUserOperationGas.test.ts | 25 ++++++++++++------- .../bundler/getUserOperationByHash.test.ts | 13 +++++++--- .../bundler/getUserOperationReceipt.test.ts | 5 ++-- .../actions/bundler/sendUserOperation.test.ts | 5 ++-- .../bundler/supportedEntryPoints.test.ts | 5 ++-- .../waitForUserOperationReceipt.test.ts | 17 ++++++++----- .../pimlico/getUserOperationGasPrice.test.ts | 3 ++- .../pimlico/getUserOperationStatus.test.ts | 17 ++++++++----- .../validateSponsorshipPolicies.test.ts | 18 +++++++------ .../actions/smartAccount/deployContract.ts | 4 ++- .../prepareUserOperationRequest.test.ts | 5 +--- packages/permissionless/vitest.config.ts | 2 +- 13 files changed, 77 insertions(+), 47 deletions(-) diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts index c95ac010..9fd55430 100644 --- a/packages/permissionless/actions/bundler/chainId.test.ts +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -8,6 +8,7 @@ import { } from "../../clients/createBundlerClient" import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { chainId } from "./chainId" describe("chainId", () => { testWithRpc("chainId", async ({ rpc }) => { @@ -19,7 +20,7 @@ describe("chainId", () => { transport: http(altoRpc), entryPoint }) - const chainId = await bundlerClient.chainId() - expect(chainId).toBe(foundry.id) + const id = await chainId(bundlerClient) + expect(id).toBe(foundry.id) }) }) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts index 80d81ecb..9329a493 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts @@ -8,6 +8,7 @@ import { } from "../../../permissionless-test/src/utils" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { estimateUserOperationGas } from "./estimateUserOperationGas" describe("eth_estimateUserOperationGas", () => { testWithRpc("eth_estimateUserOperationGas_v06", async ({ rpc }) => { @@ -41,9 +42,11 @@ describe("eth_estimateUserOperationGas", () => { }) const { preVerificationGas, verificationGasLimit, callGasLimit } = - await bundlerClientV06.estimateUserOperationGas( + await estimateUserOperationGas( + bundlerClientV06, { - userOperation + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V06 }, { "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC": { @@ -62,7 +65,7 @@ describe("eth_estimateUserOperationGas", () => { }) testWithRpc("eth_estimateUserOperationGas_v07", async ({ rpc }) => { - const { anvilRpc, altoRpc, paymasterRpc } = rpc + const { anvilRpc, altoRpc } = rpc const bundlerClientV07 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 @@ -92,7 +95,8 @@ describe("eth_estimateUserOperationGas", () => { callGasLimit, paymasterVerificationGasLimit, paymasterPostOpGasLimit - } = await bundlerClientV07.estimateUserOperationGas({ + } = await estimateUserOperationGas(bundlerClientV07, { + entryPoint: ENTRYPOINT_ADDRESS_V07, userOperation }) @@ -106,7 +110,7 @@ describe("eth_estimateUserOperationGas", () => { testWithRpc( "eth_estimateUserOperationGas_V07_with_error", async ({ rpc }) => { - const { anvilRpc, altoRpc, paymasterRpc } = rpc + const { anvilRpc, altoRpc } = rpc const bundlerClientV07 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 @@ -132,9 +136,11 @@ describe("eth_estimateUserOperationGas", () => { }) await expect(() => - bundlerClientV07.estimateUserOperationGas( + estimateUserOperationGas( + bundlerClientV07, { - userOperation + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V07 }, { [smartAccountClient.account.address]: { @@ -184,8 +190,9 @@ describe("eth_estimateUserOperationGas", () => { callGasLimit, paymasterVerificationGasLimit, paymasterPostOpGasLimit - } = await bundlerClientV07.estimateUserOperationGas({ - userOperation + } = await estimateUserOperationGas(bundlerClientV07, { + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(preVerificationGas).toBeTruthy() diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts index 6f1e7d5c..f9693cd5 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts @@ -8,6 +8,7 @@ import { } from "../../../permissionless-test/src/utils" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationByHash } from "./getUserOperationByHash" describe("getUserOperationByHash", () => { testWithRpc("getUserOperationByHash_V06", async ({ rpc }) => { @@ -53,8 +54,10 @@ describe("getUserOperationByHash", () => { timeout: 10000 }) - const userOperationFromUserOpHash = - await bundlerClientV06.getUserOperationByHash({ hash: opHash }) + const userOperationFromUserOpHash = await getUserOperationByHash( + bundlerClientV06, + { hash: opHash } + ) expect(userOperationFromUserOpHash).not.toBeNull() expect(userOperationFromUserOpHash?.entryPoint).toBe( @@ -117,8 +120,10 @@ describe("getUserOperationByHash", () => { timeout: 10000 }) - const userOperationFromUserOpHash = - await bundlerClientV07.getUserOperationByHash({ hash: opHash }) + const userOperationFromUserOpHash = await getUserOperationByHash( + bundlerClientV07, + { hash: opHash } + ) for (const key in userOperationFromUserOpHash?.userOperation) { const expected = userOperationFromUserOpHash?.userOperation[key] diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts index 6e5b3d84..e7693263 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts @@ -8,6 +8,7 @@ import { } from "../../../permissionless-test/src/utils" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationReceipt } from "./getUserOperationReceipt" describe("getUserOperationReceipt", () => { testWithRpc("getUserOperationReceipt_V06", async ({ rpc }) => { @@ -58,7 +59,7 @@ describe("getUserOperationReceipt", () => { expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() - const receipt = await bundlerClientV06.getUserOperationReceipt({ + const receipt = await getUserOperationReceipt(bundlerClientV06, { hash: opHash }) @@ -115,7 +116,7 @@ describe("getUserOperationReceipt", () => { expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() - const receipt = await bundlerClientV07.getUserOperationReceipt({ + const receipt = await getUserOperationReceipt(bundlerClientV07, { hash: opHash }) diff --git a/packages/permissionless/actions/bundler/sendUserOperation.test.ts b/packages/permissionless/actions/bundler/sendUserOperation.test.ts index 6b9d923a..e1085f95 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.test.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.test.ts @@ -8,6 +8,7 @@ import { } from "../../../permissionless-test/src/utils" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationReceipt } from "./getUserOperationReceipt" describe("sendUserOperation", () => { testWithRpc("sendUserOperation_V06", async ({ rpc }) => { @@ -57,7 +58,7 @@ describe("sendUserOperation", () => { expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() - const receipt = await bundlerClientV06.getUserOperationReceipt({ + const receipt = await getUserOperationReceipt(bundlerClientV06, { hash: opHash }) @@ -114,7 +115,7 @@ describe("sendUserOperation", () => { expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() - const receipt = await bundlerClientV07.getUserOperationReceipt({ + const receipt = await getUserOperationReceipt(bundlerClientV07, { hash: opHash }) diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts index f9f8a326..dca58f4d 100644 --- a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts @@ -3,6 +3,7 @@ import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { supportedEntryPoints } from "./supportedEntryPoints" describe("supportedEntryPoints", () => { testWithRpc("supportedEntryPoints_V06", async ({ rpc }) => { @@ -11,7 +12,7 @@ describe("supportedEntryPoints", () => { entryPoint: ENTRYPOINT_ADDRESS_V06 }) - const entryPoints = await bundlerClientV06.supportedEntryPoints() + const entryPoints = await supportedEntryPoints(bundlerClientV06) expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V06) }) @@ -20,7 +21,7 @@ describe("supportedEntryPoints", () => { transport: http(rpc.altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) - const entryPoints = await bundlerClientV07.supportedEntryPoints() + const entryPoints = await supportedEntryPoints(bundlerClientV07) expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V07) }) }) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts index 9ebd95ce..df30228b 100644 --- a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts @@ -8,6 +8,7 @@ import { } from "../../../permissionless-test/src/utils" import { createBundlerClient } from "../../clients/createBundlerClient" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { waitForUserOperationReceipt } from "./waitForUserOperationReceipt" describe("waitForUserOperationReceipt", () => { testWithRpc("waitForUserOperationReceipt_V06", async ({ rpc }) => { @@ -48,11 +49,13 @@ describe("waitForUserOperationReceipt", () => { expect(isHash(opHash)).toBe(true) - const userOperationReceipt = - await bundlerClientV06.waitForUserOperationReceipt({ + const userOperationReceipt = await waitForUserOperationReceipt( + bundlerClientV06, + { hash: opHash, timeout: 100000 - }) + } + ) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() @@ -105,11 +108,13 @@ describe("waitForUserOperationReceipt", () => { expect(isHash(opHash)).toBe(true) - const userOperationReceipt = - await bundlerClientV07.waitForUserOperationReceipt({ + const userOperationReceipt = await waitForUserOperationReceipt( + bundlerClientV07, + { hash: opHash, timeout: 100000 - }) + } + ) expect(userOperationReceipt).not.toBeNull() expect(userOperationReceipt?.userOpHash).toBe(opHash) expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() diff --git a/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts index bbbcecb5..492c353b 100644 --- a/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts +++ b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts @@ -2,6 +2,7 @@ import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getPimlicoBundlerClient } from "../../../permissionless-test/src/utils" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { getUserOperationGasPrice } from "./getUserOperationGasPrice" describe("getUserOperationGasPrice", () => { testWithRpc("getUserOperationGasPrice", async ({ rpc }) => { @@ -10,7 +11,7 @@ describe("getUserOperationGasPrice", () => { altoRpc: rpc.altoRpc }) - const gasPrice = await pimlicoBundlerClient.getUserOperationGasPrice() + const gasPrice = await getUserOperationGasPrice(pimlicoBundlerClient) expect(gasPrice).toBeTruthy() expect(gasPrice.slow).toBeTruthy() diff --git a/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts index 37109215..60c4521d 100644 --- a/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts +++ b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts @@ -9,6 +9,7 @@ import { } from "../../../permissionless-test/src/utils" import { bundlerActions } from "../../clients/decorators/bundler" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationStatus } from "./getUserOperationStatus" describe("getUserOperationStatus", () => { testWithRpc("getUserOperationStatus_V06", async ({ rpc }) => { @@ -66,10 +67,12 @@ describe("getUserOperationStatus", () => { expect(receipt?.receipt.transactionHash).toBe( userOperationReceipt?.receipt.transactionHash ) - const userOperationStatus = - await bundlerClientV06.getUserOperationStatus({ + const userOperationStatus = await getUserOperationStatus( + bundlerClientV06, + { hash: opHash - }) + } + ) expect(userOperationStatus).not.toBeNull() expect(userOperationStatus).not.toBeUndefined() expect(userOperationStatus.status).toBe("included") @@ -133,10 +136,12 @@ describe("getUserOperationStatus", () => { expect(receipt?.receipt.transactionHash).toBe( userOperationReceipt?.receipt.transactionHash ) - const userOperationStatus = - await bundlerClientV07.getUserOperationStatus({ + const userOperationStatus = await getUserOperationStatus( + bundlerClientV07, + { hash: opHash - }) + } + ) expect(userOperationStatus).not.toBeNull() expect(userOperationStatus).not.toBeUndefined() expect(userOperationStatus.status).toBe("included") diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts index c1e3dbcf..9f836468 100644 --- a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts @@ -6,6 +6,7 @@ import { getSimpleAccountClient } from "../../../permissionless-test/src/utils" import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { validateSponsorshipPolicies } from "./validateSponsorshipPolicies" describe("validateSponsorshipPolicies", () => { testWithRpc("Validating sponsorship policies", async ({ rpc }) => { @@ -38,15 +39,18 @@ describe("validateSponsorshipPolicies", () => { paymasterRpc }) - const validateSponsorshipPolicies = - await pimlicoPaymasterClient.validateSponsorshipPolicies({ + const policies = await validateSponsorshipPolicies( + pimlicoPaymasterClient, + { + entryPoint: ENTRYPOINT_ADDRESS_V06, userOperation: userOperation, sponsorshipPolicyIds: ["sp_crazy_kangaroo"] - }) + } + ) - expect(validateSponsorshipPolicies).toBeTruthy() - expect(validateSponsorshipPolicies.length).toBeGreaterThan(0) - expect(Array.isArray(validateSponsorshipPolicies)).toBe(true) - expect(validateSponsorshipPolicies.length).toBe(1) + expect(policies).toBeTruthy() + expect(policies.length).toBeGreaterThan(0) + expect(Array.isArray(policies)).toBe(true) + expect(policies.length).toBe(1) }) }) diff --git a/packages/permissionless/actions/smartAccount/deployContract.ts b/packages/permissionless/actions/smartAccount/deployContract.ts index 3782fc9d..99efd92e 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.ts @@ -59,7 +59,9 @@ export type DeployContractParametersWithPaymaster< export async function deployContract< entryPoint extends EntryPoint, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined >( client: Client, args: Prettify> diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts index 0d84ba52..f7ff2147 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts @@ -2,10 +2,7 @@ import { zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" -import { - getCoreSmartAccounts, - getPimlicoPaymasterClient -} from "../../../permissionless-test/src/utils" +import { getCoreSmartAccounts } from "../../../permissionless-test/src/utils" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" describe.each(getCoreSmartAccounts())( diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index 6a6a6671..a34713a0 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ permissionless: join(__dirname, "./") }, coverage: { - all: false, + all: true, provider: "v8", reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], exclude: [ From affc6d7873f1149f318ddf69441daad40c4bb6f8 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 12 Jun 2024 18:17:58 +0530 Subject: [PATCH 19/20] give coverage only for permissionless --- packages/permissionless/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index a34713a0..0361eae6 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ all: true, provider: "v8", reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], + include: ["**/permissionless/**"], exclude: [ "**/errors/utils.ts", "**/*.test.ts", From c17f9d05e480a2af12a373130d78de7ac235160c Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Thu, 13 Jun 2024 00:24:25 +0530 Subject: [PATCH 20/20] Add more smart account test --- .../actions/bundler/chainId.test.ts | 9 +- .../smartAccount/deployContract.test.ts | 67 +++++++-- .../prepareUserOperationRequest.test.ts | 32 ++++- .../smartAccount/sendTransaction.test.ts | 108 ++++++++++++++ .../smartAccount/sendTransactions.test.ts | 126 +++++++++++++++++ .../smartAccount/sendUserOperation.test.ts | 133 ++++++++++++++++++ 6 files changed, 453 insertions(+), 22 deletions(-) create mode 100644 packages/permissionless/actions/smartAccount/sendTransaction.test.ts create mode 100644 packages/permissionless/actions/smartAccount/sendTransactions.test.ts create mode 100644 packages/permissionless/actions/smartAccount/sendUserOperation.test.ts diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts index 9fd55430..8d5ecf5e 100644 --- a/packages/permissionless/actions/bundler/chainId.test.ts +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -15,11 +15,10 @@ describe("chainId", () => { const { altoRpc } = rpc const entryPoint = ENTRYPOINT_ADDRESS_V06 - const bundlerClient: BundlerClient = - createBundlerClient({ - transport: http(altoRpc), - entryPoint - }) + const bundlerClient = createBundlerClient({ + transport: http(altoRpc), + entryPoint + }) const id = await chainId(bundlerClient) expect(id).toBe(foundry.id) }) diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts index b6c52fde..c74b96c1 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.test.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.test.ts @@ -1,11 +1,21 @@ +import type { Chain, Client, Transport } from "viem" import { generatePrivateKey } from "viem/accounts" +import { foundry } from "viem/chains" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, getPimlicoPaymasterClient } from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, + EntryPoint +} from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { deployContract } from "./deployContract" describe.each(getCoreSmartAccounts())( "deployContract $name", @@ -31,10 +41,26 @@ describe.each(getCoreSmartAccounts())( }) await expect(async () => - smartClient.deployContract({ - abi: [], - bytecode: "0xff66" - }) + deployContract( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + account: smartClient.account, + chain: foundry, + abi: [ + { + inputs: [], + stateMutability: "payable", + type: "constructor" + } + ], + bytecode: + "0x608060405260358060116000396000f3006080604052600080fd00a165627a7a72305820f86ff341f0dff29df244305f8aa88abaf10e3a0719fa6ea1dcdd01b8b7d750970029" + } + ) ).rejects.toThrowError( /^.*doesn't support account deployment.*$/i ) @@ -46,7 +72,7 @@ describe.each(getCoreSmartAccounts())( async ({ rpc }) => { const { anvilRpc, altoRpc, paymasterRpc } = rpc - const smartClient = await getSmartAccountClient({ + const smartClient = (await getSmartAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, privateKey: generatePrivateKey(), altoRpc: altoRpc, @@ -55,13 +81,34 @@ describe.each(getCoreSmartAccounts())( entryPoint: ENTRYPOINT_ADDRESS_V07, paymasterRpc }) - }) + })) as SmartAccountClient< + ENTRYPOINT_ADDRESS_V07_TYPE, + Transport, + Chain, + SmartAccount + > await expect(async () => - smartClient.deployContract({ - abi: [], - bytecode: "0xff66" - }) + deployContract( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + account: smartClient.account, + chain: foundry, + abi: [ + { + inputs: [], + stateMutability: "payable", + type: "constructor" + } + ], + bytecode: + "0x608060405260358060116000396000f3006080604052600080fd00a165627a7a72305820f86ff341f0dff29df244305f8aa88abaf10e3a0719fa6ea1dcdd01b8b7d750970029" + } + ) ).rejects.toThrowError( /^.*doesn't support account deployment.*$/i ) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts index f7ff2147..f1755183 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts @@ -1,9 +1,13 @@ -import { zeroAddress } from "viem" +import { type Chain, type Client, type Transport, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts } from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import type { EntryPoint } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { prepareUserOperationRequest } from "./prepareUserOperationRequest" describe.each(getCoreSmartAccounts())( "prepareUserOperationRequest $name", @@ -24,8 +28,13 @@ describe.each(getCoreSmartAccounts())( anvilRpc: anvilRpc }) - const userOperation = - await smartClient.prepareUserOperationRequest({ + const userOperation = await prepareUserOperationRequest( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { userOperation: { callData: await smartClient.account.encodeCallData({ to: zeroAddress, @@ -33,7 +42,8 @@ describe.each(getCoreSmartAccounts())( value: 0n }) } - }) + } + ) expect(userOperation).toBeTruthy() expect(userOperation.sender).toBe(smartClient.account.address) expect(userOperation.nonce).toBe( @@ -55,6 +65,8 @@ describe.each(getCoreSmartAccounts())( expect(userOperation.maxPriorityFeePerGas).toBeTruthy() expect(userOperation.paymasterAndData).toBe("0x") expect(userOperation.signature).toBe( + // @ts-ignore: since tests return all smart account client, some of them don't support V06. + // The TS error is because in that case, getDummySignature would not accept the userOperation of type UserOperation await smartClient.account.getDummySignature(userOperation) ) @@ -81,8 +93,13 @@ describe.each(getCoreSmartAccounts())( anvilRpc: anvilRpc }) - const userOperation = - await smartClient.prepareUserOperationRequest({ + const userOperation = await prepareUserOperationRequest( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { userOperation: { callData: await smartClient.account.encodeCallData({ to: zeroAddress, @@ -90,7 +107,8 @@ describe.each(getCoreSmartAccounts())( value: 0n }) } - }) + } + ) expect(userOperation).toBeTruthy() expect(userOperation.sender).toBe(smartClient.account.address) diff --git a/packages/permissionless/actions/smartAccount/sendTransaction.test.ts b/packages/permissionless/actions/smartAccount/sendTransaction.test.ts new file mode 100644 index 00000000..35f5c1fa --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendTransaction.test.ts @@ -0,0 +1,108 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendTransaction } from "./sendTransaction" + +describe.each(getCoreSmartAccounts())( + "sendTransaction $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendTransaction_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const transactionHash = await sendTransaction( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendTransaction_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const transactionHash = await sendTransaction( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/sendTransactions.test.ts b/packages/permissionless/actions/smartAccount/sendTransactions.test.ts new file mode 100644 index 00000000..ef70b4b2 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendTransactions.test.ts @@ -0,0 +1,126 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendTransactions } from "./sendTransactions" + +describe.each(getCoreSmartAccounts())( + "sendTransactions $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendTransactions_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const transactionHash = await sendTransactions( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + transactions: [ + { + to: zeroAddress, + data: "0x", + value: 0n + }, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ] + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendTransactions_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const transactionHash = await sendTransactions( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + transactions: [ + { + to: zeroAddress, + data: "0x", + value: 0n + }, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ] + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts new file mode 100644 index 00000000..a5b28858 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts @@ -0,0 +1,133 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getBundlerClient, + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendUserOperation } from "./sendUserOperation" + +describe.each(getCoreSmartAccounts())( + "sendUserOperation $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendUserOperation_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperationHash = await sendUserOperation( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + + expect(userOperationHash).toBeTruthy() + + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc + }) + + const receipt = await bundlerClient.waitForUserOperationReceipt( + { + hash: userOperationHash + } + ) + + expect(receipt).toBeTruthy() + expect(receipt.userOpHash).toBe(userOperationHash) + expect(receipt.entryPoint.toLowerCase()).toBe( + ENTRYPOINT_ADDRESS_V06.toLowerCase() + ) + expect(receipt.receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendUserOperation_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperationHash = await sendUserOperation( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + + expect(userOperationHash).toBeTruthy() + + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + altoRpc + }) + + const receipt = await bundlerClient.waitForUserOperationReceipt( + { + hash: userOperationHash + } + ) + + expect(receipt).toBeTruthy() + expect(receipt.userOpHash).toBe(userOperationHash) + expect(receipt.entryPoint.toLowerCase()).toBe( + ENTRYPOINT_ADDRESS_V07.toLowerCase() + ) + expect(receipt.receipt.status).toBe("success") + } + ) + } +)