Skip to content

Commit 29defdb

Browse files
feat: init with core->base account
1 parent 8667c19 commit 29defdb

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

src/core/BaseAccount.sol

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {IBaseAccount} from '../interfaces/core/IBaseAccount.sol';
5+
import {IEntryPoint} from 'account-abstraction/interfaces/IEntryPoint.sol';
6+
7+
/// @title BaseAccount
8+
/// @notice Implements ERC-4337 and ERC-7579 standards for account management and access control.
9+
/// @dev Manages entry points and configurations as specified in the ERC-4337 and ERC-7579 documentation.
10+
/// @author Startale Labs
11+
/// Special thanks to the Biconomy team for https://github.com/bcnmy/nexus/ on which this implementation is highly based on.
12+
contract BaseAccount is IBaseAccount {
13+
/// @notice Identifier for this implementation on the network
14+
string internal constant _ACCOUNT_IMPLEMENTATION_ID = 'startale.smart-account.0.0.1';
15+
16+
/// @notice The canonical address for the ERC4337 EntryPoint contract, version 0.7.
17+
/// This address is consistent across all supported networks.
18+
address internal immutable _ENTRYPOINT;
19+
20+
/// @dev Ensures the caller is either the EntryPoint or this account itself.
21+
/// Reverts with AccountAccessUnauthorized if the check fails.
22+
modifier onlyEntryPointOrSelf() {
23+
require(msg.sender == _ENTRYPOINT || msg.sender == address(this), AccountAccessUnauthorized());
24+
_;
25+
}
26+
27+
/// @dev Ensures the caller is the EntryPoint.
28+
/// Reverts with AccountAccessUnauthorized if the check fails.
29+
modifier onlyEntryPoint() {
30+
require(msg.sender == _ENTRYPOINT, AccountAccessUnauthorized());
31+
_;
32+
}
33+
34+
/// @dev Sends to the EntryPoint (i.e. `msg.sender`) the missing funds for this transaction.
35+
/// Subclass MAY override this modifier for better funds management.
36+
/// (e.g. send to the EntryPoint more than the minimum required, so that in future transactions
37+
/// it will not be required to send again)
38+
///
39+
/// `missingAccountFunds` is the minimum value this modifier should send the EntryPoint,
40+
/// which MAY be zero, in case there is enough deposit, or the userOp has a paymaster.
41+
modifier payPrefund(uint256 missingAccountFunds) virtual {
42+
_;
43+
/// @solidity memory-safe-assembly
44+
assembly {
45+
if missingAccountFunds {
46+
// Ignore failure (it's EntryPoint's job to verify, not the account's).
47+
pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00))
48+
}
49+
}
50+
}
51+
52+
/// @notice Adds deposit to the EntryPoint to fund transactions.
53+
function addDeposit() external payable virtual {
54+
address entryPointAddress = _ENTRYPOINT;
55+
/// @solidity memory-safe-assembly
56+
assembly {
57+
// The EntryPoint has balance accounting logic in the `receive()` function.
58+
if iszero(call(gas(), entryPointAddress, callvalue(), codesize(), 0x00, codesize(), 0x00)) {
59+
revert(codesize(), 0x00)
60+
} // For gas estimation.
61+
}
62+
}
63+
64+
/// @notice Withdraws ETH from the EntryPoint to a specified address.
65+
/// @param to The address to receive the withdrawn funds.
66+
/// @param amount The amount to withdraw.
67+
function withdrawDepositTo(address to, uint256 amount) external payable virtual onlyEntryPointOrSelf {
68+
address entryPointAddress = _ENTRYPOINT;
69+
assembly {
70+
let freeMemPtr := mload(0x40) // Store the free memory pointer.
71+
mstore(0x14, to) // Store the `to` argument.
72+
mstore(0x34, amount) // Store the `amount` argument.
73+
mstore(0x00, 0x205c2878000000000000000000000000) // `withdrawTo(address,uint256)`.
74+
if iszero(call(gas(), entryPointAddress, 0, 0x10, 0x44, codesize(), 0x00)) {
75+
returndatacopy(freeMemPtr, 0x00, returndatasize())
76+
revert(freeMemPtr, returndatasize())
77+
}
78+
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
79+
}
80+
}
81+
82+
/// @notice Gets the nonce for a particular key.
83+
/// @param key The nonce key.
84+
/// @return The nonce associated with the key.
85+
function nonce(uint192 key) external view virtual returns (uint256) {
86+
return IEntryPoint(_ENTRYPOINT).getNonce(address(this), key);
87+
}
88+
89+
/// @notice Returns the current deposit balance of this account on the EntryPoint.
90+
/// @return result The current balance held at the EntryPoint.
91+
function getDeposit() external view virtual returns (uint256 result) {
92+
address entryPointAddress = _ENTRYPOINT;
93+
/// @solidity memory-safe-assembly
94+
assembly {
95+
mstore(0x20, address()) // Store the `account` argument.
96+
mstore(0x00, 0x70a08231) // `balanceOf(address)`.
97+
result :=
98+
mul(
99+
// Returns 0 if the EntryPoint does not exist.
100+
mload(0x20),
101+
and(
102+
// The arguments of `and` are evaluated from right to left.
103+
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
104+
staticcall(gas(), entryPointAddress, 0x1c, 0x24, 0x20, 0x20)
105+
)
106+
)
107+
}
108+
}
109+
110+
/// @notice Retrieves the address of the EntryPoint contract, currently using version 0.7.
111+
/// @dev This function returns the address of the canonical ERC4337 EntryPoint contract.
112+
/// It can be overridden to return a different EntryPoint address if needed.
113+
/// @return The address of the EntryPoint contract.
114+
function entryPoint() external view returns (address) {
115+
return _ENTRYPOINT;
116+
}
117+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
/// @title BaseAccount
5+
/// @notice Interface for the BaseAccount functionalities compliant with ERC-7579 and ERC-4337.
6+
/// @author Startale Labs
7+
/// Special thanks to the Biconomy team for https://github.com/bcnmy/nexus/ on which this implementation is highly based on.
8+
interface IBaseAccount {
9+
/// @dev Throws an error when a caller is not authorized to access an account.
10+
error AccountAccessUnauthorized();
11+
12+
/// @notice Adds deposit to the EntryPoint to fund transactions.
13+
function addDeposit() external payable;
14+
15+
/// @notice Withdraws ETH from the EntryPoint to a specified address.
16+
/// @param to The address to receive the withdrawn funds.
17+
/// @param amount The amount to withdraw.
18+
function withdrawDepositTo(address to, uint256 amount) external payable;
19+
20+
/// @notice Gets the nonce for a particular key.
21+
/// @param key The nonce key.
22+
/// @return The nonce associated with the key.
23+
function nonce(uint192 key) external view returns (uint256);
24+
25+
/// @notice Returns the current deposit balance of this account on the EntryPoint.
26+
/// @return The current balance held at the EntryPoint.
27+
function getDeposit() external view returns (uint256);
28+
29+
/// @notice Retrieves the address of the EntryPoint contract, currently using version 0.7.
30+
/// @return The address of the EntryPoint contract.
31+
function entryPoint() external view returns (address);
32+
}

0 commit comments

Comments
 (0)