1. A new API for an account (or paymaster) to report signature check validation: instead of revert, they should return `SIG_VALIDATION_FAILED` (1) to mark signature validation. checking for `tx.origin` as zero is no longer in use.
2. ValidateUserOp returns the SIG_VALIDATION_FAILED value (like any other deadline) for a bundler to check.
3. `handleOps` reverts on such signature failure.
4. a new `simulateHandleOp()` helper method, which executes a full UserOp (validation+execution).
like `validateUserOp`, it reverts so it never commits changes on-chain, and doesn't check for signatures, and only used for off-chain simulation. This way, a userOp can be "estimated", even if it depends on the deployed account (e.g. it is a method call on a newly deployed account, or depends on the account's state such as its balance)
* fix factories
BLSFactory use same model as SimpleAccount, using immutable wallet and
only user-specific params in initializer
add factory for TestAggregatedAccount sapmle contract
Create2Factory - use arachnid's de-facto standard deployer, instead of of
the nonstandard EIP2470 (specifically, arachnid's deployer revert on errors)
* gnosis account factory
now Gnosis-Safe based account uses only standard gnosis contracts. The new GnosisSafeAcccountFactory only wraps the standard GnosisSafeProxyFactory to create the proxy (and initialize it with our modules)
AA-74: sample account cleanup part 1 - using ERC1967Proxy instead of instance
* Remove the 'updateEntryPoint' API as it is not needed - the
'setImplementation' flow should take care of this.
* Make EntryPoint an immutable member of the SimpleAccount implementation
* Merge 'exec' and 'execFromEntryPoint' into single 'execute' method
* Remove '_requireFromAdmin' and 'transfer' functions
* use factory in getAccountInitCode/getAccountAddress, not implementation and ERC1967Proxy
Co-authored-by: Dror Tirosh <dror@opengsn.org>
* reputation (and stake) mechanism to apply to all entities (factory, paymaster, aggregator and account)
* event change: actualGasUsed instead of actualGasPrice
* all entities (sender, factory, paymaster, aggregator) return stake info from simulateValidation
* use "Factory" instead of "deployer"
* emit SignatureAggregatorChanged, AccountDeployed to help bundler with reputation calculation.
Co-authored-by: Yoav Weiss <yoavw@users.noreply.github.com>
- stake-value and unstake delay are not managed by entryPoint.
- `simulateValidation()` does return them (in its `SimulationResult`, so that the bundler can validate the paymaster stake is valid (and reject the UserOp if not)
- stake values for a signature aggregator are also returned (in SimulationResultWithAggregation`, ) if the wallet uses an aggregator.
- simulateValidation() always reverts - successful result is error `SimulationResult`
- (no need to call from address(0), but always need to catch revert reason)
- returns also aggregator address, and never calls it.
- bundler should either reject UserOP or validate the signature using `aggregator.validateUserOpSignature()` (or an equivalent native library code)
initCode as deployer+data, instead of constructor code
- supports any deployer contract
- initCode doesn't have to include entire CREATE2 constructor code (it is only a method call to the deployer contract)
* update the EIP to support aggregated signatures
* support creation of aggregated wallet (simulateValidation)
* simulateValidation with param offChainSigCheck
if false, calls aggregator.validateUserOpSignature
if true, returns also offChainSigInfo to be used by off-chain code to
validate the signature
* hash pubkey into requestId
Vitalik Buterin [01/08/2022 10:40]:
Basically, if one account has a pubkey P, someone can make an evil
account with key Q - P, where they know q (the privkey of Q), and then
they pass off a signature with q as being an "aggregate" signature of
the same message signed by both K1 = P and K2 = Q-P (because K1 + K2 =
Q)
The fix to this is to hash the pubkey into the msghash, so you never get
two different keys signing the same message.
And I think this has to be enforced at the BLS aggregate verifier layer
Co-authored-by: Alex Forshtat <forshtat1@gmail.com>
* inital code
import Gnosis code as-is.
probably can remove all non-essential contracts (e.g. test, samples)
or better, import as external library.
* removed unused contracts (not used,fail compilation)
* initial Gnosis-Safe Proxy account
* refactor:
- use @gnosis.pm/safe-contracts package
- separate contracts into separate files.
* cleanup, single owner
* cleanup contracts
simpler fallback handler
* added tests
failure cases
counterfactual creation
* change to "Manager"
- manager is not a module, only fallback, entrypoint
- replaceManager now works
* ignore from coverage
(fails to compile for coverage)
* fix dangling test
* Fix lint
* Set expected code lenght to be 324
Co-authored-by: Alex Forshtat <forshtat1@gmail.com>
* [M02] Separate stake and prepayment
seperate "stake" from deposit
- keep separate stake and deposit balances.
- stake is unmodified. paymaster only pays from its deposit.
- paymaster pre-pay for the request, just like the wallet does (and refunded at the end)
* ban GAS opcode in validateUserOp
* SimpleWallet without using "gas"
created a version of ECDSA library that doesn't use the "gas" opcode
(calling the ecrecover precompile using assembly)
also avoid using "gas" opcode while sending prefund to EntryPoint
* add eth-gas-reporter to "yarn ci" build
* `createWalletOwner()` (and `createAddress()`) now generate deterministic addresses, so they don't skew gas calculations (zero-bytes in calldata fluctuate gas usage)
* add "requestId" to event
requestID is a unique identifier of current request. it is a hash of the entire UserOperation content (except the signature) with chainid and entrypoint address.
* cleanup obsolete methods (simulateWalletValidation, simulatePaymasterValidation) - should use "simulateValidation", which combines them together.
* updated runop
- simplified stake/deposit mechanism
- send eth to EntryPoint adds to deposit
- remove "walletEth" mode: always pay from wallet deposit.
- user is not automatically refunded after the call (deposit is left for future calls) - can use "withdrawTo" call to retrieve its leftover deposit.
- add chainId to hash before signature.
- refactor:
name methods as per the EIP (verifyUserOp=>validateUserOp)
redeemer => beneficiary
redeem() => compensate
A single "static" call method that performs both wallet.validateUserOp
and paymaster.validatePaymasterUserOp.
In order to do opcode-tracing separately on those methods, the caller
should look for the SELFBALANCE at depth=1
there is exactly one such call before and another after the
`validateUserOp`, so the opcodes between (at depth>=2) are the
validateUserOp code.
The opcode validation of `verifyPaymasterUserOp` is for the code after
the 2nd SELFBALANCE
* rename fields
Singleton=>EntryPoint
target=>sender
payForSelfOp => validateUserOp
payForOp => validatePaymasterUserOp
added preVerificationGas
removed execFromSingleton from interface (it is required by actual
implementation, but actual signature is wallet-specific)
* added perOpOverhead
* added batch tests , large batches for testing construction, large TXs, heavy cpu.
* test for banned opcodes in simulateWalletVerification
* removed banning of GAS opcode in payForSelf testing.
* add github test workflow
added batch test (multiple TXs)
fixed tests to properly use execFromSingleton
- some gas optimizations (handling of calldata, modified signature
encoding)
- some refactors to wrap assembly code (_call, _create2)
- calcGasUsage- compare rcpt.gasUsed to paid userop
No explicit "signer" field.
wallet may define a signer, depending on its signature scheme.
wallet constructor MUST have signer as parameter, to make target address
unqiue.
* postOp gets dynamic context
postOp gets "bytes calldata context" instead of "bytes32" AND UserOperation.
rationale: in most cases, the entire UserOperation is not required by postOp, or at most, a single field is required.
OTOH, for complex paymasters, there might be some calculations in the payForOp that ARE required in the "postOp"
with the dynamic context, the paymaster decides exactly what to pass to its postOp, whether copy of field(s) form the UserOp, or locally calculated data.
If none is needed, it can be left empty.
- normal userOp cost ~400 more
- "create" operation cost 5000 less
* fixed test, initial geth testing support
userOp: added initCode - constructor code to run.
executed before payForOp (obviously..)
callData is the initialization code.
TokenPaymaster expects initCode to approve getting tokens (that's why it
has to "whitelist" both constructor code and init function.