From e2e8f58d0bf41edc9031bada0583a26557c127f1 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 25 Jun 2024 22:32:24 +0100 Subject: [PATCH 01/13] add tests and erc7579 actions --- package.json | 4 +- .../mock-aa-infra/alto/constants.ts | 3 + .../mock-aa-infra/alto/index.ts | 8 + packages/permissionless-test/src/utils.ts | 62 +++- .../privateKeyToBiconomySmartAccount.ts | 17 +- .../biconomy/signerToBiconomySmartAccount.ts | 10 +- .../kernel/signerToEcdsaKernelSmartAccount.ts | 80 +++-- .../accounts/kernel/utils/encodeCallData.ts | 3 +- .../accounts/kernel/utils/getNonceKey.ts | 3 +- .../light/privateKeyToLightSmartAccount.ts | 17 +- .../light/signerToLightSmartAccount.ts | 12 +- .../safe/privateKeyToSafeSmartAccount.ts | 17 +- .../accounts/safe/signerToSafeSmartAccount.ts | 37 +- .../simple/privateKeyToSimpleSmartAccount.ts | 18 +- .../simple/signerToSimpleSmartAccount.ts | 12 +- .../permissionless/accounts/toSmartAccount.ts | 8 +- .../trust/privateKeyToTrustSmartAccount.ts | 17 +- .../trust/signerToTrustSmartAccount.ts | 12 +- packages/permissionless/accounts/types.ts | 10 +- .../bundler/estimateUserOperationGas.ts | 2 +- .../actions/erc7579/accountId.test.ts | 109 ++++++ .../actions/erc7579/accountId.ts | 108 ++++++ .../actions/erc7579/installModule.ts | 103 ++++++ .../actions/erc7579/isModuleInstalled.ts | 77 ++++ .../actions/erc7579/supportsExecutionMode.ts | 122 +++++++ .../actions/erc7579/supportsModule.ts | 82 +++++ .../actions/erc7579/uninstallModule.ts | 103 ++++++ packages/permissionless/actions/index.test.ts | 329 ++++++++++++++++++ .../permissionless/actions/pimlico.test.ts | 222 ++++++++++++ .../actions/smartAccount/signMessage.test.ts | 89 +++++ .../smartAccount/signTypedData.test.ts | 118 +++++++ .../smartAccount/writeContract.test.ts | 118 +++++++ .../clients/decorators/erc7579.ts | 89 +++++ packages/permissionless/package.json | 2 +- packages/permissionless/types/index.ts | 3 +- .../permissionless/utils/encodeCallData.ts | 113 ++++++ packages/permissionless/vitest.config.ts | 3 - packages/wagmi-test-demo/src/App.tsx | 2 - 38 files changed, 2066 insertions(+), 78 deletions(-) create mode 100644 packages/permissionless/actions/erc7579/accountId.test.ts create mode 100644 packages/permissionless/actions/erc7579/accountId.ts create mode 100644 packages/permissionless/actions/erc7579/installModule.ts create mode 100644 packages/permissionless/actions/erc7579/isModuleInstalled.ts create mode 100644 packages/permissionless/actions/erc7579/supportsExecutionMode.ts create mode 100644 packages/permissionless/actions/erc7579/supportsModule.ts create mode 100644 packages/permissionless/actions/erc7579/uninstallModule.ts create mode 100644 packages/permissionless/actions/index.test.ts create mode 100644 packages/permissionless/actions/pimlico.test.ts create mode 100644 packages/permissionless/actions/smartAccount/signMessage.test.ts create mode 100644 packages/permissionless/actions/smartAccount/signTypedData.test.ts create mode 100644 packages/permissionless/actions/smartAccount/writeContract.test.ts create mode 100644 packages/permissionless/clients/decorators/erc7579.ts create mode 100644 packages/permissionless/utils/encodeCallData.ts diff --git a/package.json b/package.json index 20257823..94c861c2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "type": "module", "sideEffects": false, "devDependencies": { - "vitest": "^1.2.0", "@vitest/coverage-v8": "^1.2.0", "@biomejs/biome": "^1.0.0", "@changesets/changelog-git": "^0.1.14", @@ -61,6 +60,7 @@ "async-mutex": "^0.5.0", "get-port": "^7.0.0", "tsc-alias": "^1.8.8", - "viem": "^2.13.8" + "vitest": "^1.2.0", + "viem": "^2.14.1" } } diff --git a/packages/permissionless-test/mock-aa-infra/alto/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts index e1dfbe94..e3addc71 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -51,6 +51,9 @@ export const SAFE_MULTI_SEND_CREATECALL: Hex = export const SAFE_MULTI_SEND_CALL_ONLY_CREATECALL: Hex = "0x0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b5061019a806100206000396000f3fe60806040526004361061001e5760003560e01c80638d80ff0a14610023575b600080fd5b6100dc6004803603602081101561003957600080fd5b810190808035906020019064010000000081111561005657600080fd5b82018360208201111561006857600080fd5b8035906020019184600183028401116401000000008311171561008a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506100de565b005b805160205b8181101561015f578083015160f81c6001820184015160601c60158301850151603584018601516055850187016000856000811461012857600181146101385761013d565b6000808585888a5af1915061013d565b600080fd5b50600081141561014c57600080fd5b82605501870196505050505050506100e3565b50505056fea26469706673582212208d297bb003abee230b5dfb38774688f37a6fbb97a82a21728e8049b2acb9b73564736f6c63430007060033" +export const SAFE_7579_MODULE_CREATECALL: Hex = + "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50604051601a90605a565b604051809103906000f0801580156035573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790556067565b6109d880614a9483390190565b614a1e806100766000396000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260056020908152604080832054600683528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600560205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b506102386102333660046139e3565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613a3e565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613a89565b6109de565b60405190815260200161020f565b6102b56102b0366004613b38565b610af2565b005b6102b56102c5366004613c1e565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613c5f565b610ba0565b60405161020f929190613c8b565b6102b56103063660046139e3565b610bbc565b34801561031757600080fd5b50610320610d61565b60405161020f9190613d3e565b6102b561033b3660046139e3565b610df3565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613d67565b3360009081526006602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613d84565b610f5f565b6103e26103dd366004613a3e565b611007565b60405161020f9190613d9d565b3480156103fb57600080fd5b5061029461040a366004613e01565b6110d3565b6102b561041d366004613a3e565b611173565b34801561042e57600080fd5b506102ea61043d366004613c5f565b611518565b34801561044e57600080fd5b506102b561045d366004613e4b565b611542565b34801561046e57600080fd5b5061023861047d366004613d84565b6115b1565b34801561048e57600080fd5b50610294611600565b6060806001600160a01b03841615610517576104fe338560006104b8611659565b346000366040516024016104cf9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611665565b9150818060200190518101906105149190613fce565b91505b6001600160a01b0383161561054e57610535338460006104b8611659565b90508080602001905181019061054b9190613fce565b90505b9250929050565b3360009081526004602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61170e565b156106185761060e338388886105e8611659565b6040516020016105fa93929190614002565b604051602081830303815290604052611720565b9350505050610663565b61062381600061170e565b1561065f5761060e338360008989610639611659565b60405160200161064b93929190614002565b604051602081830303815290604052611665565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613d3e565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b1790526117e0565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613d3e565b50505050565b600060018503610706576106ff8461187f565b9050610741565b60028503610717576106ff8461188d565b6003850361072a576106ff8484846118a6565b6004850361073d576106ff8484846118f3565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614028565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e56014828688614041565b6107ee9161406b565b60601c905080158061080657506108048161187f565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614028565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405261192e565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e614041565b6040518563ffffffff1660e01b815260040161091894939291906140a0565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611659565b8a6109798a6014818e614041565b60405160240161098c9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611720565b9050808060200190518101906109d191906140d7565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611659565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c8261187f565b155b15610a5357610a4c866119a8565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f929190614139565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611665565b905080806020019051810190610ab49190614028565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da03286604051806020016040528060008152506117e0565b50509392505050565b610b24610b026020830183614238565b610b0f6020840184614255565b610b1f606086016040870161429e565b611a4e565b610b348989898989898989611afc565b505050505050505050565b610b4a600233611d3f565b8060005b818110156106e65736848483818110610b6957610b696142b9565b9050602002810190610b7b91906142cf565b9050610b9733610b8e6020840184614238565b60029190611dba565b50600101610b4e565b60606000610bb16002338686611eaf565b915091509250929050565b3360009081526005602090815260408083205460068352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611659565b6001600160a01b03161480610c5d5750610c48611659565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f898989612065565b9050610cfb565b60028a03610ca957610c8f8989896120c1565b60038a03610cbc57610c8f89898961212b565b60048a03610ccf57610c8f89898961226c565b89610cdf57610c8f8989896123eb565b60405163041c38b360e41b8152600481018b90526024016105bd565b600054604051610d549133916001600160a01b0390911690610d25908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612573565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcb9190810190614319565b905080604051602001610dde9190614361565b60405160208183030381529060405291505090565b33600090815260056020908152604080832054600683528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e3b8484610497565b91509150610e566f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e67611659565b6001600160a01b03161480610e945750610e7f611659565b6001600160a01b0316336001600160a01b0316145b610eb157604051635629665f60e11b815260040160405180910390fd5b606060018a03610ecd57610ec689898961260c565b9050610f06565b60028a03610ee057610ec6898989612635565b60038a03610ef357610ec6898989612662565b60048a03610cdf57610ec68989896126b0565b600054604051610d549133916001600160a01b0390911690610f30908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b179052612768565b600081600881901b610f7582600160f81b61170e565b15610f835760019250610fc6565b610f8e82600061170e565b15610f9c5760019250610fc6565b610fae826001600160f81b031961170e565b15610fbc5760019250610fc6565b5060009392505050565b828015610fd95750610fd981600061170e565b15610fe5575050919050565b828015610ffb5750610ffb81600160f81b61170e565b15610fbc575050919050565b6060611019611014611659565b61188d565b61104a57611025611659565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260056020908152604080832054600683528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110928484610497565b915091503360026110a3828261281e565b8a600881901b6110b581838e8e6128a9565b9950505050506110c784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614028565b336000908152600560209081526040808320546006835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111bb8484610497565b915091506111d66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b03166111e7611659565b6001600160a01b0316148061121457506111ff611659565b6001600160a01b0316336001600160a01b0316145b61123157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361124382600061170e565b156113a65761125683600160f81b61170e565b156112775789358a01602081019035611270838383612c65565b50506114ff565b61128283600061170e565b156112ea576000803660006112978e8e612cbc565b93509350935093506112e185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117e092505050565b505050506114ff565b6112fc836001600160f81b031961170e565b156113815760006113106014828c8e614041565b6113199161406b565b60601c90503660008c8c601490809261133493929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061257392505050565b5050506114ff565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113b482600160f81b61170e565b156114da576113c783600160f81b61170e565b156113e15789358a01602081019035611270838383612d0d565b6113ec83600061170e565b1561144b576000803660006114018e8e612cbc565b93509350935093506112e185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d6492505050565b61145d836001600160f81b031961170e565b156113815760006114716014828c8e614041565b61147a9161406b565b60601c90503660008c8c601490809261149593929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061276892505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061150e84848484610669565b5050505050505050565b33600090815260036020526040812060609190611536818686612e1a565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261155b611659565b6001600160a01b031614806115885750611573611659565b6001600160a01b0316336001600160a01b0316145b6115a557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a4e565b6000600182036115c357506001919050565b600282036115d357506001919050565b600382036115e357506001919050565b600482036115f357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b815260040161169c94939291906143a7565b6000604051808303816000875af11580156116bb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116e391908101906143f2565b925090508061170557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60606000838360405160240161173792919061443f565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b17905260008054915192935091611783916001600160a01b031690849060240161443f565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a7906118159087908790879087906004016143a7565b6020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118589190614463565b90508061187857604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360023384612fb8565b3360009081526003602052604081206109d78184612ffc565b6000806118b583850185613d67565b3360009081526004602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b600080806119038486018661448d565b9150915060006119138383613036565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b85858560405160200161194e9291906144b9565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ba876130ce565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a11916119f5918990879087906004016140a0565b60006040518083038186803b158015611a0d57600080fd5b505afa925050508015611a1e575060015b611a3557611a2e600184866132e3565b9550611a44565b611a41600084866132e3565b95505b5050505050919050565b3360008181526001602052604080822080546001600160a01b0319166001600160a01b03891617905551611ac092918791611a91908690899089906024016144df565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b1790526117e0565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0602052604090205487906001600160a01b0316611ba957611b45600233611d3f565b60005b81811015611ba357368a8a83818110611b6357611b636142b9565b9050602002810190611b7591906142cf565b9050611b99611b876020830183614238565b611b94602084018461453a565b612065565b5050600101611b48565b50611bca565b8015611bca5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600360205260409020611be28161331b565b86915060005b82811015611c435736898983818110611c0357611c036142b9565b9050602002810190611c1591906142cf565b9050611c39611c276020830183614238565b611c34602084018461453a565b6120c1565b5050600101611be8565b5084915060005b82811015611ca55736878783818110611c6557611c656142b9565b9050602002810190611c7791906142cf565b9050611c9b611c896020830183614238565b611c96602084018461453a565b61212b565b5050600101611c4a565b5082915060005b82811015611d075736858583818110611cc757611cc76142b9565b9050602002810190611cd991906142cf565b9050611cfd611ceb6020830183614238565b611cf8602084018461453a565b61226c565b5050600101611cac565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611d82576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611dd957506001600160a01b0381166001145b15611e0257604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e5157604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611ed55750611ed3868686612fb8565b155b15611efe57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f1f5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f3757611f37613f0c565b604051908082528060200260200182016040528015611f60578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fb057506001600160a01b038216600114155b8015611fbb57508381105b156120205781838281518110611fd357611fd36142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061201881614596565b915050611f8e565b6001600160a01b038216600114612058578261203d6001836145af565b8151811061204d5761204d6142b9565b602002602001015191505b8083525094509492505050565b6060836001612074828261281e565b61208060023388611dba565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026120d0828261281e565b3360009081526003602052604090206120e98188613378565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361213a828261281e565b6000808061214a87890189614613565b919450925090506001600160e01b031983166306d61fe760e41b148061218057506001600160e01b03198316638a91b0e360e01b145b156121aa576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612202576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b606083600461227b828261281e565b6000808061228b87890189614681565b919450925090506000808460018111156122a7576122a76146af565b1480156122bc57506001600160e01b03198316155b156123325750336000908152600560205260409020546001600160a01b031680156123055760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260056020526040902080546001600160a01b0319166001600160a01b038c161790556123de565b6001846001811115612346576123466146af565b036123c5576001600160a01b0381161561237e5760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526006602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b0319831617909255166123de565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124335760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561252c576000888883818110612452576124526142b9565b905060200201359050600181036124915761248b8d888885818110612479576124796142b9565b9050602002810190611b94919061453a565b50612523565b600281036124c15761248b8d8888858181106124af576124af6142b9565b9050602002810190611c34919061453a565b600381036124f15761248b8d8888858181106124df576124df6142b9565b9050602002810190611c96919061453a565b60048103612523576125218d88888581811061250f5761250f6142b9565b9050602002810190611cf8919061453a565b505b50600101612436565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125a9908690859087906001906004016143a7565b6020604051808303816000875af11580156125c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190614463565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061261c838501856146c5565b9250905061262d600233838861344e565b509392505050565b336000908152600360205260408120606091612653848601866146c5565b93509050610ae9828288613545565b606060006126728385018561470a565b3360009081526004602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b60606000806126c184860186614681565b9450909250905060008260018111156126dc576126dc6146af565b1480156126f157506001600160e01b03198116155b156127185733600090815260056020526040902080546001600160a01b0319169055610ae9565b600182600181111561272c5761272c6146af565b036123c5573360009081526006602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a79061279e908690859087906001906004016143a7565b6020604051808303816000875af11580156127bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e19190614463565b9050806106e657604080516001600160a01b0386168152600060208201526000805160206149c9833981519152910160405180910390a150505050565b336000908152600160205260409020546001600160a01b031680156128a45760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b15801561288b57600080fd5b505afa15801561289f573d6000803e3d6000fd5b505050505b505050565b60606128b685600061170e565b15612aac576128c984600160f81b61170e565b156128ec57823583016020810190356128e333838361361a565b92505050610741565b6128f784600061170e565b156129ab5760008036600061290c8787612cbc565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161292b57905050945061298433858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061166592505050565b85600081518110612997576129976142b9565b602002602001018190525050505050610741565b6129bd846001600160f81b031961170e565b15612a875760006129d16014828587614041565b6129da9161406b565b60601c90503660006129ef8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a09579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061369392505050565b84600081518110612a7457612a746142b9565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612aba85600160f81b61170e565b15612c4057612acd84600160f81b61170e565b15612af25782358301602081019035612ae7338383613734565b935061074192505050565b612afd84600061170e565b15612b8a57600080366000612b128787612cbc565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b3157905050945061298433858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137b692505050565b612b9c846001600160f81b031961170e565b15612a87576000612bb06014828587614041565b612bb99161406b565b60601c9050366000612bce8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612be8579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387692505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6000546040516128a49185916001600160a01b0390911690612c8d9086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612573565b6000803681612cce6014828789614041565b612cd79161406b565b60601c9350612cea603460148789614041565b612cf3916147d3565b9250612d028560348189614041565b949793965094505050565b6000546040516128a49185916001600160a01b0390911690612d359086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b179052612768565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612d999087908790879087906004016143a7565b6020604051808303816000875af1158015612db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddc9190614463565b90508061187857604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612e3f5750612e3d8585612ffc565b155b15612e6857604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612e895760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612ea157612ea1613f0c565b604051908082528060200260200182016040528015612eca578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f0f57506001600160a01b038216600114155b8015612f1a57508381105b15612f745781838281518110612f3257612f326142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612f6c81614596565b915050612eed565b6001600160a01b038216600114612fac5782612f916001836145af565b81518110612fa157612fa16142b9565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b60008083600181111561304b5761304b6146af565b14801561306057506001600160e01b03198216155b156130805750336000908152600560205260409020546001600160a01b03165b6001836001811115613094576130946146af565b0361066357503360009081526006602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b6060600080368181816130e561010089018961453a565b90925090506130f8600660008385614041565b613101916147f1565b60d01c9550613114600c60068385614041565b61311d916147f1565b60d01c945061312f81600c8185614041565b9350935050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd60001b8152602001336001600160a01b0316815260200188602001358152602001888060400190613195919061453a565b6040516131a392919061481f565b60405190819003902081526020016131be60608a018a61453a565b6040516131cc92919061481f565b604051809103902081526020016131e289613936565b81526020016131f08961394b565b81526020018860a0013581526020016132088961395b565b815260200161321689613970565b815260200161322860e08a018a61453a565b60405161323692919061481f565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff1681526020016132766f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b61329b611600565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561330b57600061330e565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b031615613353576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061339757506001600160a01b0381166001145b156133c057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b03818116600090815260208490526040902054161561340457604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061346d57506001600160a01b0381166001145b1561349657604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020868152604080832087851684529091529020548116908216146134e957604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061356457506001600160a01b0381166001145b1561358d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b038281166000908152602085905260409020548116908216146135d557604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b60008054604051606092916136749187916001600160a01b0316906136459088908890602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613693565b90508080602001905181019061368a91906148dc565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016136cb94939291906143a7565b6000604051808303816000875af11580156136ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261371291908101906143f2565b925090508061262d57604051632b3f6d1160e21b815260040160405180910390fd5b60608060006137938660008054906101000a90046001600160a01b03168787604051602401613764929190614728565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052613876565b9050808060200190518101906137a99190614910565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016137ed94939291906143a7565b6000604051808303816000875af115801561380c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261383491908101906143f2565b925090508061170557604080516001600160a01b0388168152600060208201526000805160206149c9833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016138ae94939291906143a7565b6000604051808303816000875af11580156138cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f591908101906143f2565b925090508061262d57604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a1509392505050565b60006001600160801b03608083013516610663565b6000610663826080013560801c90565b60006001600160801b0360c083013516610663565b600060c082013560801c610663565b6001600160a01b038116811461399457600080fd5b50565b80356115fb8161397f565b60008083601f8401126139b457600080fd5b5081356001600160401b038111156139cb57600080fd5b60208301915083602082850101111561054e57600080fd5b600080600080606085870312156139f957600080fd5b843593506020850135613a0b8161397f565b925060408501356001600160401b03811115613a2657600080fd5b613a32878288016139a2565b95989497509550505050565b600080600060408486031215613a5357600080fd5b8335925060208401356001600160401b03811115613a7057600080fd5b613a7c868287016139a2565b9497909650939450505050565b600080600060608486031215613a9e57600080fd5b83356001600160401b03811115613ab457600080fd5b84016101208187031215613ac757600080fd5b95602085013595506040909401359392505050565b60008083601f840112613aee57600080fd5b5081356001600160401b03811115613b0557600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613b3257600080fd5b50919050565b600080600080600080600080600060a08a8c031215613b5657600080fd5b89356001600160401b0380821115613b6d57600080fd5b613b798d838e01613adc565b909b50995060208c0135915080821115613b9257600080fd5b613b9e8d838e01613adc565b909950975060408c0135915080821115613bb757600080fd5b613bc38d838e01613adc565b909750955060608c0135915080821115613bdc57600080fd5b613be88d838e01613adc565b909550935060808c0135915080821115613c0157600080fd5b50613c0e8c828d01613b20565b9150509295985092959850929598565b60008060208385031215613c3157600080fd5b82356001600160401b03811115613c4757600080fd5b613c5385828601613adc565b90969095509350505050565b60008060408385031215613c7257600080fd5b8235613c7d8161397f565b946020939093013593505050565b604080825283519082018190526000906020906060840190828701845b82811015613ccd5781516001600160a01b031684529284019290840190600101613ca8565b5050506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613d09578181015183820152602001613cf1565b50506000910152565b60008151808452613d2a816020860160208601613cee565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613d12565b6001600160e01b03198116811461399457600080fd5b600060208284031215613d7957600080fd5b81356109d781613d51565b600060208284031215613d9657600080fd5b5035919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015613df457603f19888603018452613de2858351613d12565b94509285019290850190600101613dc6565b5092979650505050505050565b60008060408385031215613e1457600080fd5b8235613e1f8161397f565b91506020830135613e2f8161397f565b809150509250929050565b803560ff811681146115fb57600080fd5b60008060008060608587031215613e6157600080fd5b8435613e6c8161397f565b935060208501356001600160401b03811115613e8757600080fd5b613e9387828801613adc565b9094509250613ea6905060408601613e3a565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613f02606083018486613eb1565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613f4a57613f4a613f0c565b604052919050565b60006001600160401b03821115613f6b57613f6b613f0c565b50601f01601f191660200190565b6000613f8c613f8784613f52565b613f22565b9050828152838383011115613fa057600080fd5b6109d7836020830184613cee565b600082601f830112613fbf57600080fd5b6109d783835160208501613f79565b600060208284031215613fe057600080fd5b81516001600160401b03811115613ff657600080fd5b61074184828501613fae565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561403a57600080fd5b5051919050565b6000808585111561405157600080fd5b8386111561405e57600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156140985780818660140360031b1b83161692505b505092915050565b8481526060602082015260006140b96060830186613d12565b82810360408401526140cc818587613eb1565b979650505050505050565b6000602082840312156140e957600080fd5b81516109d781613d51565b6000808335601e1984360301811261410b57600080fd5b83016020810192503590506001600160401b0381111561412a57600080fd5b80360382131561054e57600080fd5b6040815261415a6040820161414d85613997565b6001600160a01b03169052565b60208301356060820152600061417360408501856140f4565b61012080608086015261418b61016086018385613eb1565b925061419a60608801886140f4565b9250603f19808786030160a08801526141b4858584613eb1565b9450608089013560c088015260a089013560e0880152610100935060c0890135848801526141e560e08a018a6140f4565b92508188870301848901526141fb868483613eb1565b95505061420a848a018a6140f4565b9450925080878603016101408801525050614226838383613eb1565b93505050508260208301529392505050565b60006020828403121561424a57600080fd5b81356109d78161397f565b6000808335601e1984360301811261426c57600080fd5b8301803591506001600160401b0382111561428657600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156142b057600080fd5b6109d782613e3a565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126142e557600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061368a90830184613d12565b60006020828403121561432b57600080fd5b81516001600160401b0381111561434157600080fd5b8201601f8101841361435257600080fd5b61074184825160208401613f79565b64736166652d60d81b815260008251614381816005850160208701613cee565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006143ce6080830185613d12565b905060ff8316606083015295945050505050565b805180151581146115fb57600080fd5b6000806040838503121561440557600080fd5b61440e836143e2565b915060208301516001600160401b0381111561442957600080fd5b61443585828601613fae565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613d12565b60006020828403121561447557600080fd5b6109d7826143e2565b8035600281106115fb57600080fd5b600080604083850312156144a057600080fd5b6144a98361447e565b91506020830135613e2f81613d51565b828152600082516144d1816020850160208701613cee565b919091016020019392505050565b60ff8416815260406020808301829052908201839052600090849060608401835b8681101561452e5783356145138161397f565b6001600160a01b031682529282019290820190600101614500565b50979650505050505050565b6000808335601e1984360301811261455157600080fd5b8301803591506001600160401b0382111561456b57600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016145a8576145a8614580565b5060010190565b8181038181111561066357610663614580565b600082601f8301126145d357600080fd5b81356145e1613f8782613f52565b8181528460208386010111156145f657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561462857600080fd5b833561463381613d51565b925060208401356001600160f81b03198116811461465057600080fd5b915060408401356001600160401b0381111561466b57600080fd5b614677868287016145c2565b9150509250925092565b60008060006060848603121561469657600080fd5b61469f8461447e565b9250602084013561465081613d51565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156146d857600080fd5b82356146e38161397f565b915060208301356001600160401b038111156146fe57600080fd5b614435858286016145c2565b6000806040838503121561471d57600080fd5b82356146e381613d51565b60208082528181018390526000906040808401600586901b850182018785805b898110156147c457888403603f190185528235368c9003605e1901811261476d578283fd5b8b016060813561477c8161397f565b6001600160a01b03168652818901358987015261479b888301836140f4565b925081898801526147af8288018483613eb1565b978a0197965050509287019250600101614748565b50919998505050505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b6001600160d01b031981358181169160068510156140985760069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561484857614848613f0c565b5060051b60200190565b600082601f83011261486357600080fd5b81516020614873613f878361482f565b82815260059290921b8401810191818101908684111561489257600080fd5b8286015b848110156148d15780516001600160401b038111156148b55760008081fd5b6148c38986838b0101613fae565b845250918301918301614896565b509695505050505050565b6000602082840312156148ee57600080fd5b81516001600160401b0381111561490457600080fd5b61074184828501614852565b6000806040838503121561492357600080fd5b82516001600160401b038082111561493a57600080fd5b818501915085601f83011261494e57600080fd5b8151602061495e613f878361482f565b82815260059290921b8401810191818101908984111561497d57600080fd5b948201945b838610156149a257614993866143e2565b82529482019490820190614982565b918801519196509093505050808211156149bb57600080fd5b506144358582860161485256feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca26469706673582212204c1b68f6eb53965f3e290e9e6a21e9c80395a1ac0fce6394aa58289d799e181864736f6c634300081900336080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033" + /* ========= V06 CORE ========= */ // Will deploy entryPoint to 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index 8f60913a..ce6b78bf 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -36,6 +36,7 @@ import { SAFE_V06_MODULE_SETUP_CREATECALL, SAFE_V07_MODULE_CREATECALL, SAFE_V07_MODULE_SETUP_CREATECALL, + SAFE_7579_MODULE_CREATECALL, SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, TRUST_ACCOUNT_FACET_CREATE_CALL, @@ -137,6 +138,12 @@ export const setupContracts = async (rpc: string) => { gas: 15_000_000n, nonce: nonce++ }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_7579_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V07_MODULE_CREATECALL, @@ -374,6 +381,7 @@ export const setupContracts = async (rpc: string) => { "0x41675C099F32341bf84BFc5382aF534df5C7461a", // Safe Singleton "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526", // Safe Multi Send "0x9641d764fc13c8B624c04430C7356C1C7C8102e2", // Safe Multi Send Call Only + "0xbaCA6f74a5549368568f387FD989C279f940f1A5", // Safe 7579 module "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // EntryPoint V0.6 "0x9406Cc6185a346906296840746125a0E44976454", // Simple Account Factory V0.6 "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", // Biconomy ECDSA Ownership Registry Module diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 86d6ffd2..4378af5b 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -9,7 +9,8 @@ import { createClient, createPublicClient, createWalletClient, - parseEther + parseEther, + getAddress } from "viem" import { generatePrivateKey, @@ -23,7 +24,8 @@ import { type SmartAccountClient, createBundlerClient, createSmartAccountClient, - getEntryPointVersion + getEntryPointVersion, + ENTRYPOINT_ADDRESS_V07 } from "../../permissionless" import { type SafeSmartAccount, @@ -45,6 +47,7 @@ import { import { paymasterActionsEip7677 } from "../../permissionless/experimental" import type { ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, EntryPoint } from "../../permissionless/types" import { @@ -317,23 +320,32 @@ export const getKernelEcdsaClient = async ({ paymasterClient, anvilRpc, altoRpc, - privateKey = generatePrivateKey() -}: AAParamType): Promise< + privateKey = generatePrivateKey(), + erc7579 +}: AAParamType & { erc7579?: boolean }): Promise< SmartAccountClient> > => { const publicClient = getPublicClient(anvilRpc) - const kernelEcdsaAccount = await signerToEcdsaKernelSmartAccount( - publicClient, - { - entryPoint, - signer: privateKeyToAccount(privateKey) - } - ) + if (erc7579 && entryPoint === ENTRYPOINT_ADDRESS_V06) { + throw new Error("ERC7579 is not supported for V06") + } + + const kernelEcdsaAccount = + erc7579 && entryPoint === ENTRYPOINT_ADDRESS_V07 + ? await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: entryPoint as ENTRYPOINT_ADDRESS_V07_TYPE, + signer: privateKeyToAccount(privateKey), + version: "0.3.0" + }) + : await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(privateKey) + }) // @ts-ignore return createSmartAccountClient({ chain: foundry, - account: kernelEcdsaAccount, + account: kernelEcdsaAccount as KernelEcdsaSmartAccount, bundlerTransport: http(altoRpc), middleware: { // @ts-ignore @@ -348,7 +360,8 @@ export const getSafeClient = async ({ paymasterClient, anvilRpc, altoRpc, - privateKey = generatePrivateKey() + privateKey = generatePrivateKey(), + erc7579 }: { setupTransactions?: { to: Address @@ -360,13 +373,22 @@ export const getSafeClient = async ({ entryPoint: T paymasterClient?: PimlicoPaymasterClient privateKey?: Hex + erc7579?: boolean }): Promise>> => { const publicClient = getPublicClient(anvilRpc) + + // const safeModules: Address[] = erc7579 + // ? [getAddress("0xbaCA6f74a5549368568f387FD989C279f940f1A5")] + // : [] + const safeSmartAccount = await signerToSafeSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), safeVersion: "1.4.1", saltNonce: 420n, + safe4337ModuleAddress: getAddress( + "0xbaCA6f74a5549368568f387FD989C279f940f1A5" + ), setupTransactions }) @@ -414,7 +436,8 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: false, - isEip1271Compliant: true + isEip1271Compliant: true, + supportsErc7579: false }, { name: "LightAccount v1.1.0", @@ -430,6 +453,7 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: false, + supportsErc7579: false, isEip1271Compliant: true }, { @@ -445,6 +469,7 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: true, + supportsErc7579: false, isEip1271Compliant: false }, { @@ -458,8 +483,12 @@ export const getCoreSmartAccounts = () => [ signer: privateKeyToAccount(conf.privateKey), entryPoint: ENTRYPOINT_ADDRESS_V06 }), + getErc7579SmartAccountClient: async ( + conf: AAParamType + ) => getKernelEcdsaClient({ ...conf, erc7579: true }), supportsEntryPointV06: true, supportsEntryPointV07: true, + supportsErc7579: false, isEip1271Compliant: true }, { @@ -481,6 +510,7 @@ export const getCoreSmartAccounts = () => [ entryPoint: ENTRYPOINT_ADDRESS_V06 }), supportsEntryPointV06: true, + supportsErc7579: false, supportsEntryPointV07: false, isEip1271Compliant: true }, @@ -496,7 +526,11 @@ export const getCoreSmartAccounts = () => [ entryPoint: ENTRYPOINT_ADDRESS_V06, safeVersion: "1.4.1" }), + getErc7579SmartAccountClient: async ( + conf: AAParamType + ) => getSafeClient({ ...conf, erc7579: true }), supportsEntryPointV06: true, + supportsErc7579: true, supportsEntryPointV07: true, isEip1271Compliant: true } diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts index 3cdd2e0e..82c1160f 100644 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -1,4 +1,11 @@ -import type { Chain, Client, Hex, Transport } from "viem" +import type { + Chain, + Client, + Hex, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { @@ -25,7 +32,13 @@ export async function privateKeyToBiconomySmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { privateKey, ...rest diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 14860e35..8e482254 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -1,4 +1,4 @@ -import type { TypedData } from "viem" +import type { PublicActions, PublicRpcSchema, TypedData } from "viem" import { type Address, type Chain, @@ -214,7 +214,13 @@ export async function signerToBiconomySmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, address, diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 4d0795e5..7184db8a 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -1,4 +1,4 @@ -import type { TypedData } from "viem" +import type { PublicActions, PublicRpcSchema, TypedData } from "viem" import { type Address, type Chain, @@ -89,29 +89,53 @@ const createAccountAbi = [ } ] as const -export type KernelVersion = "0.2.2" | "0.3.0-beta" +export type KernelVersion = + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE + ? "0.2.1" | "0.2.2" | "0.2.3" | "0.2.4" + : "0.3.0" | "0.3.1" /** * Default addresses map for different kernel smart account versions */ export const KERNEL_VERSION_TO_ADDRESSES_MAP: { - [key in KernelVersion]: { + [key in KernelVersion]: { ECDSA_VALIDATOR: Address ACCOUNT_LOGIC: Address FACTORY_ADDRESS: Address META_FACTORY_ADDRESS?: Address } } = { + "0.2.1": { + ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", + ACCOUNT_LOGIC: "0xf048AD83CB2dfd6037A43902a2A5Be04e53cd2Eb", + FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" + }, "0.2.2": { ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", ACCOUNT_LOGIC: "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" }, - "0.3.0-beta": { + "0.2.3": { + ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", + ACCOUNT_LOGIC: "0xD3F582F6B4814E989Ee8E96bc3175320B5A540ab", + FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" + }, + "0.2.4": { + ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", + ACCOUNT_LOGIC: "0xd3082872F8B06073A021b4602e022d5A070d7cfC", + FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" + }, + "0.3.0": { ECDSA_VALIDATOR: "0x8104e3Ad430EA6d354d013A6789fDFc71E671c43", ACCOUNT_LOGIC: "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27", FACTORY_ADDRESS: "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" + }, + "0.3.1": { + ECDSA_VALIDATOR: "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57", + ACCOUNT_LOGIC: "0xBAC849bB641841b44E965fB01A4Bf5F074f84b4D", + FACTORY_ADDRESS: "0xaac5D4240AF87249B3f71BC8E4A2cae074A3E419", + META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" } } @@ -119,8 +143,16 @@ export const KERNEL_VERSION_TO_ADDRESSES_MAP: { * Get supported Kernel Smart Account version based on entryPoint * @param entryPoint */ -const getKernelVersion = (entryPoint: EntryPoint): KernelVersion => { - return entryPoint === ENTRYPOINT_ADDRESS_V06 ? "0.2.2" : "0.3.0-beta" +const getKernelVersion = ( + entryPoint: TEntryPoint, + version?: KernelVersion +): KernelVersion => { + if (version) { + return version + } + return ( + entryPoint === ENTRYPOINT_ADDRESS_V06 ? "0.2.2" : "0.3.0" + ) as KernelVersion } type KERNEL_ADDRESSES = { @@ -138,16 +170,15 @@ type KERNEL_ADDRESSES = { * @param factoryAddress * @param metaFactoryAddress */ -const getDefaultAddresses = ( - entryPointAddress: entryPoint, - { - ecdsaValidatorAddress: _ecdsaValidatorAddress, - accountLogicAddress: _accountLogicAddress, - factoryAddress: _factoryAddress, - metaFactoryAddress: _metaFactoryAddress - }: Partial -): KERNEL_ADDRESSES => { - const kernelVersion = getKernelVersion(entryPointAddress) +const getDefaultAddresses = ({ + ecdsaValidatorAddress: _ecdsaValidatorAddress, + accountLogicAddress: _accountLogicAddress, + factoryAddress: _factoryAddress, + metaFactoryAddress: _metaFactoryAddress, + kernelVersion +}: Partial & { + kernelVersion: KernelVersion +}): KERNEL_ADDRESSES => { const addresses = KERNEL_VERSION_TO_ADDRESSES_MAP[kernelVersion] const ecdsaValidatorAddress = _ecdsaValidatorAddress ?? addresses.ECDSA_VALIDATOR @@ -351,6 +382,7 @@ export type SignerToEcdsaKernelSmartAccountParameters< TAddress extends Address = Address > = Prettify<{ signer: SmartAccountSigner + version?: KernelVersion entryPoint: entryPoint address?: Address index?: bigint @@ -378,10 +410,17 @@ export async function signerToEcdsaKernelSmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, address, + version, entryPoint: entryPointAddress, index = BigInt(0), factoryAddress: _factoryAddress, @@ -392,18 +431,19 @@ export async function signerToEcdsaKernelSmartAccount< }: SignerToEcdsaKernelSmartAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) - const kernelVersion = getKernelVersion(entryPointAddress) + const kernelVersion = getKernelVersion(entryPointAddress, version) const { accountLogicAddress, ecdsaValidatorAddress, factoryAddress, metaFactoryAddress - } = getDefaultAddresses(entryPointAddress, { + } = getDefaultAddresses({ ecdsaValidatorAddress: _ecdsaValidatorAddress, accountLogicAddress: _accountLogicAddress, factoryAddress: _factoryAddress, - metaFactoryAddress: _metaFactoryAddress + metaFactoryAddress: _metaFactoryAddress, + kernelVersion }) // Get the private key related account diff --git a/packages/permissionless/accounts/kernel/utils/encodeCallData.ts b/packages/permissionless/accounts/kernel/utils/encodeCallData.ts index 4e573e2a..dd667b14 100644 --- a/packages/permissionless/accounts/kernel/utils/encodeCallData.ts +++ b/packages/permissionless/accounts/kernel/utils/encodeCallData.ts @@ -11,6 +11,7 @@ import { KernelV3ExecuteAbi } from "../abi/KernelV3AccountAbi" import { CALL_TYPE, EXEC_TYPE } from "../constants" import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" import { getExecMode } from "./getExecMode" +import type { EntryPoint } from "../../../types" export const encodeCallData = ( _tx: @@ -24,7 +25,7 @@ export const encodeCallData = ( value: bigint data: Hex }[], - accountVersion: KernelVersion + accountVersion: KernelVersion ) => { if (accountVersion === "0.2.2") { if (Array.isArray(_tx)) { diff --git a/packages/permissionless/accounts/kernel/utils/getNonceKey.ts b/packages/permissionless/accounts/kernel/utils/getNonceKey.ts index b8dfbc99..7956e303 100644 --- a/packages/permissionless/accounts/kernel/utils/getNonceKey.ts +++ b/packages/permissionless/accounts/kernel/utils/getNonceKey.ts @@ -1,9 +1,10 @@ import { type Address, concatHex, maxUint16, pad, toHex } from "viem" import { VALIDATOR_MODE, VALIDATOR_TYPE } from "../constants" import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" +import type { EntryPoint } from "../../../types" export const getNonceKeyWithEncoding = ( - accountVerion: KernelVersion, + accountVerion: KernelVersion, validatorAddress: Address, nonceKey = 0n ) => { diff --git a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts index e4400743..6a1d52f0 100644 --- a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts @@ -1,4 +1,11 @@ -import type { Chain, Client, Hex, Transport } from "viem" +import type { + Chain, + Client, + Hex, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { @@ -25,7 +32,13 @@ export async function privateKeyToLightSmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { privateKey, ...rest }: PrivateKeyToLightSmartAccountParameters ): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) diff --git a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts index 67e3d058..f6d5aef1 100644 --- a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts @@ -10,7 +10,9 @@ import { concatHex, encodeFunctionData, hashMessage, - hashTypedData + hashTypedData, + type PublicRpcSchema, + type PublicActions } from "viem" import { getChainId, signMessage } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" @@ -191,7 +193,13 @@ export async function signerToLightSmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, address, diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index a482cb97..fd8884e0 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -1,4 +1,11 @@ -import type { Chain, Client, Hex, Transport } from "viem" +import type { + Chain, + Client, + Hex, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { @@ -25,7 +32,13 @@ export async function privateKeyToSafeSmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { privateKey, ...rest }: PrivateKeyToSafeSmartAccountParameters ): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index fd3e539a..2e81f9f2 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -20,7 +20,9 @@ import { pad, toBytes, toHex, - zeroAddress + zeroAddress, + type PublicRpcSchema, + type PublicActions } from "viem" import { getChainId, @@ -47,6 +49,7 @@ import { type SmartAccount, type SmartAccountSigner } from "../types" +import { encode7579CallData } from "../../utils/encodeCallData" export type SafeVersion = "1.4.1" @@ -595,6 +598,7 @@ export type SignerToSafeSmartAccountParameters< saltNonce?: bigint validUntil?: number validAfter?: number + erc7579?: boolean setupTransactions?: { to: Address data: Address @@ -615,7 +619,13 @@ export async function signerToSafeSmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, address, @@ -631,6 +641,7 @@ export async function signerToSafeSmartAccount< validUntil = 0, validAfter = 0, safeModules = [], + erc7579, setupTransactions = [] }: SignerToSafeSmartAccountParameters ): Promise> { @@ -804,12 +815,6 @@ export async function signerToSafeSmartAccount< } ] - signatures.sort((left, right) => - left.signer - .toLowerCase() - .localeCompare(right.signer.toLowerCase()) - ) - const signatureBytes = concat(signatures.map((sig) => sig.data)) return encodePacked( @@ -862,12 +867,26 @@ export async function signerToSafeSmartAccount< ) }, async encodeCallData(args) { + const isArray = Array.isArray(args) + + if (erc7579) { + return encode7579CallData({ + mode: { + callType: isArray ? "batchcall" : "call", + revertOnError: false, + modeSelector: "0x", + modeData: "0x" + }, + callData: args as any + }) + } + let to: Address let value: bigint let data: Hex let operationType = 0 - if (Array.isArray(args)) { + if (isArray) { const argsArray = args as { to: Address value: bigint diff --git a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts index a8fef7e8..3d4868b9 100644 --- a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts @@ -1,4 +1,12 @@ -import type { Address, Chain, Client, Hex, Transport } from "viem" +import type { + Address, + Chain, + Client, + Hex, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" import type { EntryPoint, Prettify } from "../../types" import { @@ -25,7 +33,13 @@ export async function privateKeyToSimpleSmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { privateKey, ...rest diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 6121530a..48a53ee0 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -6,7 +6,9 @@ import { type LocalAccount, type Transport, concatHex, - encodeFunctionData + encodeFunctionData, + type PublicRpcSchema, + type PublicActions } from "viem" import { getChainId, signMessage } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" @@ -142,7 +144,13 @@ export async function signerToSimpleSmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, factoryAddress: _factoryAddress, diff --git a/packages/permissionless/accounts/toSmartAccount.ts b/packages/permissionless/accounts/toSmartAccount.ts index d797e1f5..d85fba2a 100644 --- a/packages/permissionless/accounts/toSmartAccount.ts +++ b/packages/permissionless/accounts/toSmartAccount.ts @@ -10,7 +10,9 @@ import { type Transport, type TypedDataDefinition, concat, - encodeAbiParameters + encodeAbiParameters, + type PublicRpcSchema, + type PublicActions } from "viem" import { toAccount } from "viem/accounts" import type { UserOperation } from "../types" @@ -48,7 +50,7 @@ export function toSmartAccount< signTypedData }: TAccountSource & { source: TSource - client: Client + client: Client entryPoint: TEntryPoint getNonce: () => Promise getInitCode: () => Promise @@ -163,5 +165,5 @@ export function toSmartAccount< getDummySignature, encodeDeployCallData, signUserOperation - } as SmartAccount + } } diff --git a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts index f3cfe41d..9640c313 100644 --- a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts @@ -1,4 +1,11 @@ -import type { Chain, Client, Hex, Transport } from "viem" +import type { + Chain, + Client, + Hex, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { @@ -25,7 +32,13 @@ export async function privateKeyToTrustSmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { privateKey, ...rest }: PrivateKeyToTrustSmartAccountParameters ): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) diff --git a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts index 5330380e..345c7233 100644 --- a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts @@ -9,7 +9,9 @@ import { type TypedDataDefinition, concatHex, hashMessage, - hashTypedData + hashTypedData, + type PublicRpcSchema, + type PublicActions } from "viem" import { getChainId } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" @@ -100,7 +102,13 @@ export async function signerToTrustSmartAccount< TSource extends string = string, TAddress extends Address = Address >( - client: Client, + client: Client< + TTransport, + TChain, + undefined, + PublicRpcSchema, + PublicActions + >, { signer, factoryAddress = TRUST_ADDRESSES.factoryAddress, diff --git a/packages/permissionless/accounts/types.ts b/packages/permissionless/accounts/types.ts index a0253ecc..6a3c45c0 100644 --- a/packages/permissionless/accounts/types.ts +++ b/packages/permissionless/accounts/types.ts @@ -6,7 +6,13 @@ import { type Hex, type LocalAccount } from "viem" -import type { Chain, EncodeDeployDataParameters, Transport } from "viem" +import type { + Chain, + EncodeDeployDataParameters, + PublicActions, + PublicRpcSchema, + Transport +} from "viem" import type { UserOperation } from "../types" import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" @@ -33,7 +39,7 @@ export type SmartAccount< chain extends Chain | undefined = Chain | undefined, TAbi extends Abi | readonly unknown[] = Abi > = LocalAccount & { - client: Client + client: Client entryPoint: entryPoint getNonce: () => Promise getInitCode: () => Promise diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index f65d2c66..00f518be 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -1,5 +1,5 @@ import type { Account, BaseError, Chain, Client, Hex, Transport } from "viem" -import type { PartialBy } from "viem/types/utils" +import type { PartialBy } from "viem/chains" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema, StateOverrides } from "../../types/bundler" diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts new file mode 100644 index 00000000..1e555633 --- /dev/null +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -0,0 +1,109 @@ +import { generatePrivateKey, privateKeyToAccount } 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 { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { accountId } from "./accountId" +import { getAddress, http, zeroAddress } from "viem" +import { erc7579Actions } from "../../clients/decorators/erc7579" +import { signerToSafeSmartAccount } from "../../accounts" +import { createSmartAccountClient } from "../../clients/createSmartAccountClient" +import { foundry } from "viem/chains" + +describe.each(getCoreSmartAccounts())( + "accountId $name", + ({ getErc7579SmartAccountClient, supportsErc7579 }) => { + testWithRpc.skipIf(!supportsErc7579)("accountId", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + const publicClient = getPublicClient( + "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" + ) + + const signer = privateKeyToAccount(generatePrivateKey()) + + const safeSmartAccount = await signerToSafeSmartAccount( + publicClient, + { + entryPoint: ENTRYPOINT_ADDRESS_V07, + signer: signer, + safeVersion: "1.4.1", + saltNonce: 420n, + safe4337ModuleAddress: getAddress( + "0xbaCA6f74a5549368568f387FD989C279f940f1A5" + ), + erc7579: true + } + ) + + console.log({ signer: signer.address }) + + const paymasterClient = getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc: + "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + }) + + const smartClient = createSmartAccountClient({ + chain: foundry, + account: safeSmartAccount, + bundlerTransport: http("http://0.0.0.0:3000"), + middleware: { + sponsorUserOperation: paymasterClient.sponsorUserOperation + } + }).extend(erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 })) + + smartClient.accountId() + + const accountIdBeforeDeploy = await accountId(smartClient as any) + + console.log({ accountIdBeforeDeploy }) + + // deploy account + await smartClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // const result = await publicClient.readContract({ + // abi: [ + // { + // name: "isModuleEnabled", + // type: "function", + // stateMutability: "view", + // inputs: [ + // { + // type: "address", + // name: "module" + // } + // ], + // outputs: [ + // { + // type: "bool" + // } + // ] + // } + // ], + // functionName: "isModuleEnabled", + // args: [ + // getAddress("0xbaCA6f74a5549368568f387FD989C279f940f1A5") + // ], + // address: smartClient.account.address + // }) + + // const postDeployAccountId = await accountId(smartClient as any) + + // console.log({ result }) + + // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) + }) + } +) diff --git a/packages/permissionless/actions/erc7579/accountId.ts b/packages/permissionless/actions/erc7579/accountId.ts new file mode 100644 index 00000000..04581e95 --- /dev/null +++ b/packages/permissionless/actions/erc7579/accountId.ts @@ -0,0 +1,108 @@ +import { + ContractFunctionExecutionError, + decodeFunctionResult, + encodeFunctionData, + type Chain, + type Client, + type Transport +} from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" +import type { GetAccountParameter } from "../../types" + +// export async function accountId< +// TEntryPoint extends EntryPoint, +// TSmartAccount extends SmartAccount | undefined, +// TTransport extends Transport = Transport, +// TChain extends Chain | undefined = Chain | undefined +// >(client: Client): Promise + +// export async function accountId< +// TEntryPoint extends EntryPoint, +// TSmartAccount extends SmartAccount | undefined, +// TTransport extends Transport = Transport, +// TChain extends Chain | undefined = Chain | undefined +// >( +// client: Client, +// args: GetAccountParameter +// ): Promise + +export async function accountId< + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined +>( + client: Client, + args?: TSmartAccount extends undefined + ? GetAccountParameter + : undefined +): Promise { + let account_ = client.account + + if (args) { + account_ = args.account as TSmartAccount + } + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const publicClient = account.client + + const abi = [ + { + name: "accountId", + type: "function", + stateMutability: "view", + inputs: [], + outputs: [ + { + type: "string", + name: "accountImplementationId" + } + ] + } + ] as const + + try { + return await publicClient.readContract({ + abi, + functionName: "accountId", + address: account.address + }) + } catch (error) { + if (error instanceof ContractFunctionExecutionError) { + const factory = await account.getFactory() + const factoryData = await account.getFactoryData() + + const result = await publicClient.call({ + factory: factory, + factoryData: factoryData, + to: account.address, + data: encodeFunctionData({ + abi, + functionName: "accountId" + }) + }) + + if (!result || !result.data) { + throw new Error("accountId result is empty") + } + + return decodeFunctionResult({ + abi, + functionName: "accountId", + data: result.data + }) + } + + throw error + } +} diff --git a/packages/permissionless/actions/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts new file mode 100644 index 00000000..3b4439df --- /dev/null +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -0,0 +1,103 @@ +import { + encodeFunctionData, + type Chain, + type Client, + type Transport, + type Hex, + type Address +} from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter, Prettify } from "../../types/" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" +import { getAction } from "viem/utils" +import { sendUserOperation } from "../smartAccount/sendUserOperation" +import type { Middleware } from "../smartAccount/prepareUserOperationRequest" +import { parseModuleTypeId, type moduleType } from "./supportsModule" + +export type InstallModuleParameters< + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +> = GetAccountParameter & { + type: moduleType + address: Address + callData: Hex + maxFeePerGas?: bigint + maxPriorityFeePerGas?: bigint + nonce?: bigint +} & Middleware + +export async function installModule< + entryPoint extends EntryPoint, + TChain extends Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + parameters: Prettify> +): Promise { + const { + account: account_ = client.account, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + middleware, + address, + callData + } = parameters + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const installModuleCallData = encodeFunctionData({ + abi: [ + { + name: "installModule", + type: "function", + stateMutability: "nonpayable", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "initData" + } + ], + outputs: [] + } + ], + functionName: "installModule", + args: [parseModuleTypeId(parameters.type), address, callData] + }) + + return getAction( + client, + sendUserOperation, + "sendUserOperation" + )({ + userOperation: { + sender: account.address, + maxFeePerGas: maxFeePerGas || BigInt(0), + maxPriorityFeePerGas: maxPriorityFeePerGas || BigInt(0), + callData: installModuleCallData, + nonce: nonce ? BigInt(nonce) : undefined + }, + account: account, + middleware + }) +} diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.ts new file mode 100644 index 00000000..dc4fa007 --- /dev/null +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.ts @@ -0,0 +1,77 @@ +import type { Chain, Client, Transport, Hex, Address } from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter, Prettify } from "../../types/" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" +import type { Middleware } from "../smartAccount/prepareUserOperationRequest" +import { parseModuleTypeId, type moduleType } from "./supportsModule" + +export type IsModuleInstalledParameters< + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +> = GetAccountParameter & { + type: moduleType + address: Address + callData: Hex +} & Middleware + +export async function isModuleInstalled< + entryPoint extends EntryPoint, + TChain extends Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + parameters: Prettify> +): Promise { + const { account: account_ = client.account, address, callData } = parameters + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const publicClient = account.client + + /** + * TODO: counterfactual + */ + return publicClient.readContract({ + abi: [ + { + name: "isModuleInstalled", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "additionalContext" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ], + functionName: "isModuleInstalled", + args: [parseModuleTypeId(parameters.type), address, callData], + address: account.address + }) +} diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts new file mode 100644 index 00000000..ee2bc6cb --- /dev/null +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -0,0 +1,122 @@ +import { + type Hex, + toBytes, + type Chain, + type Client, + type Transport, + encodePacked, + toHex +} from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter, Prettify } from "../../types/" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" + +export type CallType = "call" | "delegatecall" | "batchcall" + +export type ExecutionMode = { + callType: CallType + revertOnError: boolean + modeSelector: Hex + modeData: Hex +} + +export type supportsExecutionModeParameters< + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +> = GetAccountParameter & ExecutionMode + +function parseCallType(executionMode: CallType) { + switch (executionMode) { + case "call": + return "0x00" + case "delegatecall": + return "0x01" + case "batchcall": + return "0xff" + } +} + +export function encodeExecutionMode({ + callType, + revertOnError, + modeSelector, + modeData +}: ExecutionMode): Hex { + return encodePacked( + ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], + [ + toHex(toBytes(parseCallType(callType), { size: 1 })), + toHex(toBytes(revertOnError ? "0x01" : "0x00", { size: 1 })), + toHex(toBytes("0x0", { size: 4 })), + toHex(toBytes(modeSelector, { size: 4 })), + toHex(toBytes(modeData, { size: 22 })) + ] + ) +} + +export async function supportsExecutionMode< + entryPoint extends EntryPoint, + TChain extends Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + args: Prettify> +): Promise { + const { + account: account_ = client.account, + callType, + revertOnError, + modeSelector, + modeData + } = args + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const publicClient = account.client + + const encodedMode = encodeExecutionMode({ + callType, + revertOnError, + modeSelector, + modeData + }) + + /** + * TODO: counterfactual + */ + return publicClient.readContract({ + abi: [ + { + name: "supportsExecutionMode", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "bytes32", + name: "encodedMode" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ], + functionName: "supportsExecutionMode", + args: [encodedMode], + address: account.address + }) +} diff --git a/packages/permissionless/actions/erc7579/supportsModule.ts b/packages/permissionless/actions/erc7579/supportsModule.ts new file mode 100644 index 00000000..7342d6f0 --- /dev/null +++ b/packages/permissionless/actions/erc7579/supportsModule.ts @@ -0,0 +1,82 @@ +import type { Chain, Client, Transport } from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter, Prettify } from "../../types/" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" + +export type moduleType = "validation" | "execution" | "fallback" | "hooks" + +export type SupportsModuleParameters< + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +> = GetAccountParameter & { + type: moduleType +} + +export function parseModuleTypeId(type: moduleType): bigint { + switch (type) { + case "validation": + return BigInt(1) + case "execution": + return BigInt(2) + case "fallback": + return BigInt(3) + case "hooks": + return BigInt(4) + default: + throw new Error("Invalid module type") + } +} + +export async function supportsModule< + entryPoint extends EntryPoint, + TChain extends Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + args: Prettify> +): Promise { + const { account: account_ = client.account } = args + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const publicClient = account.client + + /** + * TODO: counterfactual + */ + return publicClient.readContract({ + abi: [ + { + name: "supportsModule", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ], + functionName: "supportsModule", + args: [parseModuleTypeId(args.type)], + address: account.address + }) +} diff --git a/packages/permissionless/actions/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts new file mode 100644 index 00000000..a8757245 --- /dev/null +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -0,0 +1,103 @@ +import { + encodeFunctionData, + type Chain, + type Client, + type Transport, + type Hex, + type Address +} from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter, Prettify } from "../../types/" +import type { EntryPoint } from "../../types/entrypoint" +import { parseAccount } from "../../utils/" +import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" +import { getAction } from "viem/utils" +import { sendUserOperation } from "../smartAccount/sendUserOperation" +import type { Middleware } from "../smartAccount/prepareUserOperationRequest" +import { parseModuleTypeId, type moduleType } from "./supportsModule" + +export type UninstallModuleParameters< + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +> = GetAccountParameter & { + type: moduleType + address: Address + callData: Hex + maxFeePerGas?: bigint + maxPriorityFeePerGas?: bigint + nonce?: bigint +} & Middleware + +export async function uninstallModule< + entryPoint extends EntryPoint, + TChain extends Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + parameters: Prettify> +): Promise { + const { + account: account_ = client.account, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + middleware, + address, + callData + } = parameters + + if (!account_) { + throw new AccountOrClientNotFoundError({ + docsPath: "/docs/actions/wallet/sendTransaction" + }) + } + + const account = parseAccount(account_) as SmartAccount + + const uninstallModuleCallData = encodeFunctionData({ + abi: [ + { + name: "uninstallModule", + type: "function", + stateMutability: "nonpayable", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "deInitData" + } + ], + outputs: [] + } + ], + functionName: "uninstallModule", + args: [parseModuleTypeId(parameters.type), address, callData] + }) + + return getAction( + client, + sendUserOperation, + "sendUserOperation" + )({ + userOperation: { + sender: account.address, + maxFeePerGas: maxFeePerGas || BigInt(0), + maxPriorityFeePerGas: maxPriorityFeePerGas || BigInt(0), + callData: uninstallModuleCallData, + nonce: nonce ? BigInt(nonce) : undefined + }, + account: account, + middleware + }) +} diff --git a/packages/permissionless/actions/index.test.ts b/packages/permissionless/actions/index.test.ts new file mode 100644 index 00000000..b76d225e --- /dev/null +++ b/packages/permissionless/actions/index.test.ts @@ -0,0 +1,329 @@ +import { describe, expectTypeOf, test } from "vitest" +import { + sendUserOperation, + estimateUserOperationGas, + supportedEntryPoints, + chainId, + getUserOperationByHash, + getUserOperationReceipt, + getSenderAddress, + getAccountNonce, + waitForUserOperationReceipt +} from "./index" +import type { + Account, + Address, + Chain, + Client, + Hash, + Hex, + Log, + Transport +} from "viem" +import type { BundlerRpcSchema } from "../types/bundler" +import type { + ENTRYPOINT_ADDRESS_V07_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, + EntryPoint +} from "../types/entrypoint" +import type { PartialBy } from "viem/chains" +import type { TStatus, UserOperation } from "../types/userOperation" + +describe("index", () => { + test("sendUserOperation", () => { + expectTypeOf(sendUserOperation).toBeFunction() + expectTypeOf(sendUserOperation) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(sendUserOperation).parameter(1).toMatchTypeOf<{ + userOperation: UserOperation<"v0.6" | "v0.7"> + entryPoint: EntryPoint + }>() + expectTypeOf(sendUserOperation).returns.toMatchTypeOf>() + }) + + test("estimateUserOperationGas", () => { + expectTypeOf(estimateUserOperationGas).toBeFunction() + expectTypeOf(estimateUserOperationGas) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + + expectTypeOf(estimateUserOperationGas).parameter(1).toMatchTypeOf<{ + userOperation: + | PartialBy< + UserOperation<"v0.6">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + > + | PartialBy< + UserOperation<"v0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + > + entryPoint: EntryPoint + }>() + expectTypeOf(estimateUserOperationGas).parameter(2).toMatchTypeOf< + | { + [x: string]: { + balance?: bigint | undefined + nonce?: bigint | number | undefined + code?: Hex | undefined + state?: { + [x: Hex]: Hex + } + stateDiff?: { + [x: Hex]: Hex + } + } + } + | undefined + >() + expectTypeOf( + estimateUserOperationGas + ).returns.toMatchTypeOf< + Promise<{ + preVerificationGas: bigint + verificationGasLimit: bigint + callGasLimit: bigint + }> + >() + expectTypeOf( + estimateUserOperationGas + ).returns.toMatchTypeOf< + Promise<{ + preVerificationGas: bigint + verificationGasLimit: bigint + callGasLimit: bigint + paymasterVerificationGasLimit?: bigint + paymasterPostOpGasLimit?: bigint + }> + >() + }) + + test("supportedEntryPoints", () => { + expectTypeOf(supportedEntryPoints) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + + expectTypeOf(supportedEntryPoints).returns.toMatchTypeOf< + Promise + >() + }) + + test("chainId", () => { + expectTypeOf(chainId) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + + expectTypeOf(chainId).returns.toMatchTypeOf>() + }) + + test("getUserOperationByHash", () => { + expectTypeOf(getUserOperationByHash) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(getUserOperationByHash).parameter(1).toMatchTypeOf<{ + hash: Hash + }>() + expectTypeOf( + getUserOperationByHash + ).returns.toMatchTypeOf< + Promise<{ + userOperation: UserOperation<"v0.6"> + entryPoint: Address + transactionHash: Hash + blockHash: Hash + blockNumber: bigint + } | null> + >() + expectTypeOf( + getUserOperationByHash + ).returns.toMatchTypeOf< + Promise<{ + userOperation: UserOperation<"v0.7"> + entryPoint: Address + transactionHash: Hash + blockHash: Hash + blockNumber: bigint + } | null> + >() + }) + + test("getUserOperationReceipt", () => { + expectTypeOf(getUserOperationReceipt) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(getUserOperationReceipt).parameter(1).toMatchTypeOf<{ + hash: Hash + }>() + expectTypeOf(getUserOperationReceipt).returns.toMatchTypeOf< + Promise<{ + userOpHash: Hash + entryPoint: Address + sender: Address + nonce: bigint + paymaster?: Address + actualGasUsed: bigint + actualGasCost: bigint + success: boolean + reason?: string + receipt: { + transactionHash: Hex + transactionIndex: bigint + blockHash: Hash + blockNumber: bigint + from: Address + to: Address | null + cumulativeGasUsed: bigint + status: TStatus + gasUsed: bigint + contractAddress: Address | null + logsBloom: Hex + effectiveGasPrice: bigint + } + logs: Log[] + } | null> + >() + }) + + test("getSenderAddress", () => { + expectTypeOf(getSenderAddress) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(getSenderAddress) + .parameter(1) + .toMatchTypeOf<{ + initCode: Hex + entryPoint: ENTRYPOINT_ADDRESS_V06_TYPE + factory?: never + factoryData?: never + }>() + expectTypeOf(getSenderAddress) + .parameter(1) + .toMatchTypeOf<{ + entryPoint: ENTRYPOINT_ADDRESS_V07_TYPE + factory: Address + factoryData: Hex + initCode?: never + }>() + expectTypeOf(getSenderAddress).returns.toMatchTypeOf>() + }) + + test("getAccountNonce", () => { + expectTypeOf(getAccountNonce) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(getAccountNonce).parameter(1).toMatchTypeOf<{ + sender: Address + entryPoint: EntryPoint + key?: bigint + }>() + expectTypeOf(getAccountNonce).returns.toMatchTypeOf>() + }) + + test("waitForUserOperationReceipt", () => { + expectTypeOf(waitForUserOperationReceipt) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + BundlerRpcSchema + > + >() + expectTypeOf(waitForUserOperationReceipt).parameter(1).toMatchTypeOf<{ + hash: Hash + pollingInterval?: number + timeout?: number + }>() + expectTypeOf(waitForUserOperationReceipt).returns.toMatchTypeOf< + Promise<{ + userOpHash: Hash + entryPoint: Address + sender: Address + nonce: bigint + paymaster?: Address + actualGasUsed: bigint + actualGasCost: bigint + success: boolean + reason?: string + receipt: { + transactionHash: Hex + transactionIndex: bigint + blockHash: Hash + blockNumber: bigint + from: Address + to: Address | null + cumulativeGasUsed: bigint + status: TStatus + gasUsed: bigint + contractAddress: Address | null + logsBloom: Hex + effectiveGasPrice: bigint + } + logs: Log[] + }> + >() + }) +}) diff --git a/packages/permissionless/actions/pimlico.test.ts b/packages/permissionless/actions/pimlico.test.ts new file mode 100644 index 00000000..75ee1794 --- /dev/null +++ b/packages/permissionless/actions/pimlico.test.ts @@ -0,0 +1,222 @@ +import { describe, expectTypeOf, test } from "vitest" +import { + type PimlicoBundlerActions, + getUserOperationGasPrice, + getUserOperationStatus, + pimlicoBundlerActions, + sendCompressedUserOperation, + sponsorUserOperation, + validateSponsorshipPolicies +} from "./pimlico" +import type { + Account, + Address, + Chain, + Client, + Hash, + Hex, + Transport +} from "viem" +import type { PimlicoBundlerRpcSchema } from "../types/pimlico" +import type { UserOperation } from "../types/userOperation" +import type { EntryPoint } from "../types/entrypoint" + +describe("pimlico", () => { + test("getUserOperationGasPrice", () => { + expectTypeOf(getUserOperationGasPrice).toBeFunction() + expectTypeOf(getUserOperationGasPrice) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(getUserOperationGasPrice).returns.toMatchTypeOf | null>() + }) + + test("getUserOperationStatus", () => { + expectTypeOf(getUserOperationStatus).toBeFunction() + expectTypeOf(getUserOperationStatus) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(getUserOperationStatus).parameter(1).toMatchTypeOf<{ + hash: string + }>() + expectTypeOf(getUserOperationStatus).returns.toMatchTypeOf< + Promise<{ + status: + | "not_found" + | "not_submitted" + | "submitted" + | "rejected" + | "reverted" + | "included" + | "failed" + transactionHash: Hash | null + }> + >() + }) + + test("sendCompressedUserOperation", () => { + expectTypeOf(sendCompressedUserOperation).toBeFunction() + expectTypeOf(sendCompressedUserOperation) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(sendCompressedUserOperation).parameter(1).toMatchTypeOf<{ + compressedUserOperation: Hex + inflatorAddress: Address + entryPoint: Address + }>() + expectTypeOf(sendCompressedUserOperation).returns.toMatchTypeOf< + Promise + >() + }) + + test("sponsorUserOperation", () => { + expectTypeOf(sponsorUserOperation).toBeFunction() + expectTypeOf(sponsorUserOperation) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(sponsorUserOperation).parameter(1).toMatchTypeOf<{ + userOperation: UserOperation<"v0.6" | "v0.7"> + entryPoint: EntryPoint + sponsorshipPolicyId?: string + }>() + expectTypeOf(sponsorUserOperation).returns.toMatchTypeOf< + Promise< + | { + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + paymasterAndData: Hex + } + | { + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + paymaster: Address + paymasterVerificationGasLimit: bigint + paymasterPostOpGasLimit: bigint + paymasterData: Hex + } + > + >() + }) + + test("sponsorUserOperation", () => { + expectTypeOf(sponsorUserOperation).toBeFunction() + expectTypeOf(sponsorUserOperation) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(sponsorUserOperation).parameter(1).toMatchTypeOf<{ + userOperation: UserOperation<"v0.6" | "v0.7"> + entryPoint: EntryPoint + sponsorshipPolicyId?: string + }>() + expectTypeOf(sponsorUserOperation).returns.toMatchTypeOf< + Promise< + | { + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + paymasterAndData: Hex + } + | { + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + paymaster: Address + paymasterVerificationGasLimit: bigint + paymasterPostOpGasLimit: bigint + paymasterData: Hex + } + > + >() + }) + + test("validateSponsorshipPolicies", () => { + expectTypeOf(validateSponsorshipPolicies).toBeFunction() + expectTypeOf(validateSponsorshipPolicies) + .parameter(0) + .toMatchTypeOf< + Client< + Transport, + Chain | undefined, + Account | undefined, + PimlicoBundlerRpcSchema + > + >() + expectTypeOf(validateSponsorshipPolicies).parameter(1).toMatchTypeOf<{ + userOperation: UserOperation<"v0.6" | "v0.7"> + entryPoint: EntryPoint + sponsorshipPolicyIds: string[] + }>() + expectTypeOf(validateSponsorshipPolicies).returns.toMatchTypeOf< + Promise< + { + sponsorshipPolicyId: string + data: { + name: string | null + author: string | null + icon: string | null + description: string | null + } + }[] + > + >() + }) + + test("pimlicoBundlerActions", () => { + expectTypeOf(pimlicoBundlerActions).toBeFunction() + expectTypeOf(pimlicoBundlerActions) + .parameter(0) + .toMatchTypeOf() + expectTypeOf(pimlicoBundlerActions).returns.toMatchTypeOf< + (client: Client) => PimlicoBundlerActions + >() + }) +}) diff --git a/packages/permissionless/actions/smartAccount/signMessage.test.ts b/packages/permissionless/actions/smartAccount/signMessage.test.ts new file mode 100644 index 00000000..ecdc6eb8 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/signMessage.test.ts @@ -0,0 +1,89 @@ +import type { Chain, Client, Transport } 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 } from "../../utils" +import { signMessage } from "./signMessage" + +describe.each(getCoreSmartAccounts())( + "signMessage $name", + ({ getSmartAccountClient, isEip1271Compliant }) => { + testWithRpc.skipIf(isEip1271Compliant)( + "not isEip1271Compliant", + 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 () => + signMessage( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + message: + "slowly and steadily burning the private keys" + } + ) + ).rejects.toThrow() + } + ) + + testWithRpc.skipIf(!isEip1271Compliant)( + "isEip1271Compliant", + 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 signature = await signMessage( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + message: "slowly and steadily burning the private keys" + } + ) + + const publicClient = getPublicClient(anvilRpc) + + const isVerified = await publicClient.verifyMessage({ + address: smartClient.account.address, + message: "slowly and steadily burning the private keys", + signature + }) + + expect(isVerified).toBeTruthy() + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/signTypedData.test.ts b/packages/permissionless/actions/smartAccount/signTypedData.test.ts new file mode 100644 index 00000000..a9dd33ff --- /dev/null +++ b/packages/permissionless/actions/smartAccount/signTypedData.test.ts @@ -0,0 +1,118 @@ +import { getAddress, type Chain, type Client, type Transport } 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 } from "../../utils" +import { signTypedData } from "./signTypedData" + +const typedData = { + domain: { + name: "Ether Mail", + version: "1", + chainId: 1, + verifyingContract: getAddress( + "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + ) + }, + types: { + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" } + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" } + ] + }, + primaryType: "Mail" as const, + message: { + from: { + name: "Cow", + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + to: { + name: "Bob", + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + contents: "Hello, Bob!" + } +} + +describe.each(getCoreSmartAccounts())( + "signTypedData $name", + ({ getSmartAccountClient, isEip1271Compliant }) => { + testWithRpc.skipIf(isEip1271Compliant)( + "not isEip1271Compliant", + 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 () => + signTypedData( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + typedData + ) + ).rejects.toThrow() + } + ) + + testWithRpc.skipIf(!isEip1271Compliant)( + "isEip1271Compliant", + 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 signature = await signTypedData( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + typedData + ) + + const publicClient = getPublicClient(anvilRpc) + + const isVerified = await publicClient.verifyTypedData({ + ...typedData, + address: smartClient.account.address, + signature + }) + + expect(isVerified).toBeTruthy() + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/writeContract.test.ts b/packages/permissionless/actions/smartAccount/writeContract.test.ts new file mode 100644 index 00000000..a9dd33ff --- /dev/null +++ b/packages/permissionless/actions/smartAccount/writeContract.test.ts @@ -0,0 +1,118 @@ +import { getAddress, type Chain, type Client, type Transport } 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 } from "../../utils" +import { signTypedData } from "./signTypedData" + +const typedData = { + domain: { + name: "Ether Mail", + version: "1", + chainId: 1, + verifyingContract: getAddress( + "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + ) + }, + types: { + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" } + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" } + ] + }, + primaryType: "Mail" as const, + message: { + from: { + name: "Cow", + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + to: { + name: "Bob", + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + contents: "Hello, Bob!" + } +} + +describe.each(getCoreSmartAccounts())( + "signTypedData $name", + ({ getSmartAccountClient, isEip1271Compliant }) => { + testWithRpc.skipIf(isEip1271Compliant)( + "not isEip1271Compliant", + 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 () => + signTypedData( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + typedData + ) + ).rejects.toThrow() + } + ) + + testWithRpc.skipIf(!isEip1271Compliant)( + "isEip1271Compliant", + 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 signature = await signTypedData( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + typedData + ) + + const publicClient = getPublicClient(anvilRpc) + + const isVerified = await publicClient.verifyTypedData({ + ...typedData, + address: smartClient.account.address, + signature + }) + + expect(isVerified).toBeTruthy() + } + ) + } +) diff --git a/packages/permissionless/clients/decorators/erc7579.ts b/packages/permissionless/clients/decorators/erc7579.ts new file mode 100644 index 00000000..6f090281 --- /dev/null +++ b/packages/permissionless/clients/decorators/erc7579.ts @@ -0,0 +1,89 @@ +import type { Chain, Client, Hash, Transport } from "viem" +import type { SmartAccount } from "../../accounts/types" +import type { EntryPoint } from "../../types/entrypoint" +import { accountId } from "../../actions/erc7579/accountId" +import { installModule } from "../../actions/erc7579/installModule" +import { isModuleInstalled } from "../../actions/erc7579/isModuleInstalled" +import { supportsExecutionMode } from "../../actions/erc7579/supportsExecutionMode" +import { supportsModule } from "../../actions/erc7579/supportsModule" +import { uninstallModule } from "../../actions/erc7579/uninstallModule" + +export type Erc7579Actions< + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined +> = { + /** + * Get's the accountId of the smart account + * + * @param args - {@link SendTransactionParameters} + * @returns The [Transaction](https://viem.sh/docs/glossary/terms.html#transaction) hash. {@link SendTransactionReturnType} + * + * @example + * import { createSmartAccountClient, custom } from 'viem' + * import { mainnet } from 'viem/chains' + * + * const client = createSmartAccountClient({ + * chain: mainnet, + * transport: custom(window.ethereum), + * }) + * const hash = await client.sendTransaction({ + * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', + * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', + * value: 1000000000000000000n, + * }) + * + * @example + * // Account Hoisting + * import { createSmartAccountClient, http } from 'viem' + * import { privateKeyToAccount } from 'viem/accounts' + * import { mainnet } from 'viem/chains' + * + * const client = createSmartAccountClient({ + * account: privateKeyToAccount('0x…'), + * chain: mainnet, + * transport: http(), + * }) + * const hash = await client.sendTransaction({ + * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', + * value: 1000000000000000000n, + * }) + */ + accountId: ( + args?: TSmartAccount extends undefined + ? Parameters[1] + : undefined + ) => Promise + installModule: (args: Parameters[1]) => Promise + isModuleInstalled: ( + args: Parameters[1] + ) => Promise + supportsExecutionMode: ( + args: Parameters[1] + ) => Promise + supportsModule: ( + args: Parameters[1] + ) => Promise + uninstallModule: ( + args: Parameters[1] + ) => Promise +} + +export function erc7579Actions(_args: { + entryPoint: TEntryPoint +}) { + return < + TTransport extends Transport, + TChain extends Chain | undefined, + TSmartAccount extends SmartAccount | undefined + >( + client: Client + ): Erc7579Actions => ({ + accountId: (args) => accountId(client as any, args), + installModule: (args) => installModule(client as any, args), + isModuleInstalled: (args) => isModuleInstalled(client as any, args), + supportsExecutionMode: (args) => + supportsExecutionMode(client as any, args), + supportsModule: (args) => supportsModule(client as any, args), + uninstallModule: (args) => uninstallModule(client as any, args) + }) +} diff --git a/packages/permissionless/package.json b/packages/permissionless/package.json index a52850e7..71c733e9 100644 --- a/packages/permissionless/package.json +++ b/packages/permissionless/package.json @@ -81,6 +81,6 @@ } }, "peerDependencies": { - "viem": "^2.9.17" + "viem": "^2.14.1" } } diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index 06a01060..d5d40c6e 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -1,5 +1,4 @@ import type { Account, Chain, Client, Transport } from "viem" -import type { IsUndefined } from "viem/types/utils" import type { SmartAccount } from "../accounts/types" import type { EntryPoint } from "./entrypoint" import type { UserOperation } from "./userOperation" @@ -14,6 +13,8 @@ export type { export type { PackedUserOperation } from "./userOperation" +export type IsUndefined = [undefined] extends [T] ? true : false + export type GetAccountParameterWithClient< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, diff --git a/packages/permissionless/utils/encodeCallData.ts b/packages/permissionless/utils/encodeCallData.ts new file mode 100644 index 00000000..67776283 --- /dev/null +++ b/packages/permissionless/utils/encodeCallData.ts @@ -0,0 +1,113 @@ +import { + type Address, + concatHex, + encodeAbiParameters, + encodeFunctionData, + toHex, + type Hex +} from "viem" +import { + type ExecutionMode, + encodeExecutionMode +} from "../actions/erc7579/supportsExecutionMode" + +export type EncodeCallDataParams = { + mode: executionMode + callData: executionMode["callType"] extends "batchcall" + ? { + to: Address + value: bigint + data: Hex + }[] + : { + to: Address + value: bigint + data: Hex + } +} + +export function encode7579CallData({ + mode, + callData +}: EncodeCallDataParams): Hex { + if (Array.isArray(callData) && mode?.callType !== "batchcall") { + throw new Error( + `mode ${mode} does not supported for batchcall calldata` + ) + } + + const executeAbi = [ + { + type: "function", + name: "execute", + inputs: [ + { + name: "execMode", + type: "bytes32", + internalType: "ExecMode" + }, + { + name: "executionCalldata", + type: "bytes", + internalType: "bytes" + } + ], + outputs: [], + stateMutability: "payable" + } + ] as const + + if (Array.isArray(callData)) { + return encodeFunctionData({ + abi: executeAbi, + functionName: "execute", + args: [ + encodeExecutionMode(mode), + encodeAbiParameters( + [ + { + name: "executionBatch", + type: "tuple[]", + components: [ + { + name: "target", + type: "address" + }, + { + name: "value", + type: "uint256" + }, + { + name: "callData", + type: "bytes" + } + ] + } + ], + [ + callData.map((arg) => { + return { + target: arg.to, + value: arg.value, + callData: arg.data + } + }) + ] + ) + ] + }) + } + + return encodeFunctionData({ + abi: executeAbi, + functionName: "execute", + args: [ + encodeExecutionMode(mode), + concatHex([ + callData.to, + toHex(callData.value, { size: 32 }), + callData.data + ]) + ] + }) +} diff --git a/packages/permissionless/vitest.config.ts b/packages/permissionless/vitest.config.ts index 0361eae6..3a077b01 100644 --- a/packages/permissionless/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -3,9 +3,6 @@ import { defineConfig } from "vitest/config" export default defineConfig({ test: { - alias: { - permissionless: join(__dirname, "./") - }, coverage: { all: true, provider: "v8", diff --git a/packages/wagmi-test-demo/src/App.tsx b/packages/wagmi-test-demo/src/App.tsx index 10dd17f9..fa5401bb 100644 --- a/packages/wagmi-test-demo/src/App.tsx +++ b/packages/wagmi-test-demo/src/App.tsx @@ -111,8 +111,6 @@ function App() { }) } - console.log("error: ", sendTransactionError) - return ( <>
From 336e8d29d509aa19f0f4b30d465f77d963675216 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 25 Jun 2024 22:33:16 +0100 Subject: [PATCH 02/13] add tests and erc7579 actions --- bun.lockb | Bin 577776 -> 579144 bytes .../mock-aa-infra/alto/index.ts | 2 +- packages/permissionless-test/src/utils.ts | 8 ++--- .../accounts/kernel/utils/encodeCallData.ts | 2 +- .../accounts/kernel/utils/getNonceKey.ts | 2 +- .../light/signerToLightSmartAccount.ts | 6 ++-- .../accounts/safe/signerToSafeSmartAccount.ts | 8 ++--- .../simple/signerToSimpleSmartAccount.ts | 6 ++-- .../permissionless/accounts/toSmartAccount.ts | 6 ++-- .../trust/signerToTrustSmartAccount.ts | 6 ++-- .../actions/erc7579/accountId.test.ts | 10 +++---- .../actions/erc7579/accountId.ts | 10 +++---- .../actions/erc7579/installModule.ts | 12 ++++---- .../actions/erc7579/isModuleInstalled.ts | 4 +-- .../actions/erc7579/supportsExecutionMode.ts | 4 +-- .../actions/erc7579/uninstallModule.ts | 12 ++++---- packages/permissionless/actions/index.test.ts | 28 +++++++++--------- .../permissionless/actions/pimlico.test.ts | 22 +++++++------- .../smartAccount/signTypedData.test.ts | 2 +- .../smartAccount/writeContract.test.ts | 2 +- .../clients/decorators/erc7579.ts | 2 +- .../permissionless/utils/encodeCallData.ts | 4 +-- 22 files changed, 79 insertions(+), 79 deletions(-) diff --git a/bun.lockb b/bun.lockb index 201f4962924385b11c77b7717bd73d02fe4f21d7..7fdbc3d9bccc979c70c7b3f52aadae5488485f60 100755 GIT binary patch delta 119225 zcmeFa33OG(n)ZM8fdglwps0+Bh^Tz4GG`?Dk^Th zg;!B=Ku~c)5m3-LqKLzFM6X`GPN2(>RaB}bM$E^96$1!!?&ldc>aiQo*&-v{g&*(?6T>()IW%b zCh)eP3hLC*@}ofU%?|U6W)&-a3f+)i+%-S1Ag?U439gFzxpLy5cv)Uyd1-NZBxibd zp1Qf4)=O8t8MCwVBU5s7i@WB|%-`iAJ_HXTK^NDMS)@j)`pt_(8i7AJ{K^Z?u6IJ^ zMKt0tVN)bBam|sdpT_IXsiHTY-0jEx?Wr&&G<);8RO;XXh4{l@=G3 zmgSU|MvlUYWUVU9E-cEM5{cxNPM(#QKP7TIqe1@4s;da7;Moo*IXvCrNuUaD2Oa@7 zcDRRDi+|?ub%&cAu6B5X!v!E&tBM?s3$Zd%HN*)CkUv$&J3QQ>=kRNKqWF@c{QOzP zkx1%Mkw_c((I9`SJjZt&X)W{;cr^M-@Hp@?@ECBq(+7aB23UkZy3UVU_%;%i0 zQ!5K+=j9fteHWJMw+bu@gGoNAlU*WBPqdglIj^jo#nA>`4Q<=mHmp8e9cb$GpF3Lq zF{qhyo$L3yF1A6xf_|hvhU*eE^14<2)YUfdw{AB6wCEOof9 zug$&&RD16Xnl@-#c}|K|3-Su{inB{gm%|l%y2FBgb~v8~o1kYo{rptht201Zdr+Fq z*BVrV)%@l~vj4wtxpgW&E!SN*1sq!!{`Ca(mJ+nYp;6s3;#Z zH>BHY*wLp%B8+_1)HC%NUC{wlszYmT?SZq~453>#Y`*2&% z3!q%#BcRG#;qV$zo@pLfiI=J>ARrtMs-?pnraR0pDx8KzBOg*xJK|rX<*f3mht9G+ z$_M3PlBP{s;2xJQ*`XcRWK#nW*p`4R8Ui__hg$cKQAmV zaxYvBOAxPoZ9z@RTY`3tTC@r%O{H$7SF&Pnmu7Tc>O$J{443#s{xA>Ry>VU|m5Qq*l(bCYu4OC&hV% zMG-EOZ+ki$R1X$_&A>@ub8sZ6KFoLJ$f?Si9z|}|S~7J?j>t{;5+$9wf749c&72~fEGGGx38RWH$3qB9a?4Z?V`$S4WPY_mpAJ6+{FL-E+f0%j zNvLWJ0gZ)P+;vt--WfsDgWG0(H_Imb5R@IZkxgThJ$rT@Es0zKZvx*0s#(jx

= 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 Sr7Tv+m-{(LN5vEKUj2WA+XYep delta 119135 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, diff --git a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts index f6d5aef1..4d3a391f 100644 --- a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts @@ -4,15 +4,15 @@ import { type Client, type Hex, type LocalAccount, + type PublicActions, + type PublicRpcSchema, type Transport, type TypedData, type TypedDataDefinition, concatHex, encodeFunctionData, hashMessage, - hashTypedData, - type PublicRpcSchema, - type PublicActions + hashTypedData } from "viem" import { getChainId, signMessage } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 2e81f9f2..7088e05a 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -4,6 +4,8 @@ import { type Client, type Hex, type LocalAccount, + type PublicActions, + type PublicRpcSchema, type SignableMessage, type Transport, type TypedData, @@ -20,9 +22,7 @@ import { pad, toBytes, toHex, - zeroAddress, - type PublicRpcSchema, - type PublicActions + zeroAddress } from "viem" import { getChainId, @@ -37,6 +37,7 @@ import type { Prettify } from "../../types" import type { EntryPoint, UserOperation } from "../../types" +import { encode7579CallData } from "../../utils/encodeCallData" import { getEntryPointVersion, isUserOperationVersion06, @@ -49,7 +50,6 @@ import { type SmartAccount, type SmartAccountSigner } from "../types" -import { encode7579CallData } from "../../utils/encodeCallData" export type SafeVersion = "1.4.1" diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 48a53ee0..09f59289 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -4,11 +4,11 @@ import { type Client, type Hex, type LocalAccount, + type PublicActions, + type PublicRpcSchema, type Transport, concatHex, - encodeFunctionData, - type PublicRpcSchema, - type PublicActions + encodeFunctionData } from "viem" import { getChainId, signMessage } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" diff --git a/packages/permissionless/accounts/toSmartAccount.ts b/packages/permissionless/accounts/toSmartAccount.ts index d85fba2a..b5d705af 100644 --- a/packages/permissionless/accounts/toSmartAccount.ts +++ b/packages/permissionless/accounts/toSmartAccount.ts @@ -6,13 +6,13 @@ import { type CustomSource, type EncodeDeployDataParameters, type Hex, + type PublicActions, + type PublicRpcSchema, type SignableMessage, type Transport, type TypedDataDefinition, concat, - encodeAbiParameters, - type PublicRpcSchema, - type PublicActions + encodeAbiParameters } from "viem" import { toAccount } from "viem/accounts" import type { UserOperation } from "../types" diff --git a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts index 345c7233..79e65b16 100644 --- a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts @@ -4,14 +4,14 @@ import { type Client, type Hex, type LocalAccount, + type PublicActions, + type PublicRpcSchema, type Transport, type TypedData, type TypedDataDefinition, concatHex, hashMessage, - hashTypedData, - type PublicRpcSchema, - type PublicActions + hashTypedData } from "viem" import { getChainId } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts index 1e555633..f1473952 100644 --- a/packages/permissionless/actions/erc7579/accountId.test.ts +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -1,4 +1,6 @@ +import { http, getAddress, zeroAddress } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { foundry } from "viem/chains" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { @@ -6,13 +8,11 @@ import { getPimlicoPaymasterClient, getPublicClient } from "../../../permissionless-test/src/utils" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" -import { accountId } from "./accountId" -import { getAddress, http, zeroAddress } from "viem" -import { erc7579Actions } from "../../clients/decorators/erc7579" import { signerToSafeSmartAccount } from "../../accounts" import { createSmartAccountClient } from "../../clients/createSmartAccountClient" -import { foundry } from "viem/chains" +import { erc7579Actions } from "../../clients/decorators/erc7579" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { accountId } from "./accountId" describe.each(getCoreSmartAccounts())( "accountId $name", diff --git a/packages/permissionless/actions/erc7579/accountId.ts b/packages/permissionless/actions/erc7579/accountId.ts index 04581e95..3b5a7d77 100644 --- a/packages/permissionless/actions/erc7579/accountId.ts +++ b/packages/permissionless/actions/erc7579/accountId.ts @@ -1,16 +1,16 @@ import { - ContractFunctionExecutionError, - decodeFunctionResult, - encodeFunctionData, type Chain, type Client, - type Transport + ContractFunctionExecutionError, + type Transport, + decodeFunctionResult, + encodeFunctionData } from "viem" import type { SmartAccount } from "../../accounts/types" +import type { GetAccountParameter } from "../../types" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -import type { GetAccountParameter } from "../../types" // export async function accountId< // TEntryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts index 3b4439df..9db00cf4 100644 --- a/packages/permissionless/actions/erc7579/installModule.ts +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -1,20 +1,20 @@ import { - encodeFunctionData, + type Address, type Chain, type Client, - type Transport, type Hex, - type Address + type Transport, + encodeFunctionData } from "viem" +import { getAction } from "viem/utils" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -import { getAction } from "viem/utils" -import { sendUserOperation } from "../smartAccount/sendUserOperation" import type { Middleware } from "../smartAccount/prepareUserOperationRequest" -import { parseModuleTypeId, type moduleType } from "./supportsModule" +import { sendUserOperation } from "../smartAccount/sendUserOperation" +import { type moduleType, parseModuleTypeId } from "./supportsModule" export type InstallModuleParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.ts index dc4fa007..170ca47b 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.ts @@ -1,11 +1,11 @@ -import type { Chain, Client, Transport, Hex, Address } from "viem" +import type { Address, Chain, Client, Hex, Transport } from "viem" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" import type { Middleware } from "../smartAccount/prepareUserOperationRequest" -import { parseModuleTypeId, type moduleType } from "./supportsModule" +import { type moduleType, parseModuleTypeId } from "./supportsModule" export type IsModuleInstalledParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts index ee2bc6cb..42cb8411 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -1,10 +1,10 @@ import { - type Hex, - toBytes, type Chain, type Client, + type Hex, type Transport, encodePacked, + toBytes, toHex } from "viem" import type { SmartAccount } from "../../accounts/types" diff --git a/packages/permissionless/actions/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts index a8757245..65799955 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -1,20 +1,20 @@ import { - encodeFunctionData, + type Address, type Chain, type Client, - type Transport, type Hex, - type Address + type Transport, + encodeFunctionData } from "viem" +import { getAction } from "viem/utils" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -import { getAction } from "viem/utils" -import { sendUserOperation } from "../smartAccount/sendUserOperation" import type { Middleware } from "../smartAccount/prepareUserOperationRequest" -import { parseModuleTypeId, type moduleType } from "./supportsModule" +import { sendUserOperation } from "../smartAccount/sendUserOperation" +import { type moduleType, parseModuleTypeId } from "./supportsModule" export type UninstallModuleParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/index.test.ts b/packages/permissionless/actions/index.test.ts index b76d225e..4e992fd3 100644 --- a/packages/permissionless/actions/index.test.ts +++ b/packages/permissionless/actions/index.test.ts @@ -1,15 +1,3 @@ -import { describe, expectTypeOf, test } from "vitest" -import { - sendUserOperation, - estimateUserOperationGas, - supportedEntryPoints, - chainId, - getUserOperationByHash, - getUserOperationReceipt, - getSenderAddress, - getAccountNonce, - waitForUserOperationReceipt -} from "./index" import type { Account, Address, @@ -20,14 +8,26 @@ import type { Log, Transport } from "viem" +import type { PartialBy } from "viem/chains" +import { describe, expectTypeOf, test } from "vitest" import type { BundlerRpcSchema } from "../types/bundler" import type { - ENTRYPOINT_ADDRESS_V07_TYPE, ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, EntryPoint } from "../types/entrypoint" -import type { PartialBy } from "viem/chains" import type { TStatus, UserOperation } from "../types/userOperation" +import { + chainId, + estimateUserOperationGas, + getAccountNonce, + getSenderAddress, + getUserOperationByHash, + getUserOperationReceipt, + sendUserOperation, + supportedEntryPoints, + waitForUserOperationReceipt +} from "./index" describe("index", () => { test("sendUserOperation", () => { diff --git a/packages/permissionless/actions/pimlico.test.ts b/packages/permissionless/actions/pimlico.test.ts index 75ee1794..f6d088cf 100644 --- a/packages/permissionless/actions/pimlico.test.ts +++ b/packages/permissionless/actions/pimlico.test.ts @@ -1,13 +1,3 @@ -import { describe, expectTypeOf, test } from "vitest" -import { - type PimlicoBundlerActions, - getUserOperationGasPrice, - getUserOperationStatus, - pimlicoBundlerActions, - sendCompressedUserOperation, - sponsorUserOperation, - validateSponsorshipPolicies -} from "./pimlico" import type { Account, Address, @@ -17,9 +7,19 @@ import type { Hex, Transport } from "viem" +import { describe, expectTypeOf, test } from "vitest" +import type { EntryPoint } from "../types/entrypoint" import type { PimlicoBundlerRpcSchema } from "../types/pimlico" import type { UserOperation } from "../types/userOperation" -import type { EntryPoint } from "../types/entrypoint" +import { + type PimlicoBundlerActions, + getUserOperationGasPrice, + getUserOperationStatus, + pimlicoBundlerActions, + sendCompressedUserOperation, + sponsorUserOperation, + validateSponsorshipPolicies +} from "./pimlico" describe("pimlico", () => { test("getUserOperationGasPrice", () => { diff --git a/packages/permissionless/actions/smartAccount/signTypedData.test.ts b/packages/permissionless/actions/smartAccount/signTypedData.test.ts index a9dd33ff..ef2be0c5 100644 --- a/packages/permissionless/actions/smartAccount/signTypedData.test.ts +++ b/packages/permissionless/actions/smartAccount/signTypedData.test.ts @@ -1,4 +1,4 @@ -import { getAddress, type Chain, type Client, type Transport } from "viem" +import { type Chain, type Client, type Transport, getAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" diff --git a/packages/permissionless/actions/smartAccount/writeContract.test.ts b/packages/permissionless/actions/smartAccount/writeContract.test.ts index a9dd33ff..ef2be0c5 100644 --- a/packages/permissionless/actions/smartAccount/writeContract.test.ts +++ b/packages/permissionless/actions/smartAccount/writeContract.test.ts @@ -1,4 +1,4 @@ -import { getAddress, type Chain, type Client, type Transport } from "viem" +import { type Chain, type Client, type Transport, getAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" diff --git a/packages/permissionless/clients/decorators/erc7579.ts b/packages/permissionless/clients/decorators/erc7579.ts index 6f090281..b1ef90db 100644 --- a/packages/permissionless/clients/decorators/erc7579.ts +++ b/packages/permissionless/clients/decorators/erc7579.ts @@ -1,12 +1,12 @@ import type { Chain, Client, Hash, Transport } from "viem" import type { SmartAccount } from "../../accounts/types" -import type { EntryPoint } from "../../types/entrypoint" import { accountId } from "../../actions/erc7579/accountId" import { installModule } from "../../actions/erc7579/installModule" import { isModuleInstalled } from "../../actions/erc7579/isModuleInstalled" import { supportsExecutionMode } from "../../actions/erc7579/supportsExecutionMode" import { supportsModule } from "../../actions/erc7579/supportsModule" import { uninstallModule } from "../../actions/erc7579/uninstallModule" +import type { EntryPoint } from "../../types/entrypoint" export type Erc7579Actions< TEntryPoint extends EntryPoint, diff --git a/packages/permissionless/utils/encodeCallData.ts b/packages/permissionless/utils/encodeCallData.ts index 67776283..2d643720 100644 --- a/packages/permissionless/utils/encodeCallData.ts +++ b/packages/permissionless/utils/encodeCallData.ts @@ -1,10 +1,10 @@ import { type Address, + type Hex, concatHex, encodeAbiParameters, encodeFunctionData, - toHex, - type Hex + toHex } from "viem" import { type ExecutionMode, From bcd24e5d66a7001ddd11a7afa3e7ebeebdfb806f Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 26 Jun 2024 12:15:00 +0100 Subject: [PATCH 03/13] Kernel tests passes --- bun.lockb | Bin 579144 -> 579144 bytes package.json | 2 +- .../mock-aa-infra/alto/constants.ts | 3 + .../mock-aa-infra/alto/index.ts | 10 +- packages/permissionless-test/src/utils.ts | 25 +- .../kernel/signerToEcdsaKernelSmartAccount.ts | 13 +- .../accounts/kernel/utils/encodeCallData.ts | 3 +- .../accounts/kernel/utils/getNonceKey.ts | 3 +- .../accounts/kernel/utils/isKernelV2.ts | 7 + .../accounts/kernel/utils/signMessage.ts | 3 +- .../accounts/kernel/utils/signTypedData.ts | 3 +- .../accounts/kernel/utils/wrapMessageHash.ts | 4 +- .../accounts/safe/signerToSafeSmartAccount.ts | 1 + .../actions/erc7579/accountId.test.ts | 285 ++++++++++++------ .../actions/erc7579/installModule.test.ts | 91 ++++++ .../actions/erc7579/installModule.ts | 27 +- .../actions/erc7579/isModuleInstalled.ts | 28 +- .../actions/erc7579/supportsExecutionMode.ts | 25 +- .../actions/erc7579/supportsModule.ts | 23 +- .../actions/erc7579/uninstallModule.test.ts | 93 ++++++ .../actions/erc7579/uninstallModule.ts | 29 +- .../clients/decorators/erc7579.ts | 77 +++-- packages/permissionless/types/index.ts | 4 +- 23 files changed, 551 insertions(+), 208 deletions(-) create mode 100644 packages/permissionless/accounts/kernel/utils/isKernelV2.ts create mode 100644 packages/permissionless/actions/erc7579/installModule.test.ts create mode 100644 packages/permissionless/actions/erc7579/uninstallModule.test.ts diff --git a/bun.lockb b/bun.lockb index 7fdbc3d9bccc979c70c7b3f52aadae5488485f60..52698a02fa02724cb41608c27236c60f7550fda9 100755 GIT binary patch delta 40 tcmX@HM)|}V<%Sl<7N!>F7M3lnR@a!#^o-hVudxC#8xXTkx4p)}4FEl?4#)ri delta 40 tcmX@HM)|}V<%Sl<7N!>F7M3lnR@azK^bFf=udxC#8xXTkx4p)}4FElI4#fZf diff --git a/package.json b/package.json index 94c861c2..ffc72a6f 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,6 @@ "get-port": "^7.0.0", "tsc-alias": "^1.8.8", "vitest": "^1.2.0", - "viem": "^2.14.1" + "viem": "^2.16.2" } } diff --git a/packages/permissionless-test/mock-aa-infra/alto/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts index e3addc71..c997b854 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -143,3 +143,6 @@ export const TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL: Hex = export const TRUST_DEFAULT_FALLBACK_HANDLER: Hex = "0x00000000000000000000000000000000000000000000000000000000000000006080604052604051620020183803806200201883398101604081905262000026916200156b565b60408051600480825260a08201909252600091816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816200003e5750506040805160018082528183019092529192506000919060208083019080368337019050509050631f931c1c60e01b81600081518110620000b157620000b1620015c8565b6001600160e01b03199290921660209283029190910182015260408051600580825260c08201909252600092909190820160a08036833701905050905063b61d27f660e01b816000815181106200010c576200010c620015c8565b6001600160e01b03199092166020928302919091019091015280516323f0ed1560e11b9082906001908110620001465762000146620015c8565b6001600160e01b0319909216602092830291909101909101528051633a871cdd60e01b9082906002908110620001805762000180620015c8565b6001600160e01b0319909216602092830291909101909101528051631a10fa5160e31b9082906003908110620001ba57620001ba620015c8565b6001600160e01b031990921660209283029190910190910152805163586b48ff60e11b9082906004908110620001f457620001f4620015c8565b6001600160e01b03199290921660209283029190910182015260408051600580825260c08201909252600092909190820160a08036833701905050905063150b7a0260e01b816000815181106200024f576200024f620015c8565b6001600160e01b031990921660209283029190910190910152805163f23a6e6160e01b9082906001908110620002895762000289620015c8565b6001600160e01b031990921660209283029190910190910152805163bc197c8160e01b9082906002908110620002c357620002c3620015c8565b6001600160e01b03199092166020928302919091019091015280516223de2960e01b9082906003908110620002fc57620002fc620015c8565b6001600160e01b0319909216602092830291909101909101528051635260769b60e11b9082906004908110620003365762000336620015c8565b6001600160e01b0319929092166020928302919091018201526040805160098082526101408201909252600092909190820161012080368337019050509050637a0ed62760e01b81600081518110620003935762000393620015c8565b6001600160e01b03199092166020928302919091019091015280516356fe50af60e11b9082906001908110620003cd57620003cd620015c8565b6001600160e01b03199092166020928302919091019091015280516314bbdacb60e21b9082906002908110620004075762000407620015c8565b6001600160e01b03199092166020928302919091019091015280516366ffd66360e11b9082906003908110620004415762000441620015c8565b6001600160e01b03199092166020928302919091019091015280516301ffc9a760e01b90829060049081106200047b576200047b620015c8565b6001600160e01b031990921660209283029190910190910152805163f9796ccf60e01b9082906005908110620004b557620004b5620015c8565b6001600160e01b031990921660209283029190910190910152805162d2a81160e11b9082906006908110620004ee57620004ee620015c8565b6001600160e01b031990921660209283029190910190910152805163d42139a960e01b9082906007908110620005285762000528620015c8565b6001600160e01b03199092166020928302919091019091015280516371d17b7f60e11b9082906008908110620005625762000562620015c8565b6001600160e01b031990921660209283029190910182015260408051606081019091526001600160a01b038b168152908101600081526020018581525085600081518110620005b557620005b5620015c8565b60200260200101819052506040518060600160405280896001600160a01b0316815260200160006002811115620005f057620005f0620015de565b815260200184815250856001815181106200060f576200060f620015c8565b60200260200101819052506040518060600160405280886001600160a01b03168152602001600060028111156200064a576200064a620015de565b81526020018381525085600281518110620006695762000669620015c8565b60200260200101819052506040518060600160405280876001600160a01b0316815260200160006002811115620006a457620006a4620015de565b81526020018281525085600381518110620006c357620006c3620015c8565b6020026020010181905250620006f1856000604051806020016040528060008152506200070060201b60201c565b5050505050505050506200184c565b60005b83518110156200090c576000848281518110620007245762000724620015c8565b602002602001015160200151905060006002811115620007485762000748620015de565b8160028111156200075d576200075d620015de565b03620007bb57620007b58583815181106200077c576200077c620015c8565b6020026020010151600001518684815181106200079d576200079d620015c8565b6020026020010151604001516200095b60201b60201c565b620008f6565b6001816002811115620007d257620007d2620015de565b036200082a57620007b5858381518110620007f157620007f1620015c8565b602002602001015160000151868481518110620008125762000812620015c8565b60200260200101516040015162000bf760201b60201c565b6002816002811115620008415762000841620015de565b036200089957620007b5858381518110620008605762000860620015c8565b602002602001015160000151868481518110620008815762000881620015c8565b60200260200101516040015162000ea160201b60201c565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084015b60405180910390fd5b508062000903816200160a565b91505062000703565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405162000942939291906200167a565b60405180910390a162000956828262001005565b505050565b805180620009af5760405162461bcd60e51b815260206004820152602b602482015260008051602062001ff883398151915260448201526a1858d95d081d1bc818dd5d60aa1b6064820152608401620008ed565b60008051602062001f8c8339815191526001600160a01b03841662000a2c5760405162461bcd60e51b815260206004820152602c60248201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260448201526b65206164647265737328302960a01b6064820152608401620008ed565b6001600160a01b0384166000908152600182016020526040812054906001600160601b038216900362000a655762000a658286620010dd565b60005b8381101562000bef57600085828151811062000a885762000a88620015c8565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0316801562000b305760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c72656164792065786973747300000000000000000000006064820152608401620008ed565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558d168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b0319161790558362000bd48162001781565b9450505050808062000be6906200160a565b91505062000a68565b505050505050565b80518062000c4b5760405162461bcd60e51b815260206004820152602b602482015260008051602062001ff883398151915260448201526a1858d95d081d1bc818dd5d60aa1b6064820152608401620008ed565b60008051602062001f8c8339815191526001600160a01b03841662000ccc5760405162461bcd60e51b815260206004820152603060248201527f4c69624469616d6f6e644375743a205265706c6163652066616365742063616e60448201526f2774206265206164647265737328302960801b6064820152608401620008ed565b6001600160a01b0384166000908152600182016020526040812054906001600160601b038216900362000d055762000d058286620010dd565b60005b8381101562000bef57600085828151811062000d285762000d28620015c8565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03908116908816810362000dd55760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d6520666163657400000000000000000000006064820152608401620008ed565b62000de28582846200114a565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558d168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b0319161790558362000e868162001781565b9450505050808062000e98906200160a565b91505062000d08565b80518062000ef55760405162461bcd60e51b815260206004820152602b602482015260008051602062001ff883398151915260448201526a1858d95d081d1bc818dd5d60aa1b6064820152608401620008ed565b60008051602062001f8c8339815191526001600160a01b0384161562000f845760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d7573742062652061646472657373283029000000000000000000006064820152608401620008ed565b60005b8281101562000ffe57600084828151811062000fa75762000fa7620015c8565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b031662000fe68482846200114a565b5050808062000ff5906200160a565b91505062000f87565b5050505050565b6001600160a01b03821662001018575050565b6200103d8260405180606001604052806028815260200162001fac602891396200152a565b600080836001600160a01b0316836040516200105a9190620017b2565b600060405180830381855af49150503d806000811462001097576040519150601f19603f3d011682016040523d82523d6000602084013e6200109c565b606091505b509150915081620010d757805115620010b85780518082602001fd5b838360405163192105d760e01b8152600401620008ed929190620017d0565b50505050565b620011028160405180606001604052806024815260200162001fd4602491396200152a565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160a01b038216620011c85760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e27742065786973740000000000000000006064820152608401620008ed565b306001600160a01b03831603620012395760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b6064820152608401620008ed565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b031692916200128a91620017fe565b905080821462001383576001600160a01b03841660009081526001860160205260408120805483908110620012c357620012c3620015c8565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110620013175762001317620015c8565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480620013af57620013af6200181a565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319851682528690526040812081905581900362000ffe5760028501546000906200141590600190620017fe565b6001600160a01b0386166000908152600180890160205260409091200154909150808214620014cb576000876002018381548110620014585762001458620015c8565b6000918252602090912001546002890180546001600160a01b0390921692508291849081106200148c576200148c620015c8565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480620014e157620014e16200181a565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b8181620010d75760405162461bcd60e51b8152600401620008ed919062001830565b80516001600160a01b03811681146200156657600080fd5b919050565b600080600080608085870312156200158257600080fd5b6200158d856200154e565b93506200159d602086016200154e565b9250620015ad604086016200154e565b9150620015bd606086016200154e565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200161f576200161f620015f4565b5060010190565b60005b838110156200164357818101518382015260200162001629565b50506000910152565b600081518084526200166681602086016020860162001626565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b848110156200174f57898403607f19018652815180516001600160a01b03168552838101518986019060038110620016eb57634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015620017395783516001600160e01b03191682529286019260019290920191908601906200170d565b50978501979550505090820190600101620016a3565b50506001600160a01b038a169088015286810360408801526200177381896200164c565b9a9950505050505050505050565b60006001600160601b038281166002600160601b03198101620017a857620017a8620015f4565b6001019392505050565b60008251620017c681846020870162001626565b9190910192915050565b6001600160a01b0383168152604060208201819052600090620017f6908301846200164c565b949350505050565b81810381811115620018145762001814620015f4565b92915050565b634e487b7160e01b600052603160045260246000fd5b6020815260006200184560208301846200164c565b9392505050565b610730806200185c6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806352ef6b2c146100515780637a0ed6271461006f578063adfca15e14610084578063cdffacc6146100a4575b600080fd5b610059610140565b60405161006691906104ab565b60405180910390f35b6100776101d1565b6040516100669190610562565b61009761009236600461060a565b6103d1565b6040516100669190610647565b61011b6100b236600461065a565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081527f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610066565b60607f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f6002018054806020026020016040519081016040528092919081815260200182805480156101c757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161019c575b5050505050905090565b7f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd4921546060907f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f908067ffffffffffffffff8111156102315761023161069c565b60405190808252806020026020018201604052801561027757816020015b60408051808201909152600081526060602082015281526020019060019003908161024f5790505b50925060005b818110156103cb57600083600201828154811061029c5761029c6106cb565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050808583815181106102dc576102dc6106cb565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff928316905290821660009081526001860182526040908190208054825181850281018501909352808352919290919083018282801561039d57602002820191906000526020600020906000905b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161034a5790505b50505050508583815181106103b4576103b46106cb565b60209081029190910181015101525060010161027d565b50505090565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd4920602090815260409182902080548351818402810184019094528084526060939283018282801561049f57602002820191906000526020600020906000905b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001906004019060208260030104928301926001038202915080841161044c5790505b50505050509050919050565b6020808252825182820181905260009190848201906040850190845b818110156104f957835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016104c7565b50909695505050505050565b600081518084526020808501945080840160005b838110156105575781517fffffffff000000000000000000000000000000000000000000000000000000001687529582019590820190600101610519565b509495945050505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156105fc578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00185528151805173ffffffffffffffffffffffffffffffffffffffff1684528701518784018790526105e987850182610505565b9588019593505090860190600101610589565b509098975050505050505050565b60006020828403121561061c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461064057600080fd5b9392505050565b6020815260006106406020830184610505565b60006020828403121561066c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461064057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea264697066735822122024a872696a5ad50024326567061c50adea63ff0d49edf0ac60339459d33d571664736f6c63430008150033183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f64654c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e20660000000000000000000000000b9504140771c3688ff041917192277d2f52e1e0000000000000000000000000fde53272dcd7938d16e031a6989753c3217283320000000000000000000000003143e1c0af0cdc153423863923cf4e3818e34daa000000000000000000000000ce36b85d12d81cd619c745c7717f3396e184ac7c" + +export const ERC_7579_TEST_MODULE_CREATECALL = + "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50610f6a8061001f6000396000f3fe6080604052600436106100a75760003560e01c8063d26cdce311610064578063d26cdce3146101c1578063d60b347f146101d4578063e508600314610204578063ecd0596114610217578063fbe5ce0a14610238578063fd8b84b11461025857600080fd5b806306fdde03146100ac57806354fd4d50146100f65780636d61fe70146101245780637065cb48146101465780638a91b0e314610166578063ccfdec8c14610186575b600080fd5b3480156100b857600080fd5b5060408051808201909152600f81526e27bbb730b13632a2bc32b1baba37b960891b60208201525b6040516100ed9190610aca565b60405180910390f35b34801561010257600080fd5b506040805180820190915260058152640312e302e360dc1b60208201526100e0565b34801561013057600080fd5b5061014461013f366004610b46565b610285565b005b34801561015257600080fd5b50610144610161366004610ba4565b610311565b34801561017257600080fd5b50610144610181366004610b46565b6103c9565b34801561019257600080fd5b506101b36101a1366004610ba4565b60016020526000908152604090205481565b6040519081526020016100ed565b6101446101cf366004610bbf565b6103f5565b3480156101e057600080fd5b506101f46101ef366004610ba4565b6104b8565b60405190151581526020016100ed565b610144610212366004610bbf565b6104e8565b34801561022357600080fd5b506101f4610232366004610c12565b60021490565b34801561024457600080fd5b50610144610253366004610c2b565b61053e565b34801561026457600080fd5b50610278610273366004610ba4565b610573565b6040516100ed9190610c5e565b3360006102956014828587610cab565b61029e91610cd5565b60601c90506102cf600080846001600160a01b03166001600160a01b031681526020019081526020016000206105aa565b6001600160a01b03821660009081526020819052604090206102f19082610607565b506001600160a01b03166000908152600160208190526040909120555050565b3361031b816104b8565b6103485760405163f91bd6f160e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6001600160a01b03821661037a5760405163b20f76e360e01b81526001600160a01b038316600482015260240161033f565b6001600160a01b038116600090815260208190526040902061039c9083610607565b6001600160a01b03811660009081526001602052604081208054916103c083610d20565b91905055505050565b3360009081526020819052604090206103e1906106dd565b505033600090815260016020526040812055565b6001600160a01b03831660009081526020819052604090206104179033610758565b61043457604051631a27eac360e11b815260040160405180910390fd5b826001600160a01b031663d691c96461044b610794565b84846040518463ffffffff1660e01b815260040161046b93929190610d39565b6000604051808303816000875af115801561048a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104b29190810190610db6565b50505050565b6001600160a01b038181166000908152602081815260408083206001845290915281205490911615155b92915050565b6001600160a01b038316600090815260208190526040902061050a9033610758565b61052757604051631a27eac360e11b815260040160405180910390fd5b826001600160a01b031663d691c96461044b6107a7565b3360009081526020819052604090206105589083836107b9565b3360009081526001602052604081208054916103c083610ecd565b6001600160a01b038116600090815260016020818152604080842054918490529092206060926105a3929061088e565b5092915050565b60016000908152602082905260409020546001600160a01b0316156105e2576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061062657506001600160a01b0381166001145b1561064f57604051637c84ecfb60e01b81526001600160a01b038216600482015260240161033f565b6001600160a01b03818116600090815260208490526040902054161561069357604051631034f46960e21b81526001600160a01b038216600482015260240161033f565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b60016000908152602082905260409020546001600160a01b03165b6001600160a01b03811615610736576001600160a01b03908116600090815260208390526040902080546001600160a01b03198116909155166106f8565b50600160009081526020919091526040902080546001600160a01b0319169055565b600060016001600160a01b0383161480159061078d57506001600160a01b038281166000908152602085905260409020541615155b9392505050565b60006107a281808080610a3b565b905090565b60006107a2600160f81b828080610a3b565b6001600160a01b03811615806107d857506001600160a01b0381166001145b1561080157604051637c84ecfb60e01b81526001600160a01b038316600482015260240161033f565b6001600160a01b0382811660009081526020859052604090205481169082161461084957604051637c84ecfb60e01b81526001600160a01b038216600482015260240161033f565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b606060006001600160a01b0384166001148015906108b357506108b18585610758565b155b156108dc57604051637c84ecfb60e01b81526001600160a01b038516600482015260240161033f565b826000036108fd5760405163f725081760e01b815260040160405180910390fd5b8267ffffffffffffffff81111561091657610916610d6f565b60405190808252806020026020018201604052801561093f578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b0382161580159061098457506001600160a01b038216600114155b801561098f57508381105b156109e957818382815181106109a7576109a7610ee4565b6001600160a01b0392831660209182029290920181019190915292811660009081529287905260409092205490911690806109e181610d20565b915050610962565b6001600160a01b038216600114801590610a035750600081115b15610a2f5782610a14600183610efa565b81518110610a2457610a24610ee4565b602002602001015191505b80835250935093915050565b604080516001600160f81b03198087166020830152851660218201526000602282018190526001600160e01b03198516602683015269ffffffffffffffffffff198416602a8301529101604051602081830303815290604052610a9d90610f0d565b95945050505050565b60005b83811015610ac1578181015183820152602001610aa9565b50506000910152565b6020815260008251806020840152610ae9816040850160208701610aa6565b601f01601f19169190910160400192915050565b60008083601f840112610b0f57600080fd5b50813567ffffffffffffffff811115610b2757600080fd5b602083019150836020828501011115610b3f57600080fd5b9250929050565b60008060208385031215610b5957600080fd5b823567ffffffffffffffff811115610b7057600080fd5b610b7c85828601610afd565b90969095509350505050565b80356001600160a01b0381168114610b9f57600080fd5b919050565b600060208284031215610bb657600080fd5b61078d82610b88565b600080600060408486031215610bd457600080fd5b610bdd84610b88565b9250602084013567ffffffffffffffff811115610bf957600080fd5b610c0586828701610afd565b9497909650939450505050565b600060208284031215610c2457600080fd5b5035919050565b60008060408385031215610c3e57600080fd5b610c4783610b88565b9150610c5560208401610b88565b90509250929050565b6020808252825182820181905260009190848201906040850190845b81811015610c9f5783516001600160a01b031683529284019291840191600101610c7a565b50909695505050505050565b60008085851115610cbb57600080fd5b83861115610cc857600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff198135818116916014851015610d025780818660140360031b1b83161692505b505092915050565b634e487b7160e01b600052601160045260246000fd5b600060018201610d3257610d32610d0a565b5060010190565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610dae57610dae610d6f565b604052919050565b60006020808385031215610dc957600080fd5b825167ffffffffffffffff80821115610de157600080fd5b8185019150601f86601f840112610df757600080fd5b825182811115610e0957610e09610d6f565b8060051b610e18868201610d85565b918252848101860191868101908a841115610e3257600080fd5b87870192505b83831015610ebf57825186811115610e505760008081fd5b8701603f81018c13610e625760008081fd5b88810151604088821115610e7857610e78610d6f565b610e89828901601f19168c01610d85565b8281528e82848601011115610e9e5760008081fd5b610ead838d8301848701610aa6565b85525050509187019190870190610e38565b9a9950505050505050505050565b600081610edc57610edc610d0a565b506000190190565b634e487b7160e01b600052603260045260246000fd5b818103818111156104e2576104e2610d0a565b80516020808301519190811015610f2e576000198160200360031b1b821691505b5091905056fea2646970667358221220c65136fce0b201208eef061080f14f2bd4c40a5b6bc536237b6b4ff59f86c2aa64736f6c63430008190033" diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index e21fd6a6..274286e0 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -19,6 +19,7 @@ import { ENTRY_POINT_SIMULATIONS_CREATECALL, ENTRY_POINT_V06_CREATECALL, ENTRY_POINT_V07_CREATECALL, + ERC_7579_TEST_MODULE_CREATECALL, KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, KERNEL_V06_FACTORY_CREATECALL, @@ -239,6 +240,12 @@ export const setupContracts = async (rpc: string) => { data: TRUST_DEFAULT_FALLBACK_HANDLER, gas: 15_000_000n, nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: ERC_7579_TEST_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ }) ]) @@ -403,6 +410,7 @@ export const setupContracts = async (rpc: string) => { "0x0B9504140771C3688Ff041917192277D2f52E1e0", // Trust DiamondCutFacet "0x3143E1C0Af0Cdc153423863923Cf4e3818e34Daa", // Trust TokenReceiverFacet "0xCe36b85d12D81cd619C745c7717f3396E184Ac7C", // Trust DiamondLoupeFacet - "0x2e7f1dAe1F3799d20f5c31bEFdc7A620f664728D" // Trust DefaultFallbackHandler + "0x2e7f1dAe1F3799d20f5c31bEFdc7A620f664728D", // Trust DefaultFallbackHandler + "0xc98B026383885F41d9a995f85FC480E9bb8bB891" // ERC7579 Test Module ]) } diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 449c9697..25f40421 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -377,18 +377,15 @@ export const getSafeClient = async ({ }): Promise>> => { const publicClient = getPublicClient(anvilRpc) - // const safeModules: Address[] = erc7579 - // ? [getAddress("0xbaCA6f74a5549368568f387FD989C279f940f1A5")] - // : [] - const safeSmartAccount = await signerToSafeSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), safeVersion: "1.4.1", saltNonce: 420n, - safe4337ModuleAddress: getAddress( - "0xbaCA6f74a5549368568f387FD989C279f940f1A5" - ), + safe4337ModuleAddress: erc7579 + ? getAddress("0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C") + : undefined, + erc7579, setupTransactions }) @@ -436,8 +433,7 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: false, - isEip1271Compliant: true, - supportsErc7579: false + isEip1271Compliant: true }, { name: "LightAccount v1.1.0", @@ -453,7 +449,6 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: false, - supportsErc7579: false, isEip1271Compliant: true }, { @@ -469,7 +464,6 @@ export const getCoreSmartAccounts = () => [ }), supportsEntryPointV06: true, supportsEntryPointV07: true, - supportsErc7579: false, isEip1271Compliant: false }, { @@ -483,12 +477,11 @@ export const getCoreSmartAccounts = () => [ signer: privateKeyToAccount(conf.privateKey), entryPoint: ENTRYPOINT_ADDRESS_V06 }), - getErc7579SmartAccountClient: async ( - conf: AAParamType - ) => getKernelEcdsaClient({ ...conf, erc7579: true }), + // getErc7579SmartAccountClient: async ( + // conf: AAParamType + // ) => getKernelEcdsaClient({ ...conf, erc7579: true }), supportsEntryPointV06: true, supportsEntryPointV07: true, - supportsErc7579: false, isEip1271Compliant: true }, { @@ -510,7 +503,6 @@ export const getCoreSmartAccounts = () => [ entryPoint: ENTRYPOINT_ADDRESS_V06 }), supportsEntryPointV06: true, - supportsErc7579: false, supportsEntryPointV07: false, isEip1271Compliant: true }, @@ -530,7 +522,6 @@ export const getCoreSmartAccounts = () => [ conf: AAParamType ) => getSafeClient({ ...conf, erc7579: true }), supportsEntryPointV06: true, - supportsErc7579: true, supportsEntryPointV07: true, isEip1271Compliant: true } diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 7184db8a..33744000 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -45,6 +45,7 @@ import { } from "./constants" import { encodeCallData } from "./utils/encodeCallData" import { getNonceKeyWithEncoding } from "./utils/getNonceKey" +import { isKernelV2 } from "./utils/isKernelV2" import { signMessage } from "./utils/signMessage" import { signTypedData } from "./utils/signTypedData" @@ -143,7 +144,7 @@ export const KERNEL_VERSION_TO_ADDRESSES_MAP: { * Get supported Kernel Smart Account version based on entryPoint * @param entryPoint */ -const getKernelVersion = ( +const getDefaultKernelVersion = ( entryPoint: TEntryPoint, version?: KernelVersion ): KernelVersion => { @@ -431,7 +432,7 @@ export async function signerToEcdsaKernelSmartAccount< }: SignerToEcdsaKernelSmartAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) - const kernelVersion = getKernelVersion(entryPointAddress, version) + const kernelVersion = getDefaultKernelVersion(entryPointAddress, version) const { accountLogicAddress, @@ -501,7 +502,7 @@ export async function signerToEcdsaKernelSmartAccount< chainId }) - if (kernelVersion === "0.2.2") { + if (isKernelV2(kernelVersion)) { return signature } @@ -532,7 +533,7 @@ export async function signerToEcdsaKernelSmartAccount< chainId }) - if (kernelVersion === "0.2.2") { + if (isKernelV2(kernelVersion)) { return signature } @@ -576,7 +577,7 @@ export async function signerToEcdsaKernelSmartAccount< message: { raw: hash } }) // Always use the sudo mode, since we will use external paymaster - if (kernelVersion === "0.2.2") { + if (isKernelV2(kernelVersion)) { return concatHex(["0x00000000", signature]) } return signature @@ -640,7 +641,7 @@ export async function signerToEcdsaKernelSmartAccount< // Get simple dummy signature async getDummySignature(_userOperation) { - if (kernelVersion === "0.2.2") { + if (isKernelV2(kernelVersion)) { return concatHex([ROOT_MODE_KERNEL_V2, DUMMY_ECDSA_SIGNATURE]) } return DUMMY_ECDSA_SIGNATURE diff --git a/packages/permissionless/accounts/kernel/utils/encodeCallData.ts b/packages/permissionless/accounts/kernel/utils/encodeCallData.ts index f9f33afc..deac9b3b 100644 --- a/packages/permissionless/accounts/kernel/utils/encodeCallData.ts +++ b/packages/permissionless/accounts/kernel/utils/encodeCallData.ts @@ -12,6 +12,7 @@ import { KernelV3ExecuteAbi } from "../abi/KernelV3AccountAbi" import { CALL_TYPE, EXEC_TYPE } from "../constants" import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" import { getExecMode } from "./getExecMode" +import { isKernelV2 } from "./isKernelV2" export const encodeCallData = ( _tx: @@ -27,7 +28,7 @@ export const encodeCallData = ( }[], accountVersion: KernelVersion ) => { - if (accountVersion === "0.2.2") { + if (isKernelV2(accountVersion)) { if (Array.isArray(_tx)) { // Encode a batched call return encodeFunctionData({ diff --git a/packages/permissionless/accounts/kernel/utils/getNonceKey.ts b/packages/permissionless/accounts/kernel/utils/getNonceKey.ts index ddab6ab1..92702549 100644 --- a/packages/permissionless/accounts/kernel/utils/getNonceKey.ts +++ b/packages/permissionless/accounts/kernel/utils/getNonceKey.ts @@ -2,13 +2,14 @@ import { type Address, concatHex, maxUint16, pad, toHex } from "viem" import type { EntryPoint } from "../../../types" import { VALIDATOR_MODE, VALIDATOR_TYPE } from "../constants" import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" +import { isKernelV2 } from "./isKernelV2" export const getNonceKeyWithEncoding = ( accountVerion: KernelVersion, validatorAddress: Address, nonceKey = 0n ) => { - if (accountVerion === "0.2.2") { + if (isKernelV2(accountVerion)) { return nonceKey } diff --git a/packages/permissionless/accounts/kernel/utils/isKernelV2.ts b/packages/permissionless/accounts/kernel/utils/isKernelV2.ts new file mode 100644 index 00000000..68476b63 --- /dev/null +++ b/packages/permissionless/accounts/kernel/utils/isKernelV2.ts @@ -0,0 +1,7 @@ +import type { EntryPoint } from "../../../types" +import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" + +export const isKernelV2 = (version: KernelVersion): boolean => { + const regex = /0\.2\.\d+/ + return regex.test(version) +} diff --git a/packages/permissionless/accounts/kernel/utils/signMessage.ts b/packages/permissionless/accounts/kernel/utils/signMessage.ts index 27821ba1..98860ff5 100644 --- a/packages/permissionless/accounts/kernel/utils/signMessage.ts +++ b/packages/permissionless/accounts/kernel/utils/signMessage.ts @@ -10,6 +10,7 @@ import { publicActions } from "viem" import { signMessage as _signMessage } from "viem/actions" +import { isKernelV2 } from "./isKernelV2" import { type WrapMessageHashParams, wrapMessageHash } from "./wrapMessageHash" export async function signMessage< @@ -24,7 +25,7 @@ export async function signMessage< accountVersion }: SignMessageParameters & WrapMessageHashParams ): Promise { - if (accountVersion === "0.2.2") { + if (isKernelV2(accountVersion)) { return _signMessage(client, { account: account_ as LocalAccount, message diff --git a/packages/permissionless/accounts/kernel/utils/signTypedData.ts b/packages/permissionless/accounts/kernel/utils/signTypedData.ts index a75f1cc9..901bc204 100644 --- a/packages/permissionless/accounts/kernel/utils/signTypedData.ts +++ b/packages/permissionless/accounts/kernel/utils/signTypedData.ts @@ -17,6 +17,7 @@ import { signMessage as _signMessage, signTypedData as _signTypedData } from "viem/actions" +import { isKernelV2 } from "./isKernelV2" import { type WrapMessageHashParams, wrapMessageHash } from "./wrapMessageHash" export async function signTypedData< @@ -35,7 +36,7 @@ export async function signTypedData< accountVersion, ...typedData } = parameters as unknown as SignTypedDataParameters & WrapMessageHashParams - if (accountVersion === "0.2.2") { + if (isKernelV2(accountVersion)) { return _signTypedData(client, { account: account_, ...typedData }) } const { message, primaryType, types: _types, domain } = typedData diff --git a/packages/permissionless/accounts/kernel/utils/wrapMessageHash.ts b/packages/permissionless/accounts/kernel/utils/wrapMessageHash.ts index 2d7352f3..47b5ff20 100644 --- a/packages/permissionless/accounts/kernel/utils/wrapMessageHash.ts +++ b/packages/permissionless/accounts/kernel/utils/wrapMessageHash.ts @@ -6,9 +6,11 @@ import { stringToHex } from "viem" import { type Address, domainSeparator } from "viem" +import type { EntryPoint } from "../../../types" +import type { KernelVersion } from "../signerToEcdsaKernelSmartAccount" export type WrapMessageHashParams = { - accountVersion: string + accountVersion: KernelVersion accountAddress: Address chainId?: number } diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 7088e05a..36447024 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -752,6 +752,7 @@ export async function signerToSafeSmartAccount< entryPoint: entryPointAddress, source: "SafeSmartAccount", async getNonce() { + // TODO: Allow dapp developers to specify custom nonce key (eg: Validator address) return getAccountNonce(client, { sender: accountAddress, entryPoint: entryPointAddress diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts index f1473952..da519a80 100644 --- a/packages/permissionless/actions/erc7579/accountId.test.ts +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -1,4 +1,11 @@ -import { http, getAddress, zeroAddress } from "viem" +import { + http, + encodeAbiParameters, + encodePacked, + getAddress, + isHash, + zeroAddress +} from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { describe, expect } from "vitest" @@ -8,102 +15,206 @@ import { getPimlicoPaymasterClient, getPublicClient } from "../../../permissionless-test/src/utils" -import { signerToSafeSmartAccount } from "../../accounts" +import { + signerToEcdsaKernelSmartAccount, + signerToSafeSmartAccount +} from "../../accounts" import { createSmartAccountClient } from "../../clients/createSmartAccountClient" import { erc7579Actions } from "../../clients/decorators/erc7579" +import { createBundlerClient } from "../../index" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" import { accountId } from "./accountId" describe.each(getCoreSmartAccounts())( "accountId $name", - ({ getErc7579SmartAccountClient, supportsErc7579 }) => { - testWithRpc.skipIf(!supportsErc7579)("accountId", async ({ rpc }) => { - const { anvilRpc, altoRpc, paymasterRpc } = rpc + ({ getErc7579SmartAccountClient }) => { + // testWithRpc.skipIf(!getErc7579SmartAccountClient)( + // "accountId", + // async ({ rpc }) => { + // const { anvilRpc, altoRpc, paymasterRpc } = rpc - if (!getErc7579SmartAccountClient) { - throw new Error("getErc7579SmartAccountClient not defined") - } - const publicClient = getPublicClient( - "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" - ) + // if (!getErc7579SmartAccountClient) { + // throw new Error("getErc7579SmartAccountClient not defined") + // } - const signer = privateKeyToAccount(generatePrivateKey()) + // const smartClient = await getErc7579SmartAccountClient({ + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // privateKey: generatePrivateKey(), + // altoRpc: altoRpc, + // anvilRpc: anvilRpc, + // paymasterClient: getPimlicoPaymasterClient({ + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // paymasterRpc + // }) + // }) - const safeSmartAccount = await signerToSafeSmartAccount( - publicClient, - { - entryPoint: ENTRYPOINT_ADDRESS_V07, - signer: signer, - safeVersion: "1.4.1", - saltNonce: 420n, - safe4337ModuleAddress: getAddress( - "0xbaCA6f74a5549368568f387FD989C279f940f1A5" - ), - erc7579: true - } - ) - - console.log({ signer: signer.address }) - - const paymasterClient = getPimlicoPaymasterClient({ - entryPoint: ENTRYPOINT_ADDRESS_V07, - paymasterRpc: - "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" - }) - - const smartClient = createSmartAccountClient({ - chain: foundry, - account: safeSmartAccount, - bundlerTransport: http("http://0.0.0.0:3000"), - middleware: { - sponsorUserOperation: paymasterClient.sponsorUserOperation + // const accountIdBeforeDeploy = await accountId( + // smartClient as any + // ) + + // // deploy account + // await smartClient.sendTransaction({ + // to: zeroAddress, + // value: 0n, + // data: "0x" + // }) + + // const postDeployAccountId = await accountId(smartClient as any) + + // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) + // } + // ) + + testWithRpc.skipIf(!getErc7579SmartAccountClient)( + "accountId", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") } - }).extend(erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 })) - - smartClient.accountId() - - const accountIdBeforeDeploy = await accountId(smartClient as any) - - console.log({ accountIdBeforeDeploy }) - - // deploy account - await smartClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // const result = await publicClient.readContract({ - // abi: [ - // { - // name: "isModuleEnabled", - // type: "function", - // stateMutability: "view", - // inputs: [ - // { - // type: "address", - // name: "module" - // } - // ], - // outputs: [ - // { - // type: "bool" - // } - // ] - // } - // ], - // functionName: "isModuleEnabled", - // args: [ - // getAddress("0xbaCA6f74a5549368568f387FD989C279f940f1A5") - // ], - // address: smartClient.account.address - // }) - - // const postDeployAccountId = await accountId(smartClient as any) - - // console.log({ result }) - - // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) - }) + const publicClient = getPublicClient(anvilRpc) + const signer = privateKeyToAccount( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + ) + // const kernelSmartAccount = + // await signerToEcdsaKernelSmartAccount(publicClient, { + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // signer: signer, + // version: "0.3.0" + // }) + + const safeSmartAccount = await signerToSafeSmartAccount( + publicClient, + { + entryPoint: ENTRYPOINT_ADDRESS_V07, + signer: signer, + safeVersion: "1.4.1", + saltNonce: 420n, + safe4337ModuleAddress: getAddress( + "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C" + ), + erc7579: true + } + ) + + const paymasterClient = getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc: paymasterRpc + }) + const smartClient = createSmartAccountClient({ + chain: foundry, + account: safeSmartAccount, + bundlerTransport: http(altoRpc), + middleware: { + sponsorUserOperation: + paymasterClient.sponsorUserOperation + } + }).extend( + erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 }) + ) + + const moduleData = encodePacked( + ["address"], + [smartClient.account.address] + ) + + const accountIdBeforeDeploy = await smartClient.accountId() + + const opHashInstallModule = await smartClient.installModule({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [{ type: "bytes" }, { type: "bytes" }], + [moduleData, "0x"] + ) + ] + ) + }) + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + expect(isHash(opHashInstallModule)).toBe(true) + + const userOperationReceiptInstallModule = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHashInstallModule, + timeout: 100000 + }) + expect(userOperationReceiptInstallModule).not.toBeNull() + expect(userOperationReceiptInstallModule?.userOpHash).toBe( + opHashInstallModule + ) + expect( + userOperationReceiptInstallModule?.receipt.transactionHash + ).toBeTruthy() + + const accountIdAfterDeploy = await smartClient.accountId() + + expect(accountIdBeforeDeploy).toBe(accountIdAfterDeploy) + + const opHashIsModuleInstalled = + await smartClient.isModuleInstalled({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + }) + + expect(opHashIsModuleInstalled).toBe(true) + + const supportsExecutionMode = + await smartClient.supportsExecutionMode({ + callType: "batchcall", + revertOnError: false, + modeSelector: "0x0", + modeData: "0x" + }) + + expect(supportsExecutionMode).toBe(true) + + const supportsModule = await smartClient.supportsModule({ + type: "execution" + }) + + expect(supportsModule).toBe(true) + + const opHashUninstallModule = await smartClient.uninstallModule( + { + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + } + ) + + expect(isHash(opHashUninstallModule)).toBe(true) + + const userOperationReceiptUninstallModule = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHashUninstallModule, + timeout: 100000 + }) + expect(userOperationReceiptUninstallModule).not.toBeNull() + expect(userOperationReceiptUninstallModule?.userOpHash).toBe( + opHashUninstallModule + ) + expect( + userOperationReceiptUninstallModule?.receipt.transactionHash + ).toBeTruthy() + + expect( + await smartClient.isModuleInstalled({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + }) + ).toBe(false) + } + ) } ) diff --git a/packages/permissionless/actions/erc7579/installModule.test.ts b/packages/permissionless/actions/erc7579/installModule.test.ts new file mode 100644 index 00000000..c5589fef --- /dev/null +++ b/packages/permissionless/actions/erc7579/installModule.test.ts @@ -0,0 +1,91 @@ +import { + http, + encodeAbiParameters, + encodePacked, + isHash, + 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 { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { installModule } from "./installModule" + +describe.each(getCoreSmartAccounts())( + "installmodule $name", + ({ getErc7579SmartAccountClient, name }) => { + testWithRpc.skipIf(!getErc7579SmartAccountClient || name === "Safe")( + "installModule", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + + const smartClient = await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const moduleData = encodePacked( + ["address"], + [smartClient.account.address] + ) + + const opHash = await installModule(smartClient as any, { + account: smartClient.account, + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [{ type: "bytes" }, { type: "bytes" }], + [moduleData, "0x"] + ) + ] + ) + }) + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + 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/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts index 9db00cf4..2564d2f9 100644 --- a/packages/permissionless/actions/erc7579/installModule.ts +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -17,28 +17,25 @@ import { sendUserOperation } from "../smartAccount/sendUserOperation" import { type moduleType, parseModuleTypeId } from "./supportsModule" export type InstallModuleParameters< - entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined -> = GetAccountParameter & { + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined +> = GetAccountParameter & { type: moduleType address: Address callData: Hex maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint nonce?: bigint -} & Middleware +} & Middleware export async function installModule< - entryPoint extends EntryPoint, - TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined >( - client: Client, - parameters: Prettify> + client: Client, + parameters: Prettify> ): Promise { const { account: account_ = client.account, @@ -56,7 +53,7 @@ export async function installModule< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const installModuleCallData = encodeFunctionData({ abi: [ @@ -87,7 +84,7 @@ export async function installModule< return getAction( client, - sendUserOperation, + sendUserOperation, "sendUserOperation" )({ userOperation: { diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.ts index 170ca47b..8cb84ee0 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.ts @@ -1,32 +1,30 @@ import type { Address, Chain, Client, Hex, Transport } from "viem" import type { SmartAccount } from "../../accounts/types" -import type { GetAccountParameter, Prettify } from "../../types/" +import type { GetAccountParameter } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -import type { Middleware } from "../smartAccount/prepareUserOperationRequest" import { type moduleType, parseModuleTypeId } from "./supportsModule" export type IsModuleInstalledParameters< - entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount | undefined -> = GetAccountParameter & { +> = GetAccountParameter & { type: moduleType address: Address callData: Hex -} & Middleware +} export async function isModuleInstalled< - entryPoint extends EntryPoint, - TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined >( - client: Client, - parameters: Prettify> + client: Client, + parameters: IsModuleInstalledParameters ): Promise { const { account: account_ = client.account, address, callData } = parameters @@ -36,7 +34,7 @@ export async function isModuleInstalled< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const publicClient = account.client diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts index 42cb8411..5e25a5de 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -22,12 +22,12 @@ export type ExecutionMode = { modeData: Hex } -export type supportsExecutionModeParameters< - entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount +export type SupportsExecutionModeParameters< + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount | undefined -> = GetAccountParameter & ExecutionMode +> = GetAccountParameter & ExecutionMode function parseCallType(executionMode: CallType) { switch (executionMode) { @@ -59,14 +59,13 @@ export function encodeExecutionMode({ } export async function supportsExecutionMode< - entryPoint extends EntryPoint, - TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined >( - client: Client, - args: Prettify> + client: Client, + args: Prettify> ): Promise { const { account: account_ = client.account, @@ -82,7 +81,7 @@ export async function supportsExecutionMode< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const publicClient = account.client diff --git a/packages/permissionless/actions/erc7579/supportsModule.ts b/packages/permissionless/actions/erc7579/supportsModule.ts index 7342d6f0..f4c38436 100644 --- a/packages/permissionless/actions/erc7579/supportsModule.ts +++ b/packages/permissionless/actions/erc7579/supportsModule.ts @@ -8,11 +8,11 @@ import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashW export type moduleType = "validation" | "execution" | "fallback" | "hooks" export type SupportsModuleParameters< - entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount | undefined -> = GetAccountParameter & { +> = GetAccountParameter & { type: moduleType } @@ -32,14 +32,13 @@ export function parseModuleTypeId(type: moduleType): bigint { } export async function supportsModule< - entryPoint extends EntryPoint, - TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined >( - client: Client, - args: Prettify> + client: Client, + args: Prettify> ): Promise { const { account: account_ = client.account } = args @@ -49,7 +48,7 @@ export async function supportsModule< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const publicClient = account.client diff --git a/packages/permissionless/actions/erc7579/uninstallModule.test.ts b/packages/permissionless/actions/erc7579/uninstallModule.test.ts new file mode 100644 index 00000000..1877d608 --- /dev/null +++ b/packages/permissionless/actions/erc7579/uninstallModule.test.ts @@ -0,0 +1,93 @@ +import { + http, + encodeAbiParameters, + encodePacked, + isHash, + 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 { createBundlerClient } from "../../clients/createBundlerClient" +import { erc7579Actions } from "../../clients/decorators/erc7579" +import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { installModule } from "./installModule" + +describe.each(getCoreSmartAccounts())( + "installmodule $name", + ({ getErc7579SmartAccountClient, name }) => { + testWithRpc.skipIf(!getErc7579SmartAccountClient || name === "Safe")( + "installModule", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + + const smartClient = ( + await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + ).extend(erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 })) + + const moduleData = encodePacked( + ["address"], + [smartClient.account.address] + ) + + await smartClient.installModule({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [{ type: "bytes" }, { type: "bytes" }], + [moduleData, "0x"] + ) + ] + ) + }) + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + 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/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts index 65799955..8d00b8b3 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -17,28 +17,29 @@ import { sendUserOperation } from "../smartAccount/sendUserOperation" import { type moduleType, parseModuleTypeId } from "./supportsModule" export type UninstallModuleParameters< - entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount | undefined -> = GetAccountParameter & { +> = GetAccountParameter & { type: moduleType address: Address callData: Hex maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint nonce?: bigint -} & Middleware +} & Middleware export async function uninstallModule< - entryPoint extends EntryPoint, - TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TEntryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount + | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined >( - client: Client, - parameters: Prettify> + client: Client, + parameters: Prettify> ): Promise { const { account: account_ = client.account, @@ -56,7 +57,7 @@ export async function uninstallModule< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const uninstallModuleCallData = encodeFunctionData({ abi: [ @@ -87,7 +88,7 @@ export async function uninstallModule< return getAction( client, - sendUserOperation, + sendUserOperation, "sendUserOperation" )({ userOperation: { diff --git a/packages/permissionless/clients/decorators/erc7579.ts b/packages/permissionless/clients/decorators/erc7579.ts index b1ef90db..e169497a 100644 --- a/packages/permissionless/clients/decorators/erc7579.ts +++ b/packages/permissionless/clients/decorators/erc7579.ts @@ -1,11 +1,27 @@ import type { Chain, Client, Hash, Transport } from "viem" import type { SmartAccount } from "../../accounts/types" import { accountId } from "../../actions/erc7579/accountId" -import { installModule } from "../../actions/erc7579/installModule" -import { isModuleInstalled } from "../../actions/erc7579/isModuleInstalled" -import { supportsExecutionMode } from "../../actions/erc7579/supportsExecutionMode" -import { supportsModule } from "../../actions/erc7579/supportsModule" -import { uninstallModule } from "../../actions/erc7579/uninstallModule" +import { + type InstallModuleParameters, + installModule +} from "../../actions/erc7579/installModule" +import { + type IsModuleInstalledParameters, + isModuleInstalled +} from "../../actions/erc7579/isModuleInstalled" +import { + type SupportsExecutionModeParameters, + supportsExecutionMode +} from "../../actions/erc7579/supportsExecutionMode" +import { + type SupportsModuleParameters, + supportsModule +} from "../../actions/erc7579/supportsModule" +import { + type UninstallModuleParameters, + uninstallModule +} from "../../actions/erc7579/uninstallModule" +import type { GetAccountParameter } from "../../types" import type { EntryPoint } from "../../types/entrypoint" export type Erc7579Actions< @@ -50,21 +66,23 @@ export type Erc7579Actions< */ accountId: ( args?: TSmartAccount extends undefined - ? Parameters[1] + ? GetAccountParameter : undefined ) => Promise - installModule: (args: Parameters[1]) => Promise + installModule: ( + args: InstallModuleParameters + ) => Promise isModuleInstalled: ( - args: Parameters[1] + args: IsModuleInstalledParameters ) => Promise supportsExecutionMode: ( - args: Parameters[1] + args: SupportsExecutionModeParameters ) => Promise supportsModule: ( - args: Parameters[1] + args: SupportsModuleParameters ) => Promise uninstallModule: ( - args: Parameters[1] + args: UninstallModuleParameters ) => Promise } @@ -72,18 +90,39 @@ export function erc7579Actions(_args: { entryPoint: TEntryPoint }) { return < + TSmartAccount extends SmartAccount | undefined, TTransport extends Transport, - TChain extends Chain | undefined, - TSmartAccount extends SmartAccount | undefined + TChain extends Chain | undefined >( client: Client ): Erc7579Actions => ({ - accountId: (args) => accountId(client as any, args), - installModule: (args) => installModule(client as any, args), - isModuleInstalled: (args) => isModuleInstalled(client as any, args), + accountId: (args) => accountId(client, args), + installModule: (args) => + installModule( + client, + args + ), + isModuleInstalled: (args) => + isModuleInstalled( + client, + args + ), supportsExecutionMode: (args) => - supportsExecutionMode(client as any, args), - supportsModule: (args) => supportsModule(client as any, args), - uninstallModule: (args) => uninstallModule(client as any, args) + supportsExecutionMode< + TEntryPoint, + TSmartAccount, + TTransport, + TChain + >(client, args), + supportsModule: (args) => + supportsModule( + client, + args + ), + uninstallModule: (args) => + uninstallModule( + client, + args + ) }) } diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index d5d40c6e..486a26c1 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -25,9 +25,7 @@ export type GetAccountParameterWithClient< export type GetAccountParameter< entryPoint extends EntryPoint, - TAccount extends SmartAccount | undefined = - | SmartAccount - | undefined + TAccount extends SmartAccount | undefined > = IsUndefined extends true ? { account: SmartAccount } : { account?: SmartAccount } From 8b54245f6048ad61848f3f358c39b10b52fee600 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 26 Jun 2024 19:21:58 +0100 Subject: [PATCH 04/13] Add all 7579 tests and ability to pass key to getNonce in account --- .../mock-aa-infra/alto/constants.ts | 2 +- .../mock-aa-infra/alto/index.ts | 2 +- packages/permissionless-test/src/utils.ts | 6 +- .../biconomy/signerToBiconomySmartAccount.ts | 9 +- .../kernel/signerToEcdsaKernelSmartAccount.ts | 22 ++- .../light/signerToLightSmartAccount.ts | 9 +- .../accounts/safe/signerToSafeSmartAccount.ts | 17 +- .../simple/signerToSimpleSmartAccount.ts | 9 +- .../permissionless/accounts/toSmartAccount.ts | 2 +- .../trust/signerToTrustSmartAccount.ts | 9 +- packages/permissionless/accounts/types.ts | 2 +- .../actions/erc7579/accountId.test.ts | 177 ++++++++---------- .../actions/erc7579/installModule.test.ts | 43 ++++- .../actions/erc7579/installModule.ts | 4 +- .../actions/erc7579/isModuleInstalled.test.ts | 105 +++++++++++ .../actions/erc7579/isModuleInstalled.ts | 114 +++++++---- .../erc7579/supportsExecutionMode.test.ts | 72 +++++++ .../actions/erc7579/supportsExecutionMode.ts | 82 +++++--- .../actions/erc7579/supportsModule.test.ts | 46 +++++ .../actions/erc7579/supportsModule.ts | 100 ++++++---- .../actions/erc7579/uninstallModule.test.ts | 94 +++++++--- .../actions/erc7579/uninstallModule.ts | 4 +- ...ncodeCallData.ts => encode7579CallData.ts} | 0 23 files changed, 666 insertions(+), 264 deletions(-) create mode 100644 packages/permissionless/actions/erc7579/isModuleInstalled.test.ts create mode 100644 packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts create mode 100644 packages/permissionless/actions/erc7579/supportsModule.test.ts rename packages/permissionless/utils/{encodeCallData.ts => encode7579CallData.ts} (100%) diff --git a/packages/permissionless-test/mock-aa-infra/alto/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts index c997b854..1a59bb4c 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -52,7 +52,7 @@ export const SAFE_MULTI_SEND_CALL_ONLY_CREATECALL: Hex = "0x0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b5061019a806100206000396000f3fe60806040526004361061001e5760003560e01c80638d80ff0a14610023575b600080fd5b6100dc6004803603602081101561003957600080fd5b810190808035906020019064010000000081111561005657600080fd5b82018360208201111561006857600080fd5b8035906020019184600183028401116401000000008311171561008a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506100de565b005b805160205b8181101561015f578083015160f81c6001820184015160601c60158301850151603584018601516055850187016000856000811461012857600181146101385761013d565b6000808585888a5af1915061013d565b600080fd5b50600081141561014c57600080fd5b82605501870196505050505050506100e3565b50505056fea26469706673582212208d297bb003abee230b5dfb38774688f37a6fbb97a82a21728e8049b2acb9b73564736f6c63430007060033" export const SAFE_7579_MODULE_CREATECALL: Hex = - "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50604051601a90605a565b604051809103906000f0801580156035573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790556067565b6109d880614a9483390190565b614a1e806100766000396000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260056020908152604080832054600683528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600560205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b506102386102333660046139e3565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613a3e565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613a89565b6109de565b60405190815260200161020f565b6102b56102b0366004613b38565b610af2565b005b6102b56102c5366004613c1e565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613c5f565b610ba0565b60405161020f929190613c8b565b6102b56103063660046139e3565b610bbc565b34801561031757600080fd5b50610320610d61565b60405161020f9190613d3e565b6102b561033b3660046139e3565b610df3565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613d67565b3360009081526006602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613d84565b610f5f565b6103e26103dd366004613a3e565b611007565b60405161020f9190613d9d565b3480156103fb57600080fd5b5061029461040a366004613e01565b6110d3565b6102b561041d366004613a3e565b611173565b34801561042e57600080fd5b506102ea61043d366004613c5f565b611518565b34801561044e57600080fd5b506102b561045d366004613e4b565b611542565b34801561046e57600080fd5b5061023861047d366004613d84565b6115b1565b34801561048e57600080fd5b50610294611600565b6060806001600160a01b03841615610517576104fe338560006104b8611659565b346000366040516024016104cf9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611665565b9150818060200190518101906105149190613fce565b91505b6001600160a01b0383161561054e57610535338460006104b8611659565b90508080602001905181019061054b9190613fce565b90505b9250929050565b3360009081526004602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61170e565b156106185761060e338388886105e8611659565b6040516020016105fa93929190614002565b604051602081830303815290604052611720565b9350505050610663565b61062381600061170e565b1561065f5761060e338360008989610639611659565b60405160200161064b93929190614002565b604051602081830303815290604052611665565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613d3e565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b1790526117e0565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613d3e565b50505050565b600060018503610706576106ff8461187f565b9050610741565b60028503610717576106ff8461188d565b6003850361072a576106ff8484846118a6565b6004850361073d576106ff8484846118f3565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614028565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e56014828688614041565b6107ee9161406b565b60601c905080158061080657506108048161187f565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614028565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405261192e565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e614041565b6040518563ffffffff1660e01b815260040161091894939291906140a0565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611659565b8a6109798a6014818e614041565b60405160240161098c9493929190613eda565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611720565b9050808060200190518101906109d191906140d7565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611659565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c8261187f565b155b15610a5357610a4c866119a8565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f929190614139565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611665565b905080806020019051810190610ab49190614028565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da03286604051806020016040528060008152506117e0565b50509392505050565b610b24610b026020830183614238565b610b0f6020840184614255565b610b1f606086016040870161429e565b611a4e565b610b348989898989898989611afc565b505050505050505050565b610b4a600233611d3f565b8060005b818110156106e65736848483818110610b6957610b696142b9565b9050602002810190610b7b91906142cf565b9050610b9733610b8e6020840184614238565b60029190611dba565b50600101610b4e565b60606000610bb16002338686611eaf565b915091509250929050565b3360009081526005602090815260408083205460068352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611659565b6001600160a01b03161480610c5d5750610c48611659565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f898989612065565b9050610cfb565b60028a03610ca957610c8f8989896120c1565b60038a03610cbc57610c8f89898961212b565b60048a03610ccf57610c8f89898961226c565b89610cdf57610c8f8989896123eb565b60405163041c38b360e41b8152600481018b90526024016105bd565b600054604051610d549133916001600160a01b0390911690610d25908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612573565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610da3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcb9190810190614319565b905080604051602001610dde9190614361565b60405160208183030381529060405291505090565b33600090815260056020908152604080832054600683528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e3b8484610497565b91509150610e566f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e67611659565b6001600160a01b03161480610e945750610e7f611659565b6001600160a01b0316336001600160a01b0316145b610eb157604051635629665f60e11b815260040160405180910390fd5b606060018a03610ecd57610ec689898961260c565b9050610f06565b60028a03610ee057610ec6898989612635565b60038a03610ef357610ec6898989612662565b60048a03610cdf57610ec68989896126b0565b600054604051610d549133916001600160a01b0390911690610f30908e908e9087906024016142ef565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b179052612768565b600081600881901b610f7582600160f81b61170e565b15610f835760019250610fc6565b610f8e82600061170e565b15610f9c5760019250610fc6565b610fae826001600160f81b031961170e565b15610fbc5760019250610fc6565b5060009392505050565b828015610fd95750610fd981600061170e565b15610fe5575050919050565b828015610ffb5750610ffb81600160f81b61170e565b15610fbc575050919050565b6060611019611014611659565b61188d565b61104a57611025611659565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260056020908152604080832054600683528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110928484610497565b915091503360026110a3828261281e565b8a600881901b6110b581838e8e6128a9565b9950505050506110c784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614028565b336000908152600560209081526040808320546006835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111bb8484610497565b915091506111d66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b03166111e7611659565b6001600160a01b0316148061121457506111ff611659565b6001600160a01b0316336001600160a01b0316145b61123157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361124382600061170e565b156113a65761125683600160f81b61170e565b156112775789358a01602081019035611270838383612c65565b50506114ff565b61128283600061170e565b156112ea576000803660006112978e8e612cbc565b93509350935093506112e185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506117e092505050565b505050506114ff565b6112fc836001600160f81b031961170e565b156113815760006113106014828c8e614041565b6113199161406b565b60601c90503660008c8c601490809261133493929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061257392505050565b5050506114ff565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113b482600160f81b61170e565b156114da576113c783600160f81b61170e565b156113e15789358a01602081019035611270838383612d0d565b6113ec83600061170e565b1561144b576000803660006114018e8e612cbc565b93509350935093506112e185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d6492505050565b61145d836001600160f81b031961170e565b156113815760006114716014828c8e614041565b61147a9161406b565b60601c90503660008c8c601490809261149593929190614041565b91509150611379848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061276892505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061150e84848484610669565b5050505050505050565b33600090815260036020526040812060609190611536818686612e1a565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261155b611659565b6001600160a01b031614806115885750611573611659565b6001600160a01b0316336001600160a01b0316145b6115a557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a4e565b6000600182036115c357506001919050565b600282036115d357506001919050565b600382036115e357506001919050565b600482036115f357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b815260040161169c94939291906143a7565b6000604051808303816000875af11580156116bb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116e391908101906143f2565b925090508061170557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b60606000838360405160240161173792919061443f565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b17905260008054915192935091611783916001600160a01b031690849060240161443f565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a7906118159087908790879087906004016143a7565b6020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118589190614463565b90508061187857604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360023384612fb8565b3360009081526003602052604081206109d78184612ffc565b6000806118b583850185613d67565b3360009081526004602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b600080806119038486018661448d565b9150915060006119138383613036565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b85858560405160200161194e9291906144b9565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ba876130ce565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a11916119f5918990879087906004016140a0565b60006040518083038186803b158015611a0d57600080fd5b505afa925050508015611a1e575060015b611a3557611a2e600184866132e3565b9550611a44565b611a41600084866132e3565b95505b5050505050919050565b3360008181526001602052604080822080546001600160a01b0319166001600160a01b03891617905551611ac092918791611a91908690899089906024016144df565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b1790526117e0565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0602052604090205487906001600160a01b0316611ba957611b45600233611d3f565b60005b81811015611ba357368a8a83818110611b6357611b636142b9565b9050602002810190611b7591906142cf565b9050611b99611b876020830183614238565b611b94602084018461453a565b612065565b5050600101611b48565b50611bca565b8015611bca5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600360205260409020611be28161331b565b86915060005b82811015611c435736898983818110611c0357611c036142b9565b9050602002810190611c1591906142cf565b9050611c39611c276020830183614238565b611c34602084018461453a565b6120c1565b5050600101611be8565b5084915060005b82811015611ca55736878783818110611c6557611c656142b9565b9050602002810190611c7791906142cf565b9050611c9b611c896020830183614238565b611c96602084018461453a565b61212b565b5050600101611c4a565b5082915060005b82811015611d075736858583818110611cc757611cc76142b9565b9050602002810190611cd991906142cf565b9050611cfd611ceb6020830183614238565b611cf8602084018461453a565b61226c565b5050600101611cac565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611d82576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611dd957506001600160a01b0381166001145b15611e0257604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e5157604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611ed55750611ed3868686612fb8565b155b15611efe57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f1f5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f3757611f37613f0c565b604051908082528060200260200182016040528015611f60578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fb057506001600160a01b038216600114155b8015611fbb57508381105b156120205781838281518110611fd357611fd36142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061201881614596565b915050611f8e565b6001600160a01b038216600114612058578261203d6001836145af565b8151811061204d5761204d6142b9565b602002602001015191505b8083525094509492505050565b6060836001612074828261281e565b61208060023388611dba565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026120d0828261281e565b3360009081526003602052604090206120e98188613378565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361213a828261281e565b6000808061214a87890189614613565b919450925090506001600160e01b031983166306d61fe760e41b148061218057506001600160e01b03198316638a91b0e360e01b145b156121aa576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612202576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526004602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b606083600461227b828261281e565b6000808061228b87890189614681565b919450925090506000808460018111156122a7576122a76146af565b1480156122bc57506001600160e01b03198316155b156123325750336000908152600560205260409020546001600160a01b031680156123055760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260056020526040902080546001600160a01b0319166001600160a01b038c161790556123de565b6001846001811115612346576123466146af565b036123c5576001600160a01b0381161561237e5760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526006602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b0319831617909255166123de565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124335760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561252c576000888883818110612452576124526142b9565b905060200201359050600181036124915761248b8d888885818110612479576124796142b9565b9050602002810190611b94919061453a565b50612523565b600281036124c15761248b8d8888858181106124af576124af6142b9565b9050602002810190611c34919061453a565b600381036124f15761248b8d8888858181106124df576124df6142b9565b9050602002810190611c96919061453a565b60048103612523576125218d88888581811061250f5761250f6142b9565b9050602002810190611cf8919061453a565b505b50600101612436565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125a9908690859087906001906004016143a7565b6020604051808303816000875af11580156125c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ec9190614463565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061261c838501856146c5565b9250905061262d600233838861344e565b509392505050565b336000908152600360205260408120606091612653848601866146c5565b93509050610ae9828288613545565b606060006126728385018561470a565b3360009081526004602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b60606000806126c184860186614681565b9450909250905060008260018111156126dc576126dc6146af565b1480156126f157506001600160e01b03198116155b156127185733600090815260056020526040902080546001600160a01b0319169055610ae9565b600182600181111561272c5761272c6146af565b036123c5573360009081526006602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a79061279e908690859087906001906004016143a7565b6020604051808303816000875af11580156127bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e19190614463565b9050806106e657604080516001600160a01b0386168152600060208201526000805160206149c9833981519152910160405180910390a150505050565b336000908152600160205260409020546001600160a01b031680156128a45760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b15801561288b57600080fd5b505afa15801561289f573d6000803e3d6000fd5b505050505b505050565b60606128b685600061170e565b15612aac576128c984600160f81b61170e565b156128ec57823583016020810190356128e333838361361a565b92505050610741565b6128f784600061170e565b156129ab5760008036600061290c8787612cbc565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161292b57905050945061298433858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061166592505050565b85600081518110612997576129976142b9565b602002602001018190525050505050610741565b6129bd846001600160f81b031961170e565b15612a875760006129d16014828587614041565b6129da9161406b565b60601c90503660006129ef8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a09579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061369392505050565b84600081518110612a7457612a746142b9565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612aba85600160f81b61170e565b15612c4057612acd84600160f81b61170e565b15612af25782358301602081019035612ae7338383613734565b935061074192505050565b612afd84600061170e565b15612b8a57600080366000612b128787612cbc565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b3157905050945061298433858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137b692505050565b612b9c846001600160f81b031961170e565b15612a87576000612bb06014828587614041565b612bb99161406b565b60601c9050366000612bce8560148189614041565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612be8579050509350612a61338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387692505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6000546040516128a49185916001600160a01b0390911690612c8d9086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612573565b6000803681612cce6014828789614041565b612cd79161406b565b60601c9350612cea603460148789614041565b612cf3916147d3565b9250612d028560348189614041565b949793965094505050565b6000546040516128a49185916001600160a01b0390911690612d359086908690602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b179052612768565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612d999087908790879087906004016143a7565b6020604051808303816000875af1158015612db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddc9190614463565b90508061187857604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612e3f5750612e3d8585612ffc565b155b15612e6857604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612e895760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612ea157612ea1613f0c565b604051908082528060200260200182016040528015612eca578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f0f57506001600160a01b038216600114155b8015612f1a57508381105b15612f745781838281518110612f3257612f326142b9565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612f6c81614596565b915050612eed565b6001600160a01b038216600114612fac5782612f916001836145af565b81518110612fa157612fa16142b9565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b60008083600181111561304b5761304b6146af565b14801561306057506001600160e01b03198216155b156130805750336000908152600560205260409020546001600160a01b03165b6001836001811115613094576130946146af565b0361066357503360009081526006602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b6060600080368181816130e561010089018961453a565b90925090506130f8600660008385614041565b613101916147f1565b60d01c9550613114600c60068385614041565b61311d916147f1565b60d01c945061312f81600c8185614041565b9350935050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd60001b8152602001336001600160a01b0316815260200188602001358152602001888060400190613195919061453a565b6040516131a392919061481f565b60405190819003902081526020016131be60608a018a61453a565b6040516131cc92919061481f565b604051809103902081526020016131e289613936565b81526020016131f08961394b565b81526020018860a0013581526020016132088961395b565b815260200161321689613970565b815260200161322860e08a018a61453a565b60405161323692919061481f565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff1681526020016132766f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b61329b611600565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561330b57600061330e565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b031615613353576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061339757506001600160a01b0381166001145b156133c057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b03818116600090815260208490526040902054161561340457604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061346d57506001600160a01b0381166001145b1561349657604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020868152604080832087851684529091529020548116908216146134e957604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061356457506001600160a01b0381166001145b1561358d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b038281166000908152602085905260409020548116908216146135d557604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b60008054604051606092916136749187916001600160a01b0316906136459088908890602401614728565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b179052613693565b90508080602001905181019061368a91906148dc565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016136cb94939291906143a7565b6000604051808303816000875af11580156136ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261371291908101906143f2565b925090508061262d57604051632b3f6d1160e21b815260040160405180910390fd5b60608060006137938660008054906101000a90046001600160a01b03168787604051602401613764929190614728565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052613876565b9050808060200190518101906137a99190614910565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016137ed94939291906143a7565b6000604051808303816000875af115801561380c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261383491908101906143f2565b925090508061170557604080516001600160a01b0388168152600060208201526000805160206149c9833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016138ae94939291906143a7565b6000604051808303816000875af11580156138cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f591908101906143f2565b925090508061262d57604080516001600160a01b0387168152600060208201526000805160206149c9833981519152910160405180910390a1509392505050565b60006001600160801b03608083013516610663565b6000610663826080013560801c90565b60006001600160801b0360c083013516610663565b600060c082013560801c610663565b6001600160a01b038116811461399457600080fd5b50565b80356115fb8161397f565b60008083601f8401126139b457600080fd5b5081356001600160401b038111156139cb57600080fd5b60208301915083602082850101111561054e57600080fd5b600080600080606085870312156139f957600080fd5b843593506020850135613a0b8161397f565b925060408501356001600160401b03811115613a2657600080fd5b613a32878288016139a2565b95989497509550505050565b600080600060408486031215613a5357600080fd5b8335925060208401356001600160401b03811115613a7057600080fd5b613a7c868287016139a2565b9497909650939450505050565b600080600060608486031215613a9e57600080fd5b83356001600160401b03811115613ab457600080fd5b84016101208187031215613ac757600080fd5b95602085013595506040909401359392505050565b60008083601f840112613aee57600080fd5b5081356001600160401b03811115613b0557600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613b3257600080fd5b50919050565b600080600080600080600080600060a08a8c031215613b5657600080fd5b89356001600160401b0380821115613b6d57600080fd5b613b798d838e01613adc565b909b50995060208c0135915080821115613b9257600080fd5b613b9e8d838e01613adc565b909950975060408c0135915080821115613bb757600080fd5b613bc38d838e01613adc565b909750955060608c0135915080821115613bdc57600080fd5b613be88d838e01613adc565b909550935060808c0135915080821115613c0157600080fd5b50613c0e8c828d01613b20565b9150509295985092959850929598565b60008060208385031215613c3157600080fd5b82356001600160401b03811115613c4757600080fd5b613c5385828601613adc565b90969095509350505050565b60008060408385031215613c7257600080fd5b8235613c7d8161397f565b946020939093013593505050565b604080825283519082018190526000906020906060840190828701845b82811015613ccd5781516001600160a01b031684529284019290840190600101613ca8565b5050506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613d09578181015183820152602001613cf1565b50506000910152565b60008151808452613d2a816020860160208601613cee565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613d12565b6001600160e01b03198116811461399457600080fd5b600060208284031215613d7957600080fd5b81356109d781613d51565b600060208284031215613d9657600080fd5b5035919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015613df457603f19888603018452613de2858351613d12565b94509285019290850190600101613dc6565b5092979650505050505050565b60008060408385031215613e1457600080fd5b8235613e1f8161397f565b91506020830135613e2f8161397f565b809150509250929050565b803560ff811681146115fb57600080fd5b60008060008060608587031215613e6157600080fd5b8435613e6c8161397f565b935060208501356001600160401b03811115613e8757600080fd5b613e9387828801613adc565b9094509250613ea6905060408601613e3a565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613f02606083018486613eb1565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613f4a57613f4a613f0c565b604052919050565b60006001600160401b03821115613f6b57613f6b613f0c565b50601f01601f191660200190565b6000613f8c613f8784613f52565b613f22565b9050828152838383011115613fa057600080fd5b6109d7836020830184613cee565b600082601f830112613fbf57600080fd5b6109d783835160208501613f79565b600060208284031215613fe057600080fd5b81516001600160401b03811115613ff657600080fd5b61074184828501613fae565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561403a57600080fd5b5051919050565b6000808585111561405157600080fd5b8386111561405e57600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156140985780818660140360031b1b83161692505b505092915050565b8481526060602082015260006140b96060830186613d12565b82810360408401526140cc818587613eb1565b979650505050505050565b6000602082840312156140e957600080fd5b81516109d781613d51565b6000808335601e1984360301811261410b57600080fd5b83016020810192503590506001600160401b0381111561412a57600080fd5b80360382131561054e57600080fd5b6040815261415a6040820161414d85613997565b6001600160a01b03169052565b60208301356060820152600061417360408501856140f4565b61012080608086015261418b61016086018385613eb1565b925061419a60608801886140f4565b9250603f19808786030160a08801526141b4858584613eb1565b9450608089013560c088015260a089013560e0880152610100935060c0890135848801526141e560e08a018a6140f4565b92508188870301848901526141fb868483613eb1565b95505061420a848a018a6140f4565b9450925080878603016101408801525050614226838383613eb1565b93505050508260208301529392505050565b60006020828403121561424a57600080fd5b81356109d78161397f565b6000808335601e1984360301811261426c57600080fd5b8301803591506001600160401b0382111561428657600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156142b057600080fd5b6109d782613e3a565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126142e557600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061368a90830184613d12565b60006020828403121561432b57600080fd5b81516001600160401b0381111561434157600080fd5b8201601f8101841361435257600080fd5b61074184825160208401613f79565b64736166652d60d81b815260008251614381816005850160208701613cee565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006143ce6080830185613d12565b905060ff8316606083015295945050505050565b805180151581146115fb57600080fd5b6000806040838503121561440557600080fd5b61440e836143e2565b915060208301516001600160401b0381111561442957600080fd5b61443585828601613fae565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613d12565b60006020828403121561447557600080fd5b6109d7826143e2565b8035600281106115fb57600080fd5b600080604083850312156144a057600080fd5b6144a98361447e565b91506020830135613e2f81613d51565b828152600082516144d1816020850160208701613cee565b919091016020019392505050565b60ff8416815260406020808301829052908201839052600090849060608401835b8681101561452e5783356145138161397f565b6001600160a01b031682529282019290820190600101614500565b50979650505050505050565b6000808335601e1984360301811261455157600080fd5b8301803591506001600160401b0382111561456b57600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016145a8576145a8614580565b5060010190565b8181038181111561066357610663614580565b600082601f8301126145d357600080fd5b81356145e1613f8782613f52565b8181528460208386010111156145f657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561462857600080fd5b833561463381613d51565b925060208401356001600160f81b03198116811461465057600080fd5b915060408401356001600160401b0381111561466b57600080fd5b614677868287016145c2565b9150509250925092565b60008060006060848603121561469657600080fd5b61469f8461447e565b9250602084013561465081613d51565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156146d857600080fd5b82356146e38161397f565b915060208301356001600160401b038111156146fe57600080fd5b614435858286016145c2565b6000806040838503121561471d57600080fd5b82356146e381613d51565b60208082528181018390526000906040808401600586901b850182018785805b898110156147c457888403603f190185528235368c9003605e1901811261476d578283fd5b8b016060813561477c8161397f565b6001600160a01b03168652818901358987015261479b888301836140f4565b925081898801526147af8288018483613eb1565b978a0197965050509287019250600101614748565b50919998505050505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b6001600160d01b031981358181169160068510156140985760069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561484857614848613f0c565b5060051b60200190565b600082601f83011261486357600080fd5b81516020614873613f878361482f565b82815260059290921b8401810191818101908684111561489257600080fd5b8286015b848110156148d15780516001600160401b038111156148b55760008081fd5b6148c38986838b0101613fae565b845250918301918301614896565b509695505050505050565b6000602082840312156148ee57600080fd5b81516001600160401b0381111561490457600080fd5b61074184828501614852565b6000806040838503121561492357600080fd5b82516001600160401b038082111561493a57600080fd5b818501915085601f83011261494e57600080fd5b8151602061495e613f878361482f565b82815260059290921b8401810191818101908984111561497d57600080fd5b948201945b838610156149a257614993866143e2565b82529482019490820190614982565b918801519196509093505050808211156149bb57600080fd5b506144358582860161485256feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca26469706673582212204c1b68f6eb53965f3e290e9e6a21e9c80395a1ac0fce6394aa58289d799e181864736f6c634300081900336080604052348015600f57600080fd5b506109b98061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106c6565b6100956100ed366004610712565b6102cc565b6100956101003660046107d4565b6102ef565b6100956101133660046107d4565b610398565b61012b6101263660046105c9565b610437565b6040516100b692919061085b565b8060005b8181101561019d5736848483818110610158576101586108b5565b905060200281019061016a91906108cb565b905061019361017c60208301836108eb565b602083013561018e6040850185610906565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108b5565b90506020028101906101d591906108cb565b90506101fe6101e760208301836108eb565b60208301356101f96040850185610906565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e6106fc565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108b5565b905060200281019061029491906108cb565b90506102a661017c60208301836108eb565b8483815181106102b8576102b86108b5565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d9085908590600401610954565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c69085908590600401610954565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff811115610454576104546106fc565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a36106fc565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108b5565b90506020028101906104ff91906108cb565b90506105116101e760208301836108eb565b868481518110610523576105236108b5565b6020026020010186858151811061053c5761053c6108b5565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff808211156105f457600080fd5b818501915085601f83011261060857600080fd5b81358181111561061757600080fd5b8660208260051b850101111561062c57600080fd5b60209290920196919550909350505050565b600082825180855260208086019550808260051b8401018186016000805b858110156106b857601f1980888603018b5283518051808752845b81811015610692578281018901518882018a01528801610677565b5086810188018590529b87019b601f01909116909401850193509184019160010161065c565b509198975050505050505050565b6020815260006106d9602083018461063e565b9392505050565b80356001600160a01b03811681146106f757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072557600080fd5b61072e836106e0565b9150602083013567ffffffffffffffff8082111561074b57600080fd5b818501915085601f83011261075f57600080fd5b813581811115610771576107716106fc565b604051601f8201601f19908116603f01168101908382118183101715610799576107996106fc565b816040528281528860208487010111156107b257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600080606085870312156107ea57600080fd5b843593506107fa602086016106e0565b9250604085013567ffffffffffffffff8082111561081757600080fd5b818701915087601f83011261082b57600080fd5b81358181111561083a57600080fd5b88602082850101111561084c57600080fd5b95989497505060200194505050565b604080825283519082018190526000906020906060840190828701845b82811015610896578151151584529284019290840190600101610878565b50505083810360208501526108ab818661063e565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108e157600080fd5b9190910192915050565b6000602082840312156108fd57600080fd5b6106d9826106e0565b6000808335601e1984360301811261091d57600080fd5b83018035915067ffffffffffffffff82111561093857600080fd5b60200191503681900382131561094d57600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c249fc39b8532ba357c2c2ee22298a8dea37b717dd88be3754b2eeaaa5e1252664736f6c63430008190033" + "0x000000000000000000000000000000000000000000000000000000000000000060a0604052348015600f57600080fd5b50604051601a906046565b604051809103906000f0801580156035573d6000803e3d6000fd5b506001600160a01b03166080526053565b6109f080614bc483390190565b608051614b2c61009860003960008181610d0101528181610f1c0152818161178e01528181612cae01528181612d66015281816136cb01526137f70152614b2c6000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260046020908152604080832054600583528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600460205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b50610238610233366004613aa8565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613b03565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613b4e565b6109de565b60405190815260200161020f565b6102b56102b0366004613bfd565b610af2565b005b6102b56102c5366004613cf9565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613d3a565b610ba0565b60405161020f929190613d66565b6102b5610306366004613aa8565b610bbc565b34801561031757600080fd5b50610320610d71565b60405161020f9190613e19565b6102b561033b366004613aa8565b610e03565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613e42565b3360009081526005602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613e5f565b610f7f565b6103e26103dd366004613b03565b611027565b60405161020f9190613e78565b3480156103fb57600080fd5b5061029461040a366004613edd565b6110f3565b6102b561041d366004613b03565b611193565b34801561042e57600080fd5b506102ea61043d366004613d3a565b611538565b34801561044e57600080fd5b506102b561045d366004613f27565b611562565b34801561046e57600080fd5b5061023861047d366004613e5f565b6115d1565b34801561048e57600080fd5b50610294611620565b6060806001600160a01b03841615610517576104fe338560006104b8611679565b346000366040516024016104cf9493929190613fb6565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611685565b91508180602001905181019061051491906140aa565b91505b6001600160a01b0383161561054e57610535338460006104b8611679565b90508080602001905181019061054b91906140aa565b90505b9250929050565b3360009081526003602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61172e565b156106185761060e338388886105e8611679565b6040516020016105fa939291906140de565b604051602081830303815290604052611740565b9350505050610663565b61062381600061172e565b1561065f5761060e338360008989610639611679565b60405160200161064b939291906140de565b604051602081830303815290604052611685565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613e19565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b179052611815565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613e19565b50505050565b600060018503610706576106ff846118b4565b9050610741565b60028503610717576106ff846118c2565b6003850361072a576106ff8484846118db565b6004850361073d576106ff848484611928565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614104565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e5601482868861411d565b6107ee91614147565b60601c90508015806108065750610804816118b4565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614104565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052611963565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e61411d565b6040518563ffffffff1660e01b81526004016109189493929190614194565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611679565b8a6109798a6014818e61411d565b60405160240161098c9493929190613fb6565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611740565b9050808060200190518101906109d191906141cb565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611679565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c826118b4565b155b15610a5357610a4c866119dd565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f92919061422d565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611685565b905080806020019051810190610ab49190614104565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da0328660405180602001604052806000815250611815565b50509392505050565b610b24610b026020830183614331565b610b0f602084018461434e565b610b1f6060860160408701614397565b611a83565b610b348989898989898989611b31565b505050505050505050565b610b4a600133611d74565b8060005b818110156106e65736848483818110610b6957610b696143b2565b9050602002810190610b7b91906143c8565b9050610b9733610b8e6020840184614331565b60019190611def565b50600101610b4e565b60606000610bb16001338686611ee4565b915091509250929050565b3360009081526004602090815260408083205460058352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611679565b6001600160a01b03161480610c5d5750610c48611679565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f8989896120a8565b9050610cfb565b60028a03610ca957610c8f898989612104565b60038a03610cbc57610c8f89898961216e565b60048a03610ccf57610c8f8989896122af565b89610cdf57610c8f89898961242e565b60405163041c38b360e41b8152600481018b90526024016105bd565b610d64337f00000000000000000000000000000000000000000000000000000000000000008c8c85604051602401610d35939291906143e8565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b1790526125b6565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610db3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ddb9190810190614412565b905080604051602001610dee919061445a565b60405160208183030381529060405291505090565b33600090815260046020908152604080832054600583528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e4b8484610497565b91509150610e666f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e77611679565b6001600160a01b03161480610ea45750610e8f611679565b6001600160a01b0316336001600160a01b0316145b610ec157604051635629665f60e11b815260040160405180910390fd5b606060018a03610edd57610ed689898961264f565b9050610f16565b60028a03610ef057610ed6898989612678565b60038a03610f0357610ed68989896126a5565b60048a03610cdf57610ed68989896126f3565b610d64337f00000000000000000000000000000000000000000000000000000000000000008c8c85604051602401610f50939291906143e8565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b1790526127ab565b600081600881901b610f9582600160f81b61172e565b15610fa35760019250610fe6565b610fae82600061172e565b15610fbc5760019250610fe6565b610fce826001600160f81b031961172e565b15610fdc5760019250610fe6565b5060009392505050565b828015610ff95750610ff981600061172e565b15611005575050919050565b82801561101b575061101b81600160f81b61172e565b15610fdc575050919050565b6060611039611034611679565b6118c2565b61106a57611045611679565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260046020908152604080832054600583528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110b28484610497565b915091503360026110c38282612861565b8a600881901b6110d581838e8e6128ec565b9950505050506110e784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561116f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614104565b336000908152600460209081526040808320546005835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111db8484610497565b915091506111f66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611207611679565b6001600160a01b03161480611234575061121f611679565b6001600160a01b0316336001600160a01b0316145b61125157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361126382600061172e565b156113c65761127683600160f81b61172e565b156112975789358a01602081019035611290838383612ca8565b505061151f565b6112a283600061172e565b1561130a576000803660006112b78e8e612d0f565b935093509350935061130185858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061181592505050565b5050505061151f565b61131c836001600160f81b031961172e565b156113a15760006113306014828c8e61411d565b61133991614147565b60601c90503660008c8c60149080926113549392919061411d565b91509150611399848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506125b692505050565b50505061151f565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113d482600160f81b61172e565b156114fa576113e783600160f81b61172e565b156114015789358a01602081019035611290838383612d60565b61140c83600061172e565b1561146b576000803660006114218e8e612d0f565b935093509350935061130185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dc792505050565b61147d836001600160f81b031961172e565b156113a15760006114916014828c8e61411d565b61149a91614147565b60601c90503660008c8c60149080926114b59392919061411d565b91509150611399848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127ab92505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061152e84848484610669565b5050505050505050565b33600090815260026020526040812060609190611556818686612e7d565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261157b611679565b6001600160a01b031614806115a85750611593611679565b6001600160a01b0316336001600160a01b0316145b6115c557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a83565b6000600182036115e357506001919050565b600282036115f357506001919050565b6003820361160357506001919050565b6004820361161357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016116bc94939291906144a0565b6000604051808303816000875af11580156116db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261170391908101906144eb565b925090508061172557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b606060008383604051602401611757929190614538565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b179052519091506000906117b8907f0000000000000000000000000000000000000000000000000000000000000000908490602401614538565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a79061184a9087908790879087906004016144a0565b6020604051808303816000875af1158015611869573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188d919061455c565b9050806118ad57604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360013384613029565b3360009081526002602052604081206109d7818461306d565b6000806118ea83850185613e42565b3360009081526003602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b6000808061193884860186614586565b91509150600061194883836130a7565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b8585856040516020016119839291906145b2565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ef8761313f565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a1191611a2a91899087908790600401614194565b60006040518083038186803b158015611a4257600080fd5b505afa925050508015611a53575060015b611a6a57611a636001848661338a565b9550611a79565b611a766000848661338a565b95505b5050505050919050565b3360008181526020819052604080822080546001600160a01b0319166001600160a01b03891617905551611af592918791611ac6908690899089906024016145d8565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b179052611815565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f602052604090205487906001600160a01b0316611bde57611b7a600133611d74565b60005b81811015611bd857368a8a83818110611b9857611b986143b2565b9050602002810190611baa91906143c8565b9050611bce611bbc6020830183614331565b611bc96020840184614630565b6120a8565b5050600101611b7d565b50611bff565b8015611bff5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600260205260409020611c17816133c2565b86915060005b82811015611c785736898983818110611c3857611c386143b2565b9050602002810190611c4a91906143c8565b9050611c6e611c5c6020830183614331565b611c696020840184614630565b612104565b5050600101611c1d565b5084915060005b82811015611cda5736878783818110611c9a57611c9a6143b2565b9050602002810190611cac91906143c8565b9050611cd0611cbe6020830183614331565b611ccb6020840184614630565b61216e565b5050600101611c7f565b5082915060005b82811015611d3c5736858583818110611cfc57611cfc6143b2565b9050602002810190611d0e91906143c8565b9050611d32611d206020830183614331565b611d2d6020840184614630565b6122af565b5050600101611ce1565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611db7576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611e0e57506001600160a01b0381166001145b15611e3757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e8657604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611f0a5750611f08868686613029565b155b15611f3357604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f545760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f6c57611f6c613fe8565b604051908082528060200260200182016040528015611f95578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fe557506001600160a01b038216600114155b8015611ff057508381105b156120555781838281518110612008576120086143b2565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061204d8161468c565b915050611fc3565b6001600160a01b03821660011480159061206f5750600081115b1561209b57826120806001836146a5565b81518110612090576120906143b2565b602002602001015191505b8083525094509492505050565b60608360016120b78282612861565b6120c360013388611def565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026121138282612861565b33600090815260026020526040902061212c818861341f565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361217d8282612861565b6000808061218d87890189614709565b919450925090506001600160e01b031983166306d61fe760e41b14806121c357506001600160e01b03198316638a91b0e360e01b145b156121ed576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526003602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612245576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526003602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b60608360046122be8282612861565b600080806122ce87890189614777565b919450925090506000808460018111156122ea576122ea6147a5565b1480156122ff57506001600160e01b03198316155b156123755750336000908152600460205260409020546001600160a01b031680156123485760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260046020526040902080546001600160a01b0319166001600160a01b038c16179055612421565b6001846001811115612389576123896147a5565b03612408576001600160a01b038116156123c15760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526005602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b031983161790925516612421565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124765760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561256f576000888883818110612495576124956143b2565b905060200201359050600181036124d4576124ce8d8888858181106124bc576124bc6143b2565b9050602002810190611bc99190614630565b50612566565b60028103612504576124ce8d8888858181106124f2576124f26143b2565b9050602002810190611c699190614630565b60038103612534576124ce8d888885818110612522576125226143b2565b9050602002810190611ccb9190614630565b60048103612566576125648d888885818110612552576125526143b2565b9050602002810190611d2d9190614630565b505b50600101612479565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125ec908690859087906001906004016144a0565b6020604051808303816000875af115801561260b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262f919061455c565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061265f838501856147bb565b9250905061267060013383886134f5565b509392505050565b336000908152600260205260408120606091612696848601866147bb565b93509050610ae98282886135ec565b606060006126b583850185614800565b3360009081526003602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b606060008061270484860186614777565b94509092509050600082600181111561271f5761271f6147a5565b14801561273457506001600160e01b03198116155b1561275b5733600090815260046020526040902080546001600160a01b0319169055610ae9565b600182600181111561276f5761276f6147a5565b03612408573360009081526005602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906127e1908690859087906001906004016144a0565b6020604051808303816000875af1158015612800573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612824919061455c565b9050806106e657604080516001600160a01b038616815260006020820152600080516020614ad7833981519152910160405180910390a150505050565b336000908152602081905260409020546001600160a01b031680156128e75760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b1580156128ce57600080fd5b505afa1580156128e2573d6000803e3d6000fd5b505050505b505050565b60606128f985600061172e565b15612aef5761290c84600160f81b61172e565b1561292f57823583016020810190356129263383836136c1565b92505050610741565b61293a84600061172e565b156129ee5760008036600061294f8787612d0f565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161296e5790505094506129c733858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061168592505050565b856000815181106129da576129da6143b2565b602002602001018190525050505050610741565b612a00846001600160f81b031961172e565b15612aca576000612a14601482858761411d565b612a1d91614147565b60601c9050366000612a32856014818961411d565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a4c579050509350612aa4338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061374b92505050565b84600081518110612ab757612ab76143b2565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612afd85600160f81b61172e565b15612c8357612b1084600160f81b61172e565b15612b355782358301602081019035612b2a3383836137ec565b935061074192505050565b612b4084600061172e565b15612bcd57600080366000612b558787612d0f565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b745790505094506129c733858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387b92505050565b612bdf846001600160f81b031961172e565b15612aca576000612bf3601482858761411d565b612bfc91614147565b60601c9050366000612c11856014818961411d565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612c2b579050509350612aa4338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061393b92505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6128e7837f00000000000000000000000000000000000000000000000000000000000000008484604051602401612ce092919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b1790526125b6565b6000803681612d21601482878961411d565b612d2a91614147565b60601c9350612d3d60346014878961411d565b612d46916148d0565b9250612d55856034818961411d565b949793965094505050565b6128e7837f00000000000000000000000000000000000000000000000000000000000000008484604051602401612d9892919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b1790526127ab565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612dfc9087908790879087906004016144a0565b6020604051808303816000875af1158015612e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3f919061455c565b9050806118ad57604080516001600160a01b038716815260006020820152600080516020614ad7833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612ea25750612ea0858561306d565b155b15612ecb57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612eec5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612f0457612f04613fe8565b604051908082528060200260200182016040528015612f2d578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f7257506001600160a01b038216600114155b8015612f7d57508381105b15612fd75781838281518110612f9557612f956143b2565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612fcf8161468c565b915050612f50565b6001600160a01b038216600114801590612ff15750600081115b1561301d57826130026001836146a5565b81518110613012576130126143b2565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b6000808360018111156130bc576130bc6147a5565b1480156130d157506001600160e01b03198216155b156130f15750336000908152600460205260409020546001600160a01b03165b6001836001811115613105576131056147a5565b0361066357503360009081526005602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b606060008036818181613156610100890189614630565b909250905061316960066000838561411d565b613172916148ee565b60d01c9550613185600c6006838561411d565b61318e916148ee565b60d01c94506131a081600c818561411d565b9350935050506000604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f60001b81526020018860000160208101906131f09190614331565b6001600160a01b03168152602001886020013581526020018880604001906132189190614630565b604051613226929190614924565b604051908190039020815260200161324160608a018a614630565b60405161324f929190614924565b60405180910390208152602001613265896139fb565b6001600160801b0316815260200161327c89613a0b565b6001600160801b031681526020018860a00135815260200161329d89613a20565b6001600160801b031681526020016132b489613a2f565b6001600160801b031681526020016132cf60e08a018a614630565b6040516132dd929190614924565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff16815260200161331d6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b613342611620565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b856133b25760006133b5565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b0316156133fa576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061343e57506001600160a01b0381166001145b1561346757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020849052604090205416156134ab57604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061351457506001600160a01b0381166001145b1561353d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b03828116600090815260208681526040808320878516845290915290205481169082161461359057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061360b57506001600160a01b0381166001145b1561363457604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020859052604090205481169082161461367c57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b6060600061372c857f000000000000000000000000000000000000000000000000000000000000000086866040516024016136fd92919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b17905261374b565b90508080602001905181019061374291906149e3565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b815260040161378394939291906144a0565b6000604051808303816000875af11580156137a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137ca91908101906144eb565b925090508061267057604051632b3f6d1160e21b815260040160405180910390fd5b6060806000613858867f0000000000000000000000000000000000000000000000000000000000000000878760405160240161382992919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b17905261393b565b90508080602001905181019061386e9190614a17565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016138b294939291906144a0565b6000604051808303816000875af11580156138d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f991908101906144eb565b925090508061172557604080516001600160a01b038816815260006020820152600080516020614ad7833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b815260040161397394939291906144a0565b6000604051808303816000875af1158015613992573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526139ba91908101906144eb565b925090508061267057604080516001600160a01b038716815260006020820152600080516020614ad7833981519152910160405180910390a1509392505050565b6000610663826080013560801c90565b60006001600160801b03608083013516610663565b600060c082013560801c610663565b60006001600160801b0360c083013516610663565b6001600160a01b0381168114613a5957600080fd5b50565b803561161b81613a44565b60008083601f840112613a7957600080fd5b5081356001600160401b03811115613a9057600080fd5b60208301915083602082850101111561054e57600080fd5b60008060008060608587031215613abe57600080fd5b843593506020850135613ad081613a44565b925060408501356001600160401b03811115613aeb57600080fd5b613af787828801613a67565b95989497509550505050565b600080600060408486031215613b1857600080fd5b8335925060208401356001600160401b03811115613b3557600080fd5b613b4186828701613a67565b9497909650939450505050565b600080600060608486031215613b6357600080fd5b83356001600160401b03811115613b7957600080fd5b84016101208187031215613b8c57600080fd5b95602085013595506040909401359392505050565b60008083601f840112613bb357600080fd5b5081356001600160401b03811115613bca57600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613bf757600080fd5b50919050565b600080600080600080600080600060a08a8c031215613c1b57600080fd5b89356001600160401b03811115613c3157600080fd5b613c3d8c828d01613ba1565b909a5098505060208a01356001600160401b03811115613c5c57600080fd5b613c688c828d01613ba1565b90985096505060408a01356001600160401b03811115613c8757600080fd5b613c938c828d01613ba1565b90965094505060608a01356001600160401b03811115613cb257600080fd5b613cbe8c828d01613ba1565b90945092505060808a01356001600160401b03811115613cdd57600080fd5b613ce98c828d01613be5565b9150509295985092959850929598565b60008060208385031215613d0c57600080fd5b82356001600160401b03811115613d2257600080fd5b613d2e85828601613ba1565b90969095509350505050565b60008060408385031215613d4d57600080fd5b8235613d5881613a44565b946020939093013593505050565b6040808252835190820181905260009060208501906060840190835b81811015613da95783516001600160a01b0316835260209384019390920191600101613d82565b50506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613de4578181015183820152602001613dcc565b50506000910152565b60008151808452613e05816020860160208601613dc9565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613ded565b6001600160e01b031981168114613a5957600080fd5b600060208284031215613e5457600080fd5b81356109d781613e2c565b600060208284031215613e7157600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015613ed157603f19878603018452613ebc858351613ded565b94506020938401939190910190600101613ea0565b50929695505050505050565b60008060408385031215613ef057600080fd5b8235613efb81613a44565b91506020830135613f0b81613a44565b809150509250929050565b803560ff8116811461161b57600080fd5b60008060008060608587031215613f3d57600080fd5b8435613f4881613a44565b935060208501356001600160401b03811115613f6357600080fd5b613f6f87828801613ba1565b9094509250613f82905060408601613f16565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613fde606083018486613f8d565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402657614026613fe8565b604052919050565b60006001600160401b0382111561404757614047613fe8565b50601f01601f191660200190565b60006140686140638461402e565b613ffe565b905082815283838301111561407c57600080fd5b6109d7836020830184613dc9565b600082601f83011261409b57600080fd5b6109d783835160208501614055565b6000602082840312156140bc57600080fd5b81516001600160401b038111156140d257600080fd5b6107418482850161408a565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561411657600080fd5b5051919050565b6000808585111561412d57600080fd5b8386111561413a57600080fd5b5050820193919092039150565b80356bffffffffffffffffffffffff19811690601484101561418d576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b8481526060602082015260006141ad6060830186613ded565b82810360408401526141c0818587613f8d565b979650505050505050565b6000602082840312156141dd57600080fd5b81516109d781613e2c565b6000808335601e198436030181126141ff57600080fd5b83016020810192503590506001600160401b0381111561421e57600080fd5b80360382131561054e57600080fd5b6040815261424e6040820161424185613a5c565b6001600160a01b03169052565b60208301356060820152600061426760408501856141e8565b610120608085015261427e61016085018284613f8d565b91505061428e60608601866141e8565b848303603f190160a08601526142a5838284613f8d565b608088013560c08781019190915260a089013560e080890191909152908901356101008801529093506142dd925087019050866141e8565b848303603f19016101208601526142f5838284613f8d565b925050506143076101008601866141e8565b848303603f190161014086015261431f838284613f8d565b93505050508260208301529392505050565b60006020828403121561434357600080fd5b81356109d781613a44565b6000808335601e1984360301811261436557600080fd5b8301803591506001600160401b0382111561437f57600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156143a957600080fd5b6109d782613f16565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126143de57600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061374290830184613ded565b60006020828403121561442457600080fd5b81516001600160401b0381111561443a57600080fd5b8201601f8101841361444b57600080fd5b61074184825160208401614055565b64736166652d60d81b81526000825161447a816005850160208701613dc9565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006144c76080830185613ded565b905060ff8316606083015295945050505050565b8051801515811461161b57600080fd5b600080604083850312156144fe57600080fd5b614507836144db565b915060208301516001600160401b0381111561452257600080fd5b61452e8582860161408a565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613ded565b60006020828403121561456e57600080fd5b6109d7826144db565b80356002811061161b57600080fd5b6000806040838503121561459957600080fd5b6145a283614577565b91506020830135613f0b81613e2c565b828152600082516145ca816020850160208701613dc9565b919091016020019392505050565b60ff84168152604060208201819052810182905260008360608301825b8581101561462557823561460881613a44565b6001600160a01b03168252602092830192909101906001016145f5565b509695505050505050565b6000808335601e1984360301811261464757600080fd5b8301803591506001600160401b0382111561466157600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161469e5761469e614676565b5060010190565b8181038181111561066357610663614676565b600082601f8301126146c957600080fd5b81356146d76140638261402e565b8181528460208386010111156146ec57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561471e57600080fd5b833561472981613e2c565b925060208401356001600160f81b03198116811461474657600080fd5b915060408401356001600160401b0381111561476157600080fd5b61476d868287016146b8565b9150509250925092565b60008060006060848603121561478c57600080fd5b61479584614577565b9250602084013561474681613e2c565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156147ce57600080fd5b82356147d981613a44565b915060208301356001600160401b038111156147f457600080fd5b61452e858286016146b8565b6000806040838503121561481357600080fd5b82356147d981613e2c565b6020808252810182905260006040600584901b830181019083018583605e1936839003015b878210156148c357868503603f19018452823581811261486257600080fd5b8901803561486f81613a44565b6001600160a01b031686526020818101359087015261489160408201826141e8565b9150606060408801526148a8606088018383613f8d565b96505050602083019250602084019350600182019150614843565b5092979650505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b80356001600160d01b0319811690600684101561418d576001600160d01b031960069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561494d5761494d613fe8565b5060051b60200190565b600082601f83011261496857600080fd5b815161497661406382614934565b8082825260208201915060208360051b86010192508583111561499857600080fd5b602085015b838110156149d95780516001600160401b038111156149bb57600080fd5b6149ca886020838a010161408a565b8452506020928301920161499d565b5095945050505050565b6000602082840312156149f557600080fd5b81516001600160401b03811115614a0b57600080fd5b61074184828501614957565b60008060408385031215614a2a57600080fd5b82516001600160401b03811115614a4057600080fd5b8301601f81018513614a5157600080fd5b8051614a5f61406382614934565b8082825260208201915060208360051b850101925087831115614a8157600080fd5b6020840193505b82841015614aaa57614a99846144db565b825260209384019390910190614a88565b8095505050505060208301516001600160401b03811115614aca57600080fd5b61452e8582860161495756feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca2646970667358221220ea61ad763284881149748ddd79675cc8013f934a2a4db1bb658c0c975b908ebb64736f6c634300081a00336080604052348015600f57600080fd5b506109d18061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106d3565b6100956100ed36600461071f565b6102cc565b6100956101003660046107e9565b6102ef565b6100956101133660046107e9565b610398565b61012b6101263660046105c9565b610437565b6040516100b6929190610873565b8060005b8181101561019d5736848483818110610158576101586108cd565b905060200281019061016a91906108e3565b905061019361017c6020830183610903565b602083013561018e604085018561091e565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108cd565b90506020028101906101d591906108e3565b90506101fe6101e76020830183610903565b60208301356101f9604085018561091e565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e610709565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108cd565b905060200281019061029491906108e3565b90506102a661017c6020830183610903565b8483815181106102b8576102b86108cd565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d908590859060040161096c565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c6908590859060040161096c565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff81111561045457610454610709565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a3610709565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108cd565b90506020028101906104ff91906108e3565b90506105116101e76020830183610903565b868481518110610523576105236108cd565b6020026020010186858151811061053c5761053c6108cd565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff8111156105f357600080fd5b8301601f8101851361060457600080fd5b803567ffffffffffffffff81111561061b57600080fd5b8560208260051b840101111561063057600080fd5b6020919091019590945092505050565b600082825180855260208501945060208160051b8301016020850160005b838110156106c757848303601f190188528151805180855260005b8181101561069557602081840181015187830182015201610679565b506000602082870101526020601f19601f8301168601019450505060208201915060208801975060018101905061065e565b50909695505050505050565b6020815260006106e66020830184610640565b9392505050565b80356001600160a01b038116811461070457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561073257600080fd5b61073b836106ed565b9150602083013567ffffffffffffffff81111561075757600080fd5b8301601f8101851361076857600080fd5b803567ffffffffffffffff81111561078257610782610709565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156107b1576107b1610709565b6040528181528282016020018710156107c957600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600080606085870312156107ff57600080fd5b8435935061080f602086016106ed565b9250604085013567ffffffffffffffff81111561082b57600080fd5b8501601f8101871361083c57600080fd5b803567ffffffffffffffff81111561085357600080fd5b87602082840101111561086557600080fd5b949793965060200194505050565b6040808252835190820181905260009060208501906060840190835b818110156108af578351151583526020938401939092019160010161088f565b505083810360208501526108c38186610640565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108f957600080fd5b9190910192915050565b60006020828403121561091557600080fd5b6106e6826106ed565b6000808335601e1984360301811261093557600080fd5b83018035915067ffffffffffffffff82111561095057600080fd5b60200191503681900382131561096557600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220720ef7861d004c898c5584226bd363229b671686bc710cd9ba8dec323c2a769164736f6c634300081a0033" /* ========= V06 CORE ========= */ diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index 274286e0..e1089a9f 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -388,7 +388,7 @@ export const setupContracts = async (rpc: string) => { "0x41675C099F32341bf84BFc5382aF534df5C7461a", // Safe Singleton "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526", // Safe Multi Send "0x9641d764fc13c8B624c04430C7356C1C7C8102e2", // Safe Multi Send Call Only - "0xbaCA6f74a5549368568f387FD989C279f940f1A5", // Safe 7579 module + "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C", // Safe 7579 module "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // EntryPoint V0.6 "0x9406Cc6185a346906296840746125a0E44976454", // Simple Account Factory V0.6 "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", // Biconomy ECDSA Ownership Registry Module diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 25f40421..1b09c245 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -477,9 +477,9 @@ export const getCoreSmartAccounts = () => [ signer: privateKeyToAccount(conf.privateKey), entryPoint: ENTRYPOINT_ADDRESS_V06 }), - // getErc7579SmartAccountClient: async ( - // conf: AAParamType - // ) => getKernelEcdsaClient({ ...conf, erc7579: true }), + getErc7579SmartAccountClient: async ( + conf: AAParamType + ) => getKernelEcdsaClient({ ...conf, erc7579: true }), supportsEntryPointV06: true, supportsEntryPointV07: true, isEip1271Compliant: true diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 8e482254..6866ec36 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -187,6 +187,7 @@ export type SignerToBiconomySmartAccountParameters< TSource extends string = string, TAddress extends Address = Address > = Prettify<{ + nonceKey?: bigint signer: SmartAccountSigner entryPoint: entryPoint address?: Address @@ -229,7 +230,8 @@ export async function signerToBiconomySmartAccount< factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS, accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC, fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS, - ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE + ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE, + nonceKey }: SignerToBiconomySmartAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) @@ -334,10 +336,11 @@ export async function signerToBiconomySmartAccount< source: "biconomySmartAccount", // Get the nonce of the smart account - async getNonce() { + async getNonce(key?: bigint) { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPointAddress + entryPoint: entryPointAddress, + key: key ?? nonceKey }) }, diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 33744000..1b4e3955 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -392,6 +392,7 @@ export type SignerToEcdsaKernelSmartAccountParameters< accountLogicAddress?: Address ecdsaValidatorAddress?: Address deployedAccountAddress?: Address + nonceKey?: bigint }> /** * Build a kernel smart account from a private key, that use the ECDSA signer behind the scene @@ -428,7 +429,8 @@ export async function signerToEcdsaKernelSmartAccount< metaFactoryAddress: _metaFactoryAddress, accountLogicAddress: _accountLogicAddress, ecdsaValidatorAddress: _ecdsaValidatorAddress, - deployedAccountAddress + deployedAccountAddress, + nonceKey }: SignerToEcdsaKernelSmartAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) @@ -548,17 +550,19 @@ export async function signerToEcdsaKernelSmartAccount< source: "kernelEcdsaSmartAccount", // Get the nonce of the smart account - async getNonce() { - const key = getNonceKeyWithEncoding( - kernelVersion, - ecdsaValidatorAddress - // @dev specify the custom nonceKey here when integrating the said feature - /*, nonceKey */ - ) + async getNonce(key?: bigint) { return getAccountNonce(client, { sender: accountAddress, entryPoint: entryPointAddress, - key + key: + key ?? + nonceKey ?? + getNonceKeyWithEncoding( + kernelVersion, + ecdsaValidatorAddress + // @dev specify the custom nonceKey here when integrating the said feature + /*, nonceKey */ + ) }) }, diff --git a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts index 4d3a391f..b73b770b 100644 --- a/packages/permissionless/accounts/light/signerToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/signerToLightSmartAccount.ts @@ -126,6 +126,7 @@ export type SignerToLightSmartAccountParameters< factoryAddress?: Address index?: bigint address?: Address + nonceKey?: bigint }> async function signWith1271WrapperV1< @@ -206,7 +207,8 @@ export async function signerToLightSmartAccount< lightAccountVersion, entryPoint: entryPointAddress, index = BigInt(0), - factoryAddress: _factoryAddress + factoryAddress: _factoryAddress, + nonceKey }: SignerToLightSmartAccountParameters ): Promise> { const viemSigner: LocalAccount = { @@ -275,10 +277,11 @@ export async function signerToLightSmartAccount< publicKey: accountAddress, entryPoint: entryPointAddress, source: "LightSmartAccount", - async getNonce() { + async getNonce(key?: bigint) { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPointAddress + entryPoint: entryPointAddress, + key: key ?? nonceKey }) }, async signUserOperation(userOperation) { diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 36447024..3310d918 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -37,7 +37,7 @@ import type { Prettify } from "../../types" import type { EntryPoint, UserOperation } from "../../types" -import { encode7579CallData } from "../../utils/encodeCallData" +import { encode7579CallData } from "../../utils/encode7579CallData" import { getEntryPointVersion, isUserOperationVersion06, @@ -599,6 +599,7 @@ export type SignerToSafeSmartAccountParameters< validUntil?: number validAfter?: number erc7579?: boolean + nonceKey?: bigint setupTransactions?: { to: Address data: Address @@ -642,7 +643,8 @@ export async function signerToSafeSmartAccount< validAfter = 0, safeModules = [], erc7579, - setupTransactions = [] + setupTransactions = [], + nonceKey }: SignerToSafeSmartAccountParameters ): Promise> { const chainId = client.chain?.id ?? (await getChainId(client)) @@ -751,11 +753,12 @@ export async function signerToSafeSmartAccount< publicKey: accountAddress, entryPoint: entryPointAddress, source: "SafeSmartAccount", - async getNonce() { + async getNonce(key?: bigint) { // TODO: Allow dapp developers to specify custom nonce key (eg: Validator address) return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPointAddress + entryPoint: entryPointAddress, + key: key ?? nonceKey }) }, async signUserOperation( @@ -816,6 +819,12 @@ export async function signerToSafeSmartAccount< } ] + signatures.sort((left, right) => + left.signer + .toLowerCase() + .localeCompare(right.signer.toLowerCase()) + ) + const signatureBytes = concat(signatures.map((sig) => sig.data)) return encodePacked( diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 09f59289..6e571faa 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -119,6 +119,7 @@ export type SignerToSimpleSmartAccountParameters< entryPoint: entryPoint index?: bigint address?: Address + nonceKey?: bigint }> const getFactoryAddress = ( @@ -156,7 +157,8 @@ export async function signerToSimpleSmartAccount< factoryAddress: _factoryAddress, entryPoint: entryPointAddress, index = BigInt(0), - address + address, + nonceKey }: SignerToSimpleSmartAccountParameters ): Promise> { const viemSigner: LocalAccount = { @@ -202,10 +204,11 @@ export async function signerToSimpleSmartAccount< publicKey: accountAddress, entryPoint: entryPointAddress, source: "SimpleSmartAccount", - async getNonce() { + async getNonce(key?: bigint) { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPointAddress + entryPoint: entryPointAddress, + key: key ?? nonceKey }) }, async signUserOperation(userOperation) { diff --git a/packages/permissionless/accounts/toSmartAccount.ts b/packages/permissionless/accounts/toSmartAccount.ts index b5d705af..ecf71957 100644 --- a/packages/permissionless/accounts/toSmartAccount.ts +++ b/packages/permissionless/accounts/toSmartAccount.ts @@ -52,7 +52,7 @@ export function toSmartAccount< source: TSource client: Client entryPoint: TEntryPoint - getNonce: () => Promise + getNonce: (key?: bigint) => Promise getInitCode: () => Promise getFactory: () => Promise

getFactoryData: () => Promise diff --git a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts index 79e65b16..9e1e112f 100644 --- a/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/signerToTrustSmartAccount.ts @@ -88,6 +88,7 @@ export type SignerToTrustSmartAccountParameters< index?: bigint address?: Address secp256k1VerificationFacetAddress?: Address + nonceKey?: bigint } /** @@ -115,7 +116,8 @@ export async function signerToTrustSmartAccount< entryPoint: entryPointAddress, index = 0n, secp256k1VerificationFacetAddress = TRUST_ADDRESSES.secp256k1VerificationFacetAddress, - address + address, + nonceKey }: SignerToTrustSmartAccountParameters ): Promise> { const viemSigner: LocalAccount = { @@ -172,10 +174,11 @@ export async function signerToTrustSmartAccount< hashTypedData(typedData) ) }, - getNonce: async () => { + getNonce: async (key?: bigint) => { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPointAddress + entryPoint: entryPointAddress, + key: key ?? nonceKey }) }, signUserOperation: async (userOperation) => { diff --git a/packages/permissionless/accounts/types.ts b/packages/permissionless/accounts/types.ts index 6a3c45c0..263f8ab6 100644 --- a/packages/permissionless/accounts/types.ts +++ b/packages/permissionless/accounts/types.ts @@ -41,7 +41,7 @@ export type SmartAccount< > = LocalAccount & { client: Client entryPoint: entryPoint - getNonce: () => Promise + getNonce: (key?: bigint) => Promise getInitCode: () => Promise getFactory: () => Promise
getFactoryData: () => Promise diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts index da519a80..568e0059 100644 --- a/packages/permissionless/actions/erc7579/accountId.test.ts +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -1,5 +1,6 @@ import { http, + createPublicClient, encodeAbiParameters, encodePacked, getAddress, @@ -7,11 +8,12 @@ import { zeroAddress } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { foundry } from "viem/chains" +import { foundry, sepolia } from "viem/chains" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, + getPimlicoBundlerClient, getPimlicoPaymasterClient, getPublicClient } from "../../../permissionless-test/src/utils" @@ -28,51 +30,64 @@ import { accountId } from "./accountId" describe.each(getCoreSmartAccounts())( "accountId $name", ({ getErc7579SmartAccountClient }) => { - // testWithRpc.skipIf(!getErc7579SmartAccountClient)( - // "accountId", - // async ({ rpc }) => { - // const { anvilRpc, altoRpc, paymasterRpc } = rpc + // testWithRpc.skipIf(!getErc7579SmartAccountClient)( + // "accountId", + // async ({ rpc }) => { + // const { anvilRpc, altoRpc, paymasterRpc } = rpc - // if (!getErc7579SmartAccountClient) { - // throw new Error("getErc7579SmartAccountClient not defined") - // } + // if (!getErc7579SmartAccountClient) { + // throw new Error("getErc7579SmartAccountClient not defined") + // } - // const smartClient = await getErc7579SmartAccountClient({ - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // privateKey: generatePrivateKey(), - // altoRpc: altoRpc, - // anvilRpc: anvilRpc, - // paymasterClient: getPimlicoPaymasterClient({ + // const smartClient = await getErc7579SmartAccountClient({ // entryPoint: ENTRYPOINT_ADDRESS_V07, - // paymasterRpc + // privateKey: generatePrivateKey(), + // altoRpc: altoRpc, + // anvilRpc: anvilRpc, + // paymasterClient: getPimlicoPaymasterClient({ + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // paymasterRpc + // }) // }) - // }) - // const accountIdBeforeDeploy = await accountId( - // smartClient as any - // ) + // const accountIdBeforeDeploy = await accountId( + // smartClient as any + // ) - // // deploy account - // await smartClient.sendTransaction({ - // to: zeroAddress, - // value: 0n, - // data: "0x" - // }) + // // deploy account + // await smartClient.sendTransaction({ + // to: zeroAddress, + // value: 0n, + // data: "0x" + // }) - // const postDeployAccountId = await accountId(smartClient as any) + // const postDeployAccountId = await accountId(smartClient as any) - // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) - // } - // ) + // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) + // } + // ) + // } testWithRpc.skipIf(!getErc7579SmartAccountClient)( "accountId", async ({ rpc }) => { - const { anvilRpc, altoRpc, paymasterRpc } = rpc + // const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const anvilRpc = + "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" + const altoRpc = + "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + const paymasterRpc = + "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + if (!getErc7579SmartAccountClient) { throw new Error("getErc7579SmartAccountClient not defined") } - const publicClient = getPublicClient(anvilRpc) + const publicClient = createPublicClient({ + transport: http(anvilRpc), + // chain: foundry + chain: sepolia + }) const signer = privateKeyToAccount( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) @@ -89,7 +104,7 @@ describe.each(getCoreSmartAccounts())( entryPoint: ENTRYPOINT_ADDRESS_V07, signer: signer, safeVersion: "1.4.1", - saltNonce: 420n, + saltNonce: 120n, safe4337ModuleAddress: getAddress( "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C" ), @@ -101,11 +116,21 @@ describe.each(getCoreSmartAccounts())( entryPoint: ENTRYPOINT_ADDRESS_V07, paymasterRpc: paymasterRpc }) + + const pimlicoClient = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + altoRpc: altoRpc + }) + const smartClient = createSmartAccountClient({ - chain: foundry, + chain: sepolia, + // chain: foundry, account: safeSmartAccount, bundlerTransport: http(altoRpc), middleware: { + gasPrice: async () => + (await pimlicoClient.getUserOperationGasPrice()) + .fast, sponsorUserOperation: paymasterClient.sponsorUserOperation } @@ -119,6 +144,10 @@ describe.each(getCoreSmartAccounts())( ) const accountIdBeforeDeploy = await smartClient.accountId() + console.log( + "Fetched account id before deploy: ", + accountIdBeforeDeploy + ) const opHashInstallModule = await smartClient.installModule({ type: "execution", @@ -126,7 +155,7 @@ describe.each(getCoreSmartAccounts())( callData: encodePacked( ["address", "bytes"], [ - zeroAddress, + smartClient.account.address, encodeAbiParameters( [{ type: "bytes" }, { type: "bytes" }], [moduleData, "0x"] @@ -135,85 +164,31 @@ describe.each(getCoreSmartAccounts())( ) }) + console.log("Sent user operation: ", opHashInstallModule) + const bundlerClientV07 = createBundlerClient({ transport: http(altoRpc), entryPoint: ENTRYPOINT_ADDRESS_V07 }) - expect(isHash(opHashInstallModule)).toBe(true) - - const userOperationReceiptInstallModule = + const transactionHash = await bundlerClientV07.waitForUserOperationReceipt({ hash: opHashInstallModule, - timeout: 100000 - }) - expect(userOperationReceiptInstallModule).not.toBeNull() - expect(userOperationReceiptInstallModule?.userOpHash).toBe( - opHashInstallModule - ) - expect( - userOperationReceiptInstallModule?.receipt.transactionHash - ).toBeTruthy() - - const accountIdAfterDeploy = await smartClient.accountId() - - expect(accountIdBeforeDeploy).toBe(accountIdAfterDeploy) - - const opHashIsModuleInstalled = - await smartClient.isModuleInstalled({ - type: "execution", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" + timeout: 1000000 }) - expect(opHashIsModuleInstalled).toBe(true) - - const supportsExecutionMode = - await smartClient.supportsExecutionMode({ - callType: "batchcall", - revertOnError: false, - modeSelector: "0x0", - modeData: "0x" - }) - - expect(supportsExecutionMode).toBe(true) - - const supportsModule = await smartClient.supportsModule({ - type: "execution" - }) - - expect(supportsModule).toBe(true) - - const opHashUninstallModule = await smartClient.uninstallModule( - { - type: "execution", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" - } + console.log( + "transactionHash: ", + transactionHash.receipt.transactionHash ) - expect(isHash(opHashUninstallModule)).toBe(true) + const isModuleInstalled = await smartClient.isModuleInstalled({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + }) - const userOperationReceiptUninstallModule = - await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHashUninstallModule, - timeout: 100000 - }) - expect(userOperationReceiptUninstallModule).not.toBeNull() - expect(userOperationReceiptUninstallModule?.userOpHash).toBe( - opHashUninstallModule - ) - expect( - userOperationReceiptUninstallModule?.receipt.transactionHash - ).toBeTruthy() - - expect( - await smartClient.isModuleInstalled({ - type: "execution", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" - }) - ).toBe(false) + console.log("is module installed: ", isModuleInstalled) } ) } diff --git a/packages/permissionless/actions/erc7579/installModule.test.ts b/packages/permissionless/actions/erc7579/installModule.test.ts index c5589fef..a455b741 100644 --- a/packages/permissionless/actions/erc7579/installModule.test.ts +++ b/packages/permissionless/actions/erc7579/installModule.test.ts @@ -1,25 +1,31 @@ import { http, + type Chain, + type Transport, encodeAbiParameters, encodePacked, isHash, zeroAddress } from "viem" -import { generatePrivateKey } from "viem/accounts" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" 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 { createBundlerClient } from "../../clients/createBundlerClient" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import { erc7579Actions } from "../../clients/decorators/erc7579" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" import { installModule } from "./installModule" describe.each(getCoreSmartAccounts())( "installmodule $name", ({ getErc7579SmartAccountClient, name }) => { - testWithRpc.skipIf(!getErc7579SmartAccountClient || name === "Safe")( + testWithRpc.skipIf(!getErc7579SmartAccountClient)( "installModule", async ({ rpc }) => { const { anvilRpc, altoRpc, paymasterRpc } = rpc @@ -28,9 +34,18 @@ describe.each(getCoreSmartAccounts())( throw new Error("getErc7579SmartAccountClient not defined") } - const smartClient = await getErc7579SmartAccountClient({ + const privateKey = generatePrivateKey() + + const eoaAccount = privateKeyToAccount(privateKey) + + const smartClientWithoutExtend: SmartAccountClient< + ENTRYPOINT_ADDRESS_V07_TYPE, + Transport, + Chain, + SmartAccount + > = await getErc7579SmartAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, - privateKey: generatePrivateKey(), + privateKey: privateKey, altoRpc: altoRpc, anvilRpc: anvilRpc, paymasterClient: getPimlicoPaymasterClient({ @@ -39,19 +54,27 @@ describe.each(getCoreSmartAccounts())( }) }) + const smartClient = smartClientWithoutExtend.extend( + erc7579Actions({ + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + ) + const moduleData = encodePacked( ["address"], [smartClient.account.address] ) const opHash = await installModule(smartClient as any, { - account: smartClient.account, + account: smartClient.account as any, type: "execution", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", callData: encodePacked( ["address", "bytes"], [ - zeroAddress, + name === "Kernel" + ? zeroAddress + : eoaAccount.address, encodeAbiParameters( [{ type: "bytes" }, { type: "bytes" }], [moduleData, "0x"] @@ -85,6 +108,14 @@ describe.each(getCoreSmartAccounts())( expect(receipt?.receipt.transactionHash).toBe( userOperationReceipt?.receipt.transactionHash ) + + const isModuleInstalled = await smartClient.isModuleInstalled({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + }) + + expect(isModuleInstalled).toBe(true) } ) } diff --git a/packages/permissionless/actions/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts index 2564d2f9..6eb596b1 100644 --- a/packages/permissionless/actions/erc7579/installModule.ts +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -14,13 +14,13 @@ import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" import type { Middleware } from "../smartAccount/prepareUserOperationRequest" import { sendUserOperation } from "../smartAccount/sendUserOperation" -import { type moduleType, parseModuleTypeId } from "./supportsModule" +import { type ModuleType, parseModuleTypeId } from "./supportsModule" export type InstallModuleParameters< TEntryPoint extends EntryPoint, TSmartAccount extends SmartAccount | undefined > = GetAccountParameter & { - type: moduleType + type: ModuleType address: Address callData: Hex maxFeePerGas?: bigint diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts new file mode 100644 index 00000000..2d018e70 --- /dev/null +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts @@ -0,0 +1,105 @@ +import { + http, + type Chain, + type Transport, + encodeAbiParameters, + encodePacked, + zeroAddress +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +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 { createBundlerClient } from "../../clients/createBundlerClient" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import { erc7579Actions } from "../../clients/decorators/erc7579" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { installModule } from "./installModule" + +describe.each(getCoreSmartAccounts())( + "isModuleInstalled $name", + ({ getErc7579SmartAccountClient, name }) => { + testWithRpc.skipIf(!getErc7579SmartAccountClient)( + "isModuleInstalled", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + + const privateKey = generatePrivateKey() + + const eoaAccount = privateKeyToAccount(privateKey) + + const smartClientWithoutExtend: SmartAccountClient< + ENTRYPOINT_ADDRESS_V07_TYPE, + Transport, + Chain, + SmartAccount + > = await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: privateKey, + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const smartClient = smartClientWithoutExtend.extend( + erc7579Actions({ + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + ) + + const moduleData = encodePacked( + ["address"], + [smartClient.account.address] + ) + + const opHash = await installModule(smartClient as any, { + account: smartClient.account as any, + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: encodePacked( + ["address", "bytes"], + [ + name === "Kernel" + ? zeroAddress + : eoaAccount.address, + encodeAbiParameters( + [{ type: "bytes" }, { type: "bytes" }], + [moduleData, "0x"] + ) + ] + ) + }) + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + + const isModuleInstalled = await smartClient.isModuleInstalled({ + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + }) + + expect(isModuleInstalled).toBe(true) + } + ) + } +) diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.ts index 8cb84ee0..db7f2e34 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.ts @@ -1,10 +1,19 @@ -import type { Address, Chain, Client, Hex, Transport } from "viem" +import { + type Address, + type Chain, + type Client, + ContractFunctionExecutionError, + type Hex, + type Transport, + decodeFunctionResult, + encodeFunctionData +} from "viem" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -import { type moduleType, parseModuleTypeId } from "./supportsModule" +import { type ModuleType, parseModuleTypeId } from "./supportsModule" export type IsModuleInstalledParameters< TEntryPoint extends EntryPoint, @@ -12,7 +21,7 @@ export type IsModuleInstalledParameters< | SmartAccount | undefined > = GetAccountParameter & { - type: moduleType + type: ModuleType address: Address callData: Hex } @@ -38,38 +47,71 @@ export async function isModuleInstalled< const publicClient = account.client - /** - * TODO: counterfactual - */ - return publicClient.readContract({ - abi: [ - { - name: "isModuleInstalled", - type: "function", - stateMutability: "view", - inputs: [ - { - type: "uint256", - name: "moduleTypeId" - }, - { - type: "address", - name: "module" - }, - { - type: "bytes", - name: "additionalContext" - } - ], - outputs: [ - { - type: "bool" - } - ] + const abi = [ + { + name: "isModuleInstalled", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "additionalContext" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ] as const + + try { + return await publicClient.readContract({ + abi, + functionName: "isModuleInstalled", + args: [parseModuleTypeId(parameters.type), address, callData], + address: account.address + }) + } catch (error) { + if (error instanceof ContractFunctionExecutionError) { + const factory = await account.getFactory() + const factoryData = await account.getFactoryData() + + const result = await publicClient.call({ + factory: factory, + factoryData: factoryData, + to: account.address, + data: encodeFunctionData({ + abi, + functionName: "isModuleInstalled", + args: [ + parseModuleTypeId(parameters.type), + address, + callData + ] + }) + }) + + if (!result || !result.data) { + throw new Error("accountId result is empty") } - ], - functionName: "isModuleInstalled", - args: [parseModuleTypeId(parameters.type), address, callData], - address: account.address - }) + + return decodeFunctionResult({ + abi, + functionName: "isModuleInstalled", + data: result.data + }) + } + + throw error + } } diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts new file mode 100644 index 00000000..1548a86d --- /dev/null +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts @@ -0,0 +1,72 @@ +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_V07 } from "../../utils" +import { supportsExecutionMode } from "./supportsExecutionMode" + +describe.each(getCoreSmartAccounts())( + "supportsExecutionMode $name", + ({ getErc7579SmartAccountClient }) => { + testWithRpc.skipIf(!getErc7579SmartAccountClient)( + "supportsExecutionMode", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + + const smartClient = await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const supportsExecutionModeBatchCallBeforeDeploy = + await supportsExecutionMode(smartClient as any, { + account: smartClient.account as any, + callType: "batchcall", + revertOnError: false, + modeSelector: "0x0", + modeData: "0x" + }) + + expect(supportsExecutionModeBatchCallBeforeDeploy).toBe(true) + + // deploy account + await smartClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + const supportsExecutionModeBatchCallBeforeDeployPostDeploy = + await supportsExecutionMode(smartClient as any, { + account: smartClient.account as any, + callType: "batchcall", + revertOnError: false, + modeSelector: "0x0", + modeData: "0x" + }) + + expect( + supportsExecutionModeBatchCallBeforeDeployPostDeploy + ).toBe(true) + + expect(supportsExecutionModeBatchCallBeforeDeploy).toBe( + supportsExecutionModeBatchCallBeforeDeployPostDeploy + ) + } + ) + } +) diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts index 5e25a5de..ecce9994 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -1,8 +1,11 @@ import { type Chain, type Client, + ContractFunctionExecutionError, type Hex, type Transport, + decodeFunctionResult, + encodeFunctionData, encodePacked, toBytes, toHex @@ -92,30 +95,59 @@ export async function supportsExecutionMode< modeData }) - /** - * TODO: counterfactual - */ - return publicClient.readContract({ - abi: [ - { - name: "supportsExecutionMode", - type: "function", - stateMutability: "view", - inputs: [ - { - type: "bytes32", - name: "encodedMode" - } - ], - outputs: [ - { - type: "bool" - } - ] + const abi = [ + { + name: "supportsExecutionMode", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "bytes32", + name: "encodedMode" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ] as const + + try { + return await publicClient.readContract({ + abi, + functionName: "supportsExecutionMode", + args: [encodedMode], + address: account.address + }) + } catch (error) { + if (error instanceof ContractFunctionExecutionError) { + const factory = await account.getFactory() + const factoryData = await account.getFactoryData() + + const result = await publicClient.call({ + factory: factory, + factoryData: factoryData, + to: account.address, + data: encodeFunctionData({ + abi, + functionName: "supportsExecutionMode", + args: [encodedMode] + }) + }) + + if (!result || !result.data) { + throw new Error("accountId result is empty") } - ], - functionName: "supportsExecutionMode", - args: [encodedMode], - address: account.address - }) + + return decodeFunctionResult({ + abi, + functionName: "supportsExecutionMode", + data: result.data + }) + } + + throw error + } } diff --git a/packages/permissionless/actions/erc7579/supportsModule.test.ts b/packages/permissionless/actions/erc7579/supportsModule.test.ts new file mode 100644 index 00000000..d527d0c6 --- /dev/null +++ b/packages/permissionless/actions/erc7579/supportsModule.test.ts @@ -0,0 +1,46 @@ +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_V07 } from "../../utils" +import { supportsModule } from "./supportsModule" + +describe.each(getCoreSmartAccounts())( + "supportsModule $name", + ({ getErc7579SmartAccountClient }) => { + testWithRpc.skipIf(!getErc7579SmartAccountClient)( + "supportsModule", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + if (!getErc7579SmartAccountClient) { + throw new Error("getErc7579SmartAccountClient not defined") + } + + const smartClient = await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const supportsValidationModule = await supportsModule( + smartClient as any, + { + account: smartClient.account as any, + type: "validation" + } + ) + + expect(supportsValidationModule).toBe(true) + } + ) + } +) diff --git a/packages/permissionless/actions/erc7579/supportsModule.ts b/packages/permissionless/actions/erc7579/supportsModule.ts index f4c38436..489789c4 100644 --- a/packages/permissionless/actions/erc7579/supportsModule.ts +++ b/packages/permissionless/actions/erc7579/supportsModule.ts @@ -1,11 +1,18 @@ -import type { Chain, Client, Transport } from "viem" +import { + type Chain, + type Client, + ContractFunctionExecutionError, + type Transport, + decodeFunctionResult, + encodeFunctionData +} from "viem" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -export type moduleType = "validation" | "execution" | "fallback" | "hooks" +export type ModuleType = "validator" | "executor" | "fallback" | "hook" export type SupportsModuleParameters< TEntryPoint extends EntryPoint, @@ -13,18 +20,18 @@ export type SupportsModuleParameters< | SmartAccount | undefined > = GetAccountParameter & { - type: moduleType + type: ModuleType } -export function parseModuleTypeId(type: moduleType): bigint { +export function parseModuleTypeId(type: ModuleType): bigint { switch (type) { - case "validation": + case "validator": return BigInt(1) - case "execution": + case "executor": return BigInt(2) case "fallback": return BigInt(3) - case "hooks": + case "hook": return BigInt(4) default: throw new Error("Invalid module type") @@ -52,30 +59,59 @@ export async function supportsModule< const publicClient = account.client - /** - * TODO: counterfactual - */ - return publicClient.readContract({ - abi: [ - { - name: "supportsModule", - type: "function", - stateMutability: "view", - inputs: [ - { - type: "uint256", - name: "moduleTypeId" - } - ], - outputs: [ - { - type: "bool" - } - ] + const abi = [ + { + name: "supportsModule", + type: "function", + stateMutability: "view", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + } + ], + outputs: [ + { + type: "bool" + } + ] + } + ] as const + + try { + return await publicClient.readContract({ + abi, + functionName: "supportsModule", + args: [parseModuleTypeId(args.type)], + address: account.address + }) + } catch (error) { + if (error instanceof ContractFunctionExecutionError) { + const factory = await account.getFactory() + const factoryData = await account.getFactoryData() + + const result = await publicClient.call({ + factory: factory, + factoryData: factoryData, + to: account.address, + data: encodeFunctionData({ + abi, + functionName: "supportsModule", + args: [parseModuleTypeId(args.type)] + }) + }) + + if (!result || !result.data) { + throw new Error("accountId result is empty") } - ], - functionName: "supportsModule", - args: [parseModuleTypeId(args.type)], - address: account.address - }) + + return decodeFunctionResult({ + abi, + functionName: "supportsModule", + data: result.data + }) + } + + throw error + } } diff --git a/packages/permissionless/actions/erc7579/uninstallModule.test.ts b/packages/permissionless/actions/erc7579/uninstallModule.test.ts index 1877d608..c95cabcc 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.test.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.test.ts @@ -1,27 +1,32 @@ import { http, + type Chain, + type Transport, encodeAbiParameters, encodePacked, isHash, zeroAddress } from "viem" -import { generatePrivateKey } from "viem/accounts" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" 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 { createBundlerClient } from "../../clients/createBundlerClient" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" import { erc7579Actions } from "../../clients/decorators/erc7579" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" -import { installModule } from "./installModule" +import { uninstallModule } from "./uninstallModule" describe.each(getCoreSmartAccounts())( - "installmodule $name", + "uninstallModule $name", ({ getErc7579SmartAccountClient, name }) => { - testWithRpc.skipIf(!getErc7579SmartAccountClient || name === "Safe")( - "installModule", + testWithRpc.skipIf(!getErc7579SmartAccountClient)( + "uninstallModule", async ({ rpc }) => { const { anvilRpc, altoRpc, paymasterRpc } = rpc @@ -29,31 +34,46 @@ describe.each(getCoreSmartAccounts())( throw new Error("getErc7579SmartAccountClient not defined") } - const smartClient = ( - await getErc7579SmartAccountClient({ + const privateKey = generatePrivateKey() + + const eoaAccount = privateKeyToAccount(privateKey) + + const smartClientWithoutExtend: SmartAccountClient< + ENTRYPOINT_ADDRESS_V07_TYPE, + Transport, + Chain, + SmartAccount + > = await getErc7579SmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: privateKey, + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, - privateKey: generatePrivateKey(), - altoRpc: altoRpc, - anvilRpc: anvilRpc, - paymasterClient: getPimlicoPaymasterClient({ - entryPoint: ENTRYPOINT_ADDRESS_V07, - paymasterRpc - }) + paymasterRpc }) - ).extend(erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 })) + }) + + const smartClient = smartClientWithoutExtend.extend( + erc7579Actions({ + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + ) const moduleData = encodePacked( ["address"], [smartClient.account.address] ) - await smartClient.installModule({ + const opHash = await smartClient.installModule({ type: "execution", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", callData: encodePacked( ["address", "bytes"], [ - zeroAddress, + name === "Kernel" + ? zeroAddress + : eoaAccount.address, encodeAbiParameters( [{ type: "bytes" }, { type: "bytes" }], [moduleData, "0x"] @@ -67,25 +87,43 @@ describe.each(getCoreSmartAccounts())( entryPoint: ENTRYPOINT_ADDRESS_V07 }) - expect(isHash(opHash)).toBe(true) + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) - const userOperationReceipt = + const uninstallModuleUserOpHash = await uninstallModule( + smartClient as any, + { + account: smartClient.account as any, + type: "execution", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + callData: "0x" + } + ) + + expect(isHash(uninstallModuleUserOpHash)).toBe(true) + + const userOperationReceiptUninstallModule = await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash, + hash: uninstallModuleUserOpHash, timeout: 100000 }) - expect(userOperationReceipt).not.toBeNull() - expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceiptUninstallModule).not.toBeNull() + expect(userOperationReceiptUninstallModule?.userOpHash).toBe( + uninstallModuleUserOpHash + ) expect( - userOperationReceipt?.receipt.transactionHash + userOperationReceiptUninstallModule?.receipt.transactionHash ).toBeTruthy() - const receipt = await bundlerClientV07.getUserOperationReceipt({ - hash: opHash - }) + const receiptUninstallModule = + await bundlerClientV07.getUserOperationReceipt({ + hash: uninstallModuleUserOpHash + }) - expect(receipt?.receipt.transactionHash).toBe( - userOperationReceipt?.receipt.transactionHash + expect(receiptUninstallModule?.receipt.transactionHash).toBe( + userOperationReceiptUninstallModule?.receipt.transactionHash ) } ) diff --git a/packages/permissionless/actions/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts index 8d00b8b3..a6af4fee 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -14,7 +14,7 @@ import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" import type { Middleware } from "../smartAccount/prepareUserOperationRequest" import { sendUserOperation } from "../smartAccount/sendUserOperation" -import { type moduleType, parseModuleTypeId } from "./supportsModule" +import { type ModuleType, parseModuleTypeId } from "./supportsModule" export type UninstallModuleParameters< TEntryPoint extends EntryPoint, @@ -22,7 +22,7 @@ export type UninstallModuleParameters< | SmartAccount | undefined > = GetAccountParameter & { - type: moduleType + type: ModuleType address: Address callData: Hex maxFeePerGas?: bigint diff --git a/packages/permissionless/utils/encodeCallData.ts b/packages/permissionless/utils/encode7579CallData.ts similarity index 100% rename from packages/permissionless/utils/encodeCallData.ts rename to packages/permissionless/utils/encode7579CallData.ts From f24f493f333d4ae4b9b09ccbcf4e2101c52056e3 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 26 Jun 2024 19:26:15 +0100 Subject: [PATCH 05/13] Change callType to type --- .../accounts/safe/signerToSafeSmartAccount.ts | 2 +- .../actions/erc7579/supportsExecutionMode.ts | 10 +++++----- packages/permissionless/utils/encode7579CallData.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 3310d918..a77f8ca3 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -882,7 +882,7 @@ export async function signerToSafeSmartAccount< if (erc7579) { return encode7579CallData({ mode: { - callType: isArray ? "batchcall" : "call", + type: isArray ? "batchcall" : "call", revertOnError: false, modeSelector: "0x", modeData: "0x" diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts index ecce9994..1ab45857 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -19,7 +19,7 @@ import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashW export type CallType = "call" | "delegatecall" | "batchcall" export type ExecutionMode = { - callType: CallType + type: CallType revertOnError: boolean modeSelector: Hex modeData: Hex @@ -44,7 +44,7 @@ function parseCallType(executionMode: CallType) { } export function encodeExecutionMode({ - callType, + type, revertOnError, modeSelector, modeData @@ -52,7 +52,7 @@ export function encodeExecutionMode({ return encodePacked( ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], [ - toHex(toBytes(parseCallType(callType), { size: 1 })), + toHex(toBytes(parseCallType(type), { size: 1 })), toHex(toBytes(revertOnError ? "0x01" : "0x00", { size: 1 })), toHex(toBytes("0x0", { size: 4 })), toHex(toBytes(modeSelector, { size: 4 })), @@ -72,7 +72,7 @@ export async function supportsExecutionMode< ): Promise { const { account: account_ = client.account, - callType, + type, revertOnError, modeSelector, modeData @@ -89,7 +89,7 @@ export async function supportsExecutionMode< const publicClient = account.client const encodedMode = encodeExecutionMode({ - callType, + type, revertOnError, modeSelector, modeData diff --git a/packages/permissionless/utils/encode7579CallData.ts b/packages/permissionless/utils/encode7579CallData.ts index 2d643720..ffea79c0 100644 --- a/packages/permissionless/utils/encode7579CallData.ts +++ b/packages/permissionless/utils/encode7579CallData.ts @@ -13,7 +13,7 @@ import { export type EncodeCallDataParams = { mode: executionMode - callData: executionMode["callType"] extends "batchcall" + callData: executionMode["type"] extends "batchcall" ? { to: Address value: bigint @@ -30,7 +30,7 @@ export function encode7579CallData({ mode, callData }: EncodeCallDataParams): Hex { - if (Array.isArray(callData) && mode?.callType !== "batchcall") { + if (Array.isArray(callData) && mode?.type !== "batchcall") { throw new Error( `mode ${mode} does not supported for batchcall calldata` ) From b38f28152000f510cd6ead02d2ff9d6be02f5a2c Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Wed, 26 Jun 2024 23:06:38 +0100 Subject: [PATCH 06/13] rename calldata -> context --- .../actions/erc7579/accountId.test.ts | 271 +++++++++--------- .../actions/erc7579/installModule.test.ts | 34 ++- .../actions/erc7579/installModule.ts | 9 +- .../actions/erc7579/isModuleInstalled.test.ts | 34 ++- .../actions/erc7579/isModuleInstalled.ts | 17 +- .../erc7579/supportsExecutionMode.test.ts | 4 +- .../actions/erc7579/supportsModule.test.ts | 2 +- .../actions/erc7579/uninstallModule.test.ts | 34 ++- .../actions/erc7579/uninstallModule.ts | 9 +- 9 files changed, 209 insertions(+), 205 deletions(-) diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts index 568e0059..fd96d916 100644 --- a/packages/permissionless/actions/erc7579/accountId.test.ts +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -30,166 +30,151 @@ import { accountId } from "./accountId" describe.each(getCoreSmartAccounts())( "accountId $name", ({ getErc7579SmartAccountClient }) => { - // testWithRpc.skipIf(!getErc7579SmartAccountClient)( - // "accountId", - // async ({ rpc }) => { - // const { anvilRpc, altoRpc, paymasterRpc } = rpc - - // if (!getErc7579SmartAccountClient) { - // throw new Error("getErc7579SmartAccountClient not defined") - // } - - // const smartClient = await getErc7579SmartAccountClient({ - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // privateKey: generatePrivateKey(), - // altoRpc: altoRpc, - // anvilRpc: anvilRpc, - // paymasterClient: getPimlicoPaymasterClient({ - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // paymasterRpc - // }) - // }) - - // const accountIdBeforeDeploy = await accountId( - // smartClient as any - // ) - - // // deploy account - // await smartClient.sendTransaction({ - // to: zeroAddress, - // value: 0n, - // data: "0x" - // }) - - // const postDeployAccountId = await accountId(smartClient as any) - - // expect(accountIdBeforeDeploy).toBe(postDeployAccountId) - // } - // ) - // } - testWithRpc.skipIf(!getErc7579SmartAccountClient)( "accountId", async ({ rpc }) => { - // const { anvilRpc, altoRpc, paymasterRpc } = rpc - - const anvilRpc = - "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" - const altoRpc = - "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" - const paymasterRpc = - "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + const { anvilRpc, altoRpc, paymasterRpc } = rpc if (!getErc7579SmartAccountClient) { throw new Error("getErc7579SmartAccountClient not defined") } - const publicClient = createPublicClient({ - transport: http(anvilRpc), - // chain: foundry - chain: sepolia - }) - const signer = privateKeyToAccount( - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ) - // const kernelSmartAccount = - // await signerToEcdsaKernelSmartAccount(publicClient, { - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // signer: signer, - // version: "0.3.0" - // }) - - const safeSmartAccount = await signerToSafeSmartAccount( - publicClient, - { - entryPoint: ENTRYPOINT_ADDRESS_V07, - signer: signer, - safeVersion: "1.4.1", - saltNonce: 120n, - safe4337ModuleAddress: getAddress( - "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C" - ), - erc7579: true - } - ) - const paymasterClient = getPimlicoPaymasterClient({ + const smartClient = await getErc7579SmartAccountClient({ entryPoint: ENTRYPOINT_ADDRESS_V07, - paymasterRpc: paymasterRpc - }) - - const pimlicoClient = getPimlicoBundlerClient({ - entryPoint: ENTRYPOINT_ADDRESS_V07, - altoRpc: altoRpc + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) }) - const smartClient = createSmartAccountClient({ - chain: sepolia, - // chain: foundry, - account: safeSmartAccount, - bundlerTransport: http(altoRpc), - middleware: { - gasPrice: async () => - (await pimlicoClient.getUserOperationGasPrice()) - .fast, - sponsorUserOperation: - paymasterClient.sponsorUserOperation - } - }).extend( - erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 }) - ) - - const moduleData = encodePacked( - ["address"], - [smartClient.account.address] - ) - - const accountIdBeforeDeploy = await smartClient.accountId() - console.log( - "Fetched account id before deploy: ", - accountIdBeforeDeploy + const accountIdBeforeDeploy = await accountId( + smartClient as any ) - const opHashInstallModule = await smartClient.installModule({ - type: "execution", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: encodePacked( - ["address", "bytes"], - [ - smartClient.account.address, - encodeAbiParameters( - [{ type: "bytes" }, { type: "bytes" }], - [moduleData, "0x"] - ) - ] - ) - }) - - console.log("Sent user operation: ", opHashInstallModule) - - const bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 + // deploy account + await smartClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" }) - const transactionHash = - await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHashInstallModule, - timeout: 1000000 - }) - - console.log( - "transactionHash: ", - transactionHash.receipt.transactionHash - ) + const postDeployAccountId = await accountId(smartClient as any) - const isModuleInstalled = await smartClient.isModuleInstalled({ - type: "execution", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" - }) - - console.log("is module installed: ", isModuleInstalled) + expect(accountIdBeforeDeploy).toBe(postDeployAccountId) } ) } + + // testWithRpc.skipIf(!getErc7579SmartAccountClient)( + // "accountId", + // async ({ rpc }) => { + // const { anvilRpc, altoRpc, paymasterRpc } = rpc + + // // const anvilRpc = + // // "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" + // // const altoRpc = + // // "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + // // const paymasterRpc = + // // "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" + + // if (!getErc7579SmartAccountClient) { + // throw new Error("getErc7579SmartAccountClient not defined") + // } + // const publicClient = createPublicClient({ + // transport: http(anvilRpc), + // chain: foundry + // // chain: sepolia + // }) + // const signer = privateKeyToAccount( + // generatePrivateKey() + // // "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + // ) + // // const kernelSmartAccount = + // // await signerToEcdsaKernelSmartAccount(publicClient, { + // // entryPoint: ENTRYPOINT_ADDRESS_V07, + // // signer: signer, + // // version: "0.3.0" + // // }) + + // const safeSmartAccount = await signerToSafeSmartAccount( + // publicClient, + // { + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // signer: signer, + // safeVersion: "1.4.1", + // saltNonce: 120n, + // safe4337ModuleAddress: getAddress( + // "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C" + // ), + // erc7579: true + // } + // ) + + // const paymasterClient = getPimlicoPaymasterClient({ + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // paymasterRpc: paymasterRpc + // }) + + // const pimlicoClient = getPimlicoBundlerClient({ + // entryPoint: ENTRYPOINT_ADDRESS_V07, + // altoRpc: altoRpc + // }) + + // const smartClient = createSmartAccountClient({ + // // chain: sepolia, + // chain: foundry, + // account: safeSmartAccount, + // bundlerTransport: http(altoRpc), + // middleware: { + // gasPrice: async () => + // (await pimlicoClient.getUserOperationGasPrice()) + // .fast, + // sponsorUserOperation: + // paymasterClient.sponsorUserOperation + // } + // }).extend( + // erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 }) + // ) + + // const moduleData = encodePacked(["address"], [signer.address]) + + // const opHashInstallModule = await smartClient.installModule({ + // type: "executor", + // address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + // context: moduleData + // }) + + // console.log("Sent user operation: ", opHashInstallModule) + + // const bundlerClientV07 = createBundlerClient({ + // transport: http(altoRpc), + // entryPoint: ENTRYPOINT_ADDRESS_V07 + // }) + + // const transactionHash = + // await bundlerClientV07.waitForUserOperationReceipt({ + // hash: opHashInstallModule, + // timeout: 1000000 + // }) + + // console.log( + // "transactionHash: ", + // transactionHash.receipt.transactionHash + // ) + + // const isModuleInstalled = await smartClient.isModuleInstalled({ + // type: "executor", + // address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + // context: "0x" + // }) + + // console.log("is module installed: ", isModuleInstalled) + + // expect(isModuleInstalled).toBe(true) + // } + // ) + // } ) diff --git a/packages/permissionless/actions/erc7579/installModule.test.ts b/packages/permissionless/actions/erc7579/installModule.test.ts index a455b741..3e31ea7e 100644 --- a/packages/permissionless/actions/erc7579/installModule.test.ts +++ b/packages/permissionless/actions/erc7579/installModule.test.ts @@ -67,20 +67,24 @@ describe.each(getCoreSmartAccounts())( const opHash = await installModule(smartClient as any, { account: smartClient.account as any, - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: encodePacked( - ["address", "bytes"], - [ - name === "Kernel" - ? zeroAddress - : eoaAccount.address, - encodeAbiParameters( - [{ type: "bytes" }, { type: "bytes" }], - [moduleData, "0x"] - ) - ] - ) + context: + name === "Kernel" + ? encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [ + { type: "bytes" }, + { type: "bytes" } + ], + [moduleData, "0x"] + ) + ] + ) + : moduleData }) const bundlerClientV07 = createBundlerClient({ @@ -110,9 +114,9 @@ describe.each(getCoreSmartAccounts())( ) const isModuleInstalled = await smartClient.isModuleInstalled({ - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" + context: "0x" }) expect(isModuleInstalled).toBe(true) diff --git a/packages/permissionless/actions/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts index 6eb596b1..60bac863 100644 --- a/packages/permissionless/actions/erc7579/installModule.ts +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -4,7 +4,8 @@ import { type Client, type Hex, type Transport, - encodeFunctionData + encodeFunctionData, + getAddress } from "viem" import { getAction } from "viem/utils" import type { SmartAccount } from "../../accounts/types" @@ -22,7 +23,7 @@ export type InstallModuleParameters< > = GetAccountParameter & { type: ModuleType address: Address - callData: Hex + context: Hex maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint nonce?: bigint @@ -44,7 +45,7 @@ export async function installModule< nonce, middleware, address, - callData + context } = parameters if (!account_) { @@ -79,7 +80,7 @@ export async function installModule< } ], functionName: "installModule", - args: [parseModuleTypeId(parameters.type), address, callData] + args: [parseModuleTypeId(parameters.type), getAddress(address), context] }) return getAction( diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts index 2d018e70..723bdc2d 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts @@ -66,20 +66,24 @@ describe.each(getCoreSmartAccounts())( const opHash = await installModule(smartClient as any, { account: smartClient.account as any, - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: encodePacked( - ["address", "bytes"], - [ - name === "Kernel" - ? zeroAddress - : eoaAccount.address, - encodeAbiParameters( - [{ type: "bytes" }, { type: "bytes" }], - [moduleData, "0x"] - ) - ] - ) + context: + name === "Kernel" + ? encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [ + { type: "bytes" }, + { type: "bytes" } + ], + [moduleData, "0x"] + ) + ] + ) + : moduleData }) const bundlerClientV07 = createBundlerClient({ @@ -93,9 +97,9 @@ describe.each(getCoreSmartAccounts())( }) const isModuleInstalled = await smartClient.isModuleInstalled({ - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" + context: "0x" }) expect(isModuleInstalled).toBe(true) diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.ts index db7f2e34..a002be39 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.ts @@ -6,7 +6,8 @@ import { type Hex, type Transport, decodeFunctionResult, - encodeFunctionData + encodeFunctionData, + getAddress } from "viem" import type { SmartAccount } from "../../accounts/types" import type { GetAccountParameter } from "../../types/" @@ -23,7 +24,7 @@ export type IsModuleInstalledParameters< > = GetAccountParameter & { type: ModuleType address: Address - callData: Hex + context: Hex } export async function isModuleInstalled< @@ -35,7 +36,7 @@ export async function isModuleInstalled< client: Client, parameters: IsModuleInstalledParameters ): Promise { - const { account: account_ = client.account, address, callData } = parameters + const { account: account_ = client.account, address, context } = parameters if (!account_) { throw new AccountOrClientNotFoundError({ @@ -78,7 +79,11 @@ export async function isModuleInstalled< return await publicClient.readContract({ abi, functionName: "isModuleInstalled", - args: [parseModuleTypeId(parameters.type), address, callData], + args: [ + parseModuleTypeId(parameters.type), + getAddress(address), + context + ], address: account.address }) } catch (error) { @@ -95,8 +100,8 @@ export async function isModuleInstalled< functionName: "isModuleInstalled", args: [ parseModuleTypeId(parameters.type), - address, - callData + getAddress(address), + context ] }) }) diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts index 1548a86d..01b3b064 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts @@ -35,7 +35,7 @@ describe.each(getCoreSmartAccounts())( const supportsExecutionModeBatchCallBeforeDeploy = await supportsExecutionMode(smartClient as any, { account: smartClient.account as any, - callType: "batchcall", + type: "batchcall", revertOnError: false, modeSelector: "0x0", modeData: "0x" @@ -53,7 +53,7 @@ describe.each(getCoreSmartAccounts())( const supportsExecutionModeBatchCallBeforeDeployPostDeploy = await supportsExecutionMode(smartClient as any, { account: smartClient.account as any, - callType: "batchcall", + type: "batchcall", revertOnError: false, modeSelector: "0x0", modeData: "0x" diff --git a/packages/permissionless/actions/erc7579/supportsModule.test.ts b/packages/permissionless/actions/erc7579/supportsModule.test.ts index d527d0c6..a246954d 100644 --- a/packages/permissionless/actions/erc7579/supportsModule.test.ts +++ b/packages/permissionless/actions/erc7579/supportsModule.test.ts @@ -35,7 +35,7 @@ describe.each(getCoreSmartAccounts())( smartClient as any, { account: smartClient.account as any, - type: "validation" + type: "validator" } ) diff --git a/packages/permissionless/actions/erc7579/uninstallModule.test.ts b/packages/permissionless/actions/erc7579/uninstallModule.test.ts index c95cabcc..c754d77d 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.test.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.test.ts @@ -66,20 +66,24 @@ describe.each(getCoreSmartAccounts())( ) const opHash = await smartClient.installModule({ - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: encodePacked( - ["address", "bytes"], - [ - name === "Kernel" - ? zeroAddress - : eoaAccount.address, - encodeAbiParameters( - [{ type: "bytes" }, { type: "bytes" }], - [moduleData, "0x"] - ) - ] - ) + context: + name === "Kernel" + ? encodePacked( + ["address", "bytes"], + [ + zeroAddress, + encodeAbiParameters( + [ + { type: "bytes" }, + { type: "bytes" } + ], + [moduleData, "0x"] + ) + ] + ) + : moduleData }) const bundlerClientV07 = createBundlerClient({ @@ -96,9 +100,9 @@ describe.each(getCoreSmartAccounts())( smartClient as any, { account: smartClient.account as any, - type: "execution", + type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - callData: "0x" + context: "0x" } ) diff --git a/packages/permissionless/actions/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts index a6af4fee..8ade2973 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -4,7 +4,8 @@ import { type Client, type Hex, type Transport, - encodeFunctionData + encodeFunctionData, + getAddress } from "viem" import { getAction } from "viem/utils" import type { SmartAccount } from "../../accounts/types" @@ -24,7 +25,7 @@ export type UninstallModuleParameters< > = GetAccountParameter & { type: ModuleType address: Address - callData: Hex + context: Hex maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint nonce?: bigint @@ -48,7 +49,7 @@ export async function uninstallModule< nonce, middleware, address, - callData + context } = parameters if (!account_) { @@ -83,7 +84,7 @@ export async function uninstallModule< } ], functionName: "uninstallModule", - args: [parseModuleTypeId(parameters.type), address, callData] + args: [parseModuleTypeId(parameters.type), getAddress(address), context] }) return getAction( From a8aee8f84b48433079649158708b6dd0c38c3c82 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 28 Jun 2024 23:38:13 +0100 Subject: [PATCH 07/13] Fix safe --- .../mock-aa-infra/alto/constants.ts | 8 +- .../mock-aa-infra/alto/index.ts | 18 +- packages/permissionless-test/src/utils.ts | 24 +- .../accounts/safe/signerToSafeSmartAccount.ts | 951 ++++++++++++++---- .../actions/erc7579/accountId.test.ts | 136 +-- .../actions/erc7579/accountId.ts | 17 - .../actions/erc7579/installModule.test.ts | 2 - .../actions/erc7579/installModule.ts | 58 +- .../actions/erc7579/isModuleInstalled.test.ts | 36 +- .../erc7579/supportsExecutionMode.test.ts | 8 +- .../actions/erc7579/supportsExecutionMode.ts | 33 +- .../actions/erc7579/uninstallModule.test.ts | 41 +- .../actions/erc7579/uninstallModule.ts | 58 +- .../utils/encode7579CallData.ts | 11 +- 14 files changed, 944 insertions(+), 457 deletions(-) diff --git a/packages/permissionless-test/mock-aa-infra/alto/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts index 1a59bb4c..ff273563 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -51,8 +51,14 @@ export const SAFE_MULTI_SEND_CREATECALL: Hex = export const SAFE_MULTI_SEND_CALL_ONLY_CREATECALL: Hex = "0x0000000000000000000000000000000000000000000000000000000000000000608060405234801561001057600080fd5b5061019a806100206000396000f3fe60806040526004361061001e5760003560e01c80638d80ff0a14610023575b600080fd5b6100dc6004803603602081101561003957600080fd5b810190808035906020019064010000000081111561005657600080fd5b82018360208201111561006857600080fd5b8035906020019184600183028401116401000000008311171561008a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506100de565b005b805160205b8181101561015f578083015160f81c6001820184015160601c60158301850151603584018601516055850187016000856000811461012857600181146101385761013d565b6000808585888a5af1915061013d565b600080fd5b50600081141561014c57600080fd5b82605501870196505050505050506100e3565b50505056fea26469706673582212208d297bb003abee230b5dfb38774688f37a6fbb97a82a21728e8049b2acb9b73564736f6c63430007060033" +export const SAFE_7579_LAUNCHPAD_CREATECALL = + "0x000000000000000000000000000000000000000000000000000000000000000060e060405234801561001057600080fd5b50604051612bc8380380612bc883398101604081905261002f91610089565b6001600160a01b03821661005657604051632039d3c960e01b815260040160405180910390fd5b306080526001600160a01b0391821660a0521660c0526100c3565b6001600160a01b038116811461008657600080fd5b50565b6000806040838503121561009c57600080fd5b82516100a781610071565b60208401519092506100b881610071565b809150509250929050565b60805160a05160c051612a9f6101296000396000818161014e015281816104470152610d2401526000818161019f0152818161057501528181610e05015261113c01526000818160eb015281816105200152818161094f0152610e6e0152612a9f6000f3fe6080604052600436106100e15760003560e01c8063928107f91161007f578063d78343d911610059578063d78343d9146102ff578063d9ed0e8f1461031f578063f2dc691d1461033f578063f698da251461035f57600080fd5b8063928107f9146102715780639cfd7cff14610291578063d03c7914146102cf57600080fd5b806319822f7c116100bb57806319822f7c146101e15780633c9de1b81461020f5780634fff40e114610231578063663c87d81461025157600080fd5b806306433b1b1461013c578063137e051e1461018d57806315cca638146101c157600080fd5b36610137576000547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116911614610135576040516308e3edd160e41b815260040160405180910390fd5b005b600080fd5b34801561014857600080fd5b506101707f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019957600080fd5b506101707f000000000000000000000000000000000000000000000000000000000000000081565b3480156101cd57600080fd5b506101356101dc366004611a57565b610374565b3480156101ed57600080fd5b506102016101fc366004611b4b565b61051a565b604051908152602001610184565b34801561021b57600080fd5b50600080516020612a4a83398151915254610201565b34801561023d57600080fd5b5061013561024c366004611b9e565b61094a565b34801561025d57600080fd5b5061017061026c366004611d28565b610a7a565b34801561027d57600080fd5b5061020161028c366004611f2d565b610b54565b34801561029d57600080fd5b50604080518082018252600f81526e073616665373537392e76312e302e3608c1b6020820152905161018491906120ab565b3480156102db57600080fd5b506102ef6102ea3660046120c5565b610ba6565b6040519015158152602001610184565b34801561030b57600080fd5b5061013561031a3660046120de565b610c4e565b34801561032b57600080fd5b5061013561033a36600461220a565b610dfa565b34801561034b57600080fd5b506102ef61035a3660046120c5565b611082565b34801561036b57600080fd5b506102016110d1565b33301461039457604051630a57d61d60e01b815260040160405180910390fd5b60405163610b592560e01b81526001600160a01b038b166004820152309063610b592590602401600060405180830381600087803b1580156103d557600080fd5b505af11580156103e9573d6000803e3d6000fd5b50506040805160008082526020820190925230935063540fb4f9925090610433565b60408051808201909152600081526060602082015281526020019060019003908161040b5790505b508b8b8b8b8b8b60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018d8d8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060ff8c166020909101526040516001600160e01b031960e08b901b1681526104dc989796959493929190600401612445565b600060405180830381600087803b1580156104f657600080fd5b505af115801561050a573d6000803e3d6000fd5b5050505050505050505050505050565b600080547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161461056a576040516308e3edd160e41b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105b357604051632039d3c960e01b815260040160405180910390fd5b6105c060608501856124b8565b6105cf916004916000916124fe565b6105d891612528565b6001600160e01b03191663d9ed0e8f60e01b146106085760405163c3d40f7760e01b815260040160405180910390fd5b600061061760608601866124b8565b6106259160049082906124fe565b8101906106329190611f2d565b905061064a600080516020612a4a8339815191525490565b61065382610b54565b146106715760405163278328b160e21b815260040160405180910390fd5b600080866020013590508060601c915060008360a001516001600160a01b03168460c001516040516024016106a69190612560565b60408051601f19818403018152918152602080830180516001600160e01b0316633cd56b0760e11b17905290516106e09291339101612573565b60408051601f19818403018152908290526106fa916125a5565b6000604051808303816000865af19150503d8060008114610737576040519150601f19603f3d011682016040523d82523d6000602084013e61073c565b606091505b505090508061075e5760405163c3d40f7760e01b815260040160405180910390fd5b60c084015151600090815b818110156108805760008760c001518281518110610789576107896125c1565b6020026020010151600001519050806001600160a01b0316636d61fe708960c0015184815181106107bc576107bc6125c1565b6020026020010151602001516040518263ffffffff1660e01b81526004016107e491906120ab565b600060405180830381600087803b1580156107fe57600080fd5b505af1158015610812573d6000803e3d6000fd5b505060408051600181526001600160a01b03851660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905060405180910390a1866001600160a01b0316816001600160a01b03160361087757600193505b50600101610769565b5081156108ff57604051639700320360e01b81526001600160a01b038616906397003203906108b5908d908d906004016125d7565b6020604051808303816000875af11580156108d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f891906126db565b965061092b565b60008060006109138960a001518d8f61112a565b925092509250610925831582846112a9565b99505050505b871561093d576000806000808b335af1505b5050505050509392505050565b6000547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116911614610999576040516308e3edd160e41b815260040160405180910390fd5b60006109b1600080516020612a4a8339815191525490565b146109cf5760405163d4d496e560e01b815260040160405180910390fd5b6109e584600080516020612a4a83398151915255565b6001600160a01b03831615610a74576000836001600160a01b03168383604051610a109291906126f4565b600060405180830381855af49150503d8060008114610a4b576040519150601f19603f3d011682016040523d82523d6000602084013e610a50565b606091505b5050905080610a7257604051631f57fed560e31b815260040160405180910390fd5b505b50505050565b6000818051906020012083604051602001610a9f929190918252602082015260400190565b60405160208183030381529060405280519060200120925060ff60f81b858486896001600160a01b0316604051602001610ada929190612704565b60405160208183030381529060405280519060200120604051602001610b3294939291906001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516020808301516040808501516060860151608087015160a088015160c08901519451600098610b89989097969101612726565b604051602081830303815290604052805190602001209050919050565b600081600881901b610bbc82600160f81b6112e1565b15610bca5760019250610c0d565b610bd58260006112e1565b15610be35760019250610c0d565b610bf5826001600160f81b03196112e1565b15610c035760019250610c0d565b5060009392505050565b828015610c205750610c208160006112e1565b15610c2c575050919050565b828015610c425750610c4281600160f81b6112e1565b15610c03575050919050565b60405163610b592560e01b81526001600160a01b038d166004820152309063610b592590602401600060405180830381600087803b158015610c8f57600080fd5b505af1158015610ca3573d6000803e3d6000fd5b505060405163f08a032360e01b81526001600160a01b038f16600482015230925063f08a03239150602401600060405180830381600087803b158015610ce857600080fd5b505af1158015610cfc573d6000803e3d6000fd5b50505050306001600160a01b031663540fb4f98c8c8c8c8c8c8c8c60405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e8e8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060ff8d166020909101526040516001600160e01b031960e08c901b168152610dba999897969594939291906004016127a3565b600060405180830381600087803b158015610dd457600080fd5b505af1158015610de8573d6000803e3d6000fd5b50505050505050505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e4357604051632039d3c960e01b815260040160405180910390fd5b610e506020820182612818565b600080546001600160a01b0319166001600160a01b039283161790557f000000000000000000000000000000000000000000000000000000000000000016610e9e6080830160608401612818565b6001600160a01b031614610ec557604051633007073760e01b815260040160405180910390fd5b6302b994c760e31b610eda60808301836124b8565b610ee9916004916000916124fe565b610ef291612528565b6001600160e01b03191614610f1a57604051633007073760e01b815260040160405180910390fd5b3063b63e800d610f2d6020840184612835565b6040850135610f426080870160608801612818565b610f4f60808801886124b8565b610f5f60c08a0160a08b01612818565b60008060006040518b63ffffffff1660e01b8152600401610f899a9998979695949392919061287e565b600060405180830381600087803b158015610fa357600080fd5b505af1158015610fb7573d6000803e3d6000fd5b50506000600080516020612a4a8339815191525550610fd39050565b600080610fe660c0840160a08501612818565b6001600160a01b0316610ffc60e08501856124b8565b3060405160200161100f93929190612935565b60408051601f1981840301815290829052611029916125a5565b6000604051808303816000865af19150503d8060008114611066576040519150601f19603f3d011682016040523d82523d6000602084013e61106b565b606091505b50915091508161107d57805160208201fd5b505050565b60006001820361109457506001919050565b600282036110a457506001919050565b600382036110b457506001919050565b600482036110c457506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b600080600080600080366000611160897f00000000000000000000000000000000000000000000000000000000000000006112f8565b8451602086012094995092975090955093509150600061118360608c018c6124b8565b6111919160049082906124fe565b81019061119e9190611f2d565b905060006111e885858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505060408501518692915061152b565b90506111f38161181a565b60208201516112018161181a565b61120a81611826565b80516000805b8281101561128b57600061124685838151811061122f5761122f6125c1565b60200260200101518761182f90919063ffffffff16565b509050801561128257826112598161296c565b93505086604001518310611282575060019e50999c50979a506112a09950505050505050505050565b50600101611210565b5060009d50989b509699505050505050505050505b93509350939050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b856112d15760006112d4565b60015b60ff161717949350505050565b6001600160f81b0319828116908216145b92915050565b60606000803681818161130f6101008a018a6124b8565b90925090506113226006600083856124fe565b61132b91612985565b60d01c955061133e600c600683856124fe565b61134791612985565b60d01c945061135981600c81856124fe565b9350935050506000604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f60001b81526020018960000160208101906113a99190612818565b6001600160a01b03168152602001896020013581526020018980604001906113d191906124b8565b6040516113df9291906126f4565b60405190819003902081526020016113fa60608b018b6124b8565b6040516114089291906126f4565b6040518091039020815260200161141e8a611852565b6001600160801b031681526020016114358a611862565b6001600160801b031681526020018960a0013581526020016114568a611877565b6001600160801b0316815260200161146d8a611886565b6001600160801b0316815260200161148860e08b018b6124b8565b6040516114969291906126f4565b6040805191829003909120825265ffffffffffff80891660208401528716908201526001600160a01b0389166060909101526101c08120909150601960f81b600160f81b6114e26110d1565b6040516001600160f81b03199384166020820152929091166021830152602282015260428101829052606201604051602081830303815290604052965050509295509295909350565b6060600061153a8360416129bb565b8451909150836001600160401b0381111561155757611557611c28565b604051908082528060200260200182016040528015611580578160200160208202803683370190505b509250818110156115a457604051638baa579f60e01b815260040160405180910390fd5b60005b84811015611810576000806000806115d78a86604102016020810151604082015160609092015160001a92909190565b9250925092508260ff1660000361176f5790925082906041811015611625576040516338a245ff60e11b81526004810182905260006024820181905260448201526064015b60405180910390fd5b856116318260206129d2565b1115611661576040516338a245ff60e11b815260048101829052600060248201526044810187905260640161161c565b6020818b0181015190879082906116799085906129d2565b61168391906129d2565b11156116b3576040516338a245ff60e11b815260048101839052602481018290526044810188905260640161161c565b60606020838d01019050631626ba7e60e01b6001600160e01b031916866001600160a01b0316631626ba7e8f846040518363ffffffff1660e01b81526004016116fd9291906129e5565b602060405180830381865afa15801561171a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173e9190612a06565b6001600160e01b03191614611768578060405163605d348960e01b815260040161161c91906120ab565b50506117d5565b601e8360ff1611156117c6576117bf6117ad8c6020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b6117b8600486612a30565b848461189b565b93506117d5565b6117d28b84848461189b565b93505b838886815181106117e8576117e86125c1565b6001600160a01b03909216602092830291909101909101525050600190920191506115a79050565b5050509392505050565b611823816118d9565b50565b6118238161192e565b60008061184784846001600160a01b03166000611977565b909590945092505050565b60006112f2826080013560801c90565b60006001600160801b036080830135166112f2565b600060c082013560801c6112f2565b60006001600160801b0360c0830135166112f2565b60006040518560005260ff85166020528360405282606052602060406080600060015afa5060006060523d6060185191508060405250949350505050565b8051600082528060051b82016020601f198185015b8201838111611926578051828201805182811161190d575050506118ee565b5b818601528301805182811161190e57508401526118ee565b505050915250565b6002815110611823576020810160408201600183510160051b83015b815183511461195e57602083019250815183525b60208201915080820361194a57505081900360051c9052565b60008060001960018651600087870197505b81830160011c94508460051b89015187019050878114828411176119c3578088116119b8578385019150611989565b600185019250611989565b84151597148716989290930190950295509350505050565b6001600160a01b038116811461182357600080fd5b80356110cc816119db565b60008083601f840112611a0d57600080fd5b5081356001600160401b03811115611a2457600080fd5b6020830191508360208260051b8501011115611a3f57600080fd5b9250929050565b803560ff811681146110cc57600080fd5b60008060008060008060008060008060c08b8d031215611a7657600080fd5b611a7f8b6119f0565b995060208b01356001600160401b03811115611a9a57600080fd5b611aa68d828e016119fb565b909a5098505060408b01356001600160401b03811115611ac557600080fd5b611ad18d828e016119fb565b90985096505060608b01356001600160401b03811115611af057600080fd5b611afc8d828e016119fb565b90965094505060808b01356001600160401b03811115611b1b57600080fd5b611b278d828e016119fb565b9094509250611b3a905060a08c01611a46565b90509295989b9194979a5092959850565b600080600060608486031215611b6057600080fd5b83356001600160401b03811115611b7657600080fd5b84016101208187031215611b8957600080fd5b95602085013595506040909401359392505050565b60008060008060608587031215611bb457600080fd5b843593506020850135611bc6816119db565b925060408501356001600160401b03811115611be157600080fd5b8501601f81018713611bf257600080fd5b80356001600160401b03811115611c0857600080fd5b876020828401011115611c1a57600080fd5b949793965060200194505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715611c6057611c60611c28565b60405290565b60405161010081016001600160401b0381118282101715611c6057611c60611c28565b604051601f8201601f191681016001600160401b0381118282101715611cb157611cb1611c28565b604052919050565b600082601f830112611cca57600080fd5b81356001600160401b03811115611ce357611ce3611c28565b611cf6601f8201601f1916602001611c89565b818152846020838601011115611d0b57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611d4057600080fd5b8535611d4b816119db565b94506020860135611d5b816119db565b935060408601356001600160401b03811115611d7657600080fd5b611d8288828901611cb9565b9350506060860135915060808601356001600160401b03811115611da557600080fd5b611db188828901611cb9565b9150509295509295909350565b60006001600160401b03821115611dd757611dd7611c28565b5060051b60200190565b600082601f830112611df257600080fd5b8135611e05611e0082611dbe565b611c89565b8082825260208201915060208360051b860101925085831115611e2757600080fd5b602085015b83811015611e4d578035611e3f816119db565b835260209283019201611e2c565b5095945050505050565b600082601f830112611e6857600080fd5b8135611e76611e0082611dbe565b8082825260208201915060208360051b860101925085831115611e9857600080fd5b602085015b83811015611e4d5780356001600160401b03811115611ebb57600080fd5b86016040818903601f19011215611ed157600080fd5b611ed9611c3e565b6020820135611ee7816119db565b815260408201356001600160401b03811115611f0257600080fd5b611f118a602083860101611cb9565b6020830152508085525050602083019250602081019050611e9d565b600060208284031215611f3f57600080fd5b81356001600160401b03811115611f5557600080fd5b82016101008185031215611f6857600080fd5b611f70611c66565b611f79826119f0565b815260208201356001600160401b03811115611f9457600080fd5b611fa086828501611de1565b60208301525060408281013590820152611fbc606083016119f0565b606082015260808201356001600160401b03811115611fda57600080fd5b611fe686828501611cb9565b608083015250611ff860a083016119f0565b60a082015260c08201356001600160401b0381111561201657600080fd5b61202286828501611e57565b60c08301525060e08201356001600160401b0381111561204157600080fd5b61204d86828501611cb9565b60e083015250949350505050565b60005b8381101561207657818101518382015260200161205e565b50506000910152565b6000815180845261209781602086016020860161205b565b601f01601f19169290920160200192915050565b6020815260006120be602083018461207f565b9392505050565b6000602082840312156120d757600080fd5b5035919050565b60008060008060008060008060008060008060e08d8f03121561210057600080fd5b6121098d6119f0565b9b506001600160401b0360208e0135111561212357600080fd5b6121338e60208f01358f016119fb565b909b5099506001600160401b0360408e0135111561215057600080fd5b6121608e60408f01358f016119fb565b90995097506001600160401b0360608e0135111561217d57600080fd5b61218d8e60608f01358f016119fb565b90975095506001600160401b0360808e013511156121aa57600080fd5b6121ba8e60808f01358f016119fb565b90955093506001600160401b0360a08e013511156121d757600080fd5b6121e78e60a08f01358f016119fb565b90935091506121f860c08e01611a46565b90509295989b509295989b509295989b565b60006020828403121561221c57600080fd5b81356001600160401b0381111561223257600080fd5b820161010081850312156120be57600080fd5b600082825180855260208501945060208160051b8301016020850160005b838110156122b557848303601f19018852815180516001600160a01b0316845260209081015160409185018290529061229e9085018261207f565b6020998a0199909450929092019150600101612263565b50909695505050505050565b6000808335601e198436030181126122d857600080fd5b83016020810192503590506001600160401b038111156122f757600080fd5b803603821315611a3f57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008383855260208501945060208460051b8201018360005b868110156122b557838303601f19018852813536879003603e1901811261236e57600080fd5b8601803561237b816119db565b6001600160a01b0316845261239360208201826122c1565b9150604060208601526123aa604086018383612306565b60209a8b019a90955093909301925050600101612348565b600081518084526020840193506020830160005b828110156123fd5781516001600160a01b03168652602095860195909101906001016123d6565b5093949350505050565b60018060a01b038151168252600060208201516060602085015261242e60608501826123c2565b60409384015160ff16949093019390935250919050565b60a08152600061245860a083018b612245565b828103602084015261246b818a8c61232f565b9050828103604084015261248081888a61232f565b9050828103606084015261249581868861232f565b905082810360808401526124a98185612407565b9b9a5050505050505050505050565b6000808335601e198436030181126124cf57600080fd5b8301803591506001600160401b038211156124e957600080fd5b602001915036819003821315611a3f57600080fd5b6000808585111561250e57600080fd5b8386111561251b57600080fd5b5050820193919092039150565b80356001600160e01b03198116906004841015612559576001600160e01b0319600485900360031b81901b82161691505b5092915050565b6020815260006120be6020830184612245565b6000835161258581846020880161205b565b60609390931b6001600160601b0319169190920190815260140192915050565b600082516125b781846020870161205b565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b604081526125f8604082016125eb856119f0565b6001600160a01b03169052565b60208301356060820152600061261160408501856122c1565b610120608085015261262861016085018284612306565b91505061263860608601866122c1565b848303603f190160a086015261264f838284612306565b608088013560c08781019190915260a089013560e08089019190915290890135610100880152909350612687925087019050866122c1565b848303603f190161012086015261269f838284612306565b925050506126b16101008601866122c1565b848303603f19016101408601526126c9838284612306565b93505050508260208301529392505050565b6000602082840312156126ed57600080fd5b5051919050565b8183823760009101908152919050565b6000835161271681846020880161205b565b9190910191825250602001919050565b6001600160a01b038816815260e06020820181905260009061274a908301896123c2565b604083018890526001600160a01b03871660608401528281036080840152612772818761207f565b6001600160a01b03861660a085015283810360c085015290506127958185612245565b9a9950505050505050505050565b60a0815260006127b760a083018b8d61232f565b82810360208401526127ca818a8c61232f565b905082810360408401526127df81888a61232f565b905082810360608401526127f481868861232f565b905082810360808401526128088185612407565b9c9b505050505050505050505050565b60006020828403121561282a57600080fd5b81356120be816119db565b6000808335601e1984360301811261284c57600080fd5b8301803591506001600160401b0382111561286657600080fd5b6020019150600581901b3603821315611a3f57600080fd5b61010080825281018a905260008b6101208301825b8d8110156128c35782356128a6816119db565b6001600160a01b0316825260209283019290910190600101612893565b508b60208501526128df604085018c6001600160a01b03169052565b83810360608501526128f2818a8c612306565b9250505061290b60808301876001600160a01b03169052565b6001600160a01b03851660a08301528360c08301526124a960e08301846001600160a01b03169052565b8284823760609190911b6001600160601b0319169101908152601401919050565b634e487b7160e01b600052601160045260246000fd5b60006001820161297e5761297e612956565b5060010190565b80356001600160d01b03198116906006841015612559576001600160d01b031960069490940360031b84901b1690921692915050565b80820281158282048414176112f2576112f2612956565b808201808211156112f2576112f2612956565b8281526040602082015260006129fe604083018461207f565b949350505050565b600060208284031215612a1857600080fd5b81516001600160e01b0319811681146120be57600080fd5b60ff82811682821603908111156112f2576112f261295656fe982e06ee6a56dfc0f1ac189a5d23506361ca0a3ce45a9c7b8d33d65d43746a24a2646970667358221220b9f8a86409c3671f7b19131d085b34f0ba682783524a0bae7bea00939bae967d64736f6c634300081a00330000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03200000000000000000000000025a4b2f363678e13a0a5db79b712de00347a593e" + +export const SAFE_7579_REGISTRY_CREATECALL: Hex = + "0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b506103d18061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063529562a11161005b578063529562a1146100bf57806396fb7217146100d2578063c23697a8146100e0578063f05c04e1146100f157600080fd5b80630bb30abc146100825780632ed94467146100985780634c13560c146100ad575b600080fd5b6100966100903660046101c8565b50505050565b005b6100966100a6366004610222565b5050505050565b6100966100bb366004610284565b5050565b6100966100cd3660046102b7565b505050565b6100966100bb3660046102f4565b6100966100ee36600461031e565b50565b6100966100ff366004610340565b6040513381527fb8a00d6d8ca1be30bfec34d8f97e55f0f0fd9eeb7fb46e030516363d4cfe1ad69060200160405180910390a16040517fb6d9a72244037f5f1de04d8ff74cd328f1574efc59a02163d0fec0554871974690600090a1505050565b80356001600160a01b038116811461017757600080fd5b919050565b60008083601f84011261018e57600080fd5b50813567ffffffffffffffff8111156101a657600080fd5b6020830191508360208260051b85010111156101c157600080fd5b9250929050565b600080600080606085870312156101de57600080fd5b6101e785610160565b9350602085013567ffffffffffffffff81111561020357600080fd5b61020f8782880161017c565b9598909750949560400135949350505050565b60008060008060006080868803121561023a57600080fd5b61024386610160565b945060208601359350604086013567ffffffffffffffff81111561026657600080fd5b6102728882890161017c565b96999598509660600135949350505050565b6000806040838503121561029757600080fd5b6102a083610160565b91506102ae60208401610160565b90509250929050565b6000806000606084860312156102cc57600080fd5b6102d584610160565b92506102e360208501610160565b929592945050506040919091013590565b6000806040838503121561030757600080fd5b61031083610160565b946020939093013593505050565b60006020828403121561033057600080fd5b61033982610160565b9392505050565b60008060006040848603121561035557600080fd5b833560ff8116811461036657600080fd5b9250602084013567ffffffffffffffff81111561038257600080fd5b61038e8682870161017c565b949790965093945050505056fea2646970667358221220181467498dc4fab0c64814a0965539f6b8e992676b95c29db59b1cc06cd50f0f64736f6c634300081a0033" + export const SAFE_7579_MODULE_CREATECALL: Hex = - "0x000000000000000000000000000000000000000000000000000000000000000060a0604052348015600f57600080fd5b50604051601a906046565b604051809103906000f0801580156035573d6000803e3d6000fd5b506001600160a01b03166080526053565b6109f080614bc483390190565b608051614b2c61009860003960008181610d0101528181610f1c0152818161178e01528181612cae01528181612d66015281816136cb01526137f70152614b2c6000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c531461040f578063ea5f61d014610422578063eab77e1714610442578063f2dc691d14610462578063f698da25146104825761012a565b8063b0d691fe14610340578063b875d5d814610363578063d03c7914146103af578063d691c964146103cf578063d828435d146103ef5761012a565b80636a5e1515116100e75780636a5e1515146102b757806385571368146102ca5780639517e29f146102f85780639cfd7cff1461030b578063a71763a81461032d5761012a565b80630a664dba146101d4578063112d3a7d146102185780631626ba7e1461024857806319822f7c14610281578063540fb4f9146102a25761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b5033600090815260046020908152604080832054600583528184206001600160e01b031985351680865293529083205491926001600160a01b039182169290911690806101a88484610497565b915091506101b68888610555565b95506101c484848484610669565b5050505050915050805190602001f35b3480156101e057600080fd5b50336000908152600460205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022457600080fd5b50610238610233366004613aa8565b6106ec565b604051901515815260200161020f565b34801561025457600080fd5b50610268610263366004613b03565b610749565b6040516001600160e01b0319909116815260200161020f565b61029461028f366004613b4e565b6109de565b60405190815260200161020f565b6102b56102b0366004613bfd565b610af2565b005b6102b56102c5366004613cf9565b610b3f565b3480156102d657600080fd5b506102ea6102e5366004613d3a565b610ba0565b60405161020f929190613d66565b6102b5610306366004613aa8565b610bbc565b34801561031757600080fd5b50610320610d71565b60405161020f9190613e19565b6102b561033b366004613aa8565b610e03565b34801561034c57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fb565b34801561036f57600080fd5b506101fb61037e366004613e42565b3360009081526005602090815260408083206001600160e01b0319909416835292905220546001600160a01b031690565b3480156103bb57600080fd5b506102386103ca366004613e5f565b610f7f565b6103e26103dd366004613b03565b611027565b60405161020f9190613e78565b3480156103fb57600080fd5b5061029461040a366004613edd565b6110f3565b6102b561041d366004613b03565b611193565b34801561042e57600080fd5b506102ea61043d366004613d3a565b611538565b34801561044e57600080fd5b506102b561045d366004613f27565b611562565b34801561046e57600080fd5b5061023861047d366004613e5f565b6115d1565b34801561048e57600080fd5b50610294611620565b6060806001600160a01b03841615610517576104fe338560006104b8611679565b346000366040516024016104cf9493929190613fb6565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b179052611685565b91508180602001905181019061051491906140aa565b91505b6001600160a01b0383161561054e57610535338460006104b8611679565b90508080602001905181019061054b91906140aa565b90505b9250929050565b3360009081526003602090815260408083206001600160e01b0319843516845290915290208054606091906001600160a01b03811690600160a01b900460f81b816105c657604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b6105d481607f60f91b61172e565b156106185761060e338388886105e8611679565b6040516020016105fa939291906140de565b604051602081830303815290604052611740565b9350505050610663565b61062381600061172e565b1561065f5761060e338360008989610639611679565b60405160200161064b939291906140de565b604051602081830303815290604052611685565b5050505b92915050565b6001600160a01b038416156106bf576106bf33856000856040516024016106909190613e19565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b179052611815565b6001600160a01b038316156106e6576106e633846000846040516024016106909190613e19565b50505050565b600060018503610706576106ff846118b4565b9050610741565b60028503610717576106ff846118c2565b6003850361072a576106ff8484846118db565b6004850361073d576106ff848484611928565b5060005b949350505050565b600033821580156107c15750604051635ae6bd3760e01b8152600481018690526001600160a01b03821690635ae6bd3790602401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190614104565b15155b156107d65750630b135d3f60e11b90506109d7565b60006107e5601482868861411d565b6107ee91614147565b60601c90508015806108065750610804816118b4565b155b1561095c5760006108d1836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614104565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052611963565b805160208201209091506001600160a01b03841663934f3a1182846108f98a6014818e61411d565b6040518563ffffffff1660e01b81526004016109189493929190614194565b60006040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b50630b135d3f60e11b97506109d79650505050505050565b60006109bb338361096b611679565b8a6109798a6014818e61411d565b60405160240161098c9493929190613fb6565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611740565b9050808060200190518101906109d191906141cb565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da0326109f9611679565b6001600160a01b031614610a2057604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610a3e5750610a3c826118b4565b155b15610a5357610a4c866119dd565b9250610ab8565b6000610a9e338460008a8a604051602401610a6f92919061422d565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b179052611685565b905080806020019051810190610ab49190614104565b9350505b8315610ae957610ae9336f71727de22e5e9d8baf0edac6f37da0328660405180602001604052806000815250611815565b50509392505050565b610b24610b026020830183614331565b610b0f602084018461434e565b610b1f6060860160408701614397565b611a83565b610b348989898989898989611b31565b505050505050505050565b610b4a600133611d74565b8060005b818110156106e65736848483818110610b6957610b696143b2565b9050602002810190610b7b91906143c8565b9050610b9733610b8e6020840184614331565b60019190611def565b50600101610b4e565b60606000610bb16001338686611ee4565b915091509250929050565b3360009081526004602090815260408083205460058352818420639517e29f60e01b80865293529083205491926001600160a01b03918216929091169080610c048484610497565b91509150610c1f6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610c30611679565b6001600160a01b03161480610c5d5750610c48611679565b6001600160a01b0316336001600160a01b0316145b610c7a57604051635629665f60e11b815260040160405180910390fd5b606060018a03610c9657610c8f8989896120a8565b9050610cfb565b60028a03610ca957610c8f898989612104565b60038a03610cbc57610c8f89898961216e565b60048a03610ccf57610c8f8989896122af565b89610cdf57610c8f89898961242e565b60405163041c38b360e41b8152600481018b90526024016105bd565b610d64337f00000000000000000000000000000000000000000000000000000000000000008c8c85604051602401610d35939291906143e8565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b1790526125b6565b50610b3484848484610669565b60606000336001600160a01b031663ffa1ad746040518163ffffffff1660e01b8152600401600060405180830381865afa158015610db3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ddb9190810190614412565b905080604051602001610dee919061445a565b60405160208183030381529060405291505090565b33600090815260046020908152604080832054600583528184206314e2ec7560e31b80865293529083205491926001600160a01b03918216929091169080610e4b8484610497565b91509150610e666f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e77611679565b6001600160a01b03161480610ea45750610e8f611679565b6001600160a01b0316336001600160a01b0316145b610ec157604051635629665f60e11b815260040160405180910390fd5b606060018a03610edd57610ed689898961264f565b9050610f16565b60028a03610ef057610ed6898989612678565b60038a03610f0357610ed68989896126a5565b60048a03610cdf57610ed68989896126f3565b610d64337f00000000000000000000000000000000000000000000000000000000000000008c8c85604051602401610f50939291906143e8565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b1790526127ab565b600081600881901b610f9582600160f81b61172e565b15610fa35760019250610fe6565b610fae82600061172e565b15610fbc5760019250610fe6565b610fce826001600160f81b031961172e565b15610fdc5760019250610fe6565b5060009392505050565b828015610ff95750610ff981600061172e565b15611005575050919050565b82801561101b575061101b81600160f81b61172e565b15610fdc575050919050565b6060611039611034611679565b6118c2565b61106a57611045611679565b604051635c93ff2f60e11b81526001600160a01b0390911660048201526024016105bd565b33600090815260046020908152604080832054600583528184206335a4725960e21b80865293529083205491926001600160a01b039182169290911690806110b28484610497565b915091503360026110c38282612861565b8a600881901b6110d581838e8e6128ec565b9950505050506110e784848484610669565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa15801561116f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107419190614104565b336000908152600460209081526040808320546005835281842063e9ae5c5360e01b80865293529083205491926001600160a01b039182169290911690806111db8484610497565b915091506111f66f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316611207611679565b6001600160a01b03161480611234575061121f611679565b6001600160a01b0316336001600160a01b0316145b61125157604051635629665f60e11b815260040160405180910390fd5b87600881901b3361126382600061172e565b156113c65761127683600160f81b61172e565b156112975789358a01602081019035611290838383612ca8565b505061151f565b6112a283600061172e565b1561130a576000803660006112b78e8e612d0f565b935093509350935061130185858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061181592505050565b5050505061151f565b61131c836001600160f81b031961172e565b156113a15760006113306014828c8e61411d565b61133991614147565b60601c90503660008c8c60149080926113549392919061411d565b91509150611399848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506125b692505050565b50505061151f565b604051632e5bf3f960e21b81526001600160f81b0319841660048201526024016105bd565b6113d482600160f81b61172e565b156114fa576113e783600160f81b61172e565b156114015789358a01602081019035611290838383612d60565b61140c83600061172e565b1561146b576000803660006114218e8e612d0f565b935093509350935061130185858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dc792505050565b61147d836001600160f81b031961172e565b156113a15760006114916014828c8e61411d565b61149a91614147565b60601c90503660008c8c60149080926114b59392919061411d565b91509150611399848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127ab92505050565b6040516308c3ee0360e11b81526001600160f81b0319831660048201526024016105bd565b50505061152e84848484610669565b5050505050505050565b33600090815260026020526040812060609190611556818686612e7d565b92509250509250929050565b6f71727de22e5e9d8baf0edac6f37da03261157b611679565b6001600160a01b031614806115a85750611593611679565b6001600160a01b0316336001600160a01b0316145b6115c557604051635629665f60e11b815260040160405180910390fd5b6106e684848484611a83565b6000600182036115e357506001919050565b600282036115f357506001919050565b6003820361160357506001919050565b6004820361161357506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016116bc94939291906144a0565b6000604051808303816000875af11580156116db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261170391908101906144eb565b925090508061172557604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b606060008383604051602401611757929190614538565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b179052519091506000906117b8907f0000000000000000000000000000000000000000000000000000000000000000908490602401614538565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610ae957825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a79061184a9087908790879087906004016144a0565b6020604051808303816000875af1158015611869573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188d919061455c565b9050806118ad57604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b600061066360013384613029565b3360009081526002602052604081206109d7818461306d565b6000806118ea83850185613e42565b3360009081526003602090815260408083206001600160e01b0319909416835292905220546001600160a01b03908116908616149150509392505050565b6000808061193884860186614586565b91509150600061194883836130a7565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b8585856040516020016119839291906145b2565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b6000806000803660006119ef8761313f565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a1191611a2a91899087908790600401614194565b60006040518083038186803b158015611a4257600080fd5b505afa925050508015611a53575060015b611a6a57611a636001848661338a565b9550611a79565b611a766000848661338a565b95505b5050505050919050565b3360008181526020819052604080822080546001600160a01b0319166001600160a01b03891617905551611af592918791611ac6908690899089906024016145d8565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b179052611815565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f602052604090205487906001600160a01b0316611bde57611b7a600133611d74565b60005b81811015611bd857368a8a83818110611b9857611b986143b2565b9050602002810190611baa91906143c8565b9050611bce611bbc6020830183614331565b611bc96020840184614630565b6120a8565b5050600101611b7d565b50611bff565b8015611bff5760405163d8e3ed1b60e01b81523360048201526024016105bd565b336000908152600260205260409020611c17816133c2565b86915060005b82811015611c785736898983818110611c3857611c386143b2565b9050602002810190611c4a91906143c8565b9050611c6e611c5c6020830183614331565b611c696020840184614630565b612104565b5050600101611c1d565b5084915060005b82811015611cda5736878783818110611c9a57611c9a6143b2565b9050602002810190611cac91906143c8565b9050611cd0611cbe6020830183614331565b611ccb6020840184614630565b61216e565b5050600101611c7f565b5082915060005b82811015611d3c5736858583818110611cfc57611cfc6143b2565b9050602002810190611d0e91906143c8565b9050611d32611d206020830183614331565b611d2d6020840184614630565b6122af565b5050600101611ce1565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b60016000908152602083815260408083206001600160a01b0380861685529252909120541615611db7576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b0381161580611e0e57506001600160a01b0381166001145b15611e3757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020858152604080832086851684529091529020541615611e8657604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b606060006001600160a01b038416600114801590611f0a5750611f08868686613029565b155b15611f3357604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003611f545760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115611f6c57611f6c613fe8565b604051908082528060200260200182016040528015611f95578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b03821615801590611fe557506001600160a01b038216600114155b8015611ff057508381105b156120555781838281518110612008576120086143b2565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061204d8161468c565b915050611fc3565b6001600160a01b03821660011480159061206f5750600081115b1561209b57826120806001836146a5565b81518110612090576120906143b2565b602002602001015191505b8083525094509492505050565b60608360016120b78282612861565b6120c360013388611def565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026121138282612861565b33600090815260026020526040902061212c818861341f565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929a9950505050505050505050565b606083600361217d8282612861565b6000808061218d87890189614709565b919450925090506001600160e01b031983166306d61fe760e41b14806121c357506001600160e01b03198316638a91b0e360e01b145b156121ed576040516379bd117b60e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526003602090815260408083206001600160e01b0319871684529091529020546001600160a01b031615612245576040516374420d1560e01b81526001600160e01b0319841660048201526024016105bd565b3360009081526003602090815260408083206001600160e01b031990961683529490529290922080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b60608360046122be8282612861565b600080806122ce87890189614777565b919450925090506000808460018111156122ea576122ea6147a5565b1480156122ff57506001600160e01b03198316155b156123755750336000908152600460205260409020546001600160a01b031680156123485760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b33600090815260046020526040902080546001600160a01b0319166001600160a01b038c16179055612421565b6001846001811115612389576123896147a5565b03612408576001600160a01b038116156123c15760405163741cbe0360e01b81526001600160a01b03821660048201526024016105bd565b503360009081526005602090815260408083206001600160e01b031986168452909152902080546001600160a01b038b81166001600160a01b031983161790925516612421565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146124765760405163b4fa3fb360e01b815260040160405180910390fd5b60005b8181101561256f576000888883818110612495576124956143b2565b905060200201359050600181036124d4576124ce8d8888858181106124bc576124bc6143b2565b9050602002810190611bc99190614630565b50612566565b60028103612504576124ce8d8888858181106124f2576124f26143b2565b9050602002810190611c699190614630565b60038103612534576124ce8d888885818110612522576125226143b2565b9050602002810190611ccb9190614630565b60048103612566576125648d888885818110612552576125526143b2565b9050602002810190611d2d9190614630565b505b50600101612479565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906125ec908690859087906001906004016144a0565b6020604051808303816000875af115801561260b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262f919061455c565b9050806106e657604051632b3f6d1160e21b815260040160405180910390fd5b6060600061265f838501856147bb565b9250905061267060013383886134f5565b509392505050565b336000908152600260205260408120606091612696848601866147bb565b93509050610ae98282886135ec565b606060006126b583850185614800565b3360009081526003602090815260408083206001600160e01b031990951683529390529190912080546001600160a01b031916905595945050505050565b606060008061270484860186614777565b94509092509050600082600181111561271f5761271f6147a5565b14801561273457506001600160e01b03198116155b1561275b5733600090815260046020526040902080546001600160a01b0319169055610ae9565b600182600181111561276f5761276f6147a5565b03612408573360009081526005602090815260408083206001600160e01b031985168452909152902080546001600160a01b0319169055610ae9565b60405163468721a760e01b81526000906001600160a01b0385169063468721a7906127e1908690859087906001906004016144a0565b6020604051808303816000875af1158015612800573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612824919061455c565b9050806106e657604080516001600160a01b038616815260006020820152600080516020614ad7833981519152910160405180910390a150505050565b336000908152602081905260409020546001600160a01b031680156128e75760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b1580156128ce57600080fd5b505afa1580156128e2573d6000803e3d6000fd5b505050505b505050565b60606128f985600061172e565b15612aef5761290c84600160f81b61172e565b1561292f57823583016020810190356129263383836136c1565b92505050610741565b61293a84600061172e565b156129ee5760008036600061294f8787612d0f565b6040805160018082528183019092529498509296509094509250816020015b606081526020019060019003908161296e5790505094506129c733858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061168592505050565b856000815181106129da576129da6143b2565b602002602001018190525050505050610741565b612a00846001600160f81b031961172e565b15612aca576000612a14601482858761411d565b612a1d91614147565b60601c9050366000612a32856014818961411d565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612a4c579050509350612aa4338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061374b92505050565b84600081518110612ab757612ab76143b2565b6020026020010181905250505050610741565b604051632e5bf3f960e21b81526001600160f81b0319851660048201526024016105bd565b612afd85600160f81b61172e565b15612c8357612b1084600160f81b61172e565b15612b355782358301602081019035612b2a3383836137ec565b935061074192505050565b612b4084600061172e565b15612bcd57600080366000612b558787612d0f565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612b745790505094506129c733858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061387b92505050565b612bdf846001600160f81b031961172e565b15612aca576000612bf3601482858761411d565b612bfc91614147565b60601c9050366000612c11856014818961411d565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612c2b579050509350612aa4338484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061393b92505050565b6040516308c3ee0360e11b81526001600160f81b0319861660048201526024016105bd565b6128e7837f00000000000000000000000000000000000000000000000000000000000000008484604051602401612ce092919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b1790526125b6565b6000803681612d21601482878961411d565b612d2a91614147565b60601c9350612d3d60346014878961411d565b612d46916148d0565b9250612d55856034818961411d565b949793965094505050565b6128e7837f00000000000000000000000000000000000000000000000000000000000000008484604051602401612d9892919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b1790526127ab565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790612dfc9087908790879087906004016144a0565b6020604051808303816000875af1158015612e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3f919061455c565b9050806118ad57604080516001600160a01b038716815260006020820152600080516020614ad7833981519152910160405180910390a15050505050565b606060006001600160a01b038416600114801590612ea25750612ea0858561306d565b155b15612ecb57604051637c84ecfb60e01b81526001600160a01b03851660048201526024016105bd565b82600003612eec5760405163f725081760e01b815260040160405180910390fd5b826001600160401b03811115612f0457612f04613fe8565b604051908082528060200260200182016040528015612f2d578160200160208202803683370190505b506001600160a01b03808616600090815260208890526040812054929450911691505b6001600160a01b03821615801590612f7257506001600160a01b038216600114155b8015612f7d57508381105b15612fd75781838281518110612f9557612f956143b2565b6001600160a01b039283166020918202929092018101919091529281166000908152928790526040909220549091169080612fcf8161468c565b915050612f50565b6001600160a01b038216600114801590612ff15750600081115b1561301d57826130026001836146a5565b81518110613012576130126143b2565b602002602001015191505b80835250935093915050565b600060016001600160a01b038316148015906107415750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b600060016001600160a01b038316148015906109d75750506001600160a01b03908116600090815260209290925260409091205416151590565b6000808360018111156130bc576130bc6147a5565b1480156130d157506001600160e01b03198216155b156130f15750336000908152600460205260409020546001600160a01b03165b6001836001811115613105576131056147a5565b0361066357503360009081526005602090815260408083206001600160e01b0319851684529091529020546001600160a01b031692915050565b606060008036818181613156610100890189614630565b909250905061316960066000838561411d565b613172916148ee565b60d01c9550613185600c6006838561411d565b61318e916148ee565b60d01c94506131a081600c818561411d565b9350935050506000604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f60001b81526020018860000160208101906131f09190614331565b6001600160a01b03168152602001886020013581526020018880604001906132189190614630565b604051613226929190614924565b604051908190039020815260200161324160608a018a614630565b60405161324f929190614924565b60405180910390208152602001613265896139fb565b6001600160801b0316815260200161327c89613a0b565b6001600160801b031681526020018860a00135815260200161329d89613a20565b6001600160801b031681526020016132b489613a2f565b6001600160801b031681526020016132cf60e08a018a614630565b6040516132dd929190614924565b604051809103902081526020018665ffffffffffff1681526020018565ffffffffffff16815260200161331d6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031690526101c08120909150601960f81b600160f81b613342611620565b6040516001600160f81b031993841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b856133b25760006133b5565b60015b60ff161717949350505050565b60016000908152602082905260409020546001600160a01b0316156133fa576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602092909252604090912080546001600160a01b0319169091179055565b6001600160a01b038116158061343e57506001600160a01b0381166001145b1561346757604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0381811660009081526020849052604090205416156134ab57604051631034f46960e21b81526001600160a01b03821660048201526024016105bd565b60016000818152602093909352604080842080546001600160a01b039485168087529286208054959091166001600160a01b03199586161790559190935280549091169091179055565b6001600160a01b038116158061351457506001600160a01b0381166001145b1561353d57604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b03828116600090815260208681526040808320878516845290915290205481169082161461359057604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b6001600160a01b038116158061360b57506001600160a01b0381166001145b1561363457604051637c84ecfb60e01b81526001600160a01b03831660048201526024016105bd565b6001600160a01b0382811660009081526020859052604090205481169082161461367c57604051637c84ecfb60e01b81526001600160a01b03821660048201526024016105bd565b6001600160a01b0390811660008181526020949094526040808520805494841686529085208054949093166001600160a01b0319948516179092559092528154169055565b6060600061372c857f000000000000000000000000000000000000000000000000000000000000000086866040516024016136fd92919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b17905261374b565b90508080602001905181019061374291906149e3565b95945050505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b815260040161378394939291906144a0565b6000604051808303816000875af11580156137a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137ca91908101906144eb565b925090508061267057604051632b3f6d1160e21b815260040160405180910390fd5b6060806000613858867f0000000000000000000000000000000000000000000000000000000000000000878760405160240161382992919061481e565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b17905261393b565b90508080602001905181019061386e9190614a17565b9097909650945050505050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b81526004016138b294939291906144a0565b6000604051808303816000875af11580156138d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f991908101906144eb565b925090508061172557604080516001600160a01b038816815260006020820152600080516020614ad7833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b815260040161397394939291906144a0565b6000604051808303816000875af1158015613992573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526139ba91908101906144eb565b925090508061267057604080516001600160a01b038716815260006020820152600080516020614ad7833981519152910160405180910390a1509392505050565b6000610663826080013560801c90565b60006001600160801b03608083013516610663565b600060c082013560801c610663565b60006001600160801b0360c083013516610663565b6001600160a01b0381168114613a5957600080fd5b50565b803561161b81613a44565b60008083601f840112613a7957600080fd5b5081356001600160401b03811115613a9057600080fd5b60208301915083602082850101111561054e57600080fd5b60008060008060608587031215613abe57600080fd5b843593506020850135613ad081613a44565b925060408501356001600160401b03811115613aeb57600080fd5b613af787828801613a67565b95989497509550505050565b600080600060408486031215613b1857600080fd5b8335925060208401356001600160401b03811115613b3557600080fd5b613b4186828701613a67565b9497909650939450505050565b600080600060608486031215613b6357600080fd5b83356001600160401b03811115613b7957600080fd5b84016101208187031215613b8c57600080fd5b95602085013595506040909401359392505050565b60008083601f840112613bb357600080fd5b5081356001600160401b03811115613bca57600080fd5b6020830191508360208260051b850101111561054e57600080fd5b600060608284031215613bf757600080fd5b50919050565b600080600080600080600080600060a08a8c031215613c1b57600080fd5b89356001600160401b03811115613c3157600080fd5b613c3d8c828d01613ba1565b909a5098505060208a01356001600160401b03811115613c5c57600080fd5b613c688c828d01613ba1565b90985096505060408a01356001600160401b03811115613c8757600080fd5b613c938c828d01613ba1565b90965094505060608a01356001600160401b03811115613cb257600080fd5b613cbe8c828d01613ba1565b90945092505060808a01356001600160401b03811115613cdd57600080fd5b613ce98c828d01613be5565b9150509295985092959850929598565b60008060208385031215613d0c57600080fd5b82356001600160401b03811115613d2257600080fd5b613d2e85828601613ba1565b90969095509350505050565b60008060408385031215613d4d57600080fd5b8235613d5881613a44565b946020939093013593505050565b6040808252835190820181905260009060208501906060840190835b81811015613da95783516001600160a01b0316835260209384019390920191600101613d82565b50506001600160a01b039490941660209390930192909252509092915050565b60005b83811015613de4578181015183820152602001613dcc565b50506000910152565b60008151808452613e05816020860160208601613dc9565b601f01601f19169290920160200192915050565b6020815260006109d76020830184613ded565b6001600160e01b031981168114613a5957600080fd5b600060208284031215613e5457600080fd5b81356109d781613e2c565b600060208284031215613e7157600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015613ed157603f19878603018452613ebc858351613ded565b94506020938401939190910190600101613ea0565b50929695505050505050565b60008060408385031215613ef057600080fd5b8235613efb81613a44565b91506020830135613f0b81613a44565b809150509250929050565b803560ff8116811461161b57600080fd5b60008060008060608587031215613f3d57600080fd5b8435613f4881613a44565b935060208501356001600160401b03811115613f6357600080fd5b613f6f87828801613ba1565b9094509250613f82905060408601613f16565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000613fde606083018486613f8d565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561402657614026613fe8565b604052919050565b60006001600160401b0382111561404757614047613fe8565b50601f01601f191660200190565b60006140686140638461402e565b613ffe565b905082815283838301111561407c57600080fd5b6109d7836020830184613dc9565b600082601f83011261409b57600080fd5b6109d783835160208501614055565b6000602082840312156140bc57600080fd5b81516001600160401b038111156140d257600080fd5b6107418482850161408a565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60006020828403121561411657600080fd5b5051919050565b6000808585111561412d57600080fd5b8386111561413a57600080fd5b5050820193919092039150565b80356bffffffffffffffffffffffff19811690601484101561418d576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b8481526060602082015260006141ad6060830186613ded565b82810360408401526141c0818587613f8d565b979650505050505050565b6000602082840312156141dd57600080fd5b81516109d781613e2c565b6000808335601e198436030181126141ff57600080fd5b83016020810192503590506001600160401b0381111561421e57600080fd5b80360382131561054e57600080fd5b6040815261424e6040820161424185613a5c565b6001600160a01b03169052565b60208301356060820152600061426760408501856141e8565b610120608085015261427e61016085018284613f8d565b91505061428e60608601866141e8565b848303603f190160a08601526142a5838284613f8d565b608088013560c08781019190915260a089013560e080890191909152908901356101008801529093506142dd925087019050866141e8565b848303603f19016101208601526142f5838284613f8d565b925050506143076101008601866141e8565b848303603f190161014086015261431f838284613f8d565b93505050508260208301529392505050565b60006020828403121561434357600080fd5b81356109d781613a44565b6000808335601e1984360301811261436557600080fd5b8301803591506001600160401b0382111561437f57600080fd5b6020019150600581901b360382131561054e57600080fd5b6000602082840312156143a957600080fd5b6109d782613f16565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126143de57600080fd5b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061374290830184613ded565b60006020828403121561442457600080fd5b81516001600160401b0381111561443a57600080fd5b8201601f8101841361444b57600080fd5b61074184825160208401614055565b64736166652d60d81b81526000825161447a816005850160208701613dc9565b6e2e657263373537392e76302e302e3160881b6005939091019283015250601401919050565b60018060a01b03851681528360208201526080604082015260006144c76080830185613ded565b905060ff8316606083015295945050505050565b8051801515811461161b57600080fd5b600080604083850312156144fe57600080fd5b614507836144db565b915060208301516001600160401b0381111561452257600080fd5b61452e8582860161408a565b9150509250929050565b6001600160a01b038316815260406020820181905260009061074190830184613ded565b60006020828403121561456e57600080fd5b6109d7826144db565b80356002811061161b57600080fd5b6000806040838503121561459957600080fd5b6145a283614577565b91506020830135613f0b81613e2c565b828152600082516145ca816020850160208701613dc9565b919091016020019392505050565b60ff84168152604060208201819052810182905260008360608301825b8581101561462557823561460881613a44565b6001600160a01b03168252602092830192909101906001016145f5565b509695505050505050565b6000808335601e1984360301811261464757600080fd5b8301803591506001600160401b0382111561466157600080fd5b60200191503681900382131561054e57600080fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161469e5761469e614676565b5060010190565b8181038181111561066357610663614676565b600082601f8301126146c957600080fd5b81356146d76140638261402e565b8181528460208386010111156146ec57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561471e57600080fd5b833561472981613e2c565b925060208401356001600160f81b03198116811461474657600080fd5b915060408401356001600160401b0381111561476157600080fd5b61476d868287016146b8565b9150509250925092565b60008060006060848603121561478c57600080fd5b61479584614577565b9250602084013561474681613e2c565b634e487b7160e01b600052602160045260246000fd5b600080604083850312156147ce57600080fd5b82356147d981613a44565b915060208301356001600160401b038111156147f457600080fd5b61452e858286016146b8565b6000806040838503121561481357600080fd5b82356147d981613e2c565b6020808252810182905260006040600584901b830181019083018583605e1936839003015b878210156148c357868503603f19018452823581811261486257600080fd5b8901803561486f81613a44565b6001600160a01b031686526020818101359087015261489160408201826141e8565b9150606060408801526148a8606088018383613f8d565b96505050602083019250602084019350600182019150614843565b5092979650505050505050565b8035602083101561066357600019602084900360031b1b1692915050565b80356001600160d01b0319811690600684101561418d576001600160d01b031960069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b0382111561494d5761494d613fe8565b5060051b60200190565b600082601f83011261496857600080fd5b815161497661406382614934565b8082825260208201915060208360051b86010192508583111561499857600080fd5b602085015b838110156149d95780516001600160401b038111156149bb57600080fd5b6149ca886020838a010161408a565b8452506020928301920161499d565b5095945050505050565b6000602082840312156149f557600080fd5b81516001600160401b03811115614a0b57600080fd5b61074184828501614957565b60008060408385031215614a2a57600080fd5b82516001600160401b03811115614a4057600080fd5b8301601f81018513614a5157600080fd5b8051614a5f61406382614934565b8082825260208201915060208360051b850101925087831115614a8157600080fd5b6020840193505b82841015614aaa57614a99846144db565b825260209384019390910190614a88565b8095505050505060208301516001600160401b03811115614aca57600080fd5b61452e8582860161495756feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca2646970667358221220ea61ad763284881149748ddd79675cc8013f934a2a4db1bb658c0c975b908ebb64736f6c634300081a00336080604052348015600f57600080fd5b506109d18061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100df57806378272525146100f25780639517e29f146101055780639abb6e171461011857600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100bf575b600080fd5b6100956100903660046105c9565b610139565b005b6100aa6100a53660046105c9565b6101a3565b60405190151581526020015b60405180910390f35b6100d26100cd3660046105c9565b610212565b6040516100b691906106d3565b6100956100ed36600461071f565b6102cc565b6100956101003660046107e9565b6102ef565b6100956101133660046107e9565b610398565b61012b6101263660046105c9565b610437565b6040516100b6929190610873565b8060005b8181101561019d5736848483818110610158576101586108cd565b905060200281019061016a91906108e3565b905061019361017c6020830183610903565b602083013561018e604085018561091e565b610561565b505060010161013d565b50505050565b600081815b8181101561020a57368585838181106101c3576101c36108cd565b90506020028101906101d591906108e3565b90506101fe6101e76020830183610903565b60208301356101f9604085018561091e565b610597565b509350506001016101a8565b505092915050565b6060818067ffffffffffffffff81111561022e5761022e610709565b60405190808252806020026020018201604052801561026157816020015b606081526020019060019003908161024c5790505b50915060005b8181101561020a5736858583818110610282576102826108cd565b905060200281019061029491906108e3565b90506102a661017c6020830183610903565b8483815181106102b8576102b86108cd565b602090810291909101015250600101610267565b604051600080835160208501865afa3d6000833e80156102ea573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061031d908590859060040161096c565b600060405180830381600087803b15801561033757600080fd5b505af115801561034b573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103c6908590859060040161096c565b600060405180830381600087803b1580156103e057600080fd5b505af11580156103f4573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061038a565b606080828067ffffffffffffffff81111561045457610454610709565b60405190808252806020026020018201604052801561048757816020015b60608152602001906001900390816104725790505b5091508067ffffffffffffffff8111156104a3576104a3610709565b6040519080825280602002602001820160405280156104cc578160200160208202803683370190505b50925060005b8181101561055857368686838181106104ed576104ed6108cd565b90506020028101906104ff91906108e3565b90506105116101e76020830183610903565b868481518110610523576105236108cd565b6020026020010186858151811061053c5761053c6108cd565b60209081029190910101919091529015159052506001016104d2565b50509250929050565b60405181838237600038838387895af161057e573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105dc57600080fd5b823567ffffffffffffffff8111156105f357600080fd5b8301601f8101851361060457600080fd5b803567ffffffffffffffff81111561061b57600080fd5b8560208260051b840101111561063057600080fd5b6020919091019590945092505050565b600082825180855260208501945060208160051b8301016020850160005b838110156106c757848303601f190188528151805180855260005b8181101561069557602081840181015187830182015201610679565b506000602082870101526020601f19601f8301168601019450505060208201915060208801975060018101905061065e565b50909695505050505050565b6020815260006106e66020830184610640565b9392505050565b80356001600160a01b038116811461070457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561073257600080fd5b61073b836106ed565b9150602083013567ffffffffffffffff81111561075757600080fd5b8301601f8101851361076857600080fd5b803567ffffffffffffffff81111561078257610782610709565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156107b1576107b1610709565b6040528181528282016020018710156107c957600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600080606085870312156107ff57600080fd5b8435935061080f602086016106ed565b9250604085013567ffffffffffffffff81111561082b57600080fd5b8501601f8101871361083c57600080fd5b803567ffffffffffffffff81111561085357600080fd5b87602082840101111561086557600080fd5b949793965060200194505050565b6040808252835190820181905260009060208501906060840190835b818110156108af578351151583526020938401939092019160010161088f565b505083810360208501526108c38186610640565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108f957600080fd5b9190910192915050565b60006020828403121561091557600080fd5b6106e6826106ed565b6000808335601e1984360301811261093557600080fd5b83018035915067ffffffffffffffff82111561095057600080fd5b60200191503681900382131561096557600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220720ef7861d004c898c5584226bd363229b671686bc710cd9ba8dec323c2a769164736f6c634300081a0033" + "0x000000000000000000000000000000000000000000000000000000000000000060a0604052348015600f57600080fd5b50604051601a906046565b604051809103906000f0801580156035573d6000803e3d6000fd5b506001600160a01b03166080526053565b6109e180614d7483390190565b608051614cb96100bb60003960008181610f340152818161112c0152818161128d01528181611ad601528181611f2d015281816120070152818161209e0152818161213501528181613248015281816133000152818161385b015261397b0152614cb96000f3fe6080604052600436106101235760003560e01c8063b0d691fe116100a0578063e9ae5c5311610064578063e9ae5c5314610479578063ea5f61d014610499578063eab77e17146104b9578063f2dc691d146104d9578063f698da25146104f95761012a565b8063b0d691fe1461039e578063b875d5d8146103c1578063d03c79141461040c578063d691c9641461042c578063d828435d146104595761012a565b80635faac46b116100e75780635faac46b146102d257806379aad60e146103005780639517e29f146103205780639cfd7cff14610340578063a71763a81461037e5761012a565b80630a664dba146101d5578063112d3a7d146102195780631626ba7e1461024957806319822f7c14610282578063540fb4f9146102b05761012a565b3661012a57005b600036606060003560e01c63bc197c81811463f23a6e6182141763150b7a028214171561015b57806020526020603cf35b50336000818152600460209081526040808320546001600160e01b031984351680855260058452828520958552949092528220546001600160a01b0391821692911690806101a9848461050e565b915091506101b788886105cc565b95506101c5848484846106df565b5050505050915050805190602001f35b3480156101e157600080fd5b50336000908152600460205260409020546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561022557600080fd5b50610239610234366004613c93565b610762565b6040519015158152602001610210565b34801561025557600080fd5b50610269610264366004613cee565b6107bf565b6040516001600160e01b03199091168152602001610210565b34801561028e57600080fd5b506102a261029d366004613d39565b610b35565b604051908152602001610210565b3480156102bc57600080fd5b506102d06102cb366004613de8565b610c49565b005b3480156102de57600080fd5b506102f26102ed366004613ee4565b610cf9565b604051610210929190613f10565b34801561030c57600080fd5b506102d061031b366004613f73565b610d15565b34801561032c57600080fd5b506102d061033b366004613c93565b610dd9565b34801561034c57600080fd5b50604080518082018252600f81526e073616665373537392e76312e302e3608c1b602082015290516102109190614004565b34801561038a57600080fd5b506102d0610399366004613c93565b610fa4565b3480156103aa57600080fd5b506f71727de22e5e9d8baf0edac6f37da0326101fc565b3480156103cd57600080fd5b506101fc6103dc36600461402d565b6001600160e01b03191660009081526005602090815260408083203384529091529020546001600160a01b031690565b34801561041857600080fd5b5061023961042736600461404a565b6112cb565b34801561043857600080fd5b5061044c610447366004613cee565b611373565b6040516102109190614063565b34801561046557600080fd5b506102a26104743660046140c8565b61145c565b34801561048557600080fd5b506102d0610494366004613cee565b6114fc565b3480156104a557600080fd5b506102f26104b4366004613ee4565b611899565b3480156104c557600080fd5b506102d06104d4366004614112565b6118aa565b3480156104e557600080fd5b506102396104f436600461404a565b611919565b34801561050557600080fd5b506102a2611968565b6060806001600160a01b0384161561058e576105753385600061052f6119c1565b3460003660405160240161054694939291906141a1565b60408051601f198184030181529190526020810180516001600160e01b031663d68f602560e01b1790526119cd565b91508180602001905181019061058b919061428a565b91505b6001600160a01b038316156105c5576105ac3384600061052f6119c1565b9050808060200190518101906105c2919061428a565b90505b9250929050565b600080356001600160e01b031916815260036020908152604080832033845290915290208054606091906001600160a01b03811690600160a01b900460f81b8161063c57604051632464e76d60e11b81526001600160e01b03196000351660048201526024015b60405180910390fd5b61064a81607f60f91b611a76565b1561068e576106843383888861065e6119c1565b604051602001610670939291906142be565b604051602081830303815290604052611a88565b93505050506106d9565b610699816000611a76565b156106d5576106843383600089896106af6119c1565b6040516020016106c1939291906142be565b6040516020818303038152906040526119cd565b5050505b92915050565b6001600160a01b038416156107355761073533856000856040516024016107069190614004565b60408051601f198184030181529190526020810180516001600160e01b0316630b9dfbed60e11b179052611b5d565b6001600160a01b0383161561075c5761075c33846000846040516024016107069190614004565b50505050565b60006001850361077c5761077584611bfc565b90506107b7565b6002850361078d5761077584611c0a565b600385036107a057610775848484611c18565b600485036107b357610775848484611c64565b5060005b949350505050565b600033828203610959576000610890826001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083091906142e4565b60408051602081018a90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca91015b60408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052611c9f565b8051602090910120604051635ae6bd3760e01b8152600481018290529091506001600160a01b03831690635ae6bd3790602401602060405180830381865afa1580156108e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090491906142e4565b6000036109475760405162461bcd60e51b815260206004820152601160248201527012185cda081b9bdd08185c1c1c9bdd9959607a1b6044820152606401610633565b50630b135d3f60e11b9150610b2e9050565b600061096860148286886142fd565b61097191614327565b60601c9050801580610989575061098781611bfc565b155b15610ab3576000610a28836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f591906142e4565b60408051602081018b90527f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca910161085f565b805160208201209091506001600160a01b03841663934f3a118284610a508a6014818e6142fd565b6040518563ffffffff1660e01b8152600401610a6f9493929190614374565b60006040518083038186803b158015610a8757600080fd5b505afa158015610a9b573d6000803e3d6000fd5b50630b135d3f60e11b9750610b2e9650505050505050565b6000610b123383610ac26119c1565b8a610ad08a6014818e6142fd565b604051602401610ae394939291906141a1565b60408051601f198184030181529190526020810180516001600160e01b0316637aa8f17760e11b179052611a88565b905080806020019051810190610b2891906143ab565b93505050505b9392505050565b60006f71727de22e5e9d8baf0edac6f37da032610b506119c1565b6001600160a01b031614610b7757604051635629665f60e11b815260040160405180910390fd5b6020840135606081901c90811580610b955750610b9382611bfc565b155b15610baa57610ba386611d19565b9250610c0f565b6000610bf5338460008a8a604051602401610bc692919061440d565b60408051601f198184030181529190526020810180516001600160e01b0316639700320360e01b1790526119cd565b905080806020019051810190610c0b91906142e4565b9350505b8315610c4057610c40336f71727de22e5e9d8baf0edac6f37da0328660405180602001604052806000815250611b5d565b50509392505050565b6f71727de22e5e9d8baf0edac6f37da032610c626119c1565b6001600160a01b03161480610c8f5750610c7a6119c1565b6001600160a01b0316336001600160a01b0316145b610cac57604051635629665f60e11b815260040160405180910390fd5b610cde610cbc6020830183614511565b610cc9602084018461452e565b610cd96060860160408701614577565b611dce565b610cee8989898989898989611e85565b505050505050505050565b60606000610d0a60013386866121a4565b915091509250929050565b6f71727de22e5e9d8baf0edac6f37da032610d2e6119c1565b6001600160a01b03161480610d5b5750610d466119c1565b6001600160a01b0316336001600160a01b0316145b610d7857604051635629665f60e11b815260040160405180910390fd5b610d83600133612368565b8060005b8181101561075c5736848483818110610da257610da2614592565b9050602002810190610db491906145a8565b9050610dd033610dc76020840184614511565b600191906123e3565b50600101610d87565b336000908152600460209081526040808320547fd00bcad91b775f25eb0aee15808d12dfdaa6dc5a7d6b754e26f9c205d2a3b8df909252822054639517e29f60e01b926001600160a01b03928316929091169080610e37848461050e565b91509150610e526f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b0316610e636119c1565b6001600160a01b03161480610e905750610e7b6119c1565b6001600160a01b0316336001600160a01b0316145b610ead57604051635629665f60e11b815260040160405180910390fd5b606060018a03610ec957610ec28989896124d8565b9050610f2e565b60028a03610edc57610ec2898989612534565b60038a03610eef57610ec289898961254f565b60048a03610f0257610ec28989896126ce565b89610f1257610ec289898961286e565b60405163041c38b360e41b8152600481018b9052602401610633565b610f97337f00000000000000000000000000000000000000000000000000000000000000008c8c85604051602401610f68939291906145c8565b60408051601f198184030181529190526020810180516001600160e01b0316639517e29f60e01b179052612a1f565b50610cee848484846106df565b336000908152600460209081526040808320547fc45a7acaba78a7b4c4432b604d301355b314c0a7811768a1ee2563c9d34ca4e09092529091205484916314e2ec7560e31b916001600160a01b0391821691908116908416821480159061101d5750806001600160a01b0316846001600160a01b031614155b156111a35760008061102f848461050e565b9150915061104a6f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b031661105b6119c1565b6001600160a01b0316148061108857506110736119c1565b6001600160a01b0316336001600160a01b0316145b6110a557604051635629665f60e11b815260040160405180910390fd5b606060018b036110c1576110ba8a8a8a612ab8565b9050611126565b60028b036110d4576110ba8a8a8a612ae1565b60038b036110e7576110ba8a8a8a612b02565b60048b036110fa576110ba8a8a8a612b4e565b8a61110a576110ba8a8a8a612c06565b60405163041c38b360e41b8152600481018c9052602401610633565b61118f337f00000000000000000000000000000000000000000000000000000000000000008d8d85604051602401611160939291906145c8565b60408051601f198184030181529190526020810180516001600160e01b0316637827252560e01b179052612d59565b5061119c848484846106df565b50506112c1565b6f71727de22e5e9d8baf0edac6f37da0326111bc6119c1565b6001600160a01b031614806111e957506111d46119c1565b6001600160a01b0316336001600160a01b0316145b61120657604051635629665f60e11b815260040160405180910390fd5b6060600189036112225761121b888888612ab8565b9050611287565b600289036112355761121b888888612ae1565b600389036112485761121b888888612b02565b6004890361125b5761121b888888612b4e565b8861126b5761121b888888612c06565b60405163041c38b360e41b8152600481018a9052602401610633565b610cee337f00000000000000000000000000000000000000000000000000000000000000008b8b85604051602401611160939291906145c8565b5050505050505050565b600081600881901b6112e182600160f81b611a76565b156112ef5760019250611332565b6112fa826000611a76565b156113085760019250611332565b61131a826001600160f81b0319611a76565b156113285760019250611332565b5060009392505050565b8280156113455750611345816000611a76565b15611351575050919050565b828015611367575061136781600160f81b611a76565b15611328575050919050565b60606113856113806119c1565b611c0a565b6113b6576113916119c1565b604051635c93ff2f60e11b81526001600160a01b039091166004820152602401610633565b336000908152600460209081526040808320547f4162c930ade27880570b0eb31efbc8a626b97e81a40ced27163509dfe16398829092528220546335a4725960e21b926001600160a01b03928316929091169080611414848461050e565b915091506114206119c1565b600261142c8282612e0f565b8a600881901b61143e81838e8e612e9a565b995050505050611450848484846106df565b50505050509392505050565b6000602082901b640100000000600160c01b03166f71727de22e5e9d8baf0edac6f37da032604051631aab3f0d60e11b81526001600160a01b0386811660048301526001600160c01b038416602483015291909116906335567e1a90604401602060405180830381865afa1580156114d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b791906142e4565b336000908152600460209081526040808320547fccfe1b2bef70acd8e661aeb5430e147f4c75cb320972acba718a28da428e1a3090925282205463e9ae5c5360e01b926001600160a01b0392831692909116908061155a848461050e565b915091506115756f71727de22e5e9d8baf0edac6f37da03290565b6001600160a01b03166115866119c1565b6001600160a01b031614806115b3575061159e6119c1565b6001600160a01b0316336001600160a01b0316145b6115d057604051635629665f60e11b815260040160405180910390fd5b87600881901b336115e2826000611a76565b1561173b576115f583600160f81b611a76565b156116165789358a0160208101903561160f838383613242565b505061188a565b611621836000611a76565b15611689576000803660006116368e8e6132a9565b935093509350935061168085858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b5d92505050565b5050505061188a565b61169b836001600160f81b0319611a76565b156117205760006116af6014828c8e6142fd565b6116b891614327565b60601c90503660008c8c60149080926116d3939291906142fd565b91509150611718848484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a1f92505050565b50505061188a565b82604051632e5bf3f960e21b815260040161063391906145fb565b61174982600160f81b611a76565b1561186f5761175c83600160f81b611a76565b156117765789358a0160208101903561160f8383836132fa565b611781836000611a76565b156117e0576000803660006117968e8e6132a9565b935093509350935061168085858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061336192505050565b6117f2836001600160f81b0319611a76565b156117205760006118066014828c8e6142fd565b61180f91614327565b60601c90503660008c8c601490809261182a939291906142fd565b91509150611718848484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d5992505050565b816040516308c3ee0360e11b815260040161063391906145fb565b5050506112c1848484846106df565b60606000610d0a60023386866121a4565b6f71727de22e5e9d8baf0edac6f37da0326118c36119c1565b6001600160a01b031614806118f057506118db6119c1565b6001600160a01b0316336001600160a01b0316145b61190d57604051635629665f60e11b815260040160405180910390fd5b61075c84848484611dce565b60006001820361192b57506001919050565b6002820361193b57506001919050565b6003820361194b57506001919050565b6004820361195b57506001919050565b506000919050565b919050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b60131936013560601c90565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b8152600401611a049493929190614648565b6000604051808303816000875af1158015611a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a4b919081019061468e565b9250905080611a6d57604051632b3f6d1160e21b815260040160405180910390fd5b50949350505050565b6001600160f81b031990811691161490565b606060008383604051602401611a9f9291906146db565b60408051601f198184030181529181526020820180516001600160e01b0316636a22165760e01b17905251909150600090611b00907f00000000000000000000000000000000000000000000000000000000000000009084906024016146db565b60408051601f19818403018152919052602080820180516001600160e01b031663b4faba0960e01b17815282519293509091600091895afa5060203d036040519350808401604052806020853e50600051610c4057825160208401fd5b60405163468721a760e01b81526000906001600160a01b0386169063468721a790611b92908790879087908790600401614648565b6020604051808303816000875af1158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd591906146ff565b905080611bf557604051632b3f6d1160e21b815260040160405180910390fd5b5050505050565b60006106d960013384613417565b60006106d960023384613417565b600080611c278385018561402d565b6001600160e01b03191660009081526003602090815260408083203384529091529020546001600160a01b03908116908616149150509392505050565b60008080611c7484860186614729565b915091506000611c84838361345b565b6001600160a01b039081169088161493505050509392505050565b6060601960f81b600160f81b858585604051602001611cbf929190614755565b60408051808303601f190181529082905280516020918201206001600160f81b0319958616918301919091529290931660218401526022830152604282015260620160405160208183030381529060405290509392505050565b60008080803681611d3a876f71727de22e5e9d8baf0edac6f37da0326134f1565b8451602086012060405163934f3a1160e01b8152959a5093985091965094509250339163934f3a1191611d7591899087908790600401614374565b60006040518083038186803b158015611d8d57600080fd5b505afa925050508015611d9e575060015b611db557611dae60018486613724565b9550611dc4565b611dc160008486613724565b95505b5050505050919050565b33600090815260208190526040902080546001600160a01b0319166001600160a01b03861690811790915515611e4957611e4933856000848787604051602401611e1a9392919061477b565b60408051601f198184030181529190526020810180516001600160e01b031663f05c04e160e01b179052611b5d565b6040516001600160a01b0385169033907f9452c8fb077c3ea8f28a77c87488af657b1e44d010ad9a5992d73870da040e9490600090a350505050565b3360009081527fcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f602052604090205460609088906001600160a01b0316611f7d57611ed1600133612368565b60005b81811015611f7757368b8b83818110611eef57611eef614592565b9050602002810190611f0191906145a8565b9050611f25611f136020830183614511565b611f2060208401846147d3565b6124d8565b9350611f6e337f00000000000000000000000000000000000000000000000000000000000000006001611f5b6020860186614511565b88604051602401610f68939291906145c8565b50600101611ed4565b50611f9e565b8015611f9e5760405163d8e3ed1b60e01b8152336004820152602401610633565b611fa9600233612368565b508560005b8181101561203e5736898983818110611fc957611fc9614592565b9050602002810190611fdb91906145a8565b9050611fff611fed6020830183614511565b611ffa60208401846147d3565b612534565b9350612035337f00000000000000000000000000000000000000000000000000000000000000006002611f5b6020860186614511565b50600101611fae565b5084905060005b818110156120d5573687878381811061206057612060614592565b905060200281019061207291906145a8565b90506120966120846020830183614511565b61209160208401846147d3565b61254f565b93506120cc337f00000000000000000000000000000000000000000000000000000000000000006003611f5b6020860186614511565b50600101612045565b5082905060005b8181101561216c57368585838181106120f7576120f7614592565b905060200281019061210991906145a8565b905061212d61211b6020830183614511565b61212860208401846147d3565b6126ce565b9350612163337f00000000000000000000000000000000000000000000000000000000000000006004611f5b6020860186614511565b506001016120dc565b5060405133907ff48581d8a62b775b74f2fb67f1d5806a9a356fbcc598040ab3071d3e37af40c290600090a250505050505050505050565b606060006001600160a01b0384166001148015906121ca57506121c8868686613417565b155b156121f357604051637c84ecfb60e01b81526001600160a01b0385166004820152602401610633565b826000036122145760405163f725081760e01b815260040160405180910390fd5b826001600160401b0381111561222c5761222c6141d3565b604051908082528060200260200182016040528015612255578160200160208202803683370190505b506001600160a01b038086166000908152602089815260408083208a85168452909152812054929450911691505b6001600160a01b038216158015906122a557506001600160a01b038216600114155b80156122b057508381105b1561231557818382815181106122c8576122c8614592565b6001600160a01b039283166020918202929092018101919091529281166000908152888452604080822089841683529094529290922054909116908061230d8161482f565b915050612283565b6001600160a01b03821660011480159061232f5750600081115b1561235b5782612340600183614848565b8151811061235057612350614592565b602002602001015191505b8083525094509492505050565b60016000908152602083815260408083206001600160a01b03808616855292529091205416156123ab576040516329e42f3360e11b815260040160405180910390fd5b60016000818152602093845260408082206001600160a01b0394909416825292909352912080546001600160a01b0319169091179055565b6001600160a01b038116158061240257506001600160a01b0381166001145b1561242b57604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610633565b6001600160a01b038181166000908152602085815260408083208685168452909152902054161561247a57604051631034f46960e21b81526001600160a01b0382166004820152602401610633565b60016000908152602084815260408083206001600160a01b039586168085528184528285208054968816808752988552838620918652908452919093208054949095166001600160a01b031994851617909455528154169091179055565b60608360016124e78282612e0f565b6124f3600133886123e3565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b60608360026125438282612e0f565b6124f3600233886123e3565b606083600361255e8282612e0f565b6000808061256e878901896148ac565b919450925090506001600160e01b031983166306d61fe760e41b14806125a457506001600160e01b03198316638a91b0e360e01b145b156125ce576040516379bd117b60e01b81526001600160e01b031984166004820152602401610633565b6125d9826000611a76565b80156125ee57506125ee82607f60f91b611a76565b1561260e57816040516376087dc160e01b815260040161063391906145fb565b6001600160e01b0319831660009081526003602090815260408083203384529091529020546001600160a01b031615612666576040516374420d1560e01b81526001600160e01b031984166004820152602401610633565b6001600160e01b03199092166000908152600360209081526040808320338452909152902080546001600160a01b038a166001600160a01b031960f89490941c600160a01b02939093166001600160a81b031990911617919091179055925050509392505050565b60608360046126dd8282612e0f565b600080806126ed8789018961491a565b9194509250905060008084600181111561270957612709614610565b14801561271e57506001600160e01b03198316155b156127945750336000908152600460205260409020546001600160a01b031680156127675760405163741cbe0360e01b81526001600160a01b0382166004820152602401610633565b33600090815260046020526040902080546001600160a01b0319166001600160a01b038c16179055612861565b60018460018111156127a8576127a8614610565b0361284857506001600160e01b0319821660009081526005602090815260408083203384529091529020546001600160a01b031680156128065760405163741cbe0360e01b81526001600160a01b0382166004820152602401610633565b6001600160e01b031983166000908152600560209081526040808320338452909152902080546001600160a01b0319166001600160a01b038c16179055612861565b604051635691922f60e01b815260040160405180910390fd5b5098975050505050505050565b606082358301602081810191359085810135860180820191903590604088013588019081019035848381146128b65760405163b4fa3fb360e01b815260040160405180910390fd5b60005b818110156129d85760008888838181106128d5576128d5614592565b905060200201359050600181036129145761290e8d8888858181106128fc576128fc614592565b9050602002810190611f2091906147d3565b506129cf565b600281036129445761290e8d88888581811061293257612932614592565b9050602002810190611ffa91906147d3565b600381036129745761290e8d88888581811061296257612962614592565b905060200281019061209191906147d3565b600481036129a45761290e8d88888581811061299257612992614592565b905060200281019061212891906147d3565b60405163484d218160e01b81526001600160a01b038e16600482015260248101829052604401610633565b506001016128b9565b5082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60405163468721a760e01b81526000906001600160a01b0385169063468721a790612a5590869085908790600190600401614648565b6020604051808303816000875af1158015612a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9891906146ff565b90508061075c57604051632b3f6d1160e21b815260040160405180910390fd5b60606000612ac883850185614948565b92509050612ad9600133838861375c565b509392505050565b60606000612af183850185614948565b92509050612ad9600233838861375c565b60606000612b128385018561498d565b6001600160e01b03199091166000908152600360209081526040808320338452909152902080546001600160a01b031916905595945050505050565b6060600080612b5f8486018661491a565b945090925090506000826001811115612b7a57612b7a614610565b148015612b8f57506001600160e01b03198116155b15612bb65733600090815260046020526040902080546001600160a01b0319169055610c40565b6001826001811115612bca57612bca614610565b03612848576001600160e01b031981166000908152600560209081526040808320338452909152902080546001600160a01b0319169055610c40565b60608235830160208181019135908581013586018082019190359060408801358801908101903584838114612c4e5760405163b4fa3fb360e01b815260040160405180910390fd5b60005b818110156129d8576000888883818110612c6d57612c6d614592565b90506020020135905060018103612cb157612cab8d888885818110612c9457612c94614592565b9050602002810190612ca691906147d3565b612ab8565b50612d50565b60028103612ce657612cab8d888885818110612ccf57612ccf614592565b9050602002810190612ce191906147d3565b612ae1565b60038103612d1b57612cab8d888885818110612d0457612d04614592565b9050602002810190612d1691906147d3565b612b02565b600481036129a457612cab8d888885818110612d3957612d39614592565b9050602002810190612d4b91906147d3565b612b4e565b50600101612c51565b60405163468721a760e01b81526000906001600160a01b0385169063468721a790612d8f90869085908790600190600401614648565b6020604051808303816000875af1158015612dae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd291906146ff565b90508061075c57604080516001600160a01b038616815260006020820152600080516020614c64833981519152910160405180910390a150505050565b336000908152602081905260409020546001600160a01b03168015612e955760405163529562a160e01b81523360048201526001600160a01b0384811660248301526044820184905282169063529562a19060640160006040518083038186803b158015612e7c57600080fd5b505afa158015612e90573d6000803e3d6000fd5b505050505b505050565b6060612ea7856000611a76565b1561309357612eba84600160f81b611a76565b15612edd5782358301602081019035612ed4338383613853565b925050506107b7565b612ee8846000611a76565b15612f9c57600080366000612efd87876132a9565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081612f1c579050509450612f7533858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119cd92505050565b85600081518110612f8857612f88614592565b6020026020010181905250505050506107b7565b612fae846001600160f81b0319611a76565b15613078576000612fc260148285876142fd565b612fcb91614327565b60601c9050366000612fe085601481896142fd565b604080516001808252818301909252929450909250816020015b6060815260200190600190039081612ffa579050509350613052338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506138cf92505050565b8460008151811061306557613065614592565b60200260200101819052505050506107b7565b83604051632e5bf3f960e21b815260040161063391906145fb565b6130a185600160f81b611a76565b15613227576130b484600160f81b611a76565b156130d957823583016020810190356130ce338383613970565b93506107b792505050565b6130e4846000611a76565b15613171576000803660006130f987876132a9565b6040805160018082528183019092529498509296509094509250816020015b6060815260200190600190039081613118579050509450612f7533858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613a6692505050565b613183846001600160f81b0319611a76565b1561307857600061319760148285876142fd565b6131a091614327565b60601c90503660006131b585601481896142fd565b604080516001808252818301909252929450909250816020015b60608152602001906001900390816131cf579050509350613052338484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613b2692505050565b846040516308c3ee0360e11b815260040161063391906145fb565b612e95837f0000000000000000000000000000000000000000000000000000000000000000848460405160240161327a9291906149ab565b60408051601f198184030181529190526020810180516001600160e01b0316633f707e6b60e01b179052612a1f565b60008036816132bb60148287896142fd565b6132c491614327565b60601c93506132d76034601487896142fd565b6132e091614a5d565b92506132ef85603481896142fd565b949793965094505050565b612e95837f000000000000000000000000000000000000000000000000000000000000000084846040516024016133329291906149ab565b60408051601f198184030181529190526020810180516001600160e01b0316632864481160e11b179052612d59565b60405163468721a760e01b81526000906001600160a01b0386169063468721a790613396908790879087908790600401614648565b6020604051808303816000875af11580156133b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d991906146ff565b905080611bf557604080516001600160a01b038716815260006020820152600080516020614c64833981519152910160405180910390a15050505050565b600060016001600160a01b038316148015906107b75750506001600160a01b0390811660009081526020938452604080822093831682529290935291205416151590565b60008083600181111561347057613470614610565b14801561348557506001600160e01b03198216155b156134a55750336000908152600460205260409020546001600160a01b03165b60018360018111156134b9576134b9614610565b036106d957506001600160e01b03191660009081526005602090815260408083203384529091529020546001600160a01b0316919050565b6060600080368181816135086101008a018a6147d3565b909250905061351b6006600083856142fd565b61352491614a7b565b60d01c9550613537600c600683856142fd565b61354091614a7b565b60d01c945061355281600c81856142fd565b9350935050506000604051806101c001604052807fc03dfc11d8b10bf9cf703d558958c8c42777f785d998c62060d85a4f0ef6ea7f60001b81526020018960000160208101906135a29190614511565b6001600160a01b03168152602001896020013581526020018980604001906135ca91906147d3565b6040516135d8929190614ab1565b60405190819003902081526020016135f360608b018b6147d3565b604051613601929190614ab1565b604051809103902081526020016136178a613be6565b6001600160801b0316815260200161362e8a613bf6565b6001600160801b031681526020018960a00135815260200161364f8a613c0b565b6001600160801b031681526020016136668a613c1a565b6001600160801b0316815260200161368160e08b018b6147d3565b60405161368f929190614ab1565b6040805191829003909120825265ffffffffffff80891660208401528716908201526001600160a01b0389166060909101526101c08120909150601960f81b600160f81b6136db611968565b6040516001600160f81b03199384166020820152929091166021830152602282015260428101829052606201604051602081830303815290604052965050509295509295909350565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561374c57600061374f565b60015b60ff161717949350505050565b6001600160a01b038116158061377b57506001600160a01b0381166001145b156137a457604051637c84ecfb60e01b81526001600160a01b0383166004820152602401610633565b6001600160a01b0382811660009081526020868152604080832087851684529091529020548116908216146137f757604051637c84ecfb60e01b81526001600160a01b0382166004820152602401610633565b6001600160a01b039081166000908152602085815260408083209584168084528683528184208054968616855297835281842090845282529091208054939092166001600160a01b031993841617909155919091528154169055565b60606138bc847f0000000000000000000000000000000000000000000000000000000000000000858560405160240161388d9291906149ab565b60408051601f198184030181529190526020810180516001600160e01b0316636108557360e01b1790526138cf565b8060200190518101906107b79190614b70565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b81526004016139079493929190614648565b6000604051808303816000875af1158015613926573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261394e919081019061468e565b9250905080612ad957604051632b3f6d1160e21b815260040160405180910390fd5b60608060006139dc867f000000000000000000000000000000000000000000000000000000000000000087876040516024016139ad9291906149ab565b60408051601f198184030181529190526020810180516001600160e01b0316639abb6e1760e01b179052613b26565b9050808060200190518101906139f29190614ba4565b8151919450925060005b81811015613a5b57848181518110613a1657613a16614592565b6020026020010151613a5357604080516001600160a01b038a16815260208101839052600080516020614c64833981519152910160405180910390a15b6001016139fc565b505050935093915050565b60606000856001600160a01b0316635229073f86868660006040518563ffffffff1660e01b8152600401613a9d9493929190614648565b6000604051808303816000875af1158015613abc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ae4919081019061468e565b9250905080611a6d57604080516001600160a01b038816815260006020820152600080516020614c64833981519152910160405180910390a150949350505050565b60606000846001600160a01b0316635229073f8560008660016040518563ffffffff1660e01b8152600401613b5e9493929190614648565b6000604051808303816000875af1158015613b7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ba5919081019061468e565b9250905080612ad957604080516001600160a01b038716815260006020820152600080516020614c64833981519152910160405180910390a1509392505050565b60006106d9826080013560801c90565b60006001600160801b036080830135166106d9565b600060c082013560801c6106d9565b60006001600160801b0360c0830135166106d9565b6001600160a01b0381168114613c4457600080fd5b50565b803561196381613c2f565b60008083601f840112613c6457600080fd5b5081356001600160401b03811115613c7b57600080fd5b6020830191508360208285010111156105c557600080fd5b60008060008060608587031215613ca957600080fd5b843593506020850135613cbb81613c2f565b925060408501356001600160401b03811115613cd657600080fd5b613ce287828801613c52565b95989497509550505050565b600080600060408486031215613d0357600080fd5b8335925060208401356001600160401b03811115613d2057600080fd5b613d2c86828701613c52565b9497909650939450505050565b600080600060608486031215613d4e57600080fd5b83356001600160401b03811115613d6457600080fd5b84016101208187031215613d7757600080fd5b95602085013595506040909401359392505050565b60008083601f840112613d9e57600080fd5b5081356001600160401b03811115613db557600080fd5b6020830191508360208260051b85010111156105c557600080fd5b600060608284031215613de257600080fd5b50919050565b600080600080600080600080600060a08a8c031215613e0657600080fd5b89356001600160401b03811115613e1c57600080fd5b613e288c828d01613d8c565b909a5098505060208a01356001600160401b03811115613e4757600080fd5b613e538c828d01613d8c565b90985096505060408a01356001600160401b03811115613e7257600080fd5b613e7e8c828d01613d8c565b90965094505060608a01356001600160401b03811115613e9d57600080fd5b613ea98c828d01613d8c565b90945092505060808a01356001600160401b03811115613ec857600080fd5b613ed48c828d01613dd0565b9150509295985092959850929598565b60008060408385031215613ef757600080fd5b8235613f0281613c2f565b946020939093013593505050565b6040808252835190820181905260009060208501906060840190835b81811015613f535783516001600160a01b0316835260209384019390920191600101613f2c565b50506001600160a01b039490941660209390930192909252509092915050565b60008060208385031215613f8657600080fd5b82356001600160401b03811115613f9c57600080fd5b613fa885828601613d8c565b90969095509350505050565b60005b83811015613fcf578181015183820152602001613fb7565b50506000910152565b60008151808452613ff0816020860160208601613fb4565b601f01601f19169290920160200192915050565b602081526000610b2e6020830184613fd8565b6001600160e01b031981168114613c4457600080fd5b60006020828403121561403f57600080fd5b8135610b2e81614017565b60006020828403121561405c57600080fd5b5035919050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b828110156140bc57603f198786030184526140a7858351613fd8565b9450602093840193919091019060010161408b565b50929695505050505050565b600080604083850312156140db57600080fd5b82356140e681613c2f565b915060208301356140f681613c2f565b809150509250929050565b803560ff8116811461196357600080fd5b6000806000806060858703121561412857600080fd5b843561413381613c2f565b935060208501356001600160401b0381111561414e57600080fd5b61415a87828801613d8c565b909450925061416d905060408601614101565b905092959194509250565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b03851681528360208201526060604082015260006141c9606083018486614178565b9695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614211576142116141d3565b604052919050565b60006001600160401b03821115614232576142326141d3565b50601f01601f191660200190565b600082601f83011261425157600080fd5b815161426461425f82614219565b6141e9565b81815284602083860101111561427957600080fd5b6107b7826020830160208701613fb4565b60006020828403121561429c57600080fd5b81516001600160401b038111156142b257600080fd5b6107b784828501614240565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000602082840312156142f657600080fd5b5051919050565b6000808585111561430d57600080fd5b8386111561431a57600080fd5b5050820193919092039150565b80356bffffffffffffffffffffffff19811690601484101561436d576bffffffffffffffffffffffff196bffffffffffffffffffffffff198560140360031b1b82161691505b5092915050565b84815260606020820152600061438d6060830186613fd8565b82810360408401526143a0818587614178565b979650505050505050565b6000602082840312156143bd57600080fd5b8151610b2e81614017565b6000808335601e198436030181126143df57600080fd5b83016020810192503590506001600160401b038111156143fe57600080fd5b8036038213156105c557600080fd5b6040815261442e6040820161442185613c47565b6001600160a01b03169052565b60208301356060820152600061444760408501856143c8565b610120608085015261445e61016085018284614178565b91505061446e60608601866143c8565b848303603f190160a0860152614485838284614178565b608088013560c08781019190915260a089013560e080890191909152908901356101008801529093506144bd925087019050866143c8565b848303603f19016101208601526144d5838284614178565b925050506144e76101008601866143c8565b848303603f19016101408601526144ff838284614178565b93505050508260208301529392505050565b60006020828403121561452357600080fd5b8135610b2e81613c2f565b6000808335601e1984360301811261454557600080fd5b8301803591506001600160401b0382111561455f57600080fd5b6020019150600581901b36038213156105c557600080fd5b60006020828403121561458957600080fd5b610b2e82614101565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126145be57600080fd5b9190910192915050565b8381526001600160a01b03831660208201526060604082018190526000906145f290830184613fd8565b95945050505050565b6001600160f81b031991909116815260200190565b634e487b7160e01b600052602160045260246000fd5b6002811061464457634e487b7160e01b600052602160045260246000fd5b9052565b60018060a01b038516815283602082015260806040820152600061466f6080830185613fd8565b90506145f26060830184614626565b8051801515811461196357600080fd5b600080604083850312156146a157600080fd5b6146aa8361467e565b915060208301516001600160401b038111156146c557600080fd5b6146d185828601614240565b9150509250929050565b6001600160a01b03831681526040602082018190526000906107b790830184613fd8565b60006020828403121561471157600080fd5b610b2e8261467e565b80356002811061196357600080fd5b6000806040838503121561473c57600080fd5b6147458361471a565b915060208301356140f681614017565b8281526000825161476d816020850160208701613fb4565b919091016020019392505050565b60ff84168152604060208201819052810182905260008360608301825b858110156147c85782356147ab81613c2f565b6001600160a01b0316825260209283019290910190600101614798565b509695505050505050565b6000808335601e198436030181126147ea57600080fd5b8301803591506001600160401b0382111561480457600080fd5b6020019150368190038213156105c557600080fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161484157614841614819565b5060010190565b818103818111156106d9576106d9614819565b600082601f83011261486c57600080fd5b813561487a61425f82614219565b81815284602083860101111561488f57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156148c157600080fd5b83356148cc81614017565b925060208401356001600160f81b0319811681146148e957600080fd5b915060408401356001600160401b0381111561490457600080fd5b6149108682870161485b565b9150509250925092565b60008060006060848603121561492f57600080fd5b6149388461471a565b925060208401356148e981614017565b6000806040838503121561495b57600080fd5b823561496681613c2f565b915060208301356001600160401b0381111561498157600080fd5b6146d18582860161485b565b600080604083850312156149a057600080fd5b823561496681614017565b6020808252810182905260006040600584901b830181019083018583605e1936839003015b87821015614a5057868503603f1901845282358181126149ef57600080fd5b890180356149fc81613c2f565b6001600160a01b0316865260208181013590870152614a1e60408201826143c8565b915060606040880152614a35606088018383614178565b965050506020830192506020840193506001820191506149d0565b5092979650505050505050565b803560208310156106d957600019602084900360031b1b1692915050565b80356001600160d01b0319811690600684101561436d576001600160d01b031960069490940360031b84901b1690921692915050565b8183823760009101908152919050565b60006001600160401b03821115614ada57614ada6141d3565b5060051b60200190565b600082601f830112614af557600080fd5b8151614b0361425f82614ac1565b8082825260208201915060208360051b860101925085831115614b2557600080fd5b602085015b83811015614b665780516001600160401b03811115614b4857600080fd5b614b57886020838a0101614240565b84525060209283019201614b2a565b5095945050505050565b600060208284031215614b8257600080fd5b81516001600160401b03811115614b9857600080fd5b6107b784828501614ae4565b60008060408385031215614bb757600080fd5b82516001600160401b03811115614bcd57600080fd5b8301601f81018513614bde57600080fd5b8051614bec61425f82614ac1565b8082825260208201915060208360051b850101925087831115614c0e57600080fd5b6020840193505b82841015614c3757614c268461467e565b825260209384019390910190614c15565b8095505050505060208301516001600160401b03811115614c5757600080fd5b6146d185828601614ae456feb8bc84bd77f5eb08210b8eb20fd63b3ec6a7992d277ab94663bae0e066f792aca26469706673582212200d02bd25771a1d64ddd9e60d84bf6d2381636a59cdc715f1f0a2c7ae4cc5390864736f6c634300081a00336080604052348015600f57600080fd5b506109c28061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636a2216571161005b5780636a221657146100d357806378272525146100e65780639517e29f146100f95780639abb6e171461010c57600080fd5b80633f707e6b1461008257806350c890221461009757806361085573146100aa575b600080fd5b6100956100903660046105ba565b61012d565b005b6100956100a53660046105ba565b610197565b6100bd6100b83660046105ba565b6101fc565b6040516100ca91906106c4565b60405180910390f35b6100956100e1366004610710565b6102be565b6100956100f43660046107da565b6102e1565b6100956101073660046107da565b61038a565b61011f61011a3660046105ba565b610429565b6040516100ca929190610864565b8060005b81811015610191573684848381811061014c5761014c6108be565b905060200281019061015e91906108d4565b905061018761017060208301836108f4565b6020830135610182604085018561090f565b610553565b5050600101610131565b50505050565b8060005b8181101561019157368484838181106101b6576101b66108be565b90506020028101906101c891906108d4565b90506101f16101da60208301836108f4565b60208301356101ec604085018561090f565b610589565b50505060010161019b565b6060818067ffffffffffffffff811115610218576102186106fa565b60405190808252806020026020018201604052801561024b57816020015b60608152602001906001900390816102365790505b50915060005b818110156102b6573685858381811061026c5761026c6108be565b905060200281019061027e91906108d4565b905061029061017060208301836108f4565b8483815181106102a2576102a26108be565b602090810291909101015250600101610251565b505092915050565b604051600080835160208501865afa3d6000833e80156102dc573d82f35b503d81fd5b604051638a91b0e360e01b81526001600160a01b03841690638a91b0e39061030f908590859060040161095d565b600060405180830381600087803b15801561032957600080fd5b505af115801561033d573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527f341347516a9de374859dfda710fa4828b2d48cb57d4fbe4c1149612b8e02276e93500190505b60405180910390a150505050565b6040516306d61fe760e41b81526001600160a01b03841690636d61fe70906103b8908590859060040161095d565b600060405180830381600087803b1580156103d257600080fd5b505af11580156103e6573d6000803e3d6000fd5b5050604080518781526001600160a01b03871660208201527fd21d0b289f126c4b473ea641963e766833c2f13866e4ff480abd787c100ef123935001905061037c565b606080828067ffffffffffffffff811115610446576104466106fa565b60405190808252806020026020018201604052801561047957816020015b60608152602001906001900390816104645790505b5091508067ffffffffffffffff811115610495576104956106fa565b6040519080825280602002602001820160405280156104be578160200160208202803683370190505b50925060005b8181101561054a57368686838181106104df576104df6108be565b90506020028101906104f191906108d4565b90506105036101da60208301836108f4565b868481518110610515576105156108be565b6020026020010186858151811061052e5761052e6108be565b60209081029190910101919091529015159052506001016104c4565b50509250929050565b60405181838237600038838387895af1610570573d6000823e3d81fd5b3d8152602081013d6000823e3d01604052949350505050565b604051600090828482376000388483888a5af191503d8152602081013d6000823e3d81016040525094509492505050565b600080602083850312156105cd57600080fd5b823567ffffffffffffffff8111156105e457600080fd5b8301601f810185136105f557600080fd5b803567ffffffffffffffff81111561060c57600080fd5b8560208260051b840101111561062157600080fd5b6020919091019590945092505050565b600082825180855260208501945060208160051b8301016020850160005b838110156106b857848303601f190188528151805180855260005b818110156106865760208184018101518783018201520161066a565b506000602082870101526020601f19601f8301168601019450505060208201915060208801975060018101905061064f565b50909695505050505050565b6020815260006106d76020830184610631565b9392505050565b80356001600160a01b03811681146106f557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072357600080fd5b61072c836106de565b9150602083013567ffffffffffffffff81111561074857600080fd5b8301601f8101851361075957600080fd5b803567ffffffffffffffff811115610773576107736106fa565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156107a2576107a26106fa565b6040528181528282016020018710156107ba57600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600080606085870312156107f057600080fd5b84359350610800602086016106de565b9250604085013567ffffffffffffffff81111561081c57600080fd5b8501601f8101871361082d57600080fd5b803567ffffffffffffffff81111561084457600080fd5b87602082840101111561085657600080fd5b949793965060200194505050565b6040808252835190820181905260009060208501906060840190835b818110156108a05783511515835260209384019390920191600101610880565b505083810360208501526108b48186610631565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126108ea57600080fd5b9190910192915050565b60006020828403121561090657600080fd5b6106d7826106de565b6000808335601e1984360301811261092657600080fd5b83018035915067ffffffffffffffff82111561094157600080fd5b60200191503681900382131561095657600080fd5b9250929050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122070a59ccb068447caf8f890604a59f833f8725c3e3d150ae8a83f15caaa17700e64736f6c634300081a0033" /* ========= V06 CORE ========= */ diff --git a/packages/permissionless-test/mock-aa-infra/alto/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts index e1089a9f..4d3e7265 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -28,7 +28,9 @@ import { KERNEL_V07_FACTORY_CREATECALL, KERNEL_V07_META_FACTORY_CREATECALL, LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, + SAFE_7579_LAUNCHPAD_CREATECALL, SAFE_7579_MODULE_CREATECALL, + SAFE_7579_REGISTRY_CREATECALL, SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, SAFE_MULTI_SEND_CREATECALL, SAFE_PROXY_FACTORY_CREATECALL, @@ -145,6 +147,18 @@ export const setupContracts = async (rpc: string) => { gas: 15_000_000n, nonce: nonce++ }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_7579_REGISTRY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: DETERMINISTIC_DEPLOYER, + data: SAFE_7579_LAUNCHPAD_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V07_MODULE_CREATECALL, @@ -388,7 +402,9 @@ export const setupContracts = async (rpc: string) => { "0x41675C099F32341bf84BFc5382aF534df5C7461a", // Safe Singleton "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526", // Safe Multi Send "0x9641d764fc13c8B624c04430C7356C1C7C8102e2", // Safe Multi Send Call Only - "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C", // Safe 7579 module + "0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2", // Safe 7579 module + "0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE", // Safe 7579 launchpad + "0x25A4b2F363678E13A0A5DB79b712dE00347a593E", // Safe 7579 Registry "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // EntryPoint V0.6 "0x9406Cc6185a346906296840746125a0E44976454", // Simple Account Factory V0.6 "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", // Biconomy ECDSA Ownership Registry Module diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 1b09c245..b34adbdb 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -17,7 +17,7 @@ import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts" -import { foundry } from "viem/chains" +import { foundry, sepolia } from "viem/chains" import { type BundlerClient, ENTRYPOINT_ADDRESS_V06, @@ -138,9 +138,15 @@ export const getPimlicoBundlerClient = ({ }) export const getPublicClient = (anvilRpc: string) => { + const transport = http(anvilRpc, { + onFetchRequest: async (request) => { + // console.log("fetching", await request.json()) + } + }) + return createPublicClient({ chain: foundry, - transport: http(anvilRpc), + transport: transport, pollingInterval: 100 }) } @@ -383,10 +389,16 @@ export const getSafeClient = async ({ safeVersion: "1.4.1", saltNonce: 420n, safe4337ModuleAddress: erc7579 - ? getAddress("0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C") + ? "0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2" : undefined, - erc7579, - setupTransactions + erc7569LaunchpadAddress: erc7579 + ? "0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE" + : undefined + }) + + const pimlicoBundlerClient = getPimlicoBundlerClient({ + entryPoint, + altoRpc }) // @ts-ignore @@ -395,6 +407,8 @@ export const getSafeClient = async ({ account: safeSmartAccount, bundlerTransport: http(altoRpc), middleware: { + gasPrice: async () => + (await pimlicoBundlerClient.getUserOperationGasPrice()).fast, // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation } diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index a77f8ca3..cc252556 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -12,6 +12,7 @@ import { type TypedDataDefinition, concat, concatHex, + encodeAbiParameters, encodeFunctionData, encodePacked, getContractAddress, @@ -31,11 +32,7 @@ import { signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { - EntryPointVersion, - GetEntryPointVersion, - Prettify -} from "../../types" +import type { EntryPointVersion, GetEntryPointVersion } from "../../types" import type { EntryPoint, UserOperation } from "../../types" import { encode7579CallData } from "../../utils/encode7579CallData" import { @@ -53,6 +50,341 @@ import { export type SafeVersion = "1.4.1" +const multiSendAbi = [ + { + inputs: [ + { + internalType: "bytes", + name: "transactions", + type: "bytes" + } + ], + name: "multiSend", + outputs: [], + stateMutability: "payable", + type: "function" + } +] as const + +const initSafe7579Abi = [ + { + type: "function", + name: "initSafe7579", + inputs: [ + { + name: "safe7579", + type: "address", + internalType: "address" + }, + { + name: "executors", + type: "tuple[]", + internalType: "struct ModuleInit[]", + components: [ + { + name: "module", + type: "address", + internalType: "address" + }, + { + name: "initData", + type: "bytes", + internalType: "bytes" + } + ] + }, + { + name: "fallbacks", + type: "tuple[]", + internalType: "struct ModuleInit[]", + components: [ + { + name: "module", + type: "address", + internalType: "address" + }, + { + name: "initData", + type: "bytes", + internalType: "bytes" + } + ] + }, + { + name: "hooks", + type: "tuple[]", + internalType: "struct ModuleInit[]", + components: [ + { + name: "module", + type: "address", + internalType: "address" + }, + { + name: "initData", + type: "bytes", + internalType: "bytes" + } + ] + }, + { + name: "attesters", + type: "address[]", + internalType: "address[]" + }, + { + name: "threshold", + type: "uint8", + internalType: "uint8" + } + ], + outputs: [], + stateMutability: "nonpayable" + } +] as const + +const preValidationSetupAbi = [ + { + type: "function", + name: "preValidationSetup", + inputs: [ + { + name: "initHash", + type: "bytes32", + internalType: "bytes32" + }, + { + name: "to", + type: "address", + internalType: "address" + }, + { + name: "preInit", + type: "bytes", + internalType: "bytes" + } + ], + outputs: [], + stateMutability: "nonpayable" + } +] as const + +const enableModulesAbi = [ + { + inputs: [ + { + internalType: "address[]", + name: "modules", + type: "address[]" + } + ], + name: "enableModules", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const + +const setupAbi = [ + { + inputs: [ + { + internalType: "address[]", + name: "_owners", + type: "address[]" + }, + { + internalType: "uint256", + name: "_threshold", + type: "uint256" + }, + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + }, + { + internalType: "address", + name: "fallbackHandler", + type: "address" + }, + { + internalType: "address", + name: "paymentToken", + type: "address" + }, + { + internalType: "uint256", + name: "payment", + type: "uint256" + }, + { + internalType: "address payable", + name: "paymentReceiver", + type: "address" + } + ], + name: "setup", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const + +const createProxyWithNonceAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_singleton", + type: "address" + }, + { + internalType: "bytes", + name: "initializer", + type: "bytes" + }, + { + internalType: "uint256", + name: "saltNonce", + type: "uint256" + } + ], + name: "createProxyWithNonce", + outputs: [ + { + internalType: "contract SafeProxy", + name: "proxy", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] as const + +const proxyCreationCodeAbi = [ + { + inputs: [], + name: "proxyCreationCode", + outputs: [ + { + internalType: "bytes", + name: "", + type: "bytes" + } + ], + stateMutability: "pure", + type: "function" + } +] as const + +const setupSafeAbi = [ + { + type: "function", + name: "setupSafe", + inputs: [ + { + name: "initData", + type: "tuple", + internalType: "struct Safe7579Launchpad.InitData", + components: [ + { + name: "singleton", + type: "address", + internalType: "address" + }, + { + name: "owners", + type: "address[]", + internalType: "address[]" + }, + { + name: "threshold", + type: "uint256", + internalType: "uint256" + }, + { + name: "setupTo", + type: "address", + internalType: "address" + }, + { + name: "setupData", + type: "bytes", + internalType: "bytes" + }, + { + name: "safe7579", + type: "address", + internalType: "contract ISafe7579" + }, + { + name: "validators", + type: "tuple[]", + internalType: "struct ModuleInit[]", + components: [ + { + name: "module", + type: "address", + internalType: "address" + }, + { + name: "initData", + type: "bytes", + internalType: "bytes" + } + ] + }, + { + name: "callData", + type: "bytes", + internalType: "bytes" + } + ] + } + ], + outputs: [], + stateMutability: "nonpayable" + } +] as const + +const executeUserOpWithErrorStringAbi = [ + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + }, + { + internalType: "uint8", + name: "operation", + type: "uint8" + } + ], + name: "executeUserOpWithErrorString", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const + const EIP712_SAFE_OPERATION_TYPE_V06 = { SafeOp: [ { type: "address", name: "safe" }, @@ -204,21 +536,7 @@ const encodeMultiSend = ( .join("")}` return encodeFunctionData({ - abi: [ - { - inputs: [ - { - internalType: "bytes", - name: "transactions", - type: "bytes" - } - ], - name: "multiSend", - outputs: [], - stateMutability: "payable", - type: "function" - } - ], + abi: multiSendAbi, functionName: "multiSend", args: [data] }) @@ -230,104 +548,206 @@ export type SafeSmartAccount< chain extends Chain | undefined = Chain | undefined > = SmartAccount +const get7579LaunchPadInitData = ({ + safe4337ModuleAddress, + safeSingletonAddress, + erc7569LaunchpadAddress, + owner, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold +}: { + safe4337ModuleAddress: Address + safeSingletonAddress: Address + erc7569LaunchpadAddress: Address + owner: Address + executors: { + address: Address + context: Address + }[] + validators: { address: Address; context: Address }[] + fallbacks: { address: Address; context: Address }[] + hooks: { address: Address; context: Address }[] + attesters: Address[] + attestersThreshold: number +}) => { + const initData = { + singleton: safeSingletonAddress, + owners: [owner], + threshold: BigInt(1), + setupTo: erc7569LaunchpadAddress, + setupData: encodeFunctionData({ + abi: initSafe7579Abi, + functionName: "initSafe7579", + args: [ + safe4337ModuleAddress, // SAFE_7579_ADDRESS, + executors.map((executor) => ({ + module: executor.address, + initData: executor.context + })), + fallbacks.map((fallback) => ({ + module: fallback.address, + initData: fallback.context + })), + hooks.map((hook) => ({ + module: hook.address, + initData: hook.context + })), + attesters, + attestersThreshold + ] + }), + safe7579: safe4337ModuleAddress, + validators: validators + } + + return initData +} + const getInitializerCode = async ({ owner, safeModuleSetupAddress, safe4337ModuleAddress, multiSendAddress, + safeSingletonAddress, + erc7569LaunchpadAddress, setupTransactions = [], - safeModules = [] + safeModules = [], + validators = [], + executors = [], + fallbacks = [], + hooks = [], + attesters = [], + attestersThreshold = 0 }: { owner: Address + safeSingletonAddress: Address safeModuleSetupAddress: Address safe4337ModuleAddress: Address multiSendAddress: Address + erc7569LaunchpadAddress?: Address setupTransactions?: { to: Address data: Address value: bigint }[] safeModules?: Address[] + validators?: { address: Address; context: Address }[] + executors?: { + address: Address + context: Address + }[] + fallbacks?: { address: Address; context: Address }[] + hooks?: { address: Address; context: Address }[] + attesters?: Address[] + attestersThreshold?: number }) => { - const multiSendCallData = encodeMultiSend([ - { - to: safeModuleSetupAddress, - data: encodeFunctionData({ - abi: [ - { - inputs: [ - { - internalType: "address[]", - name: "modules", - type: "address[]" - } - ], - name: "enableModules", - outputs: [], - stateMutability: "nonpayable", - type: "function" - } - ], - functionName: "enableModules", - args: [[safe4337ModuleAddress, ...safeModules]] - }), - value: BigInt(0), - operation: 1 - }, - ...setupTransactions.map((tx) => ({ ...tx, operation: 0 as 0 | 1 })) - ]) + if (erc7569LaunchpadAddress) { + const initData = get7579LaunchPadInitData({ + safe4337ModuleAddress, + safeSingletonAddress, + erc7569LaunchpadAddress, + owner, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold + }) - return encodeFunctionData({ - abi: [ - { - inputs: [ + const initHash = keccak256( + encodeAbiParameters( + [ + { + internalType: "address", + name: "singleton", + type: "address" + }, { internalType: "address[]", - name: "_owners", + name: "owners", type: "address[]" }, { internalType: "uint256", - name: "_threshold", + name: "threshold", type: "uint256" }, { internalType: "address", - name: "to", + name: "setupTo", type: "address" }, { internalType: "bytes", - name: "data", + name: "setupData", type: "bytes" }, { - internalType: "address", - name: "fallbackHandler", - type: "address" - }, - { - internalType: "address", - name: "paymentToken", + internalType: "contract ISafe7579", + name: "safe7579", type: "address" }, { - internalType: "uint256", - name: "payment", - type: "uint256" - }, - { - internalType: "address payable", - name: "paymentReceiver", - type: "address" + internalType: "struct ModuleInit[]", + name: "validators", + type: "tuple[]", + components: [ + { + internalType: "address", + name: "module", + type: "address" + }, + { + internalType: "bytes", + name: "initData", + type: "bytes" + } + ] } ], - name: "setup", - outputs: [], - stateMutability: "nonpayable", - type: "function" - } - ], + [ + initData.singleton, + initData.owners, + initData.threshold, + initData.setupTo, + initData.setupData, + initData.safe7579, + initData.validators.map((validator) => ({ + module: validator.address, + initData: validator.context + })) + ] + ) + ) + + return encodeFunctionData({ + abi: preValidationSetupAbi, + functionName: "preValidationSetup", + args: [initHash, zeroAddress, "0x"] + }) + } + + const multiSendCallData = encodeMultiSend([ + { + to: safeModuleSetupAddress, + data: encodeFunctionData({ + abi: enableModulesAbi, + functionName: "enableModules", + args: [[safe4337ModuleAddress, ...safeModules]] + }), + value: BigInt(0), + operation: 1 + }, + ...setupTransactions.map((tx) => ({ ...tx, operation: 0 as 0 | 1 })) + ]) + + return encodeFunctionData({ + abi: setupAbi, functionName: "setup", args: [ [owner], @@ -373,16 +793,24 @@ const getAccountInitCode = async ({ safeModuleSetupAddress, safe4337ModuleAddress, safeSingletonAddress, + erc7569LaunchpadAddress, multiSendAddress, saltNonce = BigInt(0), setupTransactions = [], - safeModules = [] + safeModules = [], + validators = [], + executors = [], + fallbacks = [], + hooks = [], + attesters = [], + attestersThreshold = 0 }: { owner: Address safeModuleSetupAddress: Address safe4337ModuleAddress: Address safeSingletonAddress: Address multiSendAddress: Address + erc7569LaunchpadAddress?: Address saltNonce?: bigint setupTransactions?: { to: Address @@ -390,51 +818,45 @@ const getAccountInitCode = async ({ value: bigint }[] safeModules?: Address[] + validators?: { address: Address; context: Address }[] + executors?: { + address: Address + context: Address + }[] + fallbacks?: { address: Address; context: Address }[] + hooks?: { address: Address; context: Address }[] + attesters?: Address[] + attestersThreshold?: number }): Promise => { - if (!owner) throw new Error("Owner account not found") + if (!owner) { + throw new Error("Owner account not found") + } + const initializer = await getInitializerCode({ owner, safeModuleSetupAddress, safe4337ModuleAddress, multiSendAddress, setupTransactions, - safeModules + safeSingletonAddress, + safeModules, + erc7569LaunchpadAddress, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold }) const initCodeCallData = encodeFunctionData({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "_singleton", - type: "address" - }, - { - internalType: "bytes", - name: "initializer", - type: "bytes" - }, - { - internalType: "uint256", - name: "saltNonce", - type: "uint256" - } - ], - name: "createProxyWithNonce", - outputs: [ - { - internalType: "contract SafeProxy", - name: "proxy", - type: "address" - } - ], - stateMutability: "nonpayable", - type: "function" - } - ], + abi: createProxyWithNonceAbi, functionName: "createProxyWithNonce", - args: [safeSingletonAddress, initializer, saltNonce] + args: [ + erc7569LaunchpadAddress ?? safeSingletonAddress, + initializer, + saltNonce + ] }) return initCodeCallData @@ -451,9 +873,16 @@ const getAccountAddress = async < safeProxyFactoryAddress, safeSingletonAddress, multiSendAddress, + erc7569LaunchpadAddress, setupTransactions = [], safeModules = [], - saltNonce = BigInt(0) + saltNonce = BigInt(0), + validators = [], + executors = [], + fallbacks = [], + hooks = [], + attesters = [], + attestersThreshold = 0 }: { client: Client owner: Address @@ -469,41 +898,48 @@ const getAccountAddress = async < }[] safeModules?: Address[] saltNonce?: bigint + erc7569LaunchpadAddress?: Address + validators?: { address: Address; context: Address }[] + executors?: { + address: Address + context: Address + }[] + fallbacks?: { address: Address; context: Address }[] + hooks?: { address: Address; context: Address }[] + attesters?: Address[] + attestersThreshold?: number }): Promise
=> { const proxyCreationCode = await readContract(client, { - abi: [ - { - inputs: [], - name: "proxyCreationCode", - outputs: [ - { - internalType: "bytes", - name: "", - type: "bytes" - } - ], - stateMutability: "pure", - type: "function" - } - ], + abi: proxyCreationCodeAbi, address: safeProxyFactoryAddress, functionName: "proxyCreationCode" }) - const deploymentCode = encodePacked( - ["bytes", "uint256"], - [proxyCreationCode, hexToBigInt(safeSingletonAddress)] - ) - const initializer = await getInitializerCode({ owner, safeModuleSetupAddress, safe4337ModuleAddress, multiSendAddress, setupTransactions, - safeModules + safeSingletonAddress, + safeModules, + erc7569LaunchpadAddress, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold }) + const deploymentCode = encodePacked( + ["bytes", "uint256"], + [ + proxyCreationCode, + hexToBigInt(erc7569LaunchpadAddress ?? safeSingletonAddress) + ] + ) + const salt = keccak256( encodePacked( ["bytes32", "uint256"], @@ -580,33 +1016,66 @@ const getDefaultAddresses = ( } } +type GetErc7579Params = + TErc7579 extends undefined + ? { + safeModuleSetupAddress?: Address + multiSendAddress?: Address + multiSendCallOnlyAddress?: Address + setupTransactions?: { + to: Address + data: Address + value: bigint + }[] + safeModules?: Address[] + } + : { + validators?: { address: Address; context: Address }[] + executors?: { + address: Address + context: Address + }[] + fallbacks?: { address: Address; context: Address }[] + hooks?: { address: Address; context: Address }[] + attesters?: Address[] + attestersThreshold?: number + } + export type SignerToSafeSmartAccountParameters< entryPoint extends EntryPoint, TSource extends string = string, - TAddress extends Address = Address -> = Prettify<{ + TAddress extends Address = Address, + TErc7579 extends Address | undefined = Address | undefined +> = { signer: SmartAccountSigner safeVersion: SafeVersion entryPoint: entryPoint - address?: Address - safeModuleSetupAddress?: Address safe4337ModuleAddress?: Address + erc7569LaunchpadAddress?: TErc7579 safeProxyFactoryAddress?: Address safeSingletonAddress?: Address - multiSendAddress?: Address - multiSendCallOnlyAddress?: Address + address?: Address saltNonce?: bigint validUntil?: number validAfter?: number - erc7579?: boolean nonceKey?: bigint - setupTransactions?: { - to: Address - data: Address - value: bigint - }[] - safeModules?: Address[] -}> +} & GetErc7579Params + +function isErc7579Args( + args: SignerToSafeSmartAccountParameters< + EntryPoint, + string, + Address, + Address | undefined + > +): args is SignerToSafeSmartAccountParameters< + EntryPoint, + string, + Address, + Address +> { + return args.erc7569LaunchpadAddress !== undefined +} /** * @description Creates an Simple Account from a private key. @@ -618,7 +1087,8 @@ export async function signerToSafeSmartAccount< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = string, - TAddress extends Address = Address + TAddress extends Address = Address, + TErc7579 extends Address | undefined = undefined >( client: Client< TTransport, @@ -627,27 +1097,62 @@ export async function signerToSafeSmartAccount< PublicRpcSchema, PublicActions >, - { + args: SignerToSafeSmartAccountParameters< + entryPoint, + TSource, + TAddress, + TErc7579 + > +): Promise> { + const chainId = client.chain?.id ?? (await getChainId(client)) + + const { signer, address, safeVersion, entryPoint: entryPointAddress, - safeModuleSetupAddress: _safeModuleSetupAddress, safe4337ModuleAddress: _safe4337ModuleAddress, safeProxyFactoryAddress: _safeProxyFactoryAddress, safeSingletonAddress: _safeSingletonAddress, - multiSendAddress: _multiSendAddress, - multiSendCallOnlyAddress: _multiSendCallOnlyAddress, + erc7569LaunchpadAddress, saltNonce = BigInt(0), validUntil = 0, validAfter = 0, - safeModules = [], - erc7579, - setupTransactions = [], nonceKey - }: SignerToSafeSmartAccountParameters -): Promise> { - const chainId = client.chain?.id ?? (await getChainId(client)) + } = args + + let _safeModuleSetupAddress: Address | undefined = undefined + let _multiSendAddress: Address | undefined = undefined + let _multiSendCallOnlyAddress: Address | undefined = undefined + let safeModules: Address[] | undefined = undefined + let setupTransactions: { + to: `0x${string}` + data: `0x${string}` + value: bigint + }[] = [] + let validators: { address: Address; context: Address }[] = [] + let executors: { address: Address; context: Address }[] = [] + let fallbacks: { address: Address; context: Address }[] = [] + let hooks: { address: Address; context: Address }[] = [] + let attesters: Address[] = [] + let attestersThreshold = 0 + + if (!isErc7579Args(args)) { + _safeModuleSetupAddress = args.safeModuleSetupAddress + _multiSendAddress = args.multiSendAddress + _multiSendCallOnlyAddress = args.multiSendCallOnlyAddress + safeModules = args.safeModules + setupTransactions = args.setupTransactions ?? [] + } + + if (isErc7579Args(args)) { + validators = args.validators ?? [] + executors = args.executors ?? [] + fallbacks = args.fallbacks ?? [] + hooks = args.hooks ?? [] + attesters = args.attesters ?? [] + attestersThreshold = args.attestersThreshold ?? 0 + } const viemSigner: LocalAccount = { ...signer, @@ -682,9 +1187,16 @@ export async function signerToSafeSmartAccount< safeProxyFactoryAddress, safeSingletonAddress, multiSendAddress, + erc7569LaunchpadAddress, saltNonce, setupTransactions, - safeModules + safeModules, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold })) if (!accountAddress) throw new Error("Account address not found") @@ -694,6 +1206,10 @@ export async function signerToSafeSmartAccount< const safeSmartAccount: SafeSmartAccount = toSmartAccount({ address: accountAddress, + client: client, + publicKey: accountAddress, + entryPoint: entryPointAddress, + source: "SafeSmartAccount", async signMessage({ message }) { const messageHash = hashTypedData({ domain: { @@ -749,12 +1265,7 @@ export async function signerToSafeSmartAccount< }) ) }, - client: client, - publicKey: accountAddress, - entryPoint: entryPointAddress, - source: "SafeSmartAccount", async getNonce(key?: bigint) { - // TODO: Allow dapp developers to specify custom nonce key (eg: Validator address) return getAccountNonce(client, { sender: accountAddress, entryPoint: entryPointAddress, @@ -780,10 +1291,13 @@ export async function signerToSafeSmartAccount< entryPoint: entryPointAddress } + let isDeployed = false + if ( isUserOperationVersion06(entryPointAddress, userOperation) ) { message.paymasterAndData = userOperation.paymasterAndData + isDeployed = userOperation.initCode === "0x" } if ( @@ -797,6 +1311,13 @@ export async function signerToSafeSmartAccount< } message.paymasterAndData = getPaymasterAndData(userOperation) + isDeployed = !userOperation.factory + } + + let verifyingContract = safe4337ModuleAddress + + if (erc7569LaunchpadAddress && !isDeployed) { + verifyingContract = userOperation.sender } const signatures = [ @@ -805,8 +1326,8 @@ export async function signerToSafeSmartAccount< data: await signTypedData(client, { account: viemSigner, domain: { - chainId: chainId, - verifyingContract: safe4337ModuleAddress + chainId, + verifyingContract }, types: getEntryPointVersion(entryPointAddress) === @@ -866,9 +1387,16 @@ export async function signerToSafeSmartAccount< safe4337ModuleAddress, safeSingletonAddress, multiSendAddress, + erc7569LaunchpadAddress, saltNonce, setupTransactions, - safeModules + safeModules, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold }) }, async encodeDeployCallData(_) { @@ -879,15 +1407,63 @@ export async function signerToSafeSmartAccount< async encodeCallData(args) { const isArray = Array.isArray(args) - if (erc7579) { + if (erc7569LaunchpadAddress) { + // First transaction will be slower because we need to enable 7579 modules + + safeDeployed = + safeDeployed || + (await isSmartAccountDeployed(client, accountAddress)) + + if (!safeDeployed) { + const initData = get7579LaunchPadInitData({ + safe4337ModuleAddress, + safeSingletonAddress, + erc7569LaunchpadAddress, + owner: viemSigner.address, + validators, + executors, + fallbacks, + hooks, + attesters, + attestersThreshold + }) + + return encodeFunctionData({ + abi: setupSafeAbi, + functionName: "setupSafe", + args: [ + { + ...initData, + validators: initData.validators.map( + (validator) => ({ + module: validator.address, + initData: validator.context + }) + ), + callData: encode7579CallData({ + mode: { + type: isArray + ? "batchcall" + : "call", + revertOnError: false, + selector: "0x", + context: "0x" + }, + callData: args + }) + } + ] + }) + } + return encode7579CallData({ mode: { type: isArray ? "batchcall" : "call", revertOnError: false, - modeSelector: "0x", - modeData: "0x" + selector: "0x", + context: "0x" }, - callData: args as any + callData: args }) } @@ -922,36 +1498,7 @@ export async function signerToSafeSmartAccount< } return encodeFunctionData({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "to", - type: "address" - }, - { - internalType: "uint256", - name: "value", - type: "uint256" - }, - { - internalType: "bytes", - name: "data", - type: "bytes" - }, - { - internalType: "uint8", - name: "operation", - type: "uint8" - } - ], - name: "executeUserOpWithErrorString", - outputs: [], - stateMutability: "nonpayable", - type: "function" - } - ], + abi: executeUserOpWithErrorStringAbi, functionName: "executeUserOpWithErrorString", args: [to, value, data, operationType] }) diff --git a/packages/permissionless/actions/erc7579/accountId.test.ts b/packages/permissionless/actions/erc7579/accountId.test.ts index fd96d916..c50ea237 100644 --- a/packages/permissionless/actions/erc7579/accountId.test.ts +++ b/packages/permissionless/actions/erc7579/accountId.test.ts @@ -1,30 +1,12 @@ -import { - http, - createPublicClient, - encodeAbiParameters, - encodePacked, - getAddress, - isHash, - zeroAddress -} from "viem" -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { foundry, sepolia } from "viem/chains" +import { zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, - getPimlicoBundlerClient, - getPimlicoPaymasterClient, - getPublicClient + getPimlicoPaymasterClient } from "../../../permissionless-test/src/utils" -import { - signerToEcdsaKernelSmartAccount, - signerToSafeSmartAccount -} from "../../accounts" -import { createSmartAccountClient } from "../../clients/createSmartAccountClient" -import { erc7579Actions } from "../../clients/decorators/erc7579" -import { createBundlerClient } from "../../index" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" import { accountId } from "./accountId" describe.each(getCoreSmartAccounts())( @@ -67,114 +49,4 @@ describe.each(getCoreSmartAccounts())( } ) } - - // testWithRpc.skipIf(!getErc7579SmartAccountClient)( - // "accountId", - // async ({ rpc }) => { - // const { anvilRpc, altoRpc, paymasterRpc } = rpc - - // // const anvilRpc = - // // "https://sepolia.rpc.thirdweb.com/9fc39d5e2a3e149cc31cf9625806a2fe" - // // const altoRpc = - // // "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" - // // const paymasterRpc = - // // "https://api.pimlico.io/v2/sepolia/rpc?apikey=2a34d830-b4d4-47ad-80e8-b53278b1439a" - - // if (!getErc7579SmartAccountClient) { - // throw new Error("getErc7579SmartAccountClient not defined") - // } - // const publicClient = createPublicClient({ - // transport: http(anvilRpc), - // chain: foundry - // // chain: sepolia - // }) - // const signer = privateKeyToAccount( - // generatePrivateKey() - // // "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - // ) - // // const kernelSmartAccount = - // // await signerToEcdsaKernelSmartAccount(publicClient, { - // // entryPoint: ENTRYPOINT_ADDRESS_V07, - // // signer: signer, - // // version: "0.3.0" - // // }) - - // const safeSmartAccount = await signerToSafeSmartAccount( - // publicClient, - // { - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // signer: signer, - // safeVersion: "1.4.1", - // saltNonce: 120n, - // safe4337ModuleAddress: getAddress( - // "0x50Da3861d482116c5F2Ea6d673a58CedB786Dc1C" - // ), - // erc7579: true - // } - // ) - - // const paymasterClient = getPimlicoPaymasterClient({ - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // paymasterRpc: paymasterRpc - // }) - - // const pimlicoClient = getPimlicoBundlerClient({ - // entryPoint: ENTRYPOINT_ADDRESS_V07, - // altoRpc: altoRpc - // }) - - // const smartClient = createSmartAccountClient({ - // // chain: sepolia, - // chain: foundry, - // account: safeSmartAccount, - // bundlerTransport: http(altoRpc), - // middleware: { - // gasPrice: async () => - // (await pimlicoClient.getUserOperationGasPrice()) - // .fast, - // sponsorUserOperation: - // paymasterClient.sponsorUserOperation - // } - // }).extend( - // erc7579Actions({ entryPoint: ENTRYPOINT_ADDRESS_V07 }) - // ) - - // const moduleData = encodePacked(["address"], [signer.address]) - - // const opHashInstallModule = await smartClient.installModule({ - // type: "executor", - // address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - // context: moduleData - // }) - - // console.log("Sent user operation: ", opHashInstallModule) - - // const bundlerClientV07 = createBundlerClient({ - // transport: http(altoRpc), - // entryPoint: ENTRYPOINT_ADDRESS_V07 - // }) - - // const transactionHash = - // await bundlerClientV07.waitForUserOperationReceipt({ - // hash: opHashInstallModule, - // timeout: 1000000 - // }) - - // console.log( - // "transactionHash: ", - // transactionHash.receipt.transactionHash - // ) - - // const isModuleInstalled = await smartClient.isModuleInstalled({ - // type: "executor", - // address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - // context: "0x" - // }) - - // console.log("is module installed: ", isModuleInstalled) - - // expect(isModuleInstalled).toBe(true) - // } - // ) - // } ) diff --git a/packages/permissionless/actions/erc7579/accountId.ts b/packages/permissionless/actions/erc7579/accountId.ts index 3b5a7d77..0a1210c9 100644 --- a/packages/permissionless/actions/erc7579/accountId.ts +++ b/packages/permissionless/actions/erc7579/accountId.ts @@ -12,23 +12,6 @@ import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" -// export async function accountId< -// TEntryPoint extends EntryPoint, -// TSmartAccount extends SmartAccount | undefined, -// TTransport extends Transport = Transport, -// TChain extends Chain | undefined = Chain | undefined -// >(client: Client): Promise - -// export async function accountId< -// TEntryPoint extends EntryPoint, -// TSmartAccount extends SmartAccount | undefined, -// TTransport extends Transport = Transport, -// TChain extends Chain | undefined = Chain | undefined -// >( -// client: Client, -// args: GetAccountParameter -// ): Promise - export async function accountId< TEntryPoint extends EntryPoint, TSmartAccount extends SmartAccount | undefined, diff --git a/packages/permissionless/actions/erc7579/installModule.test.ts b/packages/permissionless/actions/erc7579/installModule.test.ts index 3e31ea7e..2558d247 100644 --- a/packages/permissionless/actions/erc7579/installModule.test.ts +++ b/packages/permissionless/actions/erc7579/installModule.test.ts @@ -36,8 +36,6 @@ describe.each(getCoreSmartAccounts())( const privateKey = generatePrivateKey() - const eoaAccount = privateKeyToAccount(privateKey) - const smartClientWithoutExtend: SmartAccountClient< ENTRYPOINT_ADDRESS_V07_TYPE, Transport, diff --git a/packages/permissionless/actions/erc7579/installModule.ts b/packages/permissionless/actions/erc7579/installModule.ts index 60bac863..1d38bed0 100644 --- a/packages/permissionless/actions/erc7579/installModule.ts +++ b/packages/permissionless/actions/erc7579/installModule.ts @@ -56,31 +56,39 @@ export async function installModule< const account = parseAccount(account_) as SmartAccount - const installModuleCallData = encodeFunctionData({ - abi: [ - { - name: "installModule", - type: "function", - stateMutability: "nonpayable", - inputs: [ - { - type: "uint256", - name: "moduleTypeId" - }, - { - type: "address", - name: "module" - }, - { - type: "bytes", - name: "initData" - } - ], - outputs: [] - } - ], - functionName: "installModule", - args: [parseModuleTypeId(parameters.type), getAddress(address), context] + const installModuleCallData = await account.encodeCallData({ + to: account.address, + value: BigInt(0), + data: encodeFunctionData({ + abi: [ + { + name: "installModule", + type: "function", + stateMutability: "nonpayable", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "initData" + } + ], + outputs: [] + } + ], + functionName: "installModule", + args: [ + parseModuleTypeId(parameters.type), + getAddress(address), + context + ] + }) }) return getAction( diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts index 723bdc2d..fa37871a 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts @@ -19,7 +19,7 @@ import type { SmartAccountClient } from "../../clients/createSmartAccountClient" import { erc7579Actions } from "../../clients/decorators/erc7579" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" -import { installModule } from "./installModule" +import { isModuleInstalled } from "./isModuleInstalled" describe.each(getCoreSmartAccounts())( "isModuleInstalled $name", @@ -35,8 +35,6 @@ describe.each(getCoreSmartAccounts())( const privateKey = generatePrivateKey() - const eoaAccount = privateKeyToAccount(privateKey) - const smartClientWithoutExtend: SmartAccountClient< ENTRYPOINT_ADDRESS_V07_TYPE, Transport, @@ -64,7 +62,7 @@ describe.each(getCoreSmartAccounts())( [smartClient.account.address] ) - const opHash = await installModule(smartClient as any, { + const opHash = await smartClient.installModule({ account: smartClient.account as any, type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", @@ -91,18 +89,30 @@ describe.each(getCoreSmartAccounts())( entryPoint: ENTRYPOINT_ADDRESS_V07 }) - await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash, - timeout: 100000 - }) + const receipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) - const isModuleInstalled = await smartClient.isModuleInstalled({ - type: "executor", - address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - context: "0x" + const isModuleInstalledResult = await isModuleInstalled( + smartClient as any, + { + account: smartClient.account as any, + type: "executor", + address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", + context: "0x" + } + ) + + expect(isModuleInstalledResult).toBe(true) + + const nextTransaction = await smartClient.sendTransaction({ + to: zeroAddress, + value: 0n }) - expect(isModuleInstalled).toBe(true) + expect(nextTransaction).toBeTruthy() } ) } diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts index 01b3b064..df2637dd 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.test.ts @@ -37,8 +37,8 @@ describe.each(getCoreSmartAccounts())( account: smartClient.account as any, type: "batchcall", revertOnError: false, - modeSelector: "0x0", - modeData: "0x" + selector: "0x0", + context: "0x" }) expect(supportsExecutionModeBatchCallBeforeDeploy).toBe(true) @@ -55,8 +55,8 @@ describe.each(getCoreSmartAccounts())( account: smartClient.account as any, type: "batchcall", revertOnError: false, - modeSelector: "0x0", - modeData: "0x" + selector: "0x0", + context: "0x" }) expect( diff --git a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts index 1ab45857..b204d2ea 100644 --- a/packages/permissionless/actions/erc7579/supportsExecutionMode.ts +++ b/packages/permissionless/actions/erc7579/supportsExecutionMode.ts @@ -18,19 +18,20 @@ import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashW export type CallType = "call" | "delegatecall" | "batchcall" -export type ExecutionMode = { - type: CallType +export type ExecutionMode = { + type: callType revertOnError: boolean - modeSelector: Hex - modeData: Hex + selector: Hex + context: Hex } export type SupportsExecutionModeParameters< TEntryPoint extends EntryPoint, TSmartAccount extends SmartAccount | undefined = | SmartAccount - | undefined -> = GetAccountParameter & ExecutionMode + | undefined, + callType extends CallType = CallType +> = GetAccountParameter & ExecutionMode function parseCallType(executionMode: CallType) { switch (executionMode) { @@ -43,20 +44,20 @@ function parseCallType(executionMode: CallType) { } } -export function encodeExecutionMode({ +export function encodeExecutionMode({ type, revertOnError, - modeSelector, - modeData -}: ExecutionMode): Hex { + selector, + context +}: ExecutionMode): Hex { return encodePacked( ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], [ toHex(toBytes(parseCallType(type), { size: 1 })), toHex(toBytes(revertOnError ? "0x01" : "0x00", { size: 1 })), toHex(toBytes("0x0", { size: 4 })), - toHex(toBytes(modeSelector, { size: 4 })), - toHex(toBytes(modeData, { size: 22 })) + toHex(toBytes(selector, { size: 4 })), + toHex(toBytes(context, { size: 22 })) ] ) } @@ -74,8 +75,8 @@ export async function supportsExecutionMode< account: account_ = client.account, type, revertOnError, - modeSelector, - modeData + selector, + context } = args if (!account_) { @@ -91,8 +92,8 @@ export async function supportsExecutionMode< const encodedMode = encodeExecutionMode({ type, revertOnError, - modeSelector, - modeData + selector, + context }) const abi = [ diff --git a/packages/permissionless/actions/erc7579/uninstallModule.test.ts b/packages/permissionless/actions/erc7579/uninstallModule.test.ts index c754d77d..40db71c5 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.test.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.test.ts @@ -12,7 +12,8 @@ import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, - getPimlicoPaymasterClient + getPimlicoPaymasterClient, + getPublicClient } from "../../../permissionless-test/src/utils" import type { SmartAccount } from "../../accounts" import { createBundlerClient } from "../../clients/createBundlerClient" @@ -65,6 +66,13 @@ describe.each(getCoreSmartAccounts())( [smartClient.account.address] ) + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const publicClient = getPublicClient(anvilRpc) + const opHash = await smartClient.installModule({ type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", @@ -86,14 +94,14 @@ describe.each(getCoreSmartAccounts())( : moduleData }) - const bundlerClientV07 = createBundlerClient({ - transport: http(altoRpc), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) - await bundlerClientV07.waitForUserOperationReceipt({ - hash: opHash, - timeout: 100000 + await publicClient.waitForTransactionReceipt({ + hash: userOperationReceipt.receipt.transactionHash }) const uninstallModuleUserOpHash = await uninstallModule( @@ -102,7 +110,22 @@ describe.each(getCoreSmartAccounts())( account: smartClient.account as any, type: "executor", address: "0xc98B026383885F41d9a995f85FC480E9bb8bB891", - context: "0x" + context: + name === "Kernel" + ? "0x" + : encodeAbiParameters( + [ + { name: "prev", type: "address" }, + { + name: "moduleInitData", + type: "bytes" + } + ], + [ + "0x0000000000000000000000000000000000000001", + "0x" + ] + ) } ) diff --git a/packages/permissionless/actions/erc7579/uninstallModule.ts b/packages/permissionless/actions/erc7579/uninstallModule.ts index 8ade2973..b9283f03 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.ts @@ -60,31 +60,39 @@ export async function uninstallModule< const account = parseAccount(account_) as SmartAccount - const uninstallModuleCallData = encodeFunctionData({ - abi: [ - { - name: "uninstallModule", - type: "function", - stateMutability: "nonpayable", - inputs: [ - { - type: "uint256", - name: "moduleTypeId" - }, - { - type: "address", - name: "module" - }, - { - type: "bytes", - name: "deInitData" - } - ], - outputs: [] - } - ], - functionName: "uninstallModule", - args: [parseModuleTypeId(parameters.type), getAddress(address), context] + const uninstallModuleCallData = await account.encodeCallData({ + to: account.address, + value: BigInt(0), + data: encodeFunctionData({ + abi: [ + { + name: "uninstallModule", + type: "function", + stateMutability: "nonpayable", + inputs: [ + { + type: "uint256", + name: "moduleTypeId" + }, + { + type: "address", + name: "module" + }, + { + type: "bytes", + name: "deInitData" + } + ], + outputs: [] + } + ], + functionName: "uninstallModule", + args: [ + parseModuleTypeId(parameters.type), + getAddress(address), + context + ] + }) }) return getAction( diff --git a/packages/permissionless/utils/encode7579CallData.ts b/packages/permissionless/utils/encode7579CallData.ts index ffea79c0..2b67887f 100644 --- a/packages/permissionless/utils/encode7579CallData.ts +++ b/packages/permissionless/utils/encode7579CallData.ts @@ -7,13 +7,14 @@ import { toHex } from "viem" import { + type CallType, type ExecutionMode, encodeExecutionMode } from "../actions/erc7579/supportsExecutionMode" -export type EncodeCallDataParams = { - mode: executionMode - callData: executionMode["type"] extends "batchcall" +export type EncodeCallDataParams = { + mode: ExecutionMode + callData: callType extends "batchcall" ? { to: Address value: bigint @@ -26,10 +27,10 @@ export type EncodeCallDataParams = { } } -export function encode7579CallData({ +export function encode7579CallData({ mode, callData -}: EncodeCallDataParams): Hex { +}: EncodeCallDataParams): Hex { if (Array.isArray(callData) && mode?.type !== "batchcall") { throw new Error( `mode ${mode} does not supported for batchcall calldata` From d7f7f0de2dfc683352a6ec91a96fc2621d37e835 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sun, 30 Jun 2024 11:24:50 +0100 Subject: [PATCH 08/13] Add changeset --- .changeset/fifty-coins-whisper.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fifty-coins-whisper.md diff --git a/.changeset/fifty-coins-whisper.md b/.changeset/fifty-coins-whisper.md new file mode 100644 index 00000000..f04eaac5 --- /dev/null +++ b/.changeset/fifty-coins-whisper.md @@ -0,0 +1,5 @@ +--- +"permissionless": patch +--- + +Added 7579 actions support From 2f60828a815ee7ecd330383b334aab1e251d1a85 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sun, 30 Jun 2024 20:51:47 +0100 Subject: [PATCH 09/13] Add privateKeyTo**SmartAccount tests --- packages/permissionless-test/src/utils.ts | 223 ++++++++++++++---- .../light/privateKeyToLightSmartAccount.ts | 2 +- .../safe/privateKeyToSafeSmartAccount.ts | 8 +- 3 files changed, 189 insertions(+), 44 deletions(-) diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index b34adbdb..4d8e68ac 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -30,6 +30,11 @@ import { import { type SafeSmartAccount, type SmartAccount, + privateKeyToBiconomySmartAccount, + privateKeyToLightSmartAccount, + privateKeyToSafeSmartAccount, + privateKeyToSimpleSmartAccount, + privateKeyToTrustSmartAccount, signerToBiconomySmartAccount, signerToEcdsaKernelSmartAccount, signerToLightSmartAccount, @@ -205,20 +210,23 @@ export const getSimpleAccountClient = async ({ paymasterClient, anvilRpc, altoRpc, - privateKey = generatePrivateKey() + privateKey }: AAParamType): Promise< SmartAccountClient> > => { const publicClient = getPublicClient(anvilRpc) - const smartAccount = await signerToSimpleSmartAccount( - publicClient, - { - entryPoint, - signer: privateKeyToAccount(privateKey), - factoryAddress: getFactoryAddress(entryPoint, "simple") - } - ) + const smartAccount = privateKey + ? await privateKeyToSimpleSmartAccount(publicClient, { + entryPoint, + privateKey, + factoryAddress: getFactoryAddress(entryPoint, "simple") + }) + : await signerToSimpleSmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(generatePrivateKey()), + factoryAddress: getFactoryAddress(entryPoint, "simple") + }) return createSmartAccountClient({ chain: foundry, @@ -238,16 +246,22 @@ export const getLightAccountClient = async ({ paymasterClient, anvilRpc, altoRpc, - privateKey = generatePrivateKey() + privateKey }: AAParamType): Promise< SmartAccountClient> > => { const publicClient = getPublicClient(anvilRpc) - const smartAccount = await signerToLightSmartAccount(publicClient, { - entryPoint, - signer: privateKeyToAccount(privateKey), - lightAccountVersion: "1.1.0" - }) + const smartAccount = privateKey + ? await privateKeyToLightSmartAccount(publicClient, { + entryPoint, + lightAccountVersion: "1.1.0", + privateKey + }) + : await signerToLightSmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(generatePrivateKey()), + lightAccountVersion: "1.1.0" + }) return createSmartAccountClient({ chain: foundry, @@ -270,18 +284,20 @@ export const getTrustAccountClient = async < paymasterClient, altoRpc, anvilRpc, - privateKey = generatePrivateKey() + privateKey }: AAParamType): Promise< SmartAccountClient> > => { const publicClient = getPublicClient(anvilRpc) - const smartAccount = await signerToTrustSmartAccount( - publicClient, - { - entryPoint, - signer: privateKeyToAccount(privateKey) - } - ) + const smartAccount = privateKey + ? await privateKeyToTrustSmartAccount(publicClient, { + entryPoint, + privateKey + }) + : await signerToTrustSmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(generatePrivateKey()) + }) // @ts-ignore return createSmartAccountClient({ @@ -298,16 +314,21 @@ export const getTrustAccountClient = async < // Only supports v0.6 for now export const getBiconomyClient = async ({ paymasterClient, - privateKey = generatePrivateKey(), + privateKey, anvilRpc, altoRpc, entryPoint = ENTRYPOINT_ADDRESS_V06 }: AAParamType) => { const publicClient = getPublicClient(anvilRpc) - const ecdsaSmartAccount = await signerToBiconomySmartAccount(publicClient, { - entryPoint, - signer: privateKeyToAccount(privateKey) - }) + const ecdsaSmartAccount = privateKey + ? await privateKeyToBiconomySmartAccount(publicClient, { + entryPoint, + privateKey + }) + : await signerToBiconomySmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(generatePrivateKey()) + }) // @ts-ignore return createSmartAccountClient({ @@ -366,7 +387,7 @@ export const getSafeClient = async ({ paymasterClient, anvilRpc, altoRpc, - privateKey = generatePrivateKey(), + privateKey, erc7579 }: { setupTransactions?: { @@ -383,18 +404,31 @@ export const getSafeClient = async ({ }): Promise>> => { const publicClient = getPublicClient(anvilRpc) - const safeSmartAccount = await signerToSafeSmartAccount(publicClient, { - entryPoint, - signer: privateKeyToAccount(privateKey), - safeVersion: "1.4.1", - saltNonce: 420n, - safe4337ModuleAddress: erc7579 - ? "0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2" - : undefined, - erc7569LaunchpadAddress: erc7579 - ? "0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE" - : undefined - }) + const safeSmartAccount = privateKey + ? await privateKeyToSafeSmartAccount(publicClient, { + entryPoint, + privateKey, + safeVersion: "1.4.1", + saltNonce: 420n, + safe4337ModuleAddress: erc7579 + ? "0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2" + : undefined, + erc7569LaunchpadAddress: erc7579 + ? "0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE" + : undefined + }) + : await signerToSafeSmartAccount(publicClient, { + entryPoint, + signer: privateKeyToAccount(generatePrivateKey()), + safeVersion: "1.4.1", + saltNonce: 420n, + safe4337ModuleAddress: erc7579 + ? "0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2" + : undefined, + erc7569LaunchpadAddress: erc7579 + ? "0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE" + : undefined + }) const pimlicoBundlerClient = getPimlicoBundlerClient({ entryPoint, @@ -538,5 +572,112 @@ export const getCoreSmartAccounts = () => [ supportsEntryPointV06: true, supportsEntryPointV07: true, isEip1271Compliant: true + }, + + // ---------------------------- Account from private key ------------------------------------------------- + + { + name: "Trust", + getSmartAccountClient: async ( + conf: AAParamType + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getTrustAccountClient({ + ...(conf as AAParamType), + privateKey: generatePrivateKey() + }) + }, + 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: false, + isEip1271Compliant: true + }, + { + name: "LightAccount v1.1.0", + getSmartAccountClient: async ( + conf: AAParamType + ) => + getLightAccountClient({ + ...conf, + privateKey: generatePrivateKey() + }), + 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: false, + isEip1271Compliant: true + }, + { + name: "Simple", + getSmartAccountClient: async ( + conf: AAParamType + ) => + getSimpleAccountClient({ + ...conf, + privateKey: generatePrivateKey() + }), + 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: "Biconomy", + getSmartAccountClient: async ( + conf: AAParamType + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getBiconomyClient({ + ...(conf as AAParamType), + privateKey: generatePrivateKey() + }) + }, + 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, privateKey: generatePrivateKey() }), + 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" + }), + getErc7579SmartAccountClient: async ( + conf: AAParamType + ) => getSafeClient({ ...conf, erc7579: true }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true } ] diff --git a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts index 6a1d52f0..07a2cce2 100644 --- a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts @@ -28,7 +28,7 @@ export type PrivateKeyToLightSmartAccountParameters< * @returns A Private Key Light Account. */ export async function privateKeyToLightSmartAccount< - entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index fd8884e0..0b9102ea 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -7,7 +7,11 @@ import type { Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + EntryPoint, + Prettify +} from "../../types" import { type SafeSmartAccount, type SignerToSafeSmartAccountParameters, @@ -28,7 +32,7 @@ export type PrivateKeyToSafeSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function privateKeyToSafeSmartAccount< - entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( From a72758bd2939069a2a06088bc26e4f00306752e0 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sun, 30 Jun 2024 21:01:30 +0100 Subject: [PATCH 10/13] resolve merge conflicts --- packages/permissionless-test/src/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 1cf7a99b..4c125a88 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -198,8 +198,7 @@ export const getSimpleAccountClient = async ({ const smartAccount = privateKey ? await privateKeyToSimpleSmartAccount(publicClient, { entryPoint, - privateKey, - factoryAddress: getFactoryAddress(entryPoint, "simple") + privateKey }) : await signerToSimpleSmartAccount(publicClient, { entryPoint, From 307e080174d25c8d9624d3ea4e49d7da39866476 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sun, 30 Jun 2024 21:11:11 +0100 Subject: [PATCH 11/13] Fix build --- .../accounts/light/privateKeyToLightSmartAccount.ts | 5 +++-- .../accounts/safe/privateKeyToSafeSmartAccount.ts | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts index 07a2cce2..bd2ab349 100644 --- a/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts +++ b/packages/permissionless/accounts/light/privateKeyToLightSmartAccount.ts @@ -7,7 +7,8 @@ import type { Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" +import type { Prettify } from "../../types" +import type { EntryPoint } from "../../types" import { type LightSmartAccount, type SignerToLightSmartAccountParameters, @@ -15,7 +16,7 @@ import { } from "./signerToLightSmartAccount" export type PrivateKeyToLightSmartAccountParameters< - entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE + entryPoint extends EntryPoint > = Prettify< { privateKey: Hex diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index 0b9102ea..80eeecb8 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -7,11 +7,7 @@ import type { Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - EntryPoint, - Prettify -} from "../../types" +import type { EntryPoint, Prettify } from "../../types" import { type SafeSmartAccount, type SignerToSafeSmartAccountParameters, @@ -19,7 +15,7 @@ import { } from "./signerToSafeSmartAccount" export type PrivateKeyToSafeSmartAccountParameters< - entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE + entryPoint extends EntryPoint > = Prettify< { privateKey: Hex From a4bc17096fa831e443d3bbb8817fb543c88d2537 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Mon, 1 Jul 2024 19:56:57 +0100 Subject: [PATCH 12/13] better exports for erc7579Actions --- .../{clients/decorators => actions}/erc7579.ts | 18 +++++++++--------- .../actions/erc7579/installModule.test.ts | 4 ++-- .../actions/erc7579/isModuleInstalled.test.ts | 2 +- .../actions/erc7579/uninstallModule.test.ts | 2 +- packages/permissionless/package.json | 5 +++++ 5 files changed, 18 insertions(+), 13 deletions(-) rename packages/permissionless/{clients/decorators => actions}/erc7579.ts (89%) diff --git a/packages/permissionless/clients/decorators/erc7579.ts b/packages/permissionless/actions/erc7579.ts similarity index 89% rename from packages/permissionless/clients/decorators/erc7579.ts rename to packages/permissionless/actions/erc7579.ts index e169497a..3f9530b3 100644 --- a/packages/permissionless/clients/decorators/erc7579.ts +++ b/packages/permissionless/actions/erc7579.ts @@ -1,28 +1,28 @@ import type { Chain, Client, Hash, Transport } from "viem" -import type { SmartAccount } from "../../accounts/types" -import { accountId } from "../../actions/erc7579/accountId" +import type { SmartAccount } from "../accounts" +import type { GetAccountParameter } from "../types" +import type { EntryPoint } from "../types/entrypoint" +import { accountId } from "./erc7579/accountId" import { type InstallModuleParameters, installModule -} from "../../actions/erc7579/installModule" +} from "./erc7579/installModule" import { type IsModuleInstalledParameters, isModuleInstalled -} from "../../actions/erc7579/isModuleInstalled" +} from "./erc7579/isModuleInstalled" import { type SupportsExecutionModeParameters, supportsExecutionMode -} from "../../actions/erc7579/supportsExecutionMode" +} from "./erc7579/supportsExecutionMode" import { type SupportsModuleParameters, supportsModule -} from "../../actions/erc7579/supportsModule" +} from "./erc7579/supportsModule" import { type UninstallModuleParameters, uninstallModule -} from "../../actions/erc7579/uninstallModule" -import type { GetAccountParameter } from "../../types" -import type { EntryPoint } from "../../types/entrypoint" +} from "./erc7579/uninstallModule" export type Erc7579Actions< TEntryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/erc7579/installModule.test.ts b/packages/permissionless/actions/erc7579/installModule.test.ts index 2558d247..0f00cefb 100644 --- a/packages/permissionless/actions/erc7579/installModule.test.ts +++ b/packages/permissionless/actions/erc7579/installModule.test.ts @@ -7,7 +7,7 @@ import { isHash, zeroAddress } from "viem" -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { generatePrivateKey } from "viem/accounts" import { describe, expect } from "vitest" import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { @@ -17,9 +17,9 @@ import { import type { SmartAccount } from "../../accounts" import { createBundlerClient } from "../../clients/createBundlerClient" import type { SmartAccountClient } from "../../clients/createSmartAccountClient" -import { erc7579Actions } from "../../clients/decorators/erc7579" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { erc7579Actions } from "../erc7579" import { installModule } from "./installModule" describe.each(getCoreSmartAccounts())( diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts index fa37871a..bcdd042e 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts @@ -8,6 +8,7 @@ import { } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { describe, expect } from "vitest" +import { erc7579Actions } from "." import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, @@ -16,7 +17,6 @@ import { import type { SmartAccount } from "../../accounts" import { createBundlerClient } from "../../clients/createBundlerClient" import type { SmartAccountClient } from "../../clients/createSmartAccountClient" -import { erc7579Actions } from "../../clients/decorators/erc7579" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" import { isModuleInstalled } from "./isModuleInstalled" diff --git a/packages/permissionless/actions/erc7579/uninstallModule.test.ts b/packages/permissionless/actions/erc7579/uninstallModule.test.ts index 40db71c5..2414394c 100644 --- a/packages/permissionless/actions/erc7579/uninstallModule.test.ts +++ b/packages/permissionless/actions/erc7579/uninstallModule.test.ts @@ -18,9 +18,9 @@ import { import type { SmartAccount } from "../../accounts" import { createBundlerClient } from "../../clients/createBundlerClient" import type { SmartAccountClient } from "../../clients/createSmartAccountClient" -import { erc7579Actions } from "../../clients/decorators/erc7579" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { erc7579Actions } from "../erc7579" import { uninstallModule } from "./uninstallModule" describe.each(getCoreSmartAccounts())( diff --git a/packages/permissionless/package.json b/packages/permissionless/package.json index 71c733e9..e2ff2674 100644 --- a/packages/permissionless/package.json +++ b/packages/permissionless/package.json @@ -29,6 +29,11 @@ "import": "./_esm/actions/index.js", "default": "./_cjs/actions/index.js" }, + "./actions/erc7579": { + "types": "./_types/actions/index.d.ts", + "import": "./_esm/actions/index.js", + "default": "./_cjs/actions/index.js" + }, "./actions/pimlico": { "types": "./_types/actions/pimlico.d.ts", "import": "./_esm/actions/pimlico.js", From 338abce7cd500616ffd4214bd9fac96401ff61bd Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Mon, 1 Jul 2024 20:02:10 +0100 Subject: [PATCH 13/13] Better exports --- packages/permissionless/actions/erc7579.ts | 58 +++++++------------ .../actions/erc7579/isModuleInstalled.test.ts | 2 +- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/packages/permissionless/actions/erc7579.ts b/packages/permissionless/actions/erc7579.ts index 3f9530b3..64bf9c7b 100644 --- a/packages/permissionless/actions/erc7579.ts +++ b/packages/permissionless/actions/erc7579.ts @@ -15,10 +15,12 @@ import { type SupportsExecutionModeParameters, supportsExecutionMode } from "./erc7579/supportsExecutionMode" +import type { CallType, ExecutionMode } from "./erc7579/supportsExecutionMode" import { type SupportsModuleParameters, supportsModule } from "./erc7579/supportsModule" +import type { ModuleType } from "./erc7579/supportsModule" import { type UninstallModuleParameters, uninstallModule @@ -28,42 +30,6 @@ export type Erc7579Actions< TEntryPoint extends EntryPoint, TSmartAccount extends SmartAccount | undefined > = { - /** - * Get's the accountId of the smart account - * - * @param args - {@link SendTransactionParameters} - * @returns The [Transaction](https://viem.sh/docs/glossary/terms.html#transaction) hash. {@link SendTransactionReturnType} - * - * @example - * import { createSmartAccountClient, custom } from 'viem' - * import { mainnet } from 'viem/chains' - * - * const client = createSmartAccountClient({ - * chain: mainnet, - * transport: custom(window.ethereum), - * }) - * const hash = await client.sendTransaction({ - * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', - * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', - * value: 1000000000000000000n, - * }) - * - * @example - * // Account Hoisting - * import { createSmartAccountClient, http } from 'viem' - * import { privateKeyToAccount } from 'viem/accounts' - * import { mainnet } from 'viem/chains' - * - * const client = createSmartAccountClient({ - * account: privateKeyToAccount('0x…'), - * chain: mainnet, - * transport: http(), - * }) - * const hash = await client.sendTransaction({ - * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', - * value: 1000000000000000000n, - * }) - */ accountId: ( args?: TSmartAccount extends undefined ? GetAccountParameter @@ -86,6 +52,26 @@ export type Erc7579Actions< ) => Promise } +export type { + InstallModuleParameters, + IsModuleInstalledParameters, + CallType, + ExecutionMode, + SupportsExecutionModeParameters, + ModuleType, + SupportsModuleParameters, + UninstallModuleParameters +} + +export { + accountId, + installModule, + isModuleInstalled, + supportsExecutionMode, + supportsModule, + uninstallModule +} + export function erc7579Actions(_args: { entryPoint: TEntryPoint }) { diff --git a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts index bcdd042e..8aebdbd6 100644 --- a/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts +++ b/packages/permissionless/actions/erc7579/isModuleInstalled.test.ts @@ -8,7 +8,6 @@ import { } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { describe, expect } from "vitest" -import { erc7579Actions } from "." import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" import { getCoreSmartAccounts, @@ -19,6 +18,7 @@ import { createBundlerClient } from "../../clients/createBundlerClient" import type { SmartAccountClient } from "../../clients/createSmartAccountClient" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../types/entrypoint" import { ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { erc7579Actions } from "../erc7579" import { isModuleInstalled } from "./isModuleInstalled" describe.each(getCoreSmartAccounts())(