Skip to content

Commit

Permalink
Merge pull request #146 from bcnmy/features/SMA-98-natspec
Browse files Browse the repository at this point in the history
📝  Add Natspec comments for clarity
  • Loading branch information
Aboudjem authored Oct 16, 2023
2 parents 2cd521a + 168a4db commit c741351
Show file tree
Hide file tree
Showing 26 changed files with 211 additions and 72 deletions.
9 changes: 9 additions & 0 deletions contracts/smart-account/base/Executor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import {Enum} from "../common/Enum.sol";

/// @title Executor - A contract that can execute transactions
abstract contract Executor is IExecutor {
/**
* @notice Executes a given operation (either Call or DelegateCall) to a specified address with provided data.
* @param to The address to which the operation should be executed.
* @param value The amount of ether (in wei) to send with the call (only for Call operations).
* @param data The call data to send with the operation.
* @param operation The type of operation to execute (either Call or DelegateCall).
* @param txGas The amount of gas to use for the operation.
* @return success A boolean indicating whether the operation was successful.
*/
function _execute(
address to,
uint256 value,
Expand Down
9 changes: 5 additions & 4 deletions contracts/smart-account/base/FallbackManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,17 @@ abstract contract FallbackManager is SelfAuthorized, IFallbackManager {
}
}

/**
* @notice Sets a new fallback handler. This function will revert if the provided handler address is zero.
* @dev This function is internal and utilizes assembly for optimized storage operations.
* @param handler The address of the new fallback handler.
*/
function _setFallbackHandler(address handler) internal {
if (handler == address(0)) revert HandlerCannotBeZero();
address previousHandler;

assembly {
previousHandler := sload(FALLBACK_HANDLER_STORAGE_SLOT)
//}
//bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;

//assembly {
sstore(FALLBACK_HANDLER_STORAGE_SLOT, handler)
}
emit ChangedFallbackHandler(previousHandler, handler);
Expand Down
18 changes: 16 additions & 2 deletions contracts/smart-account/base/ModuleManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,14 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager {
emit DisabledModule(module);
}

// TODO: can use not executor.execute, but SmartAccount._call for the unification

/**
* @notice Executes an operation from a module, emits specific events based on the result.
* @param to The address to which the operation should be executed.
* @param value The amount of ether (in wei) to send with the call (only for Call operations).
* @param data The call data to send with the operation.
* @param operation The type of operation to execute (either Call or DelegateCall).
* @return success A boolean indicating whether the operation was successful.
*/
function _executeFromModule(
address to,
uint256 value,
Expand Down Expand Up @@ -259,6 +265,14 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager {
return initialAuthorizationModule;
}

/**
* @notice Sets up a new module by calling a specified setup contract with provided data.
* The function will revert if the setupContract address is zero or if the setup call fails.
* @dev This function is internal and utilizes assembly for low-level call operations and error handling.
* @param setupContract The address of the contract that will be called to set up the module.
* @param setupData The call data to send to the setup contract.
* @return module The address of the newly set up module.
*/
function _setupModule(
address setupContract,
bytes memory setupData
Expand Down
18 changes: 17 additions & 1 deletion contracts/smart-account/common/ReentrancyGuard.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.17;

/// @title Reentrancy Guard - reentrancy protection
/**
* @title ReentrancyGuard
* @notice Provides a contract-level guard against reentrancy attacks.
* @dev Uses a single contract-wide status flag for efficiency.
* Use the `nonReentrant` modifier on functions to protect them.
*/
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;

uint256 private _reentrancyStatus;

/// @notice Custom error to denote that reentrancy protection has been activated.
error ReentrancyProtectionActivated();

/**
* @notice Modifier to prevent a contract from calling itself, directly or indirectly.
* @dev Checks if the function has been re-entered, and if so, reverts with a custom error.
*/
modifier nonReentrant() {
if (_reentrancyStatus == ENTERED)
revert ReentrancyProtectionActivated();
Expand All @@ -18,10 +28,16 @@ abstract contract ReentrancyGuard {
_reentrancyStatus = NOT_ENTERED;
}

/// @notice Initializes the `ReentrancyGuard` contract, setting the reentrancy status to `NOT_ENTERED`.
constructor() {
_reentrancyStatus = NOT_ENTERED;
}

/**
* @notice Checks if the reentrancy guard is currently activated.
* @dev Returns true if the guard is activated, false otherwise.
* @return A boolean indicating whether the reentrancy guard is activated.
*/
function _isReentrancyGuardEntered() internal view returns (bool) {
return _reentrancyStatus == ENTERED;
}
Expand Down
15 changes: 10 additions & 5 deletions contracts/smart-account/common/SecuredTokenTransfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ pragma solidity 0.8.17;

/// @title SecuredTokenTransfer - Secure token transfer
abstract contract SecuredTokenTransfer {
/// @dev Transfers a token and returns if it was a success
/// @param token Token that should be transferred
/// @param receiver Receiver to whom the token should be transferred
/// @param amount The amount of tokens that should be transferred
/**
* @dev Transfers a specified amount of ERC20 tokens to a receiver.
* @notice This function utilizes the standard `transfer` function of ERC20 tokens.
* It ensures the token address is valid and that the token contract exists before attempting the transfer.
* @param token The address of the ERC20 token to be transferred.
* @param receiver The address to receive the tokens.
* @param amount The amount of tokens to transfer.
* @return transferred A boolean indicating whether the transfer was successful.
*/
function _transferToken(
address token,
address receiver,
Expand All @@ -23,7 +28,7 @@ abstract contract SecuredTokenTransfer {

assembly {
// We write the return value to scratch space.
// See https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_memory.html#layout-in-memory
// See https://docs.soliditylang.org/en/latest/internals/layout_in_memory.html#layout-in-memory
let success := call(
sub(gas(), 10000),
token,
Expand Down
16 changes: 14 additions & 2 deletions contracts/smart-account/common/SelfAuthorized.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ pragma solidity 0.8.17;

import {ISelfAuthorized} from "../interfaces/common/ISelfAuthorized.sol";

/// @title SelfAuthorized - authorizes current contract to perform actions
/**
* @title SelfAuthorized
* @notice This contract provides a modifier to ensure that only the contract itself can call certain functions.
* @dev Functions with the `authorized` modifier can only be called by the contract itself.
* This can be useful for security purposes or to ensure a specific call flow.
*/
contract SelfAuthorized is ISelfAuthorized {
/**
* @notice Modifier to ensure a function is only callable by the contract itself.
* @dev Checks if the caller is the current contract. If not, reverts.
*/
modifier authorized() {
// This is a function call as it minimized the bytecode size
_requireSelfCall();
_;
}

/**
* @dev Internal function to check if the caller is the current contract.
* @dev If the caller isn't the contract, it reverts with a specific error.
*/
function _requireSelfCall() private view {
if (msg.sender != address(this)) revert CallerIsNotSelf(msg.sender);
}
Expand Down
12 changes: 10 additions & 2 deletions contracts/smart-account/common/SignatureDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ pragma solidity 0.8.17;

/// @title SignatureDecoder - Decodes signatures that a encoded as bytes
abstract contract SignatureDecoder {
/// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
/// @param signature concatenated rsv signatures
/**
* @dev Splits a given signature into its `r`, `s`, and `v` components.
* @notice The signature is assumed to be in the compact format:
* r (32 bytes) + s (32 bytes) + v (1 byte).
* This function uses assembly for efficient memory operations.
* @param signature The signature bytes.
* @return v The `v` component of the signature.
* @return r The `r` component of the signature as bytes32.
* @return s The `s` component of the signature as bytes32.
*/
function _signatureSplit(
bytes memory signature
) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
Expand Down
17 changes: 17 additions & 0 deletions contracts/smart-account/common/Stakeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ contract Stakeable is Ownable, IStakeable {
_transferOwnership(_newOwner);
}

/**
* @dev Stakes a certain amount of Ether on an EntryPoint.
* @notice The contract should have enough Ether to cover the stake.
* @param epAddress Address of the EntryPoint where the stake is added.
* @param unstakeDelaySec The delay in seconds before the stake can be unlocked.
*/
function addStake(
address epAddress,
uint32 unstakeDelaySec
Expand All @@ -22,11 +28,22 @@ contract Stakeable is Ownable, IStakeable {
IEntryPoint(epAddress).addStake{value: msg.value}(unstakeDelaySec);
}

/**
* @dev Unlocks the stake on an EntryPoint.
* @notice This starts the unstaking delay after which funds can be withdrawn.
* @param epAddress Address of the EntryPoint where the stake is unlocked.
*/
function unlockStake(address epAddress) external override onlyOwner {
require(epAddress != address(0), "Invalid EP address");
IEntryPoint(epAddress).unlockStake();
}

/**
* @dev Withdraws the stake from an EntryPoint to a specified address.
* @notice This can only be done after the unstaking delay has passed since the unlock.
* @param epAddress Address of the EntryPoint where the stake is withdrawn from.
* @param withdrawAddress Address to receive the withdrawn stake.
*/
function withdrawStake(
address epAddress,
address payable withdrawAddress
Expand Down
13 changes: 9 additions & 4 deletions contracts/smart-account/deployer/Create3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ library Create3 {
if (!success || codeSize(addr) == 0) revert ErrorCreatingContract();
}

/**
* @dev Computes the CREATE2 proxy address using the provided salt.
* @param _salt The salt used to derive the proxy contract address.
* @return Address of the proxy contract derived using CREATE2.
*/
function addressOfProxy(bytes32 _salt) internal view returns (address) {
return
address(
Expand Down Expand Up @@ -129,10 +134,10 @@ library Create3 {
}

/**
@notice Returns the size of the code on a given address
@param _addr Address that may or may not contain code
@return size of the code on the given `_addr`
*/
* @dev Returns the size of the code stored at a specific address.
* @param _addr The address to check.
* @return size The size of the code stored at the given address.
*/
function codeSize(address _addr) internal view returns (uint256 size) {
assembly {
size := extcodesize(_addr)
Expand Down
10 changes: 10 additions & 0 deletions contracts/smart-account/deployer/Deployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ import "./Create3.sol";
contract Deployer {
event ContractDeployed(address indexed contractAddress);

/**
* @dev Deploys a new contract using the Create3 library with a specific salt and initialization code.
* @param _salt The salt used to derive the deployed contract address.
* @param _creationCode The bytecode used to initialize and deploy the contract.
*/
function deploy(bytes32 _salt, bytes calldata _creationCode) external {
address deployedContract = Create3.create3(_salt, _creationCode);
emit ContractDeployed(deployedContract);
}

/**
* @dev Computes the final deployed address using the Create3 library and a given salt.
* @param _salt The salt used in the original Create3 deployment.
* @return Address of the final deployed contract.
*/
function addressOf(bytes32 _salt) external view returns (address) {
return Create3.addressOf(_salt);
}
Expand Down
21 changes: 21 additions & 0 deletions contracts/smart-account/handler/DefaultCallbackHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ contract DefaultCallbackHandler is
string public constant NAME = "Default Callback Handler";
string public constant VERSION = "1.0.0";

/**
* @dev Checks if the contract supports a given interface.
* @param interfaceId The interface identifier, as specified in ERC-165.
* @return True if the contract implements the given interface, false otherwise.
*/
function supportsInterface(
bytes4 interfaceId
) external view virtual override returns (bool) {
Expand All @@ -31,6 +36,10 @@ contract DefaultCallbackHandler is
interfaceId == type(IERC165).interfaceId;
}

/**
* @dev Handles the receipt of a single ERC1155 token type.
* @return The interface selector for the called function.
*/
function onERC1155Received(
address,
address,
Expand All @@ -41,6 +50,10 @@ contract DefaultCallbackHandler is
return IERC1155Receiver.onERC1155Received.selector;
}

/**
* @dev Handles the receipt of multiple ERC1155 token types.
* @return The interface selector for the called function.
*/
function onERC1155BatchReceived(
address,
address,
Expand All @@ -51,6 +64,10 @@ contract DefaultCallbackHandler is
return IERC1155Receiver.onERC1155BatchReceived.selector;
}

/**
* @dev Handles the receipt of an ERC721 token.
* @return The interface selector for the called function.
*/
function onERC721Received(
address,
address,
Expand All @@ -60,6 +77,10 @@ contract DefaultCallbackHandler is
return IERC721Receiver.onERC721Received.selector;
}

/**
* @dev Handles the receipt of an ERC777 token.
* This function does not have any specific logic as it's implemented for completeness.
*/
function tokensReceived(
address,
address,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/// @dev Contract containing constants related to authorization module results.
contract AuthorizationModulesConstants {
uint256 internal constant VALIDATION_SUCCESS = 0;
uint256 internal constant SIG_VALIDATION_FAILED = 1;
}
11 changes: 5 additions & 6 deletions contracts/smart-account/modules/BaseAuthorizationModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ pragma solidity 0.8.17;
/* solhint-disable no-empty-blocks */

import {IBaseAuthorizationModule} from "../interfaces/modules/IBaseAuthorizationModule.sol";
import {AuthorizationModulesConstants} from "./AuthorizationModulesConstants.sol";

contract AuthorizationModulesConstants {
uint256 internal constant VALIDATION_SUCCESS = 0;
uint256 internal constant SIG_VALIDATION_FAILED = 1;
}

/// @dev Base contract for authorization modules
abstract contract BaseAuthorizationModule is
IBaseAuthorizationModule,
AuthorizationModulesConstants
{}
{

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/* solhint-disable function-max-lines,no-unused-import */
/* solhint-disable function-max-lines */

import {BaseAuthorizationModule} from "./BaseAuthorizationModule.sol";
import {ISessionValidationModule} from "../interfaces/modules/ISessionValidationModule.sol";
Expand All @@ -11,7 +11,7 @@ import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.s
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {IBatchedSessionRouterModule} from "../interfaces/modules/IBatchedSessionRouterModule.sol";
import {IAuthorizationModule} from "../interfaces/IAuthorizationModule.sol";
import {ISignatureValidator} from "../interfaces/ISignatureValidator.sol";


/**
* @title Batched Session Router
Expand Down Expand Up @@ -130,7 +130,6 @@ contract BatchedSessionRouter is
}

/**
* @inheritdoc ISignatureValidator
* @dev isValidSignature according to BaseAuthorizationModule
* @param _dataHash Hash of the data to be validated.
* @param _signature Signature over the the _dataHash.
Expand Down
Loading

0 comments on commit c741351

Please sign in to comment.