Skip to main content

Managed Account

import "@thirdweb-dev/contracts/smart-wallet/managed/ManagedAccount.sol";

This contract inherits from the BaseAccount contract.

Like DynamicAccount, the ManagedAccount smart wallet is an upgradeable smart contract written in the dynamic contract pattern.

App developers can issue ManagedAccount smart wallets programmatically by deploying a ManagedAccountFactory smart contract.

The admin of the ManagedAccountFactory contract can push upgrades to all ManagedAccount contracts that it creates. This admin does not require any permissions on the ManagedAccount smart wallets to do so.

An upgrade to the features of ManagedAccount applies to all ManagedAccount smart wallets created by the factory. This is the right wallet for developers who anticipate pushing upgrades to their users’ wallets.


info

If you intend to issue accounts programmatically using a custom factory contract, you must do the following:

  • Create a new factory contract by extending the BaseAccountFactory extension.

  • Override the _initializeAccount function on the factory to create a new wallet. (reference)

Detected Extensions

Once deployed, you can use the features made available by these extensions on the SDK and dashboard:

Click on each feature to learn more about what functions are available.

Usage

Import the contract and inherit from it. This is an example contract demonstrating one way that you could override the functionality to create a token bound account.

import "@thirdweb-dev/contracts/smart-wallet/managed/ManagedAccount.sol";

contract ManagedTokenBoundAccount is ManagedAccount {
constructor(
IEntryPoint _entrypoint
)
ManagedAccount(
_entrypoint
)
{}
}

Functions to Override

The following functions have been implemented on this contract & are available to be overridden to add custom logic:

initialize

Initializes the smart contract wallet.

function initialize(address _defaultAdmin, bytes calldata _data) public virtual initializer {
factory = msg.sender;
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
}

_defaultAdmin

The account admin. Must be of type address.

_data

The abi encoded data to initialize the contract with. Must be of type bytes.

getImplementationForFunction

Returns the extension implementation address, stored in the router, for the given function.

function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) {
return Router(payable(factory)).getImplementationForFunction(_functionSelector);
}

_functionSelector

The function selector to get the extension implementation address. Must be of type bytes4.

isValidSigner

Returns whether a signer is authorized to perform transactions using the wallet.

function isValidSigner(address _signer) public view virtual returns (bool) {
return _hasRole(SIGNER_ROLE, _signer) || _hasRole(DEFAULT_ADMIN_ROLE, _signer);
}

_signer

The signer to check authorization for. Must be of type address.

entryPoint

Returns the entry point contract address.

function entryPoint() public view virtual override returns (IEntryPoint) {
return entrypointContract;
}
_validateSignature

Validates the signature of a user operation.

function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
internal
virtual
override
returns (uint256 validationData)
{
bytes32 hash = userOpHash.toEthSignedMessageHash();
address signer = hash.recover(userOp.signature);

if (!isValidSigner(signer)) return SIG_VALIDATION_FAILED;
return 0;
}