-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from openfort-xyz/development
First working version of Managed Accounts
- Loading branch information
Showing
20 changed files
with
1,583 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,3 @@ broadcast/ | |
|
||
/.DS_Store | ||
.DS_Store | ||
|
||
contracts/mock/* | ||
script/deployMock.sol |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"solidity.compileUsingRemoteVersion": "v0.8.19+commit.7dd6d404" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
// Base account contract to inherit from | ||
import {BaseOpenfortAccount} from "../BaseOpenfortAccount.sol"; | ||
|
||
/** | ||
* @title ManagedOpenfortAccount (Upgradeable via Beacon) | ||
* @author Eloi<[email protected]> | ||
* @notice Smart contract wallet managed via Beacon with session keys following the ERC-4337 standard. | ||
* It inherits from: | ||
* - BaseOpenfortAccount | ||
*/ | ||
contract ManagedOpenfortAccount is BaseOpenfortAccount { | ||
/* | ||
* @notice Initialize the smart contract wallet. | ||
*/ | ||
function initialize(address _defaultAdmin, address _entrypoint, bytes calldata) public override initializer { | ||
if (_defaultAdmin == address(0) || _entrypoint == address(0)) { | ||
revert ZeroAddressNotAllowed(); | ||
} | ||
_transferOwnership(_defaultAdmin); | ||
entrypointContract = _entrypoint; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; | ||
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; | ||
// Smart wallet implementation to use | ||
import {ManagedOpenfortAccount} from "./ManagedOpenfortAccount.sol"; | ||
import {OpenfortBeacon} from "./OpenfortBeacon.sol"; | ||
// Interfaces | ||
import {IBaseOpenfortFactory} from "../../interfaces/IBaseOpenfortFactory.sol"; | ||
|
||
/** | ||
* @title ManagedOpenfortFactory (Non-upgradeable) | ||
* @author Eloi<[email protected]> | ||
* @notice Contract to create an on-chain factory to deploy new ManagedOpenfortAccounts. | ||
* It uses OpenZeppelin's Create2 and BeaconProxy libraries. | ||
* It inherits from: | ||
* - IBaseOpenfortFactory | ||
*/ | ||
contract ManagedOpenfortFactory is IBaseOpenfortFactory { | ||
address public immutable entrypointContract; | ||
address public immutable openfortBeacon; | ||
|
||
constructor(address _entrypoint, address _openfortBeacon) { | ||
if (_entrypoint == address(0) || _openfortBeacon == address(0)) { | ||
revert ZeroAddressNotAllowed(); | ||
} | ||
entrypointContract = _entrypoint; | ||
openfortBeacon = _openfortBeacon; | ||
} | ||
|
||
/* | ||
* @notice Deploy a new Account for _admin. | ||
*/ | ||
function createAccount(address _admin, bytes calldata _data) external returns (address account) { | ||
bytes32 salt = keccak256(abi.encode(_admin)); | ||
account = getAddress(_admin); | ||
|
||
if (account.code.length > 0) { | ||
return account; | ||
} | ||
|
||
emit AccountCreated(account, _admin); | ||
account = address( | ||
new BeaconProxy{salt: salt}( | ||
openfortBeacon, | ||
abi.encodeCall(ManagedOpenfortAccount.initialize, (_admin, entrypointContract, _data)) | ||
) | ||
); | ||
} | ||
|
||
/* | ||
* @notice Deploy a new account for _admin with a nonce. | ||
*/ | ||
function createAccountWithNonce(address _admin, bytes calldata _data, uint256 nonce) | ||
external | ||
returns (address account) | ||
{ | ||
bytes32 salt = keccak256(abi.encode(_admin, nonce)); | ||
account = getAddressWithNonce(_admin, nonce); | ||
|
||
if (account.code.length > 0) { | ||
return account; | ||
} | ||
|
||
emit AccountCreated(account, _admin); | ||
account = address( | ||
new BeaconProxy{salt: salt}( | ||
openfortBeacon, | ||
abi.encodeCall(ManagedOpenfortAccount.initialize, (_admin, entrypointContract, _data)) | ||
) | ||
); | ||
} | ||
|
||
/* | ||
* @notice Return the address of an account that would be deployed with the given admin signer. | ||
*/ | ||
function getAddress(address _admin) public view returns (address) { | ||
bytes32 salt = keccak256(abi.encode(_admin)); | ||
return Create2.computeAddress( | ||
bytes32(salt), | ||
keccak256( | ||
abi.encodePacked( | ||
type(BeaconProxy).creationCode, | ||
abi.encode( | ||
openfortBeacon, | ||
abi.encodeCall(ManagedOpenfortAccount.initialize, (_admin, entrypointContract, "")) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
|
||
/* | ||
* @notice Return the address of an account that would be deployed with the given admin signer and nonce. | ||
*/ | ||
function getAddressWithNonce(address _admin, uint256 nonce) public view returns (address) { | ||
bytes32 salt = keccak256(abi.encode(_admin, nonce)); | ||
return Create2.computeAddress( | ||
bytes32(salt), | ||
keccak256( | ||
abi.encodePacked( | ||
type(BeaconProxy).creationCode, | ||
abi.encode( | ||
openfortBeacon, | ||
abi.encodeCall(ManagedOpenfortAccount.initialize, (_admin, entrypointContract, "")) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
|
||
function accountImplementation() external view override returns (address) { | ||
return OpenfortBeacon(openfortBeacon).implementation(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; | ||
|
||
/** | ||
* @title OpenfortBeacon (Non-upgradeable) | ||
* @author Eloi<[email protected]> | ||
* @notice Contract to create the Beacon to determine implementation contract, which is where they will delegate all function calls. | ||
* It inherits from: | ||
* - UpgradeableBeacon | ||
*/ | ||
contract OpenfortBeacon is UpgradeableBeacon { | ||
constructor(address implementation_) UpgradeableBeacon(implementation_) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
// Base account contract to inherit from | ||
import {BaseOpenfortAccount} from "../core/BaseOpenfortAccount.sol"; | ||
|
||
/** | ||
* @title ManagedOpenfortAccount (Upgradeable via Beacon) | ||
* @author Eloi<[email protected]> | ||
* @notice Smart contract wallet managed via Beacon with session keys following the ERC-4337 standard. | ||
* It inherits from: | ||
* - BaseOpenfortAccount | ||
*/ | ||
contract MockedV2ManagedOpenfortAccount is BaseOpenfortAccount { | ||
/* | ||
* @notice Initialize the smart contract wallet. | ||
*/ | ||
function initialize(address _defaultAdmin, address _entrypoint, bytes calldata) public override initializer { | ||
if (_defaultAdmin == address(0) || _entrypoint == address(0)) { | ||
revert ZeroAddressNotAllowed(); | ||
} | ||
_transferOwnership(_defaultAdmin); | ||
entrypointContract = _entrypoint; | ||
} | ||
|
||
function version() external pure override returns (uint256) { | ||
return 2; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity ^0.8.12; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
|
||
contract Rewards is ERC20 { | ||
constructor() | ||
// solhint-disable-next-line no-empty-blocks | ||
ERC20("GEMS", "GEMS") | ||
{} | ||
|
||
function claim() external { | ||
_mint(msg.sender, 10); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity ^0.8.12; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
|
||
contract USDC is ERC20 { | ||
constructor() | ||
// solhint-disable-next-line no-empty-blocks | ||
ERC20("USDC", "USDC") | ||
{} | ||
|
||
function mint(address sender, uint256 amount) external { | ||
_mint(sender, amount); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.12; | ||
|
||
import {Script, console} from "forge-std/Script.sol"; | ||
import {IEntryPoint} from "lib/account-abstraction/contracts/interfaces/IEntryPoint.sol"; | ||
import {ManagedOpenfortAccount} from "../contracts/core/managed/ManagedOpenfortAccount.sol"; | ||
import {OpenfortBeacon} from "contracts/core/managed/OpenfortBeacon.sol"; | ||
import {ManagedOpenfortFactory} from "../contracts/core/managed/ManagedOpenfortFactory.sol"; | ||
import {MockedV2ManagedOpenfortAccount} from "../contracts/mock/MockedV2ManagedOpenfortAccount.sol"; | ||
|
||
contract ManagedOpenfortDeploy 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")))); | ||
|
||
function run() public { | ||
bytes32 versionSalt = vm.envBytes32("VERSION_SALT"); | ||
vm.startBroadcast(deployPrivKey); | ||
|
||
// Create an acccount to server as implementation | ||
ManagedOpenfortAccount managedOpenfortAccount = new ManagedOpenfortAccount{salt: versionSalt}(); | ||
|
||
OpenfortBeacon openfortBeacon = new OpenfortBeacon(address(managedOpenfortAccount)); | ||
|
||
// Create a factory to deploy cloned accounts | ||
ManagedOpenfortFactory managedOpenfortFactory = new ManagedOpenfortFactory{salt: versionSalt}(address(entryPoint), address(openfortBeacon)); | ||
// address account1 = managedOpenfortFactory.accountImplementation(); | ||
|
||
// The first call should create a new account, while the second will just return the corresponding account address | ||
address account2 = managedOpenfortFactory.createAccount(deployAddress, bytes("")); | ||
console.log( | ||
"Factory at address %s has created an account at address %s", address(managedOpenfortFactory), account2 | ||
); | ||
|
||
MockedV2ManagedOpenfortAccount mockedOpenfortAccount = new MockedV2ManagedOpenfortAccount{salt: versionSalt}(); | ||
|
||
// assert(account1 != account2); | ||
// address account3 = managedOpenfortFactory.createAccountWithNonce(deployAddress, "", 3); | ||
// console.log( | ||
// "Factory at address %s has created an account at address %s", address(managedOpenfortFactory), account3 | ||
// ); | ||
// assert(account2 != account3); | ||
// address account4 = managedOpenfortFactory.createAccountWithNonce(deployAddress, "", 4); | ||
// console.log( | ||
// "Factory at address %s has created an account at address %s", address(managedOpenfortFactory), account4 | ||
// ); | ||
// assert(account3 != account4); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.12; | ||
|
||
import {Script, console} from "forge-std/Script.sol"; | ||
import {IEntryPoint} from "lib/account-abstraction/contracts/interfaces/IEntryPoint.sol"; | ||
import {StaticOpenfortFactory} from "../contracts/core/static/StaticOpenfortFactory.sol"; | ||
// import {USDC} from "../contracts/mock/USDC.sol"; | ||
import {Rewards} from "../contracts/mock/Rewards.sol"; | ||
|
||
contract DeployMock 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")))); | ||
|
||
function run() public { | ||
vm.startBroadcast(deployPrivKey); | ||
|
||
// USDC u = new USDC(); | ||
Rewards r = new Rewards(); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
} |
Oops, something went wrong.