Abstract

This proposal introduces a mechanism leveraging ERC-6551 to develop a GiftBox feature that allows users to gift various assets through a dedicated Ethereum account to another recipient.

Motivation

The purpose of this concept is to offer a system that is semi-permissionless for crafting and delivering a GiftBox from one user to another. The system’s design incorporates an upgradeable feature for the ERC6551 account in the future, governed by a GiftedAccountGuardian. This guardian has the capability to appoint a trusted executor to perform actions on behalf of the user during urgent situations. The entity possessing the GiftBox retains absolute authority over the ERC6551 account, with the power to establish or dispense with its own GiftedAccountGuardian.

Specification

gifted account design

GiftedAccountProxy

The GiftedAccountProxy is the ERC6551 account deployed from a permissionless ERC6551Registry. The actual implementation is determined by the method outlined below. Should a custom account implementation exist, that will be used; if not, the shared implementation provided by the account guardian is utilized.

GiftedAccountProxy.sol

function _implementation() internal view virtual override returns (address) {
	address customImpl = _accountGuardian.getCustomAccountImplementation(address(this));
	if (customImpl != address(0)) {
		return customImpl;
	}

	return _accountGuardian.getImplementation();
}

A custom implementation for the ERC6551 account is exclusively set by its owner, the token holder of the GiftBox. If addressed to 0, the custom implementation is disregarded.

GiftedAccountGuardian.sol

function setCustomAccountImplementation(address account, address implementation) external {
	require(IGiftedAccount(account).isOwner(msg.sender));
	require(
		implementation == address(0) || Address.isContract(implementation),
		"!implementation-is-not-a-contract-or-zero"
	);
	_customAccountImplementation[account] = implementation;
	emit CustomAccountImplementationUpdated(account, implementation);
}

GiftedAccountGuardian

The GiftedAccountGuardian is tasked with the management of the executor for the ERC6551 account, particularly in scenarios where there is a loss of access to the assets. It can execute emergency low-level calls to recover the assets and is also responsible for maintaining the implementation of the GiftedAccount, allowing for future updates and feature expansions.

GiftedAccount

The GiftedAccount operates under the ERC6551Account protocol, including adhering to the ERC165, ERC1271, ERC721 Receiver, and ERC1155Receiver protocols. Its initial account guardian is established through an initializer function.

function initialize(address guardian) public initializer {
	_guardian = IGiftedAccountGuardian(guardian);
}

Account creation is enacted via an ERC6551 registry, as demonstrated below:

registry.createAccount(
    address(_accountImpl),
    block.chainid,
    address(_giftNft),
    giftBoxTokenId,
    0,
    abi.encodeWithSignature("initialize(address)", address(_guardian))

Only the owner of the GiftBox can alter the Guardian of the account. The onlyOwner modifier safeguards this process. Assigning the guardian to address(0) disables the ability for the account guardian to make emergency calls.

GiftedAccount.sol

function setAccountGuardian(address guardian) external onlyOwner {
	emit AccountGuardianUpgraded(address(_guardian), guardian);
	_guardian = IGiftedAccountGuardian(guardian);
}

GiftBox

The GiftBox is an ERC721 contract, embodying a standard NFT contract without any involvement with ERC6551 or the GiftedAccountGuardian.

GiftBoxAccountHelper

The GiftBoxAccountHelper serves as a utility to amalgamate several transactions into a single action, facilitating the minting and delivering process of a GiftBox.

Account Graduate

As the project matures, the governance of the AccountGuardian can transition to address(0) or a DAO-controlled contract.  The owner of the GiftBox possesses complete control over the token-bound account and can dispose of its account guardian and proxy upgrade by setting a new implementation for the TokenAccount and designating the AccountGuardian to address(0):

guardian.setCustomAccountImplementation(account, address(upgradedImplementation));
IGiftedAccount(account).setAccountGuardian(address(0));

References