Merge account abstraction work into master (#5274)
Co-authored-by: Ernesto García <ernestognw@gmail.com> Co-authored-by: Elias Rad <146735585+nnsW3@users.noreply.github.com> Co-authored-by: cairo <cairoeth@protonmail.com> Co-authored-by: Arr00 <13561405+arr00@users.noreply.github.com>
This commit is contained in:
95
test/helpers/erc4337.js
Normal file
95
test/helpers/erc4337.js
Normal file
@ -0,0 +1,95 @@
|
||||
const { ethers } = require('hardhat');
|
||||
|
||||
const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000';
|
||||
const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001';
|
||||
|
||||
function getAddress(account) {
|
||||
return account.target ?? account.address ?? account;
|
||||
}
|
||||
|
||||
function pack(left, right) {
|
||||
return ethers.solidityPacked(['uint128', 'uint128'], [left, right]);
|
||||
}
|
||||
|
||||
function packValidationData(validAfter, validUntil, authorizer) {
|
||||
return ethers.solidityPacked(
|
||||
['uint48', 'uint48', 'address'],
|
||||
[
|
||||
validAfter,
|
||||
validUntil,
|
||||
typeof authorizer == 'boolean'
|
||||
? authorizer
|
||||
? SIG_VALIDATION_SUCCESS
|
||||
: SIG_VALIDATION_FAILURE
|
||||
: getAddress(authorizer),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
function packPaymasterData(paymaster, verificationGasLimit, postOpGasLimit) {
|
||||
return ethers.solidityPacked(
|
||||
['address', 'uint128', 'uint128'],
|
||||
[getAddress(paymaster), verificationGasLimit, postOpGasLimit],
|
||||
);
|
||||
}
|
||||
|
||||
/// Represent one user operation
|
||||
class UserOperation {
|
||||
constructor(params) {
|
||||
this.sender = getAddress(params.sender);
|
||||
this.nonce = params.nonce;
|
||||
this.initCode = params.initCode ?? '0x';
|
||||
this.callData = params.callData ?? '0x';
|
||||
this.verificationGas = params.verificationGas ?? 10_000_000n;
|
||||
this.callGas = params.callGas ?? 100_000n;
|
||||
this.preVerificationGas = params.preVerificationGas ?? 100_000n;
|
||||
this.maxPriorityFee = params.maxPriorityFee ?? 100_000n;
|
||||
this.maxFeePerGas = params.maxFeePerGas ?? 100_000n;
|
||||
this.paymasterAndData = params.paymasterAndData ?? '0x';
|
||||
this.signature = params.signature ?? '0x';
|
||||
}
|
||||
|
||||
get packed() {
|
||||
return {
|
||||
sender: this.sender,
|
||||
nonce: this.nonce,
|
||||
initCode: this.initCode,
|
||||
callData: this.callData,
|
||||
accountGasLimits: pack(this.verificationGas, this.callGas),
|
||||
preVerificationGas: this.preVerificationGas,
|
||||
gasFees: pack(this.maxPriorityFee, this.maxFeePerGas),
|
||||
paymasterAndData: this.paymasterAndData,
|
||||
signature: this.signature,
|
||||
};
|
||||
}
|
||||
|
||||
hash(entrypoint, chainId) {
|
||||
const p = this.packed;
|
||||
const h = ethers.keccak256(
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(
|
||||
['address', 'uint256', 'bytes32', 'bytes32', 'uint256', 'uint256', 'uint256', 'uint256'],
|
||||
[
|
||||
p.sender,
|
||||
p.nonce,
|
||||
ethers.keccak256(p.initCode),
|
||||
ethers.keccak256(p.callData),
|
||||
p.accountGasLimits,
|
||||
p.preVerificationGas,
|
||||
p.gasFees,
|
||||
ethers.keccak256(p.paymasterAndData),
|
||||
],
|
||||
),
|
||||
);
|
||||
return ethers.keccak256(
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(['bytes32', 'address', 'uint256'], [h, getAddress(entrypoint), chainId]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SIG_VALIDATION_SUCCESS,
|
||||
SIG_VALIDATION_FAILURE,
|
||||
packValidationData,
|
||||
packPaymasterData,
|
||||
UserOperation,
|
||||
};
|
||||
58
test/helpers/erc7579.js
Normal file
58
test/helpers/erc7579.js
Normal file
@ -0,0 +1,58 @@
|
||||
const { ethers } = require('hardhat');
|
||||
|
||||
const MODULE_TYPE_VALIDATOR = 1;
|
||||
const MODULE_TYPE_EXECUTOR = 2;
|
||||
const MODULE_TYPE_FALLBACK = 3;
|
||||
const MODULE_TYPE_HOOK = 4;
|
||||
|
||||
const EXEC_TYPE_DEFAULT = '0x00';
|
||||
const EXEC_TYPE_TRY = '0x01';
|
||||
|
||||
const CALL_TYPE_CALL = '0x00';
|
||||
const CALL_TYPE_BATCH = '0x01';
|
||||
const CALL_TYPE_DELEGATE = '0xff';
|
||||
|
||||
const encodeMode = ({
|
||||
callType = '0x00',
|
||||
execType = '0x00',
|
||||
selector = '0x00000000',
|
||||
payload = '0x00000000000000000000000000000000000000000000',
|
||||
} = {}) =>
|
||||
ethers.solidityPacked(
|
||||
['bytes1', 'bytes1', 'bytes4', 'bytes4', 'bytes22'],
|
||||
[callType, execType, '0x00000000', selector, payload],
|
||||
);
|
||||
|
||||
const encodeSingle = (target, value = 0n, data = '0x') =>
|
||||
ethers.solidityPacked(['address', 'uint256', 'bytes'], [target.target ?? target.address ?? target, value, data]);
|
||||
|
||||
const encodeBatch = (...entries) =>
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(
|
||||
['(address,uint256,bytes)[]'],
|
||||
[
|
||||
entries.map(entry =>
|
||||
Array.isArray(entry)
|
||||
? [entry[0].target ?? entry[0].address ?? entry[0], entry[1] ?? 0n, entry[2] ?? '0x']
|
||||
: [entry.target.target ?? entry.target.address ?? entry.target, entry.value ?? 0n, entry.data ?? '0x'],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
const encodeDelegate = (target, data = '0x') =>
|
||||
ethers.solidityPacked(['address', 'bytes'], [target.target ?? target.address ?? target, data]);
|
||||
|
||||
module.exports = {
|
||||
MODULE_TYPE_VALIDATOR,
|
||||
MODULE_TYPE_EXECUTOR,
|
||||
MODULE_TYPE_FALLBACK,
|
||||
MODULE_TYPE_HOOK,
|
||||
EXEC_TYPE_DEFAULT,
|
||||
EXEC_TYPE_TRY,
|
||||
CALL_TYPE_CALL,
|
||||
CALL_TYPE_BATCH,
|
||||
CALL_TYPE_DELEGATE,
|
||||
encodeMode,
|
||||
encodeSingle,
|
||||
encodeBatch,
|
||||
encodeDelegate,
|
||||
};
|
||||
Reference in New Issue
Block a user