diff --git a/.github/codecov.yml b/.github/codecov.yml
index e4802e57a..9359748ed 100644
--- a/.github/codecov.yml
+++ b/.github/codecov.yml
@@ -14,10 +14,15 @@ coverage:
patch:
default:
informational: true
-# Test files aren't important for coverage.
+# Docs and examples are not relevant to coverage.
+# Motsu and e2e should be moved outside of this repo.
ignore:
- - "tests"
- "docs"
+ - "examples"
+ - "lib/e2e"
+ - "lib/e2e-proc"
+ - "lib/motsu"
+ - "lib/motsu-proc"
# Make comments less noisy.
comment:
layout: "files"
diff --git a/.github/workflows/nostd.yml b/.github/workflows/nostd.yml
index 409b76f5c..67de59ab3 100644
--- a/.github/workflows/nostd.yml
+++ b/.github/workflows/nostd.yml
@@ -6,7 +6,7 @@ permissions:
contents: read
on:
push:
- branches: [ main, release/* ]
+ branches: [ main, release/* ]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ae3c2fdfa..f22146905 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ permissions:
contents: read
on:
push:
- branches: [main, release/*]
+ branches: [ main, release/* ]
paths-ignore:
- "**.md"
- "**.adoc"
@@ -32,7 +32,7 @@ jobs:
matrix:
# Run on stable and beta to ensure that tests won't break on the next
# version of the rust toolchain.
- toolchain: [stable, beta]
+ toolchain: [ stable, beta ]
steps:
- uses: actions/checkout@v4
with:
@@ -69,7 +69,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-latest]
+ os: [ macos-latest ]
# Windows fails because of `stylus-proc`.
# os: [macos-latest, windows-latest]
steps:
@@ -117,16 +117,19 @@ jobs:
#
# for lots of more discussion.
runs-on: ubuntu-latest
- name: ubuntu / stable / coverage
+ name: ubuntu / nightly / coverage
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install rust
+ # We run in nightly to make use of the `#[coverage(off)]` attribute (see _contracts/src/lib.rs_)
+ # We'll return to stable release after the tracking issue is merged (and the feature is stable)
+ # See: https://github.com/rust-lang/rust/issues/84605
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
- toolchain: stable
+ toolchain: nightly
components: llvm-tools-preview
rustflags: ""
diff --git a/Cargo.toml b/Cargo.toml
index 413dba717..66270beb7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -67,6 +67,7 @@ version = "0.2.0-alpha.1"
missing_docs = "warn"
unreachable_pub = "warn"
rust_2021_compatibility = { level = "warn", priority = -1 }
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }
[workspace.lints.clippy]
pedantic = "warn"
diff --git a/README.md b/README.md
index 4eeb8d7bd..dbdc27521 100644
--- a/README.md
+++ b/README.md
@@ -64,14 +64,14 @@ Once defined as a dependency, use one of our pre-defined implementations by
importing them:
```rust
+use stylus_sdk::prelude::*;
use openzeppelin_stylus::token::erc20::Erc20;
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
}
#[public]
diff --git a/contracts/src/access/control.rs b/contracts/src/access/control.rs
index 1a73cf023..216b794f5 100644
--- a/contracts/src/access/control.rs
+++ b/contracts/src/access/control.rs
@@ -41,52 +41,59 @@
//! accounts that have been granted it. We recommend using
//! `AccessControlDefaultAdminRules` to enforce additional security measures for
//! this role.
-use alloy_primitives::{Address, B256};
-use alloy_sol_types::sol;
+use alloy_primitives::{Address, FixedBytes, B256};
+pub use sol::*;
use stylus_sdk::{
evm, msg,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::{StorageBool, StorageFixedBytes, StorageMap},
+ stylus_proc::{public, SolidityError},
};
-sol! {
- /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing
- /// `previous_admin_role`.
- ///
- /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
- /// `RoleAdminChanged` not being emitted signaling this.
- #[allow(missing_docs)]
- event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previous_admin_role, bytes32 indexed new_admin_role);
- /// Emitted when `account` is granted `role`.
- ///
- /// `sender` is the account that originated the contract call. This account
- /// bears the admin role (for the granted role).
- /// Expected in cases where the role was granted using the internal
- /// [`AccessControl::grant_role`].
- #[allow(missing_docs)]
- event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
- /// Emitted when `account` is revoked `role`.
- ///
- /// `sender` is the account that originated the contract call:
- /// - if using `revoke_role`, it is the admin role bearer.
- /// - if using `renounce_role`, it is the role bearer (i.e. `account`).
- #[allow(missing_docs)]
- event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
-}
-
-sol! {
- /// The `account` is missing a role.
- ///
- /// * `account` - Account that was found to not be authorized.
- /// * `needed_role` - The missing role.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error AccessControlUnauthorizedAccount(address account, bytes32 needed_role);
- /// The caller of a function is not the expected one.
- ///
- /// NOTE: Don't confuse with [`AccessControlUnauthorizedAccount`].
- #[derive(Debug)]
- #[allow(missing_docs)]
- error AccessControlBadConfirmation();
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when `new_admin_role` is set as `role`'s admin role, replacing
+ /// `previous_admin_role`.
+ ///
+ /// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
+ /// `RoleAdminChanged` not being emitted signaling this.
+ #[allow(missing_docs)]
+ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previous_admin_role, bytes32 indexed new_admin_role);
+ /// Emitted when `account` is granted `role`.
+ ///
+ /// `sender` is the account that originated the contract call. This account
+ /// bears the admin role (for the granted role).
+ /// Expected in cases where the role was granted using the internal
+ /// [`AccessControl::grant_role`].
+ #[allow(missing_docs)]
+ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
+ /// Emitted when `account` is revoked `role`.
+ ///
+ /// `sender` is the account that originated the contract call:
+ /// - if using `revoke_role`, it is the admin role bearer.
+ /// - if using `renounce_role`, it is the role bearer (i.e. `account`).
+ #[allow(missing_docs)]
+ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
+ }
+
+ sol! {
+ /// The `account` is missing a role.
+ ///
+ /// * `account` - Account that was found to not be authorized.
+ /// * `needed_role` - The missing role.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error AccessControlUnauthorizedAccount(address account, bytes32 needed_role);
+ /// The caller of a function is not the expected one.
+ ///
+ /// NOTE: Don't confuse with [`AccessControlUnauthorizedAccount`].
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error AccessControlBadConfirmation();
+ }
}
/// An error that occurred in the implementation of an [`AccessControl`]
@@ -99,20 +106,20 @@ pub enum Error {
BadConfirmation(AccessControlBadConfirmation),
}
-sol_storage! {
- /// Information about a specific role.
- pub struct RoleData {
- /// Whether an account is member of a certain role.
- mapping(address => bool) has_role;
- /// The admin role for this role.
- bytes32 admin_role;
- }
+/// Information about a specific role.
+#[storage]
+pub struct RoleData {
+ /// Whether an account is member of a certain role.
+ pub has_role: StorageMap
,
+ /// The admin role for this role.
+ pub admin_role: StorageFixedBytes<32>,
+}
- /// State of an `AccessControl` contract.
- pub struct AccessControl {
- /// Role identifier -> Role information.
- mapping(bytes32 => RoleData) _roles;
- }
+/// State of an `AccessControl` contract.
+#[storage]
+pub struct AccessControl {
+ /// Role identifier -> Role information.
+ pub _roles: StorageMap, RoleData>,
}
#[public]
diff --git a/contracts/src/access/ownable.rs b/contracts/src/access/ownable.rs
index 50692973f..7caf659d7 100644
--- a/contracts/src/access/ownable.rs
+++ b/contracts/src/access/ownable.rs
@@ -9,36 +9,43 @@
//! [`Ownable::only_owner`] function, which can be called to restrict operations
//! to the owner.
use alloy_primitives::Address;
-use alloy_sol_types::sol;
use openzeppelin_stylus_proc::interface_id;
+pub use sol::*;
use stylus_sdk::{
call::MethodError,
evm, msg,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::StorageAddress,
+ stylus_proc::{public, SolidityError},
};
-sol! {
- /// Emitted when ownership gets transferred between accounts.
- ///
- /// * `previous_owner` - Address of the previous owner.
- /// * `new_owner` - Address of the new owner.
- #[allow(missing_docs)]
- event OwnershipTransferred(address indexed previous_owner, address indexed new_owner);
-}
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when ownership gets transferred between accounts.
+ ///
+ /// * `previous_owner` - Address of the previous owner.
+ /// * `new_owner` - Address of the new owner.
+ #[allow(missing_docs)]
+ event OwnershipTransferred(address indexed previous_owner, address indexed new_owner);
+ }
-sol! {
- /// The caller account is not authorized to perform an operation.
- ///
- /// * `account` - Account that was found to not be authorized.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error OwnableUnauthorizedAccount(address account);
- /// The owner is not a valid owner account. (eg. `Address::ZERO`)
- ///
- /// * `owner` - Account that's not allowed to become the owner.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error OwnableInvalidOwner(address owner);
+ sol! {
+ /// The caller account is not authorized to perform an operation.
+ ///
+ /// * `account` - Account that was found to not be authorized.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error OwnableUnauthorizedAccount(address account);
+ /// The owner is not a valid owner account. (eg. `Address::ZERO`)
+ ///
+ /// * `owner` - Account that's not allowed to become the owner.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error OwnableInvalidOwner(address owner);
+ }
}
/// An error that occurred in the implementation of an [`Ownable`] contract.
@@ -56,12 +63,11 @@ impl MethodError for Error {
}
}
-sol_storage! {
- /// State of an `Ownable` contract.
- pub struct Ownable {
- /// The current owner of this contract.
- address _owner;
- }
+/// State of an `Ownable` contract.
+#[storage]
+pub struct Ownable {
+ /// The current owner of this contract.
+ pub _owner: StorageAddress,
}
/// Interface for an [`Ownable`] contract.
diff --git a/contracts/src/access/ownable_two_step.rs b/contracts/src/access/ownable_two_step.rs
index f5d9a2be1..c3f8543ea 100644
--- a/contracts/src/access/ownable_two_step.rs
+++ b/contracts/src/access/ownable_two_step.rs
@@ -17,27 +17,34 @@
//! available.
use alloy_primitives::Address;
-use alloy_sol_types::sol;
+pub use sol::*;
use stylus_sdk::{
evm, msg,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::StorageAddress,
+ stylus_proc::{public, SolidityError},
};
use crate::access::ownable::{
Error as OwnableError, IOwnable, Ownable, OwnableUnauthorizedAccount,
};
-sol! {
- /// Emitted when ownership transfer starts.
- ///
- /// * `previous_owner` - Address of the previous owner.
- /// * `new_owner` - Address of the new owner, to which the ownership
- /// will be transferred.
- event OwnershipTransferStarted(
- address indexed previous_owner,
- address indexed new_owner
- );
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when ownership transfer starts.
+ ///
+ /// * `previous_owner` - Address of the previous owner.
+ /// * `new_owner` - Address of the new owner, to which the ownership
+ /// will be transferred.
+ event OwnershipTransferStarted(
+ address indexed previous_owner,
+ address indexed new_owner
+ );
+ }
}
/// An error that occurred in the implementation of an [`Ownable2Step`]
@@ -48,14 +55,13 @@ pub enum Error {
Ownable(OwnableError),
}
-sol_storage! {
- /// State of an `Ownable2Step` contract.
- pub struct Ownable2Step {
- /// [`Ownable`] contract.
- Ownable _ownable;
- /// Pending owner of the contract.
- address _pending_owner;
- }
+/// State of an `Ownable2Step` contract.
+#[storage]
+pub struct Ownable2Step {
+ /// [`Ownable`] contract.
+ pub _ownable: Ownable,
+ /// Pending owner of the contract.
+ pub _pending_owner: StorageAddress,
}
/// Interface for an [`Ownable2Step`] contract.
diff --git a/contracts/src/finance/vesting_wallet.rs b/contracts/src/finance/vesting_wallet.rs
index 3870fba2d..e065c7b76 100644
--- a/contracts/src/finance/vesting_wallet.rs
+++ b/contracts/src/finance/vesting_wallet.rs
@@ -26,14 +26,15 @@
//! intended.
use alloy_primitives::{Address, U256, U64};
-use alloy_sol_types::sol;
use openzeppelin_stylus_proc::interface_id;
+pub use sol::*;
use stylus_sdk::{
block,
call::{self, call, Call},
contract, evm, function_selector,
- storage::TopLevelStorage,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::{StorageMap, StorageU256, StorageU64, TopLevelStorage},
+ stylus_proc::{public, SolidityError},
};
use crate::{
@@ -41,33 +42,38 @@ use crate::{
token::erc20::utils::safe_erc20::{self, ISafeErc20, SafeErc20},
};
-sol! {
- /// Emitted when `amount` of Ether has been released.
- ///
- /// * `amount` - Total Ether released.
- #[allow(missing_docs)]
- event EtherReleased(uint256 amount);
-
- /// Emitted when `amount` of ERC-20 `token` has been released.
- ///
- /// * `token` - Address of the token being released.
- /// * `amount` - Number of tokens released.
- #[allow(missing_docs)]
- event ERC20Released(address indexed token, uint256 amount);
-}
-
-sol! {
- /// Indicates an error related to the underlying Ether transfer.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ReleaseEtherFailed();
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when `amount` of Ether has been released.
+ ///
+ /// * `amount` - Total Ether released.
+ #[allow(missing_docs)]
+ event EtherReleased(uint256 amount);
+
+ /// Emitted when `amount` of ERC-20 `token` has been released.
+ ///
+ /// * `token` - Address of the token being released.
+ /// * `amount` - Number of tokens released.
+ #[allow(missing_docs)]
+ event ERC20Released(address indexed token, uint256 amount);
+ }
- /// The token address is not valid (eg. `Address::ZERO`).
- ///
- /// * `token` - Address of the token being released.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error InvalidToken(address token);
+ sol! {
+ /// Indicates an error related to the underlying Ether transfer.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ReleaseEtherFailed();
+
+ /// The token address is not valid (eg. `Address::ZERO`).
+ ///
+ /// * `token` - Address of the token being released.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error InvalidToken(address token);
+ }
}
/// An error that occurred in the [`VestingWallet`] contract.
@@ -84,8 +90,9 @@ pub enum Error {
}
pub use token::IErc20;
-#[allow(missing_docs)]
mod token {
+ #![allow(missing_docs)]
+ #![cfg_attr(coverage_nightly, coverage(off))]
stylus_sdk::stylus_proc::sol_interface! {
/// Interface of the ERC-20 token.
interface IErc20 {
@@ -94,22 +101,21 @@ mod token {
}
}
-sol_storage! {
- /// State of the [`VestingWallet`] Contract.
- pub struct VestingWallet {
- /// [`Ownable`] contract.
- Ownable ownable;
- /// Amount of Ether already released.
- uint256 _released;
- /// Amount of ERC-20 tokens already released.
- mapping(address => uint256) _erc20_released;
- /// Start timestamp.
- uint64 _start;
- /// Vesting duration.
- uint64 _duration;
- /// [`SafeErc20`] contract.
- SafeErc20 safe_erc20;
- }
+/// State of the [`VestingWallet`] Contract.
+#[storage]
+pub struct VestingWallet {
+ /// [`Ownable`] contract.
+ pub ownable: Ownable,
+ /// Amount of Ether already released.
+ pub _released: StorageU256,
+ /// Amount of ERC-20 tokens already released.
+ pub _erc20_released: StorageMap,
+ /// Start timestamp.
+ pub _start: StorageU64,
+ /// Vesting duration.
+ pub _duration: StorageU64,
+ /// [`SafeErc20`] contract.
+ pub safe_erc20: SafeErc20,
}
/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs
index aa0055308..266a150f9 100644
--- a/contracts/src/lib.rs
+++ b/contracts/src/lib.rs
@@ -25,12 +25,11 @@ importing them:
use stylus_sdk::prelude::*;
use openzeppelin_stylus::token::erc20::Erc20;
-sol_storage! {
- #[entrypoint]
- struct MyContract {
- #[borrow]
- Erc20 erc20;
- }
+#[entrypoint]
+#[storage]
+struct MyContract {
+ #[borrow]
+ pub erc20: Erc20,
}
#[public]
@@ -45,6 +44,7 @@ impl MyContract { }
clippy::used_underscore_items
)]
#![cfg_attr(not(feature = "std"), no_std, no_main)]
+#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#![deny(rustdoc::broken_intra_doc_links)]
extern crate alloc;
diff --git a/contracts/src/token/erc1155/extensions/metadata_uri.rs b/contracts/src/token/erc1155/extensions/metadata_uri.rs
index 6f822a7df..a77eaa0ff 100644
--- a/contracts/src/token/erc1155/extensions/metadata_uri.rs
+++ b/contracts/src/token/erc1155/extensions/metadata_uri.rs
@@ -6,31 +6,37 @@
use alloc::string::String;
use alloy_primitives::{FixedBytes, U256};
-use alloy_sol_macro::sol;
use openzeppelin_stylus_proc::interface_id;
-use stylus_sdk::stylus_proc::{public, sol_storage};
+pub use sol::*;
+use stylus_sdk::{
+ prelude::storage, storage::StorageString, stylus_proc::public,
+};
use crate::utils::introspection::erc165::{Erc165, IErc165};
-sol! {
- /// Emitted when the URI for token type `id` changes to `value`, if it is
- /// a non-programmatic URI.
- ///
- /// If a [`URI`] event was emitted for `id`, the standard [guarantees] that
- /// `value` will equal the value returned by [`IErc1155MetadataUri::uri`].
- ///
- /// [guarantees]: https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions
- #[allow(missing_docs)]
- event URI(string value, uint256 indexed id);
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when the URI for token type `id` changes to `value`, if it is
+ /// a non-programmatic URI.
+ ///
+ /// If a [`URI`] event was emitted for `id`, the standard [guarantees] that
+ /// `value` will equal the value returned by [`IErc1155MetadataUri::uri`].
+ ///
+ /// [guarantees]: https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions
+ #[allow(missing_docs)]
+ event URI(string value, uint256 indexed id);
+ }
}
-sol_storage! {
- /// URI Metadata of an [`crate::token::erc1155::Erc1155`] token.
- pub struct Erc1155MetadataUri {
- /// Used as the URI for all token types by relying on ID substitution,
- /// e.g. https://token-cdn-domain/{id}.json.
- string _uri;
- }
+/// URI Metadata of an [`crate::token::erc1155::Erc1155`] token.
+#[storage]
+pub struct Erc1155MetadataUri {
+ /// Used as the URI for all token types by relying on ID substitution,
+ /// e.g. https://token-cdn-domain/{id}.json.
+ pub _uri: StorageString,
}
/// Interface for the optional metadata functions from the ERC-1155 standard.
diff --git a/contracts/src/token/erc1155/extensions/supply.rs b/contracts/src/token/erc1155/extensions/supply.rs
index 0c5e218c3..80e9fd61f 100644
--- a/contracts/src/token/erc1155/extensions/supply.rs
+++ b/contracts/src/token/erc1155/extensions/supply.rs
@@ -18,7 +18,8 @@ use openzeppelin_stylus_proc::interface_id;
use stylus_sdk::{
abi::Bytes,
msg,
- prelude::{public, sol_storage},
+ prelude::{public, storage},
+ storage::{StorageMap, StorageU256},
};
use crate::{
@@ -26,16 +27,15 @@ use crate::{
utils::math::storage::SubAssignUnchecked,
};
-sol_storage! {
- /// State of an [`Erc1155Supply`] token.
- pub struct Erc1155Supply {
- /// ERC-1155 contract storage.
- Erc1155 erc1155;
- /// Mapping from token id to total supply.
- mapping(uint256 => uint256) _total_supply;
- /// Total supply of all token ids.
- uint256 _total_supply_all;
- }
+/// State of an [`Erc1155Supply`] token.
+#[storage]
+pub struct Erc1155Supply {
+ /// ERC-1155 contract storage.
+ pub erc1155: Erc1155,
+ /// Mapping from token id to total supply.
+ pub _total_supply: StorageMap,
+ /// Total supply of all token ids.
+ pub _total_supply_all: StorageU256,
}
/// Required interface of a [`Erc1155Supply`] contract.
diff --git a/contracts/src/token/erc1155/extensions/uri_storage.rs b/contracts/src/token/erc1155/extensions/uri_storage.rs
index fd0052ab3..442c260fa 100644
--- a/contracts/src/token/erc1155/extensions/uri_storage.rs
+++ b/contracts/src/token/erc1155/extensions/uri_storage.rs
@@ -4,18 +4,21 @@
use alloc::string::String;
use alloy_primitives::U256;
-use stylus_sdk::{evm, stylus_proc::sol_storage};
+use stylus_sdk::{
+ evm,
+ prelude::storage,
+ storage::{StorageMap, StorageString},
+};
use super::metadata_uri::{IErc1155MetadataUri, URI};
-sol_storage! {
- /// Uri Storage.
- pub struct Erc1155UriStorage {
- /// Optional base URI
- string _base_uri;
- /// Optional mapping for token URIs.
- mapping(uint256 => string) _token_uris;
- }
+/// Uri Storage.
+#[storage]
+pub struct Erc1155UriStorage {
+ /// Optional base URI.
+ pub _base_uri: StorageString,
+ /// Optional mapping for token URIs.
+ pub _token_uris: StorageMap,
}
impl Erc1155UriStorage {
@@ -88,7 +91,7 @@ impl Erc1155UriStorage {
#[cfg(all(test, feature = "std"))]
mod tests {
use alloy_primitives::U256;
- use stylus_sdk::stylus_proc::sol_storage;
+ use stylus_sdk::prelude::storage;
use super::Erc1155UriStorage;
use crate::token::erc1155::{extensions::Erc1155MetadataUri, Erc1155};
@@ -98,17 +101,15 @@ mod tests {
U256::from(num)
}
- sol_storage! {
- struct Erc1155Example {
- Erc1155 erc1155;
- Erc1155MetadataUri metadata_uri;
- Erc1155UriStorage uri_storage;
- }
+ #[storage]
+ struct Erc1155MetadataExample {
+ pub metadata_uri: Erc1155MetadataUri,
+ pub uri_storage: Erc1155UriStorage,
}
#[motsu::test]
fn uri_returns_metadata_uri_when_token_uri_is_not_set(
- contract: Erc1155Example,
+ contract: Erc1155MetadataExample,
) {
let token_id = random_token_id();
let uri = "https://some.metadata/token/uri";
@@ -122,7 +123,9 @@ mod tests {
}
#[motsu::test]
- fn uri_returns_empty_string_when_no_uri_is_set(contract: Erc1155Example) {
+ fn uri_returns_empty_string_when_no_uri_is_set(
+ contract: Erc1155MetadataExample,
+ ) {
let token_id = random_token_id();
assert!(contract
@@ -132,7 +135,9 @@ mod tests {
}
#[motsu::test]
- fn uri_returns_token_uri_when_base_uri_is_empty(contract: Erc1155Example) {
+ fn uri_returns_token_uri_when_base_uri_is_empty(
+ contract: Erc1155MetadataExample,
+ ) {
let token_id = random_token_id();
let token_uri = "https://some.short/token/uri";
@@ -150,7 +155,7 @@ mod tests {
#[motsu::test]
fn uri_returns_concatenated_base_uri_and_token_uri(
- contract: Erc1155Example,
+ contract: Erc1155MetadataExample,
) {
let token_id = random_token_id();
let base_uri = "https://some.base.uri";
@@ -171,7 +176,7 @@ mod tests {
#[motsu::test]
fn uri_ignores_metadata_uri_when_token_uri_is_set(
- contract: Erc1155Example,
+ contract: Erc1155MetadataExample,
) {
let token_id = random_token_id();
let uri = "https://some.metadata/token/uri";
@@ -191,7 +196,7 @@ mod tests {
}
#[motsu::test]
- fn test_set_uri(contract: Erc1155Example) {
+ fn test_set_uri(contract: Erc1155MetadataExample) {
let token_id = random_token_id();
let uri = "https://some.metadata/token/uri";
let token_uri = "https://some.short/token/uri".to_string();
diff --git a/contracts/src/token/erc1155/mod.rs b/contracts/src/token/erc1155/mod.rs
index 521e92655..c0dd5dcfd 100644
--- a/contracts/src/token/erc1155/mod.rs
+++ b/contracts/src/token/erc1155/mod.rs
@@ -5,11 +5,10 @@ use alloy_primitives::{Address, FixedBytes, U256};
use openzeppelin_stylus_proc::interface_id;
use stylus_sdk::{
abi::Bytes,
- alloy_sol_types::sol,
call::{self, Call, MethodError},
evm, function_selector, msg,
- prelude::{public, sol_storage, AddressVM, SolidityError},
- storage::TopLevelStorage,
+ prelude::{public, storage, AddressVM, SolidityError},
+ storage::{StorageBool, StorageMap, StorageU256, TopLevelStorage},
};
use crate::utils::{
@@ -40,108 +39,114 @@ const BATCH_TRANSFER_FN_SELECTOR: [u8; 4] = function_selector!(
Bytes
);
-sol! {
- /// Emitted when `value` amount of tokens of type `id` are
- /// transferred from `from` to `to` by `operator`.
- #[allow(missing_docs)]
- event TransferSingle(
- address indexed operator,
- address indexed from,
- address indexed to,
- uint256 id,
- uint256 value
- );
-
- /// Equivalent to multiple [`TransferSingle`] events, where `operator`
- /// `from` and `to` are the same for all transfers.
- #[allow(missing_docs)]
- event TransferBatch(
- address indexed operator,
- address indexed from,
- address indexed to,
- uint256[] ids,
- uint256[] values
- );
-
- /// Emitted when `account` grants or revokes permission to `operator`
- /// to transfer their tokens, according to `approved`.
- #[allow(missing_docs)]
- event ApprovalForAll(
- address indexed account,
- address indexed operator,
- bool approved
- );
-}
-
-sol! {
- /// Indicates an error related to the current `balance` of a `sender`.
- /// Used in transfers.
- ///
- /// * `sender` - Address whose tokens are being transferred.
- /// * `balance` - Current balance for the interacting account.
- /// * `needed` - Minimum amount required to perform a transfer.
- /// * `token_id` - Identifier number of a token.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InsufficientBalance(
- address sender,
- uint256 balance,
- uint256 needed,
- uint256 token_id
- );
-
- /// Indicates a failure with the token `sender`.
- /// Used in transfers.
- ///
- /// * `sender` - Address whose tokens are being transferred.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InvalidSender(address sender);
-
- /// Indicates a failure with the token `receiver`.
- /// Used in transfers.
- ///
- /// * `receiver` - Address to which tokens are being transferred.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InvalidReceiver(address receiver);
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when `value` amount of tokens of type `id` are
+ /// transferred from `from` to `to` by `operator`.
+ #[allow(missing_docs)]
+ event TransferSingle(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256 id,
+ uint256 value
+ );
- /// Indicates a failure with the `operator`’s approval.
- /// Used in transfers.
- ///
- /// * `operator` - Address that may be allowed to operate on tokens
- /// without being their owner.
- /// * `owner` - Address of the current owner of a token.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155MissingApprovalForAll(address operator, address owner);
+ /// Equivalent to multiple [`TransferSingle`] events, where `operator`
+ /// `from` and `to` are the same for all transfers.
+ #[allow(missing_docs)]
+ event TransferBatch(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256[] ids,
+ uint256[] values
+ );
- /// Indicates a failure with the `approver` of a token to be approved.
- /// Used in approvals.
- ///
- /// * `approver` - Address initiating an approval operation.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InvalidApprover(address approver);
+ /// Emitted when `account` grants or revokes permission to `operator`
+ /// to transfer their tokens, according to `approved`.
+ #[allow(missing_docs)]
+ event ApprovalForAll(
+ address indexed account,
+ address indexed operator,
+ bool approved
+ );
+ }
- /// Indicates a failure with the `operator` to be approved.
- /// Used in approvals.
- ///
- /// * `operator` - Address that may be allowed to operate on tokens
- /// without being their owner.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InvalidOperator(address operator);
+ sol! {
+ /// Indicates an error related to the current `balance` of a `sender`.
+ /// Used in transfers.
+ ///
+ /// * `sender` - Address whose tokens are being transferred.
+ /// * `balance` - Current balance for the interacting account.
+ /// * `needed` - Minimum amount required to perform a transfer.
+ /// * `token_id` - Identifier number of a token.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InsufficientBalance(
+ address sender,
+ uint256 balance,
+ uint256 needed,
+ uint256 token_id
+ );
- /// Indicates an array length mismatch between token ids and values in a
- /// [`IErc1155::safe_batch_transfer_from`] operation.
- /// Used in batch transfers.
- ///
- /// * `ids_length` - Length of the array of token identifiers.
- /// * `values_length` - Length of the array of token amounts.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC1155InvalidArrayLength(uint256 ids_length, uint256 values_length);
+ /// Indicates a failure with the token `sender`.
+ /// Used in transfers.
+ ///
+ /// * `sender` - Address whose tokens are being transferred.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InvalidSender(address sender);
+
+ /// Indicates a failure with the token `receiver`.
+ /// Used in transfers.
+ ///
+ /// * `receiver` - Address to which tokens are being transferred.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InvalidReceiver(address receiver);
+
+ /// Indicates a failure with the `operator`’s approval.
+ /// Used in transfers.
+ ///
+ /// * `operator` - Address that may be allowed to operate on tokens
+ /// without being their owner.
+ /// * `owner` - Address of the current owner of a token.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155MissingApprovalForAll(address operator, address owner);
+
+ /// Indicates a failure with the `approver` of a token to be approved.
+ /// Used in approvals.
+ ///
+ /// * `approver` - Address initiating an approval operation.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InvalidApprover(address approver);
+
+ /// Indicates a failure with the `operator` to be approved.
+ /// Used in approvals.
+ ///
+ /// * `operator` - Address that may be allowed to operate on tokens
+ /// without being their owner.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InvalidOperator(address operator);
+
+ /// Indicates an array length mismatch between token ids and values in a
+ /// [`IErc1155::safe_batch_transfer_from`] operation.
+ /// Used in batch transfers.
+ ///
+ /// * `ids_length` - Length of the array of token identifiers.
+ /// * `values_length` - Length of the array of token amounts.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC1155InvalidArrayLength(uint256 ids_length, uint256 values_length);
+ }
}
/// An [`Erc1155`] error defined as described in [ERC-6093].
@@ -179,14 +184,14 @@ impl MethodError for Error {
}
}
-sol_storage! {
- /// State of an [`Erc1155`] token.
- pub struct Erc1155 {
- /// Maps users to balances.
- mapping(uint256 => mapping(address => uint256)) _balances;
- /// Maps owners to a mapping of operator approvals.
- mapping(address => mapping(address => bool)) _operator_approvals;
- }
+/// State of an [`Erc1155`] token.
+#[storage]
+pub struct Erc1155 {
+ /// Maps users to balances.
+ pub _balances: StorageMap>,
+ /// Maps owners to a mapping of operator approvals.
+ pub _operator_approvals:
+ StorageMap>,
}
/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
diff --git a/contracts/src/token/erc1155/receiver.rs b/contracts/src/token/erc1155/receiver.rs
index 49da4798f..0a78dc556 100644
--- a/contracts/src/token/erc1155/receiver.rs
+++ b/contracts/src/token/erc1155/receiver.rs
@@ -1,4 +1,5 @@
#![allow(missing_docs)]
+#![cfg_attr(coverage_nightly, coverage(off))]
//! Module with an interface required for smart contract
//! in order to receive ERC-1155 token transfers.
diff --git a/contracts/src/token/erc20/extensions/capped.rs b/contracts/src/token/erc20/extensions/capped.rs
index a971900b5..1e38e7f40 100644
--- a/contracts/src/token/erc20/extensions/capped.rs
+++ b/contracts/src/token/erc20/extensions/capped.rs
@@ -6,21 +6,30 @@
//! but only once the checks are put in place.
use alloy_primitives::U256;
-use alloy_sol_types::sol;
-use stylus_sdk::stylus_proc::{public, sol_storage, SolidityError};
+pub use sol::*;
+use stylus_sdk::{
+ prelude::storage,
+ storage::StorageU256,
+ stylus_proc::{public, SolidityError},
+};
-sol! {
- /// Indicates an error related to the operation that failed
- /// because `total_supply` exceeded the `_cap`.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20ExceededCap(uint256 increased_supply, uint256 cap);
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
- /// Indicates an error related to the operation that failed
- /// because the supplied `cap` is not a valid cap value.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InvalidCap(uint256 cap);
+ sol! {
+ /// Indicates an error related to the operation that failed
+ /// because `total_supply` exceeded the `_cap`.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20ExceededCap(uint256 increased_supply, uint256 cap);
+
+ /// Indicates an error related to the operation that failed
+ /// because the supplied `cap` is not a valid cap value.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InvalidCap(uint256 cap);
+ }
}
/// A Capped error.
@@ -34,13 +43,11 @@ pub enum Error {
InvalidCap(ERC20InvalidCap),
}
-sol_storage! {
- /// State of a Capped Contract.
- #[allow(clippy::pub_underscore_fields)]
- pub struct Capped {
- /// A cap to the supply of tokens.
- uint256 _cap;
- }
+/// State of a Capped Contract.
+#[storage]
+pub struct Capped {
+ /// A cap to the supply of tokens.
+ pub _cap: StorageU256,
}
#[public]
diff --git a/contracts/src/token/erc20/extensions/metadata.rs b/contracts/src/token/erc20/extensions/metadata.rs
index 6cc10141f..20f8f99fc 100644
--- a/contracts/src/token/erc20/extensions/metadata.rs
+++ b/contracts/src/token/erc20/extensions/metadata.rs
@@ -4,7 +4,7 @@ use alloc::string::String;
use alloy_primitives::FixedBytes;
use openzeppelin_stylus_proc::interface_id;
-use stylus_sdk::stylus_proc::{public, sol_storage};
+use stylus_sdk::stylus_proc::{public, storage};
use crate::utils::introspection::erc165::IErc165;
@@ -13,14 +13,13 @@ pub const DEFAULT_DECIMALS: u8 = 18;
use crate::utils::Metadata;
-sol_storage! {
- /// Metadata of the [`super::super::Erc20`] token.
- ///
- /// It has hardcoded `decimals` to [`DEFAULT_DECIMALS`].
- pub struct Erc20Metadata {
- /// Common Metadata.
- Metadata _metadata
- }
+/// Metadata of the [`super::super::Erc20`] token.
+///
+/// It has hardcoded `decimals` to [`DEFAULT_DECIMALS`].
+#[storage]
+pub struct Erc20Metadata {
+ /// Common Metadata.
+ pub _metadata: Metadata,
}
/// Interface for the optional metadata functions from the ERC-20 standard.
diff --git a/contracts/src/token/erc20/extensions/permit.rs b/contracts/src/token/erc20/extensions/permit.rs
index 64af6492a..28d7bcf46 100644
--- a/contracts/src/token/erc20/extensions/permit.rs
+++ b/contracts/src/token/erc20/extensions/permit.rs
@@ -13,12 +13,12 @@
//! [ERC]: https://eips.ethereum.org/EIPS/eip-2612
use alloy_primitives::{b256, keccak256, Address, B256, U256};
-use alloy_sol_types::{sol, SolType};
+use alloy_sol_types::SolType;
use stylus_sdk::{
block,
- prelude::StorageType,
+ prelude::{storage, StorageType},
storage::TopLevelStorage,
- stylus_proc::{public, sol_storage, SolidityError},
+ stylus_proc::{public, SolidityError},
};
use crate::{
@@ -34,21 +34,27 @@ use crate::{
const PERMIT_TYPEHASH: B256 =
b256!("6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9");
-type StructHashTuple = sol! {
- tuple(bytes32, address, address, uint256, uint256, uint256)
-};
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
-sol! {
- /// Indicates an error related to the fact that
- /// permit deadline has expired.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC2612ExpiredSignature(uint256 deadline);
+ pub(crate) type StructHashTuple = sol! {
+ tuple(bytes32, address, address, uint256, uint256, uint256)
+ };
- /// Indicates an error related to the issue about mismatched signature.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC2612InvalidSigner(address signer, address owner);
+ sol! {
+ /// Indicates an error related to the fact that
+ /// permit deadline has expired.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC2612ExpiredSignature(uint256 deadline);
+
+ /// Indicates an error related to the issue about mismatched signature.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC2612InvalidSigner(address signer, address owner);
+ }
}
/// A Permit error.
@@ -65,18 +71,15 @@ pub enum Error {
ECDSA(ecdsa::Error),
}
-sol_storage! {
- /// State of a Permit Contract.
- pub struct Erc20Permit{
- /// ERC-20 contract.
- Erc20 erc20;
-
- /// Nonces contract.
- Nonces nonces;
-
- /// EIP-712 contract. Must implement [`IEip712`] trait.
- T eip712;
- }
+/// State of a Permit Contract.
+#[storage]
+pub struct Erc20Permit {
+ /// ERC-20 contract.
+ pub erc20: Erc20,
+ /// Nonces contract.
+ pub nonces: Nonces,
+ /// EIP-712 contract. Must implement [`IEip712`] trait.
+ pub eip712: T,
}
/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
diff --git a/contracts/src/token/erc20/mod.rs b/contracts/src/token/erc20/mod.rs
index 7d4c46ecf..dca8fd755 100644
--- a/contracts/src/token/erc20/mod.rs
+++ b/contracts/src/token/erc20/mod.rs
@@ -5,12 +5,13 @@
//! nonetheless conventional and does not conflict with the expectations of
//! [`Erc20`] applications.
use alloy_primitives::{Address, FixedBytes, U256};
-use alloy_sol_types::sol;
use openzeppelin_stylus_proc::interface_id;
use stylus_sdk::{
call::MethodError,
evm, msg,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::{StorageMap, StorageU256},
+ stylus_proc::{public, SolidityError},
};
use crate::utils::introspection::erc165::{Erc165, IErc165};
@@ -18,69 +19,75 @@ use crate::utils::introspection::erc165::{Erc165, IErc165};
pub mod extensions;
pub mod utils;
-sol! {
- /// Emitted when `value` tokens are moved from one account (`from`) to
- /// another (`to`).
- ///
- /// Note that `value` may be zero.
- #[allow(missing_docs)]
- event Transfer(address indexed from, address indexed to, uint256 value);
- /// Emitted when the allowance of a `spender` for an `owner` is set by a
- /// call to `approve`. `value` is the new allowance.
- #[allow(missing_docs)]
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-sol! {
- /// Indicates an error related to the current `balance` of `sender`. Used
- /// in transfers.
- ///
- /// * `sender` - Address whose tokens are being transferred.
- /// * `balance` - Current balance for the interacting account.
- /// * `needed` - Minimum amount required to perform a transfer.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
- /// Indicates a failure with the token `sender`. Used in transfers.
- ///
- /// * `sender` - Address whose tokens are being transferred.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InvalidSender(address sender);
- /// Indicates a failure with the token `receiver`. Used in transfers.
- ///
- /// * `receiver` - Address to which the tokens are being transferred.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InvalidReceiver(address receiver);
- /// Indicates a failure with the `spender`’s `allowance`. Used in
- /// transfers.
- ///
- /// * `spender` - Address that may be allowed to operate on tokens without
- /// being their owner.
- /// * `allowance` - Amount of tokens a `spender` is allowed to operate
- /// with.
- /// * `needed` - Minimum amount required to perform a transfer.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
- /// Indicates a failure with the `spender` to be approved. Used in
- /// approvals.
- ///
- /// * `spender` - Address that may be allowed to operate on tokens without
- /// being their owner.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InvalidSpender(address spender);
-
- /// Indicates a failure with the `approver` of a token to be approved. Used in approvals.
- /// approver Address initiating an approval operation.
- ///
- /// * `approver` - Address initiating an approval operation.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC20InvalidApprover(address approver);
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when `value` tokens are moved from one account (`from`) to
+ /// another (`to`).
+ ///
+ /// Note that `value` may be zero.
+ #[allow(missing_docs)]
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ /// Emitted when the allowance of a `spender` for an `owner` is set by a
+ /// call to `approve`. `value` is the new allowance.
+ #[allow(missing_docs)]
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+ }
+
+ sol! {
+ /// Indicates an error related to the current `balance` of `sender`. Used
+ /// in transfers.
+ ///
+ /// * `sender` - Address whose tokens are being transferred.
+ /// * `balance` - Current balance for the interacting account.
+ /// * `needed` - Minimum amount required to perform a transfer.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
+ /// Indicates a failure with the token `sender`. Used in transfers.
+ ///
+ /// * `sender` - Address whose tokens are being transferred.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InvalidSender(address sender);
+ /// Indicates a failure with the token `receiver`. Used in transfers.
+ ///
+ /// * `receiver` - Address to which the tokens are being transferred.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InvalidReceiver(address receiver);
+ /// Indicates a failure with the `spender`’s `allowance`. Used in
+ /// transfers.
+ ///
+ /// * `spender` - Address that may be allowed to operate on tokens without
+ /// being their owner.
+ /// * `allowance` - Amount of tokens a `spender` is allowed to operate
+ /// with.
+ /// * `needed` - Minimum amount required to perform a transfer.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
+ /// Indicates a failure with the `spender` to be approved. Used in
+ /// approvals.
+ ///
+ /// * `spender` - Address that may be allowed to operate on tokens without
+ /// being their owner.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InvalidSpender(address spender);
+
+ /// Indicates a failure with the `approver` of a token to be approved. Used in approvals.
+ /// approver Address initiating an approval operation.
+ ///
+ /// * `approver` - Address initiating an approval operation.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC20InvalidApprover(address approver);
+ }
}
/// An [`Erc20`] error defined as described in [ERC-6093].
@@ -112,16 +119,15 @@ impl MethodError for Error {
}
}
-sol_storage! {
- /// State of an `Erc20` token.
- pub struct Erc20 {
- /// Maps users to balances.
- mapping(address => uint256) _balances;
- /// Maps users to a mapping of each spender's allowance.
- mapping(address => mapping(address => uint256)) _allowances;
- /// The total supply of the token.
- uint256 _total_supply;
- }
+/// State of an `Erc20` token.
+#[storage]
+pub struct Erc20 {
+ /// Maps users to balances.
+ pub _balances: StorageMap,
+ /// Maps users to a mapping of each spender's allowance.
+ pub _allowances: StorageMap>,
+ /// The total supply of the token.
+ pub _total_supply: StorageU256,
}
/// Required interface of an [`Erc20`] compliant contract.
diff --git a/contracts/src/token/erc20/utils/safe_erc20.rs b/contracts/src/token/erc20/utils/safe_erc20.rs
index d64f18661..20bb84e9e 100644
--- a/contracts/src/token/erc20/utils/safe_erc20.rs
+++ b/contracts/src/token/erc20/utils/safe_erc20.rs
@@ -10,39 +10,46 @@
//! `contract.safe_transfer(token_addr, ...)`, etc.
use alloy_primitives::{Address, U256};
-use alloy_sol_types::{sol, SolCall};
+use alloy_sol_types::SolCall;
+pub use sol::*;
use stylus_sdk::{
call::{MethodError, RawCall},
contract::address,
evm::gas_left,
function_selector,
+ prelude::storage,
storage::TopLevelStorage,
- stylus_proc::{public, sol_storage, SolidityError},
+ stylus_proc::{public, SolidityError},
types::AddressVM,
};
use crate::token::erc20;
-sol! {
- /// An operation with an ERC-20 token failed.
- ///
- /// * `token` - Address of the ERC-20 token.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error SafeErc20FailedOperation(address token);
-
- /// Indicates a failed [`ISafeErc20::safe_decrease_allowance`] request.
- ///
- /// * `spender` - Address of future tokens' spender.
- /// * `current_allowance` - Current allowance of the `spender`.
- /// * `requested_decrease` - Requested decrease in allowance for `spender`.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error SafeErc20FailedDecreaseAllowance(
- address spender,
- uint256 current_allowance,
- uint256 requested_decrease
- );
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// An operation with an ERC-20 token failed.
+ ///
+ /// * `token` - Address of the ERC-20 token.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error SafeErc20FailedOperation(address token);
+
+ /// Indicates a failed [`ISafeErc20::safe_decrease_allowance`] request.
+ ///
+ /// * `spender` - Address of future tokens' spender.
+ /// * `current_allowance` - Current allowance of the `spender`.
+ /// * `requested_decrease` - Requested decrease in allowance for `spender`.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error SafeErc20FailedDecreaseAllowance(
+ address spender,
+ uint256 current_allowance,
+ uint256 requested_decrease
+ );
+ }
}
/// A [`SafeErc20`] error.
@@ -63,8 +70,9 @@ impl MethodError for Error {
}
pub use token::*;
-#[allow(missing_docs)]
mod token {
+ #![allow(missing_docs)]
+ #![cfg_attr(coverage_nightly, coverage(off))]
alloy_sol_types::sol! {
/// Interface of the ERC-20 token.
interface IErc20 {
@@ -75,10 +83,10 @@ mod token {
}
}
}
-sol_storage! {
- /// State of the [`SafeErc20`] Contract.
- pub struct SafeErc20 {}
-}
+
+/// State of the [`SafeErc20`] Contract.
+#[storage]
+pub struct SafeErc20 {}
/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
/// calling other contracts and not `&mut (impl TopLevelStorage +
diff --git a/contracts/src/token/erc721/extensions/consecutive.rs b/contracts/src/token/erc721/extensions/consecutive.rs
index e457d0de2..c0c458fa6 100644
--- a/contracts/src/token/erc721/extensions/consecutive.rs
+++ b/contracts/src/token/erc721/extensions/consecutive.rs
@@ -27,12 +27,11 @@
use alloc::vec;
use alloy_primitives::{uint, Address, U256};
-use alloy_sol_types::sol;
use stylus_sdk::{
abi::Bytes,
evm, msg,
- prelude::TopLevelStorage,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::{storage, TopLevelStorage},
+ stylus_proc::{public, SolidityError},
};
use crate::{
@@ -55,64 +54,71 @@ use crate::{
};
type U96 = ::Key;
-
-sol_storage! {
- /// State of an [`Erc721Consecutive`] token.
- pub struct Erc721Consecutive {
- /// Erc721 contract storage.
- Erc721 erc721;
- /// Checkpoint library contract for sequential ownership.
- Trace _sequential_ownership;
- /// BitMap library contract for sequential burn of tokens.
- BitMap _sequential_burn;
- /// Used to offset the first token id.
- uint96 _first_consecutive_id;
- /// Maximum size of a batch of consecutive tokens. This is designed to limit
- /// stress on off-chain indexing services that have to record one entry per
- /// token, and have protections against "unreasonably large" batches of
- /// tokens.
- uint96 _max_batch_size;
- }
-}
-
-sol! {
- /// Emitted when the tokens from `from_token_id` to `to_token_id` are transferred from `from_address` to `to_address`.
- ///
- /// * `from_token_id` - First token being transferred.
- /// * `to_token_id` - Last token being transferred.
- /// * `from_address` - Address from which tokens will be transferred.
- /// * `to_address` - Address where the tokens will be transferred to.
- #[allow(missing_docs)]
- event ConsecutiveTransfer(
- uint256 indexed from_token_id,
- uint256 to_token_id,
- address indexed from_address,
- address indexed to_address
- );
+type StorageU96 = ::KeyStorage;
+
+/// State of an [`Erc721Consecutive`] token.
+#[storage]
+pub struct Erc721Consecutive {
+ /// Erc721 contract storage.
+ pub erc721: Erc721,
+ /// Checkpoint library contract for sequential ownership.
+ pub _sequential_ownership: Trace,
+ /// BitMap library contract for sequential burn of tokens.
+ pub _sequential_burn: BitMap,
+ /// Used to offset the first token id in
+ /// [`Erc721Consecutive::_next_consecutive_id`].
+ pub _first_consecutive_id: StorageU96,
+ /// Maximum size of a batch of consecutive tokens. This is designed to
+ /// limit stress on off-chain indexing services that have to record one
+ /// entry per token, and have protections against "unreasonably large"
+ /// batches of tokens.
+ pub _max_batch_size: StorageU96,
}
-sol! {
- /// Batch mint is restricted to the constructor.
- /// Any batch mint not emitting the [`Transfer`] event outside of the constructor
- /// is non ERC-721 compliant.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721ForbiddenBatchMint();
-
- /// Exceeds the max number of mints per batch.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721ExceededMaxBatchMint(uint256 batch_size, uint256 max_batch);
-
- /// Individual minting is not allowed.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721ForbiddenMint();
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Emitted when the tokens from `from_token_id` to `to_token_id` are transferred from `from_address` to `to_address`.
+ ///
+ /// * `from_token_id` - First token being transferred.
+ /// * `to_token_id` - Last token being transferred.
+ /// * `from_address` - Address from which tokens will be transferred.
+ /// * `to_address` - Address where the tokens will be transferred to.
+ #[allow(missing_docs)]
+ event ConsecutiveTransfer(
+ uint256 indexed from_token_id,
+ uint256 to_token_id,
+ address indexed from_address,
+ address indexed to_address
+ );
+ }
- /// Batch burn is not supported.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721ForbiddenBatchBurn();
+ sol! {
+ /// Batch mint is restricted to the constructor.
+ /// Any batch mint not emitting the [`Transfer`] event outside of the constructor
+ /// is non ERC-721 compliant.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721ForbiddenBatchMint();
+
+ /// Exceeds the max number of mints per batch.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721ExceededMaxBatchMint(uint256 batch_size, uint256 max_batch);
+
+ /// Individual minting is not allowed.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721ForbiddenMint();
+
+ /// Batch burn is not supported.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721ForbiddenBatchBurn();
+ }
}
/// An [`Erc721Consecutive`] error.
diff --git a/contracts/src/token/erc721/extensions/enumerable.rs b/contracts/src/token/erc721/extensions/enumerable.rs
index e8d1223c8..936009e12 100644
--- a/contracts/src/token/erc721/extensions/enumerable.rs
+++ b/contracts/src/token/erc721/extensions/enumerable.rs
@@ -10,29 +10,38 @@
//! [`Erc721Enumerable`].
use alloy_primitives::{uint, Address, FixedBytes, U256};
-use alloy_sol_types::sol;
use openzeppelin_stylus_proc::interface_id;
-use stylus_sdk::stylus_proc::{public, sol_storage, SolidityError};
+pub use sol::*;
+use stylus_sdk::{
+ prelude::storage,
+ storage::{StorageMap, StorageU256, StorageVec},
+ stylus_proc::{public, SolidityError},
+};
use crate::{
token::{erc721, erc721::IErc721},
utils::introspection::erc165::IErc165,
};
-sol! {
- /// Indicates an error when an `owner`'s token query
- /// was out of bounds for `index`.
- ///
- /// NOTE: The owner being `Address::ZERO`
- /// indicates a global out of bounds index.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721OutOfBoundsIndex(address owner, uint256 index);
-
- /// Indicates an error related to batch minting not allowed.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721EnumerableForbiddenBatchMint();
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// Indicates an error when an `owner`'s token query
+ /// was out of bounds for `index`.
+ ///
+ /// NOTE: The owner being `Address::ZERO`
+ /// indicates a global out of bounds index.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721OutOfBoundsIndex(address owner, uint256 index);
+
+ /// Indicates an error related to batch minting not allowed.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721EnumerableForbiddenBatchMint();
+ }
}
/// An [`Erc721Enumerable`] extension error.
@@ -49,19 +58,17 @@ pub enum Error {
EnumerableForbiddenBatchMint(ERC721EnumerableForbiddenBatchMint),
}
-sol_storage! {
- /// State of an Enumerable extension.
- pub struct Erc721Enumerable {
- /// Maps owners to a mapping of indices to tokens ids.
- mapping(address => mapping(uint256 => uint256)) _owned_tokens;
- /// Maps tokens ids to indices in `_owned_tokens`.
- mapping(uint256 => uint256) _owned_tokens_index;
- /// Stores all tokens ids.
- uint256[] _all_tokens;
- /// Maps indices at `_all_tokens` to tokens ids.
- mapping(uint256 => uint256) _all_tokens_index;
- }
-
+/// State of an Enumerable extension.
+#[storage]
+pub struct Erc721Enumerable {
+ /// Maps owners to a mapping of indices to tokens ids.
+ pub _owned_tokens: StorageMap>,
+ /// Maps tokens ids to indices in `_owned_tokens`.
+ pub _owned_tokens_index: StorageMap,
+ /// Stores all tokens ids.
+ pub _all_tokens: StorageVec,
+ /// Maps indices at `_all_tokens` to tokens ids.
+ pub _all_tokens_index: StorageMap,
}
/// This is the interface of the optional `Enumerable` extension
diff --git a/contracts/src/token/erc721/extensions/metadata.rs b/contracts/src/token/erc721/extensions/metadata.rs
index ff19adbd9..f85efb331 100644
--- a/contracts/src/token/erc721/extensions/metadata.rs
+++ b/contracts/src/token/erc721/extensions/metadata.rs
@@ -4,21 +4,22 @@ use alloc::string::{String, ToString};
use alloy_primitives::{FixedBytes, U256};
use openzeppelin_stylus_proc::interface_id;
-use stylus_sdk::stylus_proc::{public, sol_storage};
+use stylus_sdk::{
+ prelude::storage, storage::StorageString, stylus_proc::public,
+};
use crate::{
token::erc721::{Error, IErc721},
utils::{introspection::erc165::IErc165, Metadata},
};
-sol_storage! {
- /// Metadata of an [`crate::token::erc721::Erc721`] token.
- pub struct Erc721Metadata {
- /// Common Metadata.
- Metadata _metadata;
- /// Base URI for tokens.
- string _base_uri;
- }
+/// Metadata of an [`crate::token::erc721::Erc721`] token.
+#[storage]
+pub struct Erc721Metadata {
+ /// Common Metadata.
+ pub _metadata: Metadata,
+ /// Base URI for tokens.
+ pub _base_uri: StorageString,
}
/// Interface for the optional metadata functions from the ERC-721 standard.
diff --git a/contracts/src/token/erc721/extensions/uri_storage.rs b/contracts/src/token/erc721/extensions/uri_storage.rs
index 527a3983e..704f4e64b 100644
--- a/contracts/src/token/erc721/extensions/uri_storage.rs
+++ b/contracts/src/token/erc721/extensions/uri_storage.rs
@@ -4,32 +4,40 @@
use alloc::string::String;
use alloy_primitives::U256;
-use alloy_sol_types::sol;
-use stylus_sdk::{evm, stylus_proc::sol_storage};
+pub use sol::*;
+use stylus_sdk::{
+ evm,
+ prelude::storage,
+ storage::{StorageMap, StorageString},
+};
use crate::token::erc721::{extensions::Erc721Metadata, Error, IErc721};
-sol! {
- /// This event gets emitted when the metadata of a token is changed.
- ///
- /// The event comes from IERC4096.
- #[allow(missing_docs)]
- event MetadataUpdate(uint256 token_id);
-
- /// This event gets emitted when the metadata of a range of tokens
- /// is changed.
- ///
- /// The event comes from IERC4096.
- #[allow(missing_docs)]
- event BatchMetadataUpdate(uint256 from_token_id, uint256 to_token_id);
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// This event gets emitted when the metadata of a token is changed.
+ ///
+ /// The event comes from IERC4096.
+ #[allow(missing_docs)]
+ event MetadataUpdate(uint256 token_id);
+
+ /// This event gets emitted when the metadata of a range of tokens
+ /// is changed.
+ ///
+ /// The event comes from IERC4096.
+ #[allow(missing_docs)]
+ event BatchMetadataUpdate(uint256 from_token_id, uint256 to_token_id);
+ }
}
-sol_storage! {
- /// Uri Storage.
- pub struct Erc721UriStorage {
- /// Optional mapping for token URIs.
- mapping(uint256 => string) _token_uris;
- }
+/// Uri Storage.
+#[storage]
+pub struct Erc721UriStorage {
+ /// Optional mapping for token URIs.
+ pub _token_uris: StorageMap,
}
impl Erc721UriStorage {
@@ -106,7 +114,7 @@ impl Erc721UriStorage {
#[cfg(all(test, feature = "std"))]
mod tests {
use alloy_primitives::U256;
- use stylus_sdk::{msg, stylus_proc::sol_storage};
+ use stylus_sdk::{msg, prelude::storage};
use super::Erc721UriStorage;
use crate::token::erc721::{extensions::Erc721Metadata, Erc721};
@@ -116,12 +124,11 @@ mod tests {
U256::from(num)
}
- sol_storage! {
- struct Erc721MetadataExample {
- Erc721 erc721;
- Erc721Metadata metadata;
- Erc721UriStorage uri_storage;
- }
+ #[storage]
+ struct Erc721MetadataExample {
+ pub erc721: Erc721,
+ pub metadata: Erc721Metadata,
+ pub uri_storage: Erc721UriStorage,
}
#[motsu::test]
diff --git a/contracts/src/token/erc721/mod.rs b/contracts/src/token/erc721/mod.rs
index da61a97d0..2747366cd 100644
--- a/contracts/src/token/erc721/mod.rs
+++ b/contracts/src/token/erc721/mod.rs
@@ -5,10 +5,10 @@ use alloy_primitives::{uint, Address, FixedBytes, U128, U256};
use openzeppelin_stylus_proc::interface_id;
use stylus_sdk::{
abi::Bytes,
- alloy_sol_types::sol,
call::{self, Call, MethodError},
evm, function_selector, msg,
prelude::*,
+ storage::{StorageAddress, StorageBool, StorageMap, StorageU256},
};
use crate::utils::{
@@ -18,109 +18,115 @@ use crate::utils::{
pub mod extensions;
-sol! {
- /// Emitted when the `token_id` token is transferred from `from` to `to`.
- ///
- /// * `from` - Address from which the token will be transferred.
- /// * `to` - Address where the token will be transferred to.
- /// * `token_id` - Token id as a number.
- #[allow(missing_docs)]
- event Transfer(
- address indexed from,
- address indexed to,
- uint256 indexed token_id
- );
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
- /// Emitted when `owner` enables `approved` to manage the `token_id` token.
- ///
- /// * `owner` - Address of the owner of the token.
- /// * `approved` - Address of the approver.
- /// * `token_id` - Token id as a number.
- #[allow(missing_docs)]
- event Approval(
- address indexed owner,
- address indexed approved,
- uint256 indexed token_id
- );
-
- /// Emitted when `owner` enables or disables (`approved`) `operator`
- /// to manage all of its assets.
- ///
- /// * `owner` - Address of the owner of the token.
- /// * `operator` - Address of an operator that
- /// will manage operations on the token.
- /// * `approved` - Whether or not permission has been granted. If true,
- /// this means `operator` will be allowed to manage `owner`'s assets.
- #[allow(missing_docs)]
- event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-}
+ sol! {
+ /// Emitted when the `token_id` token is transferred from `from` to `to`.
+ ///
+ /// * `from` - Address from which the token will be transferred.
+ /// * `to` - Address where the token will be transferred to.
+ /// * `token_id` - Token id as a number.
+ #[allow(missing_docs)]
+ event Transfer(
+ address indexed from,
+ address indexed to,
+ uint256 indexed token_id
+ );
-sol! {
- /// Indicates that an address can't be an owner.
- /// For example, `Address::ZERO` is a forbidden owner in [`Erc721`].
- /// Used in balance queries.
- ///
- /// * `owner` - The address deemed to be an invalid owner.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InvalidOwner(address owner);
+ /// Emitted when `owner` enables `approved` to manage the `token_id` token.
+ ///
+ /// * `owner` - Address of the owner of the token.
+ /// * `approved` - Address of the approver.
+ /// * `token_id` - Token id as a number.
+ #[allow(missing_docs)]
+ event Approval(
+ address indexed owner,
+ address indexed approved,
+ uint256 indexed token_id
+ );
- /// Indicates a `token_id` whose `owner` is the zero address.
- ///
- /// * `token_id` - Token id as a number.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721NonexistentToken(uint256 token_id);
+ /// Emitted when `owner` enables or disables (`approved`) `operator`
+ /// to manage all of its assets.
+ ///
+ /// * `owner` - Address of the owner of the token.
+ /// * `operator` - Address of an operator that
+ /// will manage operations on the token.
+ /// * `approved` - Whether or not permission has been granted. If true,
+ /// this means `operator` will be allowed to manage `owner`'s assets.
+ #[allow(missing_docs)]
+ event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+ }
+
+ sol! {
+ /// Indicates that an address can't be an owner.
+ /// For example, `Address::ZERO` is a forbidden owner in [`Erc721`].
+ /// Used in balance queries.
+ ///
+ /// * `owner` - The address deemed to be an invalid owner.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InvalidOwner(address owner);
- /// Indicates an error related to the ownership over a particular token.
- /// Used in transfers.
- ///
- /// * `sender` - Address whose tokens are being transferred.
- /// * `token_id` - Token id as a number.
- /// * `owner` - Address of the owner of the token.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721IncorrectOwner(address sender, uint256 token_id, address owner);
+ /// Indicates a `token_id` whose `owner` is the zero address.
+ ///
+ /// * `token_id` - Token id as a number.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721NonexistentToken(uint256 token_id);
- /// Indicates a failure with the token `sender`. Used in transfers.
- ///
- /// * `sender` - An address whose token is being transferred.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InvalidSender(address sender);
+ /// Indicates an error related to the ownership over a particular token.
+ /// Used in transfers.
+ ///
+ /// * `sender` - Address whose tokens are being transferred.
+ /// * `token_id` - Token id as a number.
+ /// * `owner` - Address of the owner of the token.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721IncorrectOwner(address sender, uint256 token_id, address owner);
+
+ /// Indicates a failure with the token `sender`. Used in transfers.
+ ///
+ /// * `sender` - An address whose token is being transferred.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InvalidSender(address sender);
- /// Indicates a failure with the token `receiver`. Used in transfers.
- ///
- /// * `receiver` - Address that receives the token.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InvalidReceiver(address receiver);
+ /// Indicates a failure with the token `receiver`. Used in transfers.
+ ///
+ /// * `receiver` - Address that receives the token.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InvalidReceiver(address receiver);
- /// Indicates a failure with the `operator`’s approval. Used in transfers.
- ///
- /// * `operator` - Address that may be allowed to operate on tokens
- /// without being their owner.
- /// * `token_id` - Token id as a number.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InsufficientApproval(address operator, uint256 token_id);
-
- /// Indicates a failure with the `approver` of a token to be approved.
- /// Used in approvals.
- ///
- /// * `approver` - Address initiating an approval operation.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InvalidApprover(address approver);
-
- /// Indicates a failure with the `operator` to be approved.
- /// Used in approvals.
- ///
- /// * `operator` - Address that may be allowed to operate on tokens
- /// without being their owner.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ERC721InvalidOperator(address operator);
+ /// Indicates a failure with the `operator`’s approval. Used in transfers.
+ ///
+ /// * `operator` - Address that may be allowed to operate on tokens
+ /// without being their owner.
+ /// * `token_id` - Token id as a number.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InsufficientApproval(address operator, uint256 token_id);
+
+ /// Indicates a failure with the `approver` of a token to be approved.
+ /// Used in approvals.
+ ///
+ /// * `approver` - Address initiating an approval operation.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InvalidApprover(address approver);
+
+ /// Indicates a failure with the `operator` to be approved.
+ /// Used in approvals.
+ ///
+ /// * `operator` - Address that may be allowed to operate on tokens
+ /// without being their owner.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ERC721InvalidOperator(address operator);
+ }
}
/// An [`Erc721`] error defined as described in [ERC-6093].
@@ -161,8 +167,9 @@ impl MethodError for Error {
}
pub use receiver::IERC721Receiver;
-#[allow(missing_docs)]
mod receiver {
+ #![allow(missing_docs)]
+ #![cfg_attr(coverage_nightly, coverage(off))]
stylus_sdk::stylus_proc::sol_interface! {
/// [`Erc721`] token receiver interface.
///
@@ -186,18 +193,18 @@ mod receiver {
}
}
-sol_storage! {
- /// State of an [`Erc721`] token.
- pub struct Erc721 {
- /// Maps tokens to owners.
- mapping(uint256 => address) _owners;
- /// Maps users to balances.
- mapping(address => uint256) _balances;
- /// Maps tokens to approvals.
- mapping(uint256 => address) _token_approvals;
- /// Maps owners to a mapping of operator approvals.
- mapping(address => mapping(address => bool)) _operator_approvals;
- }
+/// State of an [`Erc721`] token.
+#[storage]
+pub struct Erc721 {
+ /// Maps tokens to owners.
+ pub _owners: StorageMap,
+ /// Maps users to balances.
+ pub _balances: StorageMap,
+ /// Maps tokens to approvals.
+ pub _token_approvals: StorageMap,
+ /// Maps owners to a mapping of operator approvals.
+ pub _operator_approvals:
+ StorageMap>,
}
/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
diff --git a/contracts/src/utils/cryptography/ecdsa.rs b/contracts/src/utils/cryptography/ecdsa.rs
index eeffca3e8..5f8c6bf6a 100644
--- a/contracts/src/utils/cryptography/ecdsa.rs
+++ b/contracts/src/utils/cryptography/ecdsa.rs
@@ -5,7 +5,7 @@
use alloc::vec::Vec;
use alloy_primitives::{address, uint, Address, B256, U256};
-use alloy_sol_types::{sol, SolType};
+use alloy_sol_types::SolType;
use stylus_sdk::{
call::{self, Call, MethodError},
storage::TopLevelStorage,
@@ -23,18 +23,39 @@ pub const SIGNATURE_S_UPPER_BOUND: U256 = uint!(
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0_U256
);
-sol! {
- /// The signature derives the `Address::ZERO`.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ECDSAInvalidSignature();
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
- /// The signature has an `S` value that is in the upper half order.
- ///
- /// * `s` - Invalid `S` value.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ECDSAInvalidSignatureS(bytes32 s);
+ sol! {
+ /// The signature derives the `Address::ZERO`.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ECDSAInvalidSignature();
+
+ /// The signature has an `S` value that is in the upper half order.
+ ///
+ /// * `s` - Invalid `S` value.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ECDSAInvalidSignatureS(bytes32 s);
+ }
+
+ sol! {
+ /// Struct with callable data to the `ecrecover` precompile.
+ #[allow(missing_docs)]
+ struct EcRecoverData {
+ /// EIP-191 Hash of the message.
+ bytes32 hash;
+ /// `v` value from the signature.
+ uint8 v;
+ /// `r` value from the signature.
+ bytes32 r;
+ /// `s` value from the signature.
+ bytes32 s;
+ }
+ }
}
/// An error that occurred in the implementation of an `ECDSA` library.
@@ -52,21 +73,6 @@ impl MethodError for ecdsa::Error {
}
}
-sol! {
- /// Struct with callable data to the `ecrecover` precompile.
- #[allow(missing_docs)]
- struct EcRecoverData {
- /// EIP-191 Hash of the message.
- bytes32 hash;
- /// `v` value from the signature.
- uint8 v;
- /// `r` value from the signature.
- bytes32 r;
- /// `s` value from the signature.
- bytes32 s;
- }
-}
-
/// Returns the address that signed a hashed message (`hash`).
///
/// # Arguments
diff --git a/contracts/src/utils/metadata.rs b/contracts/src/utils/metadata.rs
index 7d904dbb0..fe42e017c 100644
--- a/contracts/src/utils/metadata.rs
+++ b/contracts/src/utils/metadata.rs
@@ -1,16 +1,17 @@
//! Common Metadata Smart Contract.
use alloc::string::String;
-use stylus_sdk::stylus_proc::{public, sol_storage};
+use stylus_sdk::{
+ prelude::storage, storage::StorageString, stylus_proc::public,
+};
-sol_storage! {
- /// Metadata of the token.
- pub struct Metadata {
- /// Token name.
- string _name;
- /// Token symbol.
- string _symbol;
- }
+/// Metadata of the token.
+#[storage]
+pub struct Metadata {
+ /// Token name.
+ pub _name: StorageString,
+ /// Token symbol.
+ pub _symbol: StorageString,
}
#[public]
diff --git a/contracts/src/utils/nonces.rs b/contracts/src/utils/nonces.rs
index 13678fcc3..4627b4ea5 100644
--- a/contracts/src/utils/nonces.rs
+++ b/contracts/src/utils/nonces.rs
@@ -3,16 +3,25 @@
//! Nonces will only increment.
use alloy_primitives::{uint, Address, U256};
-use alloy_sol_types::sol;
-use stylus_sdk::stylus_proc::{public, sol_storage, SolidityError};
+use stylus_sdk::{
+ prelude::storage,
+ storage::{StorageMap, StorageU256},
+ stylus_proc::{public, SolidityError},
+};
const ONE: U256 = uint!(1_U256);
-sol! {
- /// The nonce used for an `account` is not the expected current nonce.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error InvalidAccountNonce(address account, uint256 currentNonce);
+pub use sol::*;
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// The nonce used for an `account` is not the expected current nonce.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error InvalidAccountNonce(address account, uint256 currentNonce);
+ }
}
/// A Nonces error.
@@ -22,12 +31,11 @@ pub enum Error {
InvalidAccountNonce(InvalidAccountNonce),
}
-sol_storage! {
- /// State of a Nonces Contract.
- pub struct Nonces {
- /// Mapping from address to its nonce.
- mapping(address => uint256) _nonces;
- }
+/// State of a Nonces Contract.
+#[storage]
+pub struct Nonces {
+ /// Mapping from address to its nonce.
+ pub _nonces: StorageMap,
}
#[public]
diff --git a/contracts/src/utils/pausable.rs b/contracts/src/utils/pausable.rs
index 638e78d8b..33e0421c6 100644
--- a/contracts/src/utils/pausable.rs
+++ b/contracts/src/utils/pausable.rs
@@ -14,34 +14,41 @@
//! exposed by default.
//! You should expose them manually in your contract's abi.
-use alloy_sol_types::sol;
+pub use sol::*;
use stylus_sdk::{
evm, msg,
- stylus_proc::{public, sol_storage, SolidityError},
+ prelude::storage,
+ storage::StorageBool,
+ stylus_proc::{public, SolidityError},
};
-sol! {
- /// Emitted when pause is triggered by `account`.
- #[allow(missing_docs)]
- event Paused(address account);
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
- /// Emitted when the pause is lifted by `account`.
- #[allow(missing_docs)]
- event Unpaused(address account);
-}
+ sol! {
+ /// Emitted when pause is triggered by `account`.
+ #[allow(missing_docs)]
+ event Paused(address account);
-sol! {
- /// Indicates an error related to the operation that failed
- /// because the contract is paused.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error EnforcedPause();
+ /// Emitted when the pause is lifted by `account`.
+ #[allow(missing_docs)]
+ event Unpaused(address account);
+ }
- /// Indicates an error related to the operation that failed
- /// because the contract is not paused.
- #[derive(Debug)]
- #[allow(missing_docs)]
- error ExpectedPause();
+ sol! {
+ /// Indicates an error related to the operation that failed
+ /// because the contract is paused.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error EnforcedPause();
+
+ /// Indicates an error related to the operation that failed
+ /// because the contract is not paused.
+ #[derive(Debug)]
+ #[allow(missing_docs)]
+ error ExpectedPause();
+ }
}
/// A Pausable error.
@@ -55,12 +62,11 @@ pub enum Error {
ExpectedPause(ExpectedPause),
}
-sol_storage! {
- /// State of a Pausable Contract.
- pub struct Pausable {
- /// Indicates whether the contract is `Paused`.
- bool _paused;
- }
+/// State of a Pausable Contract.
+#[storage]
+pub struct Pausable {
+ /// Indicates whether the contract is `Paused`.
+ pub _paused: StorageBool,
}
#[public]
diff --git a/contracts/src/utils/structs/bitmap.rs b/contracts/src/utils/structs/bitmap.rs
index 55fdedec0..821bf9b19 100644
--- a/contracts/src/utils/structs/bitmap.rs
+++ b/contracts/src/utils/structs/bitmap.rs
@@ -14,17 +14,19 @@
//!
//! [merkle-distributor]: https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol
use alloy_primitives::{uint, U256};
-use stylus_sdk::stylus_proc::sol_storage;
+use stylus_sdk::{
+ prelude::storage,
+ storage::{StorageMap, StorageU256},
+};
const ONE: U256 = uint!(0x1_U256);
const HEX_FF: U256 = uint!(0xff_U256);
-sol_storage! {
- /// State of bit map.
- pub struct BitMap {
- /// Inner laying mapping.
- mapping(uint256 => uint256) _data;
- }
+/// State of bit map.
+#[storage]
+pub struct BitMap {
+ /// Inner laying mapping.
+ pub _data: StorageMap,
}
impl BitMap {
diff --git a/contracts/src/utils/structs/checkpoints/mod.rs b/contracts/src/utils/structs/checkpoints/mod.rs
index 88b1eb22c..ee99b586f 100644
--- a/contracts/src/utils/structs/checkpoints/mod.rs
+++ b/contracts/src/utils/structs/checkpoints/mod.rs
@@ -10,8 +10,8 @@
pub mod generic_size;
use alloy_primitives::{uint, U256, U32};
-use alloy_sol_types::sol;
pub use generic_size::{Size, S160, S208, S224};
+pub use sol::*;
use stylus_sdk::{
call::MethodError,
prelude::*,
@@ -23,10 +23,15 @@ use crate::utils::{
structs::checkpoints::generic_size::{Accessor, Num},
};
-sol! {
- /// A value was attempted to be inserted into a past checkpoint.
- #[derive(Debug)]
- error CheckpointUnorderedInsertion();
+#[cfg_attr(coverage_nightly, coverage(off))]
+mod sol {
+ use alloy_sol_macro::sol;
+
+ sol! {
+ /// A value was attempted to be inserted into a past checkpoint.
+ #[derive(Debug)]
+ error CheckpointUnorderedInsertion();
+ }
}
/// An error that occurred while calling the [`Trace`] checkpoint contract.
@@ -42,20 +47,20 @@ impl MethodError for Error {
}
}
-sol_storage! {
- /// State of the checkpoint library contract.
- pub struct Trace {
- /// Stores checkpoints in a dynamic array sorted by key.
- StorageVec> _checkpoints;
- }
+/// State of the checkpoint library contract.
+#[storage]
+pub struct Trace {
+ /// Stores checkpoints in a dynamic array sorted by key.
+ pub _checkpoints: StorageVec>,
+}
- /// State of a single checkpoint.
- pub struct Checkpoint {
- /// The key of the checkpoint. Used as a sorting key.
- S::KeyStorage _key;
- /// The value corresponding to the key.
- S::ValueStorage _value;
- }
+/// State of a single checkpoint.
+#[storage]
+pub struct Checkpoint {
+ /// The key of the checkpoint. Used as a sorting key.
+ pub _key: S::KeyStorage,
+ /// The value corresponding to the key.
+ pub _value: S::ValueStorage,
}
impl Trace {
diff --git a/docs/modules/ROOT/pages/access-control.adoc b/docs/modules/ROOT/pages/access-control.adoc
index 0e3bfb914..b819af28e 100644
--- a/docs/modules/ROOT/pages/access-control.adoc
+++ b/docs/modules/ROOT/pages/access-control.adoc
@@ -13,12 +13,11 @@ OpenZeppelin Contracts for Stylus provides https://docs.rs/openzeppelin-stylus/0
----
use openzeppelin_stylus::access::ownable::Ownable;
-sol_storage! {
- #[entrypoint]
- struct OwnableExample {
- #[borrow]
- Ownable ownable;
- }
+#[entrypoint]
+#[storage]
+struct OwnableExample {
+ #[borrow]
+ pub ownable: Ownable,
}
#[public]
@@ -73,14 +72,13 @@ Here's a simple example of using `AccessControl` in an xref:erc20.adoc[ERC-20 to
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- struct Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- AccessControl access;
- }
+#[entrypoint]
+#[storage]
+struct Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub access: AccessControl,
}
// `keccak256("MINTER_ROLE")`
@@ -113,14 +111,13 @@ Let's augment our ERC-20 token example by also defining a 'burner' role, which l
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- struct Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- AccessControl access;
- }
+#[entrypoint]
+#[storage]
+struct Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub access: AccessControl,
}
// `keccak256("MINTER_ROLE")`
diff --git a/docs/modules/ROOT/pages/deploy.adoc b/docs/modules/ROOT/pages/deploy.adoc
index 3cff7ea0f..4ac25e5d7 100644
--- a/docs/modules/ROOT/pages/deploy.adoc
+++ b/docs/modules/ROOT/pages/deploy.adoc
@@ -30,11 +30,10 @@ For a contract like this:
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- pub struct Counter {
- uint256 number;
- }
+#[entrypoint]
+#[storage]
+struct Counter {
+ pub number: StorageU256,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc1155-burnable.adoc b/docs/modules/ROOT/pages/erc1155-burnable.adoc
index 546b2e813..f824afc43 100644
--- a/docs/modules/ROOT/pages/erc1155-burnable.adoc
+++ b/docs/modules/ROOT/pages/erc1155-burnable.adoc
@@ -14,12 +14,11 @@ use openzeppelin_stylus::token::erc1155::{
extensions::IErc1155Burnable, Erc1155,
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155 erc1155;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155: Erc1155,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc1155-metadata-uri.adoc b/docs/modules/ROOT/pages/erc1155-metadata-uri.adoc
index 71bdbf845..fcccbcb40 100644
--- a/docs/modules/ROOT/pages/erc1155-metadata-uri.adoc
+++ b/docs/modules/ROOT/pages/erc1155-metadata-uri.adoc
@@ -16,14 +16,12 @@ use openzeppelin_stylus::token::erc1155::{
extensions::Erc1155MetadataUri, Erc1155,
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155 erc1155;
- #[borrow]
- Erc1155MetadataUri metadata_uri;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155: Erc1155,
+ pub metadata_uri: Erc1155MetadataUri,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc1155-pausable.adoc b/docs/modules/ROOT/pages/erc1155-pausable.adoc
index 4d9dcd633..528ca5557 100644
--- a/docs/modules/ROOT/pages/erc1155-pausable.adoc
+++ b/docs/modules/ROOT/pages/erc1155-pausable.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
utils::Pausable,
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155 erc1155;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155: Erc1155,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc1155-supply.adoc b/docs/modules/ROOT/pages/erc1155-supply.adoc
index ea9ba4405..900d945c7 100644
--- a/docs/modules/ROOT/pages/erc1155-supply.adoc
+++ b/docs/modules/ROOT/pages/erc1155-supply.adoc
@@ -17,12 +17,11 @@ use openzeppelin_stylus::token::erc1155::extensions::{
Erc1155Supply, IErc1155Supply,
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155Supply erc1155_supply;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155_supply: Erc1155Supply,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc1155-uri-storage.adoc b/docs/modules/ROOT/pages/erc1155-uri-storage.adoc
index 22a994e00..5878893a3 100644
--- a/docs/modules/ROOT/pages/erc1155-uri-storage.adoc
+++ b/docs/modules/ROOT/pages/erc1155-uri-storage.adoc
@@ -17,16 +17,14 @@ use openzeppelin_stylus::token::erc1155::{
extensions::{Erc1155MetadataUri, Erc1155UriStorage},
Erc1155,
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
-
-sol_storage! {
- #[entrypoint]
- struct Erc1155MetadataUriExample {
- #[borrow]
- Erc1155 erc1155;
- Erc1155MetadataUri metadata_uri;
- Erc1155UriStorage uri_storage;
- }
+
+#[entrypoint]
+#[storage]
+struct Erc1155MetadataUriExample {
+ #[borrow]
+ pub erc1155: Erc1155,
+ pub metadata_uri: Erc1155MetadataUri,
+ pub uri_storage: Erc1155UriStorage,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc20-burnable.adoc b/docs/modules/ROOT/pages/erc20-burnable.adoc
index dd0d3337c..75f4c63c2 100644
--- a/docs/modules/ROOT/pages/erc20-burnable.adoc
+++ b/docs/modules/ROOT/pages/erc20-burnable.adoc
@@ -16,12 +16,11 @@ use openzeppelin_stylus::{
},
};
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc20-capped.adoc b/docs/modules/ROOT/pages/erc20-capped.adoc
index 350f46c6a..3b1621441 100644
--- a/docs/modules/ROOT/pages/erc20-capped.adoc
+++ b/docs/modules/ROOT/pages/erc20-capped.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
}
};
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Capped capped;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub capped: Capped,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc20-metadata.adoc b/docs/modules/ROOT/pages/erc20-metadata.adoc
index 05e91cabe..5d2329887 100644
--- a/docs/modules/ROOT/pages/erc20-metadata.adoc
+++ b/docs/modules/ROOT/pages/erc20-metadata.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
},
};
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Erc20Metadata metadata;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub metadata: Erc20Metadata,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc20-pausable.adoc b/docs/modules/ROOT/pages/erc20-pausable.adoc
index ecfc16283..6bc954ff6 100644
--- a/docs/modules/ROOT/pages/erc20-pausable.adoc
+++ b/docs/modules/ROOT/pages/erc20-pausable.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
utils::Pausable,
};
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc20-permit.adoc b/docs/modules/ROOT/pages/erc20-permit.adoc
index c9bfa1dde..bf69b2ed5 100644
--- a/docs/modules/ROOT/pages/erc20-permit.adoc
+++ b/docs/modules/ROOT/pages/erc20-permit.adoc
@@ -15,16 +15,16 @@ use openzeppelin_stylus::{
token::erc20::extensions::Erc20Permit, utils::cryptography::eip712::IEip712,
};
-sol_storage! {
- #[entrypoint]
- struct Erc20PermitExample {
- #[borrow]
- Erc20Permit erc20_permit;
- }
-
- struct Eip712 {}
+#[entrypoint]
+#[storage]
+struct Erc20PermitExample {
+ #[borrow]
+ pub erc20_permit: Erc20Permit,
}
+#[storage]
+struct Eip712 {}
+
// Define `NAME` and `VERSION` for your contract.
impl IEip712 for Eip712 {
const NAME: &'static str = "ERC-20 Permit Example";
diff --git a/docs/modules/ROOT/pages/erc20.adoc b/docs/modules/ROOT/pages/erc20.adoc
index 5a15c3720..6294fefd5 100644
--- a/docs/modules/ROOT/pages/erc20.adoc
+++ b/docs/modules/ROOT/pages/erc20.adoc
@@ -15,14 +15,13 @@ Here's what our GLD token might look like.
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- struct GLDToken {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Erc20Metadata metadata;
- }
+#[entrypoint]
+#[storage]
+struct GLDToken {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub metadata: Erc20Metadata,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-burnable.adoc b/docs/modules/ROOT/pages/erc721-burnable.adoc
index b02a719b7..c058b747a 100644
--- a/docs/modules/ROOT/pages/erc721-burnable.adoc
+++ b/docs/modules/ROOT/pages/erc721-burnable.adoc
@@ -16,12 +16,11 @@ use openzeppelin_stylus::{
},
};
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-consecutive.adoc b/docs/modules/ROOT/pages/erc721-consecutive.adoc
index 2ddaa74ad..b327fefc5 100644
--- a/docs/modules/ROOT/pages/erc721-consecutive.adoc
+++ b/docs/modules/ROOT/pages/erc721-consecutive.adoc
@@ -13,12 +13,11 @@ use openzeppelin_stylus::token::erc721::extensions::consecutive::{
Erc721Consecutive, Error,
};
-sol_storage! {
- #[entrypoint]
- struct Erc721ConsecutiveExample {
- #[borrow]
- Erc721Consecutive erc721_consecutive;
- }
+#[entrypoint]
+#[storage]
+struct Erc721ConsecutiveExample {
+ #[borrow]
+ pub erc721_consecutive: Erc721Consecutive,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-enumerable.adoc b/docs/modules/ROOT/pages/erc721-enumerable.adoc
index 35f27d6c2..9069ac578 100644
--- a/docs/modules/ROOT/pages/erc721-enumerable.adoc
+++ b/docs/modules/ROOT/pages/erc721-enumerable.adoc
@@ -15,14 +15,13 @@ use openzeppelin_stylus::token::erc721::{
Erc721, IErc721,
};
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Erc721Enumerable enumerable;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub enumerable: Enumerable,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-metadata.adoc b/docs/modules/ROOT/pages/erc721-metadata.adoc
index 5f7eea358..c209cb153 100644
--- a/docs/modules/ROOT/pages/erc721-metadata.adoc
+++ b/docs/modules/ROOT/pages/erc721-metadata.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
},
};
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Erc721Metadata metadata;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub metadata: Metadata,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-pausable.adoc b/docs/modules/ROOT/pages/erc721-pausable.adoc
index 593ce1038..ffb450e40 100644
--- a/docs/modules/ROOT/pages/erc721-pausable.adoc
+++ b/docs/modules/ROOT/pages/erc721-pausable.adoc
@@ -16,14 +16,13 @@ use openzeppelin_stylus::{
utils::Pausable,
};
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721-uri-storage.adoc b/docs/modules/ROOT/pages/erc721-uri-storage.adoc
index 99c363201..efa4344e6 100644
--- a/docs/modules/ROOT/pages/erc721-uri-storage.adoc
+++ b/docs/modules/ROOT/pages/erc721-uri-storage.adoc
@@ -21,15 +21,14 @@ use openzeppelin_stylus::token::erc721::{
Erc721, IErc721,
};
-sol_storage! {
- #[entrypoint]
- struct Erc721MetadataExample {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Erc721Metadata metadata;
- Erc721UriStorage uri_storage;
- }
+#[entrypoint]
+#[storage]
+struct Erc721MetadataExample {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub metadata: Metadata,
+ pub uri_storage: UriStorage,
}
#[public]
diff --git a/docs/modules/ROOT/pages/erc721.adoc b/docs/modules/ROOT/pages/erc721.adoc
index 1f5b9e636..f6ce79384 100644
--- a/docs/modules/ROOT/pages/erc721.adoc
+++ b/docs/modules/ROOT/pages/erc721.adoc
@@ -21,15 +21,14 @@ Here's what a contract for tokenized items might look like:
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- struct GameItem {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Metadata metadata;
- uint256 _next_token_id;
- }
+#[entrypoint]
+#[storage]
+struct GameItem {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub metadata: Metadata,
+ pub next_token_id: StorageU256,
}
#[public]
@@ -40,7 +39,7 @@ impl GameItem {
player: Address,
) -> Result> {
let token_id = self._next_token_id.get() + uint!(1_U256);
- self._next_token_id.set(token_id);
+ self.next_token_id.set(token_id);
self.erc721._mint(player, token_id)?;
diff --git a/docs/modules/ROOT/pages/utilities.adoc b/docs/modules/ROOT/pages/utilities.adoc
index ff7ab20ca..066d590ad 100644
--- a/docs/modules/ROOT/pages/utilities.adoc
+++ b/docs/modules/ROOT/pages/utilities.adoc
@@ -15,12 +15,11 @@ Contracts for Stylus provides helpers for implementing ERC-165 in your contracts
[source,rust]
----
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
}
#[public]
diff --git a/examples/access-control/src/lib.rs b/examples/access-control/src/lib.rs
index 0b4590d1f..81d8777e0 100644
--- a/examples/access-control/src/lib.rs
+++ b/examples/access-control/src/lib.rs
@@ -8,16 +8,15 @@ use openzeppelin_stylus::{
access::control::AccessControl,
token::erc20::{Erc20, IErc20},
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
-
-sol_storage! {
- #[entrypoint]
- struct AccessControlExample {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- AccessControl access;
- }
+use stylus_sdk::prelude::{entrypoint, public, storage};
+
+#[entrypoint]
+#[storage]
+struct AccessControlExample {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub access: AccessControl,
}
// `keccak256("TRANSFER_ROLE")`
diff --git a/examples/basic/token/src/lib.rs b/examples/basic/token/src/lib.rs
index 9976743ab..aaa6efe1f 100644
--- a/examples/basic/token/src/lib.rs
+++ b/examples/basic/token/src/lib.rs
@@ -5,16 +5,15 @@ use alloc::vec::Vec;
use alloy_primitives::{Address, U256};
use openzeppelin_stylus::token::erc20::{extensions::Erc20Metadata, Erc20};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Erc20Metadata metadata;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub metadata: Erc20Metadata,
}
#[public]
diff --git a/examples/ecdsa/src/lib.rs b/examples/ecdsa/src/lib.rs
index de6bf0576..f94e0a5da 100644
--- a/examples/ecdsa/src/lib.rs
+++ b/examples/ecdsa/src/lib.rs
@@ -5,12 +5,11 @@ use alloc::vec::Vec;
use alloy_primitives::{Address, B256};
use openzeppelin_stylus::utils::cryptography::ecdsa;
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct ECDSAExample {}
-}
+#[entrypoint]
+#[storage]
+struct ECDSAExample {}
#[public]
impl ECDSAExample {
diff --git a/examples/erc1155-metadata-uri/src/lib.rs b/examples/erc1155-metadata-uri/src/lib.rs
index bb7cb97bc..b460a383e 100644
--- a/examples/erc1155-metadata-uri/src/lib.rs
+++ b/examples/erc1155-metadata-uri/src/lib.rs
@@ -9,16 +9,15 @@ use openzeppelin_stylus::{
},
utils::introspection::erc165::IErc165,
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct Erc1155MetadataUriExample {
- #[borrow]
- Erc1155 erc1155;
- Erc1155MetadataUri metadata_uri;
- Erc1155UriStorage uri_storage;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155MetadataUriExample {
+ #[borrow]
+ pub erc1155: Erc1155,
+ pub metadata_uri: Erc1155MetadataUri,
+ pub uri_storage: Erc1155UriStorage,
}
#[public]
diff --git a/examples/erc1155-supply/src/lib.rs b/examples/erc1155-supply/src/lib.rs
index dd18816ed..845c81d01 100644
--- a/examples/erc1155-supply/src/lib.rs
+++ b/examples/erc1155-supply/src/lib.rs
@@ -9,16 +9,16 @@ use openzeppelin_stylus::token::erc1155::extensions::{
};
use stylus_sdk::{
abi::Bytes,
- prelude::{entrypoint, public, sol_storage},
+ prelude::{entrypoint, public, storage},
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155Supply erc1155_supply;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155_supply: Erc1155Supply,
}
+
#[public]
#[inherit(Erc1155Supply)]
impl Erc1155Example {
diff --git a/examples/erc1155/src/lib.rs b/examples/erc1155/src/lib.rs
index 778a66c71..8666b4004 100644
--- a/examples/erc1155/src/lib.rs
+++ b/examples/erc1155/src/lib.rs
@@ -10,17 +10,16 @@ use openzeppelin_stylus::{
};
use stylus_sdk::{
abi::Bytes,
- prelude::{entrypoint, public, sol_storage},
+ prelude::{entrypoint, public, storage},
};
-sol_storage! {
- #[entrypoint]
- struct Erc1155Example {
- #[borrow]
- Erc1155 erc1155;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc1155Example {
+ #[borrow]
+ pub erc1155: Erc1155,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/examples/erc20-permit/src/lib.rs b/examples/erc20-permit/src/lib.rs
index b4e9ef425..81f3c80db 100644
--- a/examples/erc20-permit/src/lib.rs
+++ b/examples/erc20-permit/src/lib.rs
@@ -7,17 +7,16 @@ use alloy_primitives::{Address, U256};
use openzeppelin_stylus::{
token::erc20::extensions::Erc20Permit, utils::cryptography::eip712::IEip712,
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct Erc20PermitExample {
- #[borrow]
- Erc20Permit erc20_permit;
- }
-
- struct Eip712 {}
+#[entrypoint]
+#[storage]
+struct Erc20PermitExample {
+ #[borrow]
+ pub erc20_permit: Erc20Permit,
}
+#[storage]
+struct Eip712 {}
impl IEip712 for Eip712 {
const NAME: &'static str = "ERC-20 Permit Example";
diff --git a/examples/erc20/src/lib.rs b/examples/erc20/src/lib.rs
index 28ec60b25..1f4d01db1 100644
--- a/examples/erc20/src/lib.rs
+++ b/examples/erc20/src/lib.rs
@@ -11,22 +11,21 @@ use openzeppelin_stylus::{
},
utils::{introspection::erc165::IErc165, Pausable},
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
const DECIMALS: u8 = 10;
-sol_storage! {
- #[entrypoint]
- struct Erc20Example {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Erc20Metadata metadata;
- #[borrow]
- Capped capped;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc20Example {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub metadata: Erc20Metadata,
+ #[borrow]
+ pub capped: Capped,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/examples/erc721-consecutive/src/lib.rs b/examples/erc721-consecutive/src/lib.rs
index 798850905..6e13be0ff 100644
--- a/examples/erc721-consecutive/src/lib.rs
+++ b/examples/erc721-consecutive/src/lib.rs
@@ -7,12 +7,11 @@ use openzeppelin_stylus::token::erc721::extensions::consecutive::{
};
use stylus_sdk::prelude::*;
-sol_storage! {
- #[entrypoint]
- struct Erc721ConsecutiveExample {
- #[borrow]
- Erc721Consecutive erc721_consecutive;
- }
+#[entrypoint]
+#[storage]
+struct Erc721ConsecutiveExample {
+ #[borrow]
+ pub erc721_consecutive: Erc721Consecutive,
}
#[public]
diff --git a/examples/erc721-metadata/src/lib.rs b/examples/erc721-metadata/src/lib.rs
index f5e7237ca..7d72c4e29 100644
--- a/examples/erc721-metadata/src/lib.rs
+++ b/examples/erc721-metadata/src/lib.rs
@@ -14,17 +14,16 @@ use openzeppelin_stylus::{
},
utils::introspection::erc165::IErc165,
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
-
-sol_storage! {
- #[entrypoint]
- struct Erc721MetadataExample {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Metadata metadata;
- UriStorage uri_storage;
- }
+use stylus_sdk::prelude::{entrypoint, public, storage};
+
+#[entrypoint]
+#[storage]
+struct Erc721MetadataExample {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub metadata: Metadata,
+ pub uri_storage: UriStorage,
}
#[public]
diff --git a/examples/erc721/src/lib.rs b/examples/erc721/src/lib.rs
index 5be6fb439..cb71c5ff8 100644
--- a/examples/erc721/src/lib.rs
+++ b/examples/erc721/src/lib.rs
@@ -13,19 +13,18 @@ use openzeppelin_stylus::{
};
use stylus_sdk::{
abi::Bytes,
- prelude::{entrypoint, public, sol_storage},
+ prelude::{entrypoint, public, storage},
};
-sol_storage! {
- #[entrypoint]
- struct Erc721Example {
- #[borrow]
- Erc721 erc721;
- #[borrow]
- Enumerable enumerable;
- #[borrow]
- Pausable pausable;
- }
+#[entrypoint]
+#[storage]
+struct Erc721Example {
+ #[borrow]
+ pub erc721: Erc721,
+ #[borrow]
+ pub enumerable: Enumerable,
+ #[borrow]
+ pub pausable: Pausable,
}
#[public]
diff --git a/examples/merkle-proofs/src/lib.rs b/examples/merkle-proofs/src/lib.rs
index a1db588d2..d0dd8fcef 100644
--- a/examples/merkle-proofs/src/lib.rs
+++ b/examples/merkle-proofs/src/lib.rs
@@ -10,7 +10,7 @@ use openzeppelin_crypto::{
};
use stylus_sdk::{
alloy_sol_types::sol,
- prelude::{entrypoint, public, sol_storage},
+ prelude::{entrypoint, public, storage},
stylus_proc::SolidityError,
};
@@ -47,10 +47,9 @@ impl core::convert::From for VerifierError {
}
}
-sol_storage! {
- #[entrypoint]
- struct VerifierContract { }
-}
+#[entrypoint]
+#[storage]
+struct VerifierContract {}
#[public]
impl VerifierContract {
diff --git a/examples/ownable-two-step/src/lib.rs b/examples/ownable-two-step/src/lib.rs
index 11d9583ea..79f4a9a77 100644
--- a/examples/ownable-two-step/src/lib.rs
+++ b/examples/ownable-two-step/src/lib.rs
@@ -8,16 +8,15 @@ use openzeppelin_stylus::{
access::ownable_two_step::Ownable2Step,
token::erc20::{Erc20, IErc20},
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct Ownable2StepExample {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Ownable2Step ownable;
- }
+#[entrypoint]
+#[storage]
+struct Ownable2StepExample {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub ownable: Ownable2Step,
}
#[public]
diff --git a/examples/ownable/src/lib.rs b/examples/ownable/src/lib.rs
index b7654c423..864d2ee5d 100644
--- a/examples/ownable/src/lib.rs
+++ b/examples/ownable/src/lib.rs
@@ -8,16 +8,15 @@ use openzeppelin_stylus::{
access::ownable::Ownable,
token::erc20::{Erc20, IErc20},
};
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct OwnableExample {
- #[borrow]
- Erc20 erc20;
- #[borrow]
- Ownable ownable;
- }
+#[entrypoint]
+#[storage]
+struct OwnableExample {
+ #[borrow]
+ pub erc20: Erc20,
+ #[borrow]
+ pub ownable: Ownable,
}
#[public]
diff --git a/examples/safe-erc20/src/lib.rs b/examples/safe-erc20/src/lib.rs
index fcc64a9cc..a93915453 100644
--- a/examples/safe-erc20/src/lib.rs
+++ b/examples/safe-erc20/src/lib.rs
@@ -2,14 +2,13 @@
extern crate alloc;
use openzeppelin_stylus::token::erc20::utils::safe_erc20::SafeErc20;
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct SafeErc20Example {
- #[borrow]
- SafeErc20 safe_erc20;
- }
+#[entrypoint]
+#[storage]
+struct SafeErc20Example {
+ #[borrow]
+ pub safe_erc20: SafeErc20,
}
#[public]
diff --git a/examples/vesting-wallet/src/lib.rs b/examples/vesting-wallet/src/lib.rs
index 6e74ebe28..372f2f398 100644
--- a/examples/vesting-wallet/src/lib.rs
+++ b/examples/vesting-wallet/src/lib.rs
@@ -2,14 +2,13 @@
extern crate alloc;
use openzeppelin_stylus::finance::vesting_wallet::VestingWallet;
-use stylus_sdk::prelude::{entrypoint, public, sol_storage};
+use stylus_sdk::prelude::{entrypoint, public, storage};
-sol_storage! {
- #[entrypoint]
- struct VestingWalletExample {
- #[borrow]
- VestingWallet vesting_wallet;
- }
+#[entrypoint]
+#[storage]
+struct VestingWalletExample {
+ #[borrow]
+ pub vesting_wallet: VestingWallet,
}
#[public]
diff --git a/lib/motsu-proc/src/test.rs b/lib/motsu-proc/src/test.rs
index 2e2425d1e..2e88961cd 100644
--- a/lib/motsu-proc/src/test.rs
+++ b/lib/motsu-proc/src/test.rs
@@ -3,7 +3,7 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, FnArg};
-/// Defines a unit test that provides access to Stylus' execution context.
+/// Defines a unit test that provides access to Stylus execution context.
///
/// For more information see [`crate::test`].
pub(crate) fn test(_attr: &TokenStream, input: TokenStream) -> TokenStream {
@@ -21,31 +21,49 @@ pub(crate) fn test(_attr: &TokenStream, input: TokenStream) -> TokenStream {
}
// Whether 1 or none contracts will be declared.
- let contract_declarations = fn_args.into_iter().map(|arg| {
- let FnArg::Typed(arg) = arg else {
- error!(arg, "unexpected receiver argument in test signature");
- };
- let contract_arg_binding = &arg.pat;
- let contract_ty = &arg.ty;
+ let arg_binding_and_ty = match fn_args
+ .into_iter()
+ .map(|arg| {
+ let FnArg::Typed(arg) = arg else {
+ error!(@arg, "unexpected receiver argument in test signature");
+ };
+ let contract_arg_binding = &arg.pat;
+ let contract_ty = &arg.ty;
+ Ok((contract_arg_binding, contract_ty))
+ })
+ .collect::, _>>()
+ {
+ Ok(res) => res,
+ Err(err) => return err.to_compile_error().into(),
+ };
- // Test case assumes, that contract's variable has `&mut` reference
- // to contract's type.
- quote! {
- let mut #contract_arg_binding = <#contract_ty>::default();
- let #contract_arg_binding = &mut #contract_arg_binding;
- }
- });
+ let contract_arg_defs =
+ arg_binding_and_ty.iter().map(|(arg_binding, contract_ty)| {
+ // Test case assumes, that contract's variable has `&mut` reference
+ // to contract's type.
+ quote! {
+ #arg_binding: &mut #contract_ty
+ }
+ });
+
+ let contract_args =
+ arg_binding_and_ty.iter().map(|(_arg_binding, contract_ty)| {
+ // Pass mutable reference to the contract.
+ quote! {
+ &mut <#contract_ty>::default()
+ }
+ });
- // Output full testcase function.
- // Declare contract.
- // And in the end, reset storage for test context.
+ // Declare test case closure.
+ // Pass mut ref to the test closure and call it.
+ // Reset storage for the test context and return test's output.
quote! {
#( #attrs )*
#[test]
fn #fn_name() #fn_return_type {
use ::motsu::prelude::DefaultStorage;
- #( #contract_declarations )*
- let res = #fn_block;
+ let test = | #( #contract_arg_defs ),* | #fn_block;
+ let res = test( #( #contract_args ),* );
::motsu::prelude::Context::current().reset_storage();
res
}
diff --git a/lib/motsu/README.md b/lib/motsu/README.md
index f7e8c074c..3356e2038 100644
--- a/lib/motsu/README.md
+++ b/lib/motsu/README.md
@@ -13,7 +13,8 @@ Annotate tests with `#[motsu::test]` instead of `#[test]` to get access to VM
affordances.
Note that we require contracts to implement `stylus_sdk::prelude::StorageType`.
-This trait is typically implemented by default with `stylus_proc::sol_storage` macro.
+This trait is typically implemented by default with `stylus_proc::sol_storage`
+or `stylus_proc::storage` macros.
```rust
#[cfg(test)]
diff --git a/lib/motsu/src/lib.rs b/lib/motsu/src/lib.rs
index 88eb49707..7636b7541 100644
--- a/lib/motsu/src/lib.rs
+++ b/lib/motsu/src/lib.rs
@@ -14,7 +14,7 @@
//!
//! Note that we require contracts to implement
//! `stylus_sdk::prelude::StorageType`. This trait is typically implemented by
-//! default with `stylus_proc::sol_storage` macro.
+//! default with `stylus_proc::sol_storage` or `stylus_proc::storage` macros.
//!
//! ```rust
//! #[cfg(test)]