Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions src/ERC20/ERC20/libraries/LibERC20.sol
Original file line number Diff line number Diff line change
@@ -1,38 +1,69 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.30;

/// @title LibERC20 — Minimal ERC-20 Library for Diamond Storage Implementation
/// @notice Provides internal functions and storage layout for ERC-20 token logic.
/// @dev Uses ERC-8042 for storage location standardization and ERC-6093 for error conventions.
library LibERC20 {

// ERC-6093: Custom errors for ERC-20

/// @notice Thrown when a sender attempts to transfer or burn more tokens than their balance.
/// @param _sender The address attempting the transfer or burn.
/// @param _balance The sender's current balance.
/// @param _needed The amount required to complete the operation.
error ERC20InsufficientBalance(address _sender, uint256 _balance, uint256 _needed);

/// @notice Thrown when the sender address is invalid (e.g., zero address).
/// @param _sender The invalid sender address.
error ERC20InvalidSender(address _sender);

/// @notice Thrown when the receiver address is invalid (e.g., zero address).
/// @param _receiver The invalid receiver address.
error ERC20InvalidReceiver(address _receiver);

/// @notice Thrown when a spender tries to spend more than their allowance.
/// @param _spender The address attempting to spend.
/// @param _allowance The current allowance.
/// @param _needed The required amount to complete the transfer.
error ERC20InsufficientAllowance(address _spender, uint256 _allowance, uint256 _needed);


/// @notice Emitted when tokens are transferred between addresses.
/// @param _from The address tokens are transferred from.
/// @param _to The address tokens are transferred to.
/// @param _value The amount of tokens transferred.
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// Struct storage position defined by keccak256 hash
// of diamond storage identifier


/// @notice Storage slot identifier, defined using keccak256 hash of the library namespace.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is called a "diamond storage identifier", not a namespace.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes made. Thank you

bytes32 constant STORAGE_POSITION = keccak256("compose.erc20");

// Storage defined using the ERC-8042 standard
// @custom:storage-location erc8042:compose.erc20
/// @notice ERC-20 storage layout using the ERC-8042 standard.
/// @custom:storage-location erc8042:compose.erc20
struct ERC20Storage {
string name;
string symbol;
uint8 decimals;
uint256 totalSupply;
mapping(address owner => uint256 balance) balanceOf;
mapping(address owner => mapping(address spender => uint256 allowance)) allowances;
mapping(address owner => mapping(address spender => uint256 allowance)) allowances;
}


/// @notice Returns a pointer to the ERC-20 storage struct.
/// @dev Uses inline assembly to bind the storage struct to the fixed storage position.
/// @return s The ERC-20 storage struct.
function getStorage() internal pure returns (ERC20Storage storage s) {
bytes32 position = STORAGE_POSITION;
assembly {
s.slot := position
}
}
}

/// @notice Mints new tokens to a specified address.
/// @dev Increases both total supply and the recipient’s balance.
/// @param _account The address receiving the newly minted tokens.
/// @param _value The number of tokens to mint.
function mint(address _account, uint256 _value) internal {
ERC20Storage storage s = getStorage();
if (_account == address(0)) {
Expand All @@ -45,6 +76,10 @@ library LibERC20 {
emit Transfer(address(0), _account, _value);
}

/// @notice Burns tokens from a specified address.
/// @dev Decreases both total supply and the sender’s balance.
/// @param _account The address whose tokens will be burned.
/// @param _value The number of tokens to burn.
function burn(address _account, uint256 _value) internal {
ERC20Storage storage s = getStorage();
if (_account == address(0)) {
Expand All @@ -61,6 +96,11 @@ library LibERC20 {
emit Transfer(_account, address(0), _value);
}

/// @notice Transfers tokens from one address to another using an allowance.
/// @dev Deducts the spender’s allowance and updates balances.
/// @param _from The address to send tokens from.
/// @param _to The address to send tokens to.
/// @param _value The number of tokens to transfer.
function transferFrom(address _from, address _to, uint256 _value) internal {
ERC20Storage storage s = getStorage();
if (_from == address(0)) {
Expand All @@ -84,6 +124,4 @@ library LibERC20 {
}
emit Transfer(_from, _to, _value);
}


}
}
70 changes: 53 additions & 17 deletions src/ERC721/ERC721/libraries/LibERC721.sol
Original file line number Diff line number Diff line change
@@ -1,42 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.30;

/// @title ERC-721 Library for Compose
/// @notice Provides internal logic for ERC-721 token management using diamond storage.
/// @dev Implements minting, burning, and transferring of ERC-721 tokens without dependencies.
/// Uses ERC-8042-compliant storage definition and includes ERC-6093 standard custom errors.
library LibERC721 {

// ERC-6093: Custom errors for ERC-721
error ERC721NonexistentToken(uint256 _tokenId);
/// @notice Thrown when attempting to interact with a non-existent token.
/// @param _tokenId The ID of the token that does not exist.
error ERC721NonexistentToken(uint256 _tokenId);

/// @notice Thrown when the sender is not the owner of the token.
/// @param _sender The address attempting the operation.
/// @param _tokenId The ID of the token being transferred.
/// @param _owner The actual owner of the token.
error ERC721IncorrectOwner(address _sender, uint256 _tokenId, address _owner);

/// @notice Thrown when the sender address is invalid (e.g., zero address).
/// @param _sender The invalid sender address.
error ERC721InvalidSender(address _sender);

/// @notice Thrown when the receiver address is invalid (e.g., zero address).
/// @param _receiver The invalid receiver address.
error ERC721InvalidReceiver(address _receiver);

/// @notice Thrown when an operator lacks sufficient approval to manage a token.
/// @param _operator The address attempting the unauthorized operation.
/// @param _tokenId The ID of the token involved.
error ERC721InsufficientApproval(address _operator, uint256 _tokenId);

/// @notice Emitted when ownership of a token changes, including minting and burning.
/// @param _from The address transferring the token, or zero for minting.
/// @param _to The address receiving the token, or zero for burning.
/// @param _tokenId The ID of the token being transferred.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

// Struct storage position defined by keccak256 hash
// of diamond storage identifier

/// @dev Storage position constant defined via keccak256 hash of diamond storage identifier.
bytes32 constant STORAGE_POSITION = keccak256("compose.erc721");

// Storage defined using the ERC-8042 standard
// @custom:storage-location erc8042:compose.erc721
/// @custom:storage-location erc8042:compose.erc721
/// @notice Storage layout for ERC-721 token management.
/// @dev Defines ownership, balances, approvals, and operator mappings per ERC-721 standard.
struct ERC721Storage {
string name;
string symbol;
string symbol;
mapping(uint256 tokenId => address owner) ownerOf;
mapping(address owner => uint256 balance) balanceOf;
mapping(uint256 tokenId => address approved) approved;
mapping(address owner => mapping(address operator => bool approved)) isApprovedForAll;
mapping(address owner => mapping(address operator => bool approved)) isApprovedForAll;
}

/// @notice Returns the ERC-721 storage struct from its predefined slot.
/// @dev Uses inline assembly to access diamond storage location.
/// @return s The storage reference for ERC-721 state variables.
function getStorage() internal pure returns (ERC721Storage storage s) {
bytes32 position = STORAGE_POSITION;
assembly {
s.slot := position
}
}

/// @notice Transfers ownership of a token ID from one address to another.
/// @dev Validates ownership, approval, and receiver address before updating state.
/// @param _from The current owner of the token.
/// @param _to The address that will receive the token.
/// @param _tokenId The ID of the token being transferred.
function transferFrom(address _from, address _to, uint256 _tokenId) internal {
ERC721Storage storage s = getStorage();
if (_to == address(0)) {
if (_to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address owner = s.ownerOf[_tokenId];
Expand All @@ -45,9 +77,9 @@ library LibERC721 {
}
if (owner != _from) {
revert ERC721IncorrectOwner(_from, _tokenId, owner);
}
}
if (msg.sender != _from) {
if(!s.isApprovedForAll[_from][msg.sender] && msg.sender != s.approved[_tokenId]) {
if (!s.isApprovedForAll[_from][msg.sender] && msg.sender != s.approved[_tokenId]) {
revert ERC721InsufficientApproval(msg.sender, _tokenId);
}
}
Expand All @@ -56,10 +88,14 @@ library LibERC721 {
s.balanceOf[_from]--;
s.balanceOf[_to]++;
}
s.ownerOf[_tokenId] = _to;
s.ownerOf[_tokenId] = _to;
emit Transfer(_from, _to, _tokenId);
}

/// @notice Mints a new ERC-721 token to the specified address.
/// @dev Reverts if the receiver address is zero or if the token already exists.
/// @param _to The address that will own the newly minted token.
/// @param _tokenId The ID of the token to mint.
function mint(address _to, uint256 _tokenId) internal {
ERC721Storage storage s = getStorage();
if (_to == address(0)) {
Expand All @@ -75,6 +111,9 @@ library LibERC721 {
emit Transfer(address(0), _to, _tokenId);
}

/// @notice Burns (destroys) a specific ERC-721 token.
/// @dev Reverts if the token does not exist. Clears ownership and approval.
/// @param _tokenId The ID of the token to burn.
function burn(uint256 _tokenId) internal {
ERC721Storage storage s = getStorage();
address owner = s.ownerOf[_tokenId];
Expand All @@ -88,7 +127,4 @@ library LibERC721 {
}
emit Transfer(owner, address(0), _tokenId);
}



}
}
Loading
Loading