Skip to content

Commit

Permalink
Renaming EIP6551 to ERC6551
Browse files Browse the repository at this point in the history
  • Loading branch information
eloi010 committed Nov 21, 2023
1 parent e3ed943 commit c4700e2
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 162 deletions.
17 changes: 13 additions & 4 deletions contracts/core/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Recoverable Accounts
# Openfort Accounts


## Recoverable Accounts
Recoverable accounts are a special type of accounts that support social recovery.
They let owners define a set of guardians to help recover the account in case the private key of the owner is compromised (forgotten, disclosed, stolen...).

## Context
### Context

As explained by Vitalik in a famous post (https://vitalik.ca/general/2021/01/11/recovery.html), guardians are the next thing after multisig wallets.

Expand All @@ -14,7 +17,7 @@ Observe the image below from the mentioned blog post to visualize how guardians

If enough guardians confirm the recovery of an account, they can help the legitimate owner of the account update the signing key (aka owner).

## How do Recoverable Accounts Work
### How do Recoverable Accounts Work

The owner can:
- Propose a new guardian.
Expand All @@ -34,10 +37,16 @@ Anyone can:
- When in recovery mode, submit the list of needed signatures (from half of the guardians) to complete the recovery of the account.


## More Information
### More Information
- https://vitalik.ca/general/2021/01/11/recovery.html
- https://old.reddit.com/r/ethereum/comments/11tijiv/how_i_think_about_choosing_guardians_for_multisig/
- https://medium.com/nightlycrypto/smart-wallets-guardians-756d27a749c7
- https://www.makeuseof.com/what-is-crypto-social-recovery-wallet-how-does-it-work/
- https://support.argent.xyz/hc/en-us/articles/360022631992-About-guardians
- https://docs-wallet.loopring.io/security/guardians

## ERC6551 Accounts

### Context

### How do ERC6551 Accounts work
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {ERC6551AccountLib} from "erc6551/src/lib/ERC6551AccountLib.sol";
import {BaseOpenfortAccount, IEntryPoint, ECDSAUpgradeable} from "../base/BaseOpenfortAccount.sol";

/**
* @title EIP6551OpenfortAccount (Non-upgradeable)
* @title ERC6551OpenfortAccount (Non-upgradeable)
* @notice Smart contract wallet with session keys following the ERC-4337 and EIP-6551 standards.
* It inherits from:
* - BaseOpenfortAccount to comply with ERC-4337
* - IERC6551Account to have permissions using ERC-721 tokens
* - IERC6551Executable
*/
contract EIP6551OpenfortAccount is BaseOpenfortAccount, IERC6551Account, IERC6551Executable {
contract ERC6551OpenfortAccount is BaseOpenfortAccount, IERC6551Account, IERC6551Executable {
using ECDSAUpgradeable for bytes32;

address internal entrypointContract;
Expand Down
8 changes: 4 additions & 4 deletions script/deployEIP6551.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ pragma solidity =0.8.19;
import {Script, console} from "forge-std/Script.sol";
import {IEntryPoint} from "lib/account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {MockERC721} from "contracts/mock/MockERC721.sol";
import {EIP6551OpenfortAccount} from "contracts/core/eip6551/EIP6551OpenfortAccount.sol";
import {ERC6551OpenfortAccount} from "contracts/core/erc6551/ERC6551OpenfortAccount.sol";
import {IERC6551Registry} from "lib/erc6551/src/ERC6551Registry.sol";

contract EIP6551OpenfortDeploy is Script {
contract ERC6551OpenfortDeploy is Script {
uint256 internal deployPrivKey = vm.deriveKey(vm.envString("MNEMONIC"), 0);
address internal deployAddress = vm.addr(deployPrivKey);
IEntryPoint internal entryPoint = IEntryPoint((payable(vm.envAddress("ENTRY_POINT_ADDRESS"))));
Expand All @@ -19,7 +19,7 @@ contract EIP6551OpenfortDeploy is Script {
vm.startBroadcast(deployPrivKey);

// Create an acccount to serve as implementation
EIP6551OpenfortAccount eip6551OpenfortAccount = new EIP6551OpenfortAccount{salt: versionSalt}();
ERC6551OpenfortAccount erc6551OpenfortAccount = new ERC6551OpenfortAccount{salt: versionSalt}();

uint256 chainId;
assembly {
Expand All @@ -31,7 +31,7 @@ contract EIP6551OpenfortDeploy is Script {

// The first call should create a new account, while the second will just return the corresponding account address
address account2 =
erc6551Registry.createAccount(address(eip6551OpenfortAccount), versionSalt, chainId, address(nft721), 1);
erc6551Registry.createAccount(address(erc6551OpenfortAccount), versionSalt, chainId, address(nft721), 1);
console.log("Registry at address %s has created an account at address %s", address(erc6551Registry), account2);

vm.stopBroadcast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {ERC6551Registry, IERC6551Registry} from "erc6551/src/ERC6551Registry.sol";
import {EntryPoint, IEntryPoint, UserOperation} from "account-abstraction/core/EntryPoint.sol";
import {MockERC721} from "contracts/mock/MockERC721.sol";
import {EIP6551OpenfortAccount} from "contracts/core/eip6551/EIP6551OpenfortAccount.sol";
import {ERC6551OpenfortAccount} from "contracts/core/erc6551/ERC6551OpenfortAccount.sol";
import {OpenfortBaseTest} from "../OpenfortBaseTest.t.sol";

contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
contract ERC6551OpenfortAccountTest is OpenfortBaseTest {
using ECDSA for bytes32;

ERC6551Registry public erc6551Registry;
EIP6551OpenfortAccount public eip6551OpenfortAccount;
EIP6551OpenfortAccount public implEIP6551OpenfortAccount;
ERC6551OpenfortAccount public erc6551OpenfortAccount;
ERC6551OpenfortAccount public implERC6551OpenfortAccount;
MockERC721 public mockERC721;

/**
Expand Down Expand Up @@ -69,16 +69,16 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
// deploy a new MockERC721 collection
mockERC721 = new MockERC721{salt: versionSalt}();

implEIP6551OpenfortAccount = new EIP6551OpenfortAccount{salt: versionSalt}();
implERC6551OpenfortAccount = new ERC6551OpenfortAccount{salt: versionSalt}();

address eip6551OpenfortAccountAddress = erc6551Registry.createAccount(
address(implEIP6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
address erc6551OpenfortAccountAddress = erc6551Registry.createAccount(
address(implERC6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
);

eip6551OpenfortAccount = EIP6551OpenfortAccount(payable(eip6551OpenfortAccountAddress));
eip6551OpenfortAccount.initialize(address(entryPoint));
erc6551OpenfortAccount = ERC6551OpenfortAccount(payable(erc6551OpenfortAccountAddress));
erc6551OpenfortAccount.initialize(address(entryPoint));

mockERC721.mint(eip6551OpenfortAccountAddress, 1);
mockERC721.mint(erc6551OpenfortAccountAddress, 1);

vm.stopPrank();
}
Expand All @@ -87,20 +87,20 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
* Test reinitialize. It should fail.
*/
function testFailReinitialize() public {
eip6551OpenfortAccount.initialize(address(entryPoint));
erc6551OpenfortAccount.initialize(address(entryPoint));
}

/*
* Test deploy. Regular, no userOps.
*/
function testERC6551Deploy() public {
address deployedAccount =
erc6551Registry.createAccount(address(implEIP6551OpenfortAccount), 0, block.chainid, address(0), 0);
erc6551Registry.createAccount(address(implERC6551OpenfortAccount), 0, block.chainid, address(0), 0);

assertTrue(deployedAccount != address(0));

address predictedAccount =
erc6551Registry.account(address(implEIP6551OpenfortAccount), 0, block.chainid, address(0), 0);
erc6551Registry.account(address(implERC6551OpenfortAccount), 0, block.chainid, address(0), 0);

assertEq(predictedAccount, deployedAccount);
}
Expand All @@ -109,15 +109,15 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
* Test initialize implementation. It should fail.
*/
function testFailInitializeImplementation() public {
implEIP6551OpenfortAccount.initialize(address(entryPoint));
implERC6551OpenfortAccount.initialize(address(entryPoint));
}

/*
* Check implementation has not been initialized.
* EntryPoint address should be 0. Should pass.
*/
function testImplementationNoEntryPointAddr() public {
IEntryPoint e = implEIP6551OpenfortAccount.entryPoint();
IEntryPoint e = implERC6551OpenfortAccount.entryPoint();
assertEq(address(e), address(0));
}

Expand All @@ -129,14 +129,14 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
assembly {
chainId := chainid()
}
address eip6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implEIP6551OpenfortAccount), bytes32(0), chainId, address(mockERC721), 1
address erc6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implERC6551OpenfortAccount), bytes32(0), chainId, address(mockERC721), 1
);

EIP6551OpenfortAccount eip6551OpenfortAccount2 = EIP6551OpenfortAccount(payable(eip6551OpenfortAccountAddress2));
IEntryPoint e = eip6551OpenfortAccount2.entryPoint();
ERC6551OpenfortAccount erc6551OpenfortAccount2 = ERC6551OpenfortAccount(payable(erc6551OpenfortAccountAddress2));
IEntryPoint e = erc6551OpenfortAccount2.entryPoint();
assertEq(address(e), address(entryPoint));
assertNotEq(address(e), eip6551OpenfortAccountAddress2);
assertNotEq(address(e), erc6551OpenfortAccountAddress2);
}

/*
Expand All @@ -147,11 +147,11 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
assembly {
chainId := chainid()
}
address eip6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implEIP6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
address erc6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implERC6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
);
EIP6551OpenfortAccount eip6551OpenfortAccount2 = EIP6551OpenfortAccount(payable(eip6551OpenfortAccountAddress2));
IEntryPoint e = eip6551OpenfortAccount2.entryPoint();
ERC6551OpenfortAccount erc6551OpenfortAccount2 = ERC6551OpenfortAccount(payable(erc6551OpenfortAccountAddress2));
IEntryPoint e = erc6551OpenfortAccount2.entryPoint();
assertEq(address(e), address(entryPoint));
}

Expand All @@ -164,55 +164,55 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {
assembly {
chainId := chainid()
}
address eip6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implEIP6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
address erc6551OpenfortAccountAddress2 = erc6551Registry.createAccount(
address(implERC6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1
);

EIP6551OpenfortAccount eip6551OpenfortAccount2 = EIP6551OpenfortAccount(payable(eip6551OpenfortAccountAddress2));
eip6551OpenfortAccount2.initialize(address(entryPoint));
ERC6551OpenfortAccount erc6551OpenfortAccount2 = ERC6551OpenfortAccount(payable(erc6551OpenfortAccountAddress2));
erc6551OpenfortAccount2.initialize(address(entryPoint));
}

/*
* Test getDeposit() function.
* First ERC4337 function called by this EIP6551-compatible account.
* First ERC4337 function called by this ERC6551-compatible account.
*/
function testGetDeposit() public {
uint256 deposit;
deposit = eip6551OpenfortAccount.getDeposit();
deposit = erc6551OpenfortAccount.getDeposit();
assertEq(deposit, 0);

// We can add deposit by directly calling the EntryPoint
entryPoint.depositTo{value: 1}(address(eip6551OpenfortAccount));
deposit = eip6551OpenfortAccount.getDeposit();
entryPoint.depositTo{value: 1}(address(erc6551OpenfortAccount));
deposit = erc6551OpenfortAccount.getDeposit();
assertEq(deposit, 1);

// We can ALSO add deposit by calling the EntryPoint addDeposit() function of the account
eip6551OpenfortAccount.addDeposit{value: 1}();
deposit = eip6551OpenfortAccount.getDeposit();
erc6551OpenfortAccount.addDeposit{value: 1}();
deposit = erc6551OpenfortAccount.getDeposit();
assertEq(deposit, 2);
}

/*
* Test owner() function.
* Check that the owner of the eip6551 account is the owner of the NFT
* Check that the owner of the erc6551 account is the owner of the NFT
*/
function testOwner() public {
assertEq(eip6551OpenfortAccount.owner(), mockERC721.ownerOf(1));
assertEq(eip6551OpenfortAccount.owner(), address(eip6551OpenfortAccount));
assertEq(erc6551OpenfortAccount.owner(), mockERC721.ownerOf(1));
assertEq(erc6551OpenfortAccount.owner(), address(erc6551OpenfortAccount));
}

/*
* Test owner() function.
* Check that the owner of the eip6551 account is the owner of the NFT
* Check that the owner of the erc6551 account is the owner of the NFT
*/
function testNotOwner() public {
// Burning the NFT
vm.prank(address(eip6551OpenfortAccount));
mockERC721.transferFrom(address(eip6551OpenfortAccount), address(1), 1);
vm.prank(address(erc6551OpenfortAccount));
mockERC721.transferFrom(address(erc6551OpenfortAccount), address(1), 1);

assertEq(eip6551OpenfortAccount.owner(), mockERC721.ownerOf(1));
assertNotEq(eip6551OpenfortAccount.owner(), address(eip6551OpenfortAccount));
assertEq(eip6551OpenfortAccount.owner(), address(1));
assertEq(erc6551OpenfortAccount.owner(), mockERC721.ownerOf(1));
assertNotEq(erc6551OpenfortAccount.owner(), address(erc6551OpenfortAccount));
assertEq(erc6551OpenfortAccount.owner(), address(1));
}

/*
Expand All @@ -226,36 +226,36 @@ contract EIP6551OpenfortAccountTest is OpenfortBaseTest {

// Get the counterfactual address
vm.prank(factoryAdmin);
address eip6551OpenfortAccountAddress2 =
erc6551Registry.account(address(eip6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1);
address erc6551OpenfortAccountAddress2 =
erc6551Registry.account(address(erc6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1);

// Expect that we will see an event containing the account and admin
// vm.expectEmit(true, true, false, true);
// emit IERC6551Registry.ERC6551AccountCreated(
// eip6551OpenfortAccountAddress2, address(eip6551OpenfortAccount), chainId, address(mockERC721), 1, 2
// erc6551OpenfortAccountAddress2, address(erc6551OpenfortAccount), chainId, address(mockERC721), 1, 2
// );

// Deploy a static account to the counterfactual address
vm.prank(factoryAdmin);
erc6551Registry.createAccount(address(eip6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1);
erc6551Registry.createAccount(address(erc6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1);

// Make sure the counterfactual address has not been altered
vm.prank(factoryAdmin);
assertEq(
eip6551OpenfortAccountAddress2,
erc6551Registry.account(address(eip6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1)
erc6551OpenfortAccountAddress2,
erc6551Registry.account(address(erc6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1)
);
// assertNotEq(
// eip6551OpenfortAccountAddress2,
// erc6551Registry.account(address(eip6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1)
// erc6551OpenfortAccountAddress2,
// erc6551Registry.account(address(erc6551OpenfortAccount), versionSalt, chainId, address(mockERC721), 1)
// );
assertNotEq(
eip6551OpenfortAccountAddress2,
erc6551Registry.account(address(eip6551OpenfortAccount), versionSalt, chainId + 1, address(mockERC721), 1)
erc6551OpenfortAccountAddress2,
erc6551Registry.account(address(erc6551OpenfortAccount), versionSalt, chainId + 1, address(mockERC721), 1)
);
assertNotEq(
eip6551OpenfortAccountAddress2,
erc6551Registry.account(address(eip6551OpenfortAccount), versionSalt, chainId, address(0), 1)
erc6551OpenfortAccountAddress2,
erc6551Registry.account(address(erc6551OpenfortAccount), versionSalt, chainId, address(0), 1)
);
}
}
Loading

0 comments on commit c4700e2

Please sign in to comment.