Nexus - bcnmy/nexus GitHub Wiki
Inherits: INexus, EIP712, BaseAccount, ExecutionHelper, ModuleManager, UUPSUpgradeable
This contract integrates various functionalities to handle modular smart accounts compliant with ERC-7579 and ERC-4337 standards.
Comprehensive suite of methods for managing smart accounts, integrating module management, execution management, and upgradability via UUPS.
-
Nexus
- Table of Contents
- State Variables
-
Functions
- constructor
- validateUserOp
- execute
- executeFromExecutor
- executeUserOp
- installModule
- uninstallModule
- initializeAccount
- isValidSignature
- getImplementation
- supportsModule
- supportsExecutionMode
- isModuleInstalled
- hashTypedData
- DOMAIN_SEPARATOR
- accountId
- upgradeToAndCall
- replaySafeHash
- _authorizeUpgrade
- _eip712Hash
- _erc1271HashForIsValidSignatureViaNestedEIP712
- _domainNameAndVersion
- _handleSingleExecution
- _handleBatchExecution
- _isModuleInstalled
- _typedDataSignFields
*Precomputed typeHash
used to produce EIP-712 compliant hash when applying the anti cross-account-replay layer.
The original hash must either be:
- An EIP-191 hash: keccak256("\x19Ethereum Signed Message:\n" || len(someMessage) || someMessage)
- An EIP-712 hash: keccak256("\x19\x01" || someDomainSeparator || hashStruct(someStruct)*
bytes32 private constant _MESSAGE_TYPEHASH = keccak256("BiconomyNexusMessage(bytes32 hash)");
Important
This precomputed typeHash
ensures that messages adhere to EIP-712 standards, providing a secure way to handle anti cross-account-replay measures.
address private immutable _SELF;
Note
The _SELF
variable stores the address of the contract itself. This is immutable and set at deployment, ensuring consistency and security in the contract's identity.
keccak256("PersonalSign(bytes prefixed)")
.
bytes32 internal constant _PERSONAL_SIGN_TYPEHASH = 0x983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de;
Caution
The _PERSONAL_SIGN_TYPEHASH
is crucial for handling personal sign requests securely, adhering to EIP-712 standards to prevent signature replays.
Initializes the smart account with the specified entry point.
constructor(address anEntryPoint);
Validates a user operation against a specified validator, extracted from the operation's nonce.
The entryPoint calls this only if validation succeeds. Fails by returning VALIDATION_FAILED
for invalid signatures.
Other validation failures (e.g., nonce mismatch) should revert.
Expects the validator's address to be encoded in the upper 96 bits of the userOp's nonce. This method forwards the validation task to the extracted validator module address.
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
)
external
virtual
payPrefund(missingAccountFunds)
onlyEntryPoint
returns (uint256 validationData);
Parameters
Name | Type | Description |
---|---|---|
userOp |
PackedUserOperation |
The operation to validate, encapsulating all transaction details. |
userOpHash |
bytes32 |
Hash of the operation data, used for signature validation. |
missingAccountFunds |
uint256 |
Funds missing from the account's deposit necessary for transaction execution. This can be zero if covered by a paymaster or sufficient deposit exists. |
Returns
Name | Type | Description |
---|---|---|
validationData |
uint256 |
Encoded validation result or failure, propagated from the validator module. - Encoded format in validationData: - First 20 bytes: Validator address, 0x0 for valid or specific failure modes. - SIG_VALIDATION_FAILED (1) denotes signature validation failure allowing simulation calls without a valid signature. |
Warning
Ensure that the validator's address is correctly encoded in the nonce to prevent validation failures.
Executes transactions in single or batch modes as specified by the execution mode.
This function handles transaction execution flexibility and is protected by the onlyEntryPointOrSelf
modifier.
This function also goes through hook checks via withHook modifier.
function execute(ExecutionMode mode, bytes calldata executionCalldata) external payable onlyEntryPointOrSelf withHook;
Parameters
Name | Type | Description |
---|---|---|
mode |
ExecutionMode |
The execution mode detailing how transactions should be handled (single, batch, default, try/catch). |
executionCalldata |
bytes |
The encoded transaction data to execute. |
Note
This function's flexibility allows for handling various transaction execution strategies, making it versatile for different use cases.
Executes transactions from an executor module, supporting both single and batch transactions.
This function is callable only by an executor module and goes through hook checks.
function executeFromExecutor(
ExecutionMode mode,
bytes calldata executionCalldata
)
external
payable
onlyExecutorModule
withHook
returns (bytes[] memory returnData);
Parameters
Name | Type | Description |
---|---|---|
mode |
ExecutionMode |
The execution mode (single or batch, default or try). |
executionCalldata |
bytes |
The transaction data to execute. |
Returns
Name | Type | Description |
---|---|---|
returnData |
bytes[] |
The results of the transaction executions, which may include errors in try mode. |
Important
Only executor modules can call this function, ensuring that transaction execution is controlled and secure.
Executes a user operation via a call using the contract's context.
Only callable by the EntryPoint. Decodes the user operation calldata, skipping the first four bytes, and executes the inner call.
function executeUserOp(PackedUserOperation calldata userOp, bytes32) external payable virtual onlyEntryPoint;
Parameters
Name | Type | Description |
---|---|---|
userOp |
PackedUserOperation |
The user operation to execute, containing transaction details. |
<none> |
bytes32 |
Caution
This function should only be called by the EntryPoint to ensure the integrity of the user operation execution.
Installs a new module to the smart account.
This function can only be called by the EntryPoint or the account itself for security reasons.
This function also goes through hook checks via withHook modifier.
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable onlyEntryPointOrSelf withHook;
Parameters
Name | Type | Description |
---|---|---|
moduleTypeId |
uint256 |
The type identifier of the module being installed, which determines its role: - 1 for Validator - 2 for Executor - 3 for Fallback - 4 for Hook |
module |
address |
The address of the module to install. |
initData |
bytes |
Initialization data for the module. |
Note
This function allows the installation of various types of modules (Validator, Executor, Fallback, Hook) to enhance the smart account's functionality.
Uninstalls a module from the smart account.
Ensures that the operation is authorized and valid before proceeding with the uninstallation.
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable onlyEntryPointOrSelf;
Parameters
Name | Type | Description |
---|---|---|
moduleTypeId |
uint256 |
The type ID of the module to be uninstalled, matching the installation type: - 1 for Validator - 2 for Executor - 3 for Fallback - 4 for Hook |
module |
address |
The address of the module to uninstall. |
deInitData |
bytes |
De-initialization data for the module. |
Caution
Make sure to provide the correct module type ID and de-initialization data to avoid issues during the uninstallation process.
Initializes the account with provided data.
function initializeAccount(bytes calldata initData) external payable virtual;
Important
This function should be called to set up the account with necessary initialization parameters.
Validates a signature according to ERC-1271 standards.
Delegates the validation to a validator module specified within the signature data.
function isValidSignature(bytes32 hash, bytes calldata data) external view virtual override returns (bytes4);
Parameters
Name | Type | Description |
---|---|---|
hash |
bytes32 |
The hash of the data being validated. |
data |
bytes |
Signature data that needs to be validated. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bytes4 |
The status code of the signature validation (0x1626ba7e if valid). |
Note
This function ensures that the signature conforms to ERC-1271 standards, providing a robust mechanism for signature validation.
Retrieves the address of the current implementation from the EIP-1967 slot.
Checks the 1967 implementation slot, if not found then checks the slot defined by address (Biconomy V2 smart account).
function getImplementation() external view returns (address implementation);
Returns
Name | Type | Description |
---|---|---|
implementation |
address |
The address of the current contract implementation. |
Important
This function is crucial for verifying the current implementation of the contract, ensuring the correct version is in use.
Checks if a specific module type is supported by this smart account.
function supportsModule(uint256 moduleTypeId) external view virtual returns (bool);
Parameters
Name | Type | Description |
---|---|---|
moduleTypeId |
uint256 |
The identifier of the module type to check. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bool |
True if the module type is supported, false otherwise. |
Note
Use this function to verify if a certain type of module can be installed or used with this smart account.
Determines if a specific execution mode is supported.
function supportsExecutionMode(ExecutionMode mode) external view virtual returns (bool isSupported);
Parameters
Name | Type | Description |
---|---|---|
mode |
ExecutionMode |
The execution mode to evaluate. |
Returns
Name | Type | Description |
---|---|---|
isSupported |
bool |
True if the execution mode is supported, false otherwise. |
Important
Check the support for different execution modes to ensure compatibility with specific transaction types.
Determines whether a module is installed on the smart account.
function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool);
Parameters
Name | Type | Description |
---|---|---|
moduleTypeId |
uint256 |
The ID corresponding to the type of module (Validator, Executor, Fallback, Hook). |
module |
address |
The address of the module to check. |
additionalContext |
bytes |
Optional context that may be needed for certain checks. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bool |
True if the module is installed, false otherwise. |
Note
Use this function to confirm if a particular module is currently active in the smart account.
EIP712 hashTypedData method.
function hashTypedData(bytes32 structHash) external view returns (bytes32);
Important
This function helps in generating the EIP-712 compliant hash required for signature verification and replay protection.
EIP712 domain separator.
function DOMAIN_SEPARATOR() external view returns (bytes32);
Note
The DOMAIN_SEPARATOR is essential for EIP-712 compliance, ensuring unique domain separation for the hashing process.
Returns the account's implementation ID.
function accountId() external pure virtual returns (string memory);
Returns
Name | Type | Description |
---|---|---|
<none> |
string |
The unique identifier for this account implementation. |
Important
The account ID uniquely identifies the implementation, ensuring consistent behavior and identification across different instances.
Upgrades the contract to a new implementation and calls a function on the new contract.
Updates two slots:
- ERC1967 slot and
- address() slot in case if it's potentially upgraded earlier from Biconomy V2 account, as Biconomy v2 Account (proxy) reads implementation from the slot that is defined by its address.
function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override onlyEntryPointOrSelf;
Parameters
Name | Type | Description |
---|---|---|
newImplementation |
address |
The address of the new contract implementation. |
data |
bytes |
The calldata to be sent to the new implementation. |
Warning
Ensure that the new implementation address is valid and the calldata is properly structured to avoid issues during the upgrade process.
Wrapper around _eip712Hash()
to produce a replay-safe hash from the given hash
.
The returned EIP-712 compliant replay-safe hash is the result of:
keccak256( \x19\x01 || this.domainSeparator || hashStruct(BiconomyNexusMessage({ hash:
hash})) )
function replaySafeHash(bytes32 hash) public view virtual returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
hash |
bytes32 |
The original hash. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bytes32 |
The corresponding replay-safe hash. |
Note
This function ensures that the hash is replay-safe, preventing replay attacks by generating a unique EIP-712 compliant hash.
Ensures that only authorized callers can upgrade the smart contract implementation. This is part of the UUPS (Universal Upgradeable Proxy Standard) pattern.
function _authorizeUpgrade(address newImplementation) internal virtual override(UUPSUpgradeable) onlyEntryPointOrSelf;
Parameters
Name | Type | Description |
---|---|---|
newImplementation |
address |
The address of the new implementation to upgrade to. |
Important
This function ensures that only authorized upgrades are performed, maintaining the integrity and security of the contract.
Returns the EIP-712 typed hash of the BiconomyNexusMessage(bytes32 hash)
data structure.
Implements encode(domainSeparator : ๐นยฒโตโถ, message : ๐) = "\x19\x01" || domainSeparator || hashStruct(message).
See https://eips.ethereum.org/EIPS/eip-712#specification.
function _eip712Hash(bytes32 hash) internal view virtual returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
hash |
bytes32 |
The BiconomyNexusMessage.hash field to hash. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bytes32 |
The resulting EIP-712 hash. |
Note
This function is crucial for generating EIP-712 compliant hashes used in signature verification, ensuring replay protection and data integrity.
ERC1271 signature validation (Nested EIP-712 workflow). This implementation uses a nested EIP-712 approach to prevent signature replays when a single signer owns multiple smart contract accounts, while still enabling wallet UIs (e.g. Metamask) to show the EIP-712 values. Crafted for phishing resistance, efficiency, flexibility.
function _erc1271HashForIsValidSignatureViaNestedEIP712(
bytes32 hash,
bytes calldata signature
)
internal
view
virtual
returns (bytes32, bytes calldata);
Parameters
Name | Type | Description |
---|---|---|
hash |
bytes32 |
The original hash to be validated. |
signature |
bytes |
The signature data. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bytes32 |
The resulting EIP-712 hash. |
<none> |
bytes calldata |
The remaining signature data. |
Important
This function enhances security by preventing signature replays, even when a single signer controls multiple smart accounts.
EIP712 domain name and version.
function _domainNameAndVersion() internal pure override returns (string memory name, string memory version);
Returns
Name | Type | Description |
---|---|---|
name |
string |
The domain name. |
version |
string |
The domain version. |
Note
This function provides the domain name and version for EIP-712 compliance, ensuring consistency across different uses.
Executes a single transaction based on the specified execution type.
function _handleSingleExecution(bytes calldata executionCalldata, ExecType execType) private;
Parameters
Name | Type | Description |
---|---|---|
executionCalldata |
bytes |
The calldata containing the transaction details (target address, value, and data). |
execType |
ExecType |
The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). |
Caution
Ensure the execution calldata and type are correctly specified to avoid unintended behavior during transaction execution.
Executes a batch of transactions based on the specified execution type.
function _handleBatchExecution(bytes calldata executionCalldata, ExecType execType) private;
Parameters
Name | Type | Description |
---|---|---|
executionCalldata |
bytes |
The calldata for a batch of transactions. |
execType |
ExecType |
The execution type, which can be DEFAULT (revert on failure) or TRY (return on failure). |
Important
Batch execution allows handling multiple transactions in one call, improving efficiency and reducing gas costs.
Checks if a module is installed on the smart account.
function _isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) private view returns (bool);
Parameters
Name | Type | Description |
---|---|---|
moduleTypeId |
uint256 |
The module type ID. |
module |
address |
The module address. |
additionalContext |
bytes |
Additional context for checking installation. |
Returns
Name | Type | Description |
---|---|---|
<none> |
bool |
True if the module is installed, false otherwise. |
Note
Use this function to verify if a specific module is currently active within the smart account.
For use in _erc1271HashForIsValidSignatureViaNestedEIP712
function _typedDataSignFields() private view returns (bytes32 m);
Important
This function is used internally for EIP-712 signature validation, ensuring signatures are valid and secure.