diff --git a/CHANGELOG.md b/CHANGELOG.md index bd5749f7..17ab68dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implement `AddAssignUnchecked` and `SubAssignUnchecked` for `StorageUint`. #418 - Implement `MethodError` for `safe_erc20::Error`. #402 - Use `function_selector!` to calculate transfer type selector in `Erc1155`. #417 -- Update internal functions of `Erc721` and `Erc721Consecutive` accept reference to `Bytes`. #437 + +### Changed (Breaking) + +- Update internal functions of `Erc721` and `Erc721Consecutive` to accept a reference to `Bytes`. #437 +- Stop supporting reentrancy, and borrow `self` immutably in `IErc721::_check_on_erc721_received`. #440 +- Remove `&mut self` parameter from `IErc1155::_check_on_erc1155_received` and make it an associated function. #440 +- Remove `storage: &mut impl TopLevelStorage` parameter from `ecdsa::recover`. #440 +- Remove `TopLevelStorage` trait implementation from `VestingWallet`, `Erc1155`, `Erc20Permit`, `SafeErc20`, `Erc721Consecutive`, and `Erc721`. #440 ### Fixed diff --git a/contracts/src/finance/vesting_wallet.rs b/contracts/src/finance/vesting_wallet.rs index e065c7b7..3cbd55c4 100644 --- a/contracts/src/finance/vesting_wallet.rs +++ b/contracts/src/finance/vesting_wallet.rs @@ -33,7 +33,7 @@ use stylus_sdk::{ call::{self, call, Call}, contract, evm, function_selector, prelude::storage, - storage::{StorageMap, StorageU256, StorageU64, TopLevelStorage}, + storage::{StorageMap, StorageU256, StorageU64}, stylus_proc::{public, SolidityError}, }; @@ -118,11 +118,6 @@ pub struct VestingWallet { pub safe_erc20: SafeErc20, } -/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when -/// calling other contracts and not `&mut (impl TopLevelStorage + -/// BorrowMut)`. Should be fixed in the future by the Stylus team. -unsafe impl TopLevelStorage for VestingWallet {} - /// Required interface of a [`VestingWallet`] compliant contract. #[interface_id] pub trait IVestingWallet { @@ -426,7 +421,7 @@ impl IVestingWallet for VestingWallet { let owner = self.ownable.owner(); - call(Call::new_in(self).value(amount), owner, &[])?; + call(Call::new().value(amount), owner, &[])?; evm::log(EtherReleased { amount }); diff --git a/contracts/src/token/erc1155/extensions/supply.rs b/contracts/src/token/erc1155/extensions/supply.rs index 80e9fd61..6efbbf93 100644 --- a/contracts/src/token/erc1155/extensions/supply.rs +++ b/contracts/src/token/erc1155/extensions/supply.rs @@ -279,7 +279,7 @@ impl Erc1155Supply { self._update(from, to, ids.clone(), values.clone())?; if !to.is_zero() { - self.erc1155._check_on_erc1155_received( + Erc1155::_check_on_erc1155_received( msg::sender(), from, to, diff --git a/contracts/src/token/erc1155/extensions/uri_storage.rs b/contracts/src/token/erc1155/extensions/uri_storage.rs index 442c260f..cc510039 100644 --- a/contracts/src/token/erc1155/extensions/uri_storage.rs +++ b/contracts/src/token/erc1155/extensions/uri_storage.rs @@ -94,7 +94,7 @@ mod tests { use stylus_sdk::prelude::storage; use super::Erc1155UriStorage; - use crate::token::erc1155::{extensions::Erc1155MetadataUri, Erc1155}; + use crate::token::erc1155::extensions::Erc1155MetadataUri; fn random_token_id() -> U256 { let num: u32 = rand::random(); diff --git a/contracts/src/token/erc1155/mod.rs b/contracts/src/token/erc1155/mod.rs index c0dd5dcf..5a0e1c76 100644 --- a/contracts/src/token/erc1155/mod.rs +++ b/contracts/src/token/erc1155/mod.rs @@ -8,7 +8,7 @@ use stylus_sdk::{ call::{self, Call, MethodError}, evm, function_selector, msg, prelude::{public, storage, AddressVM, SolidityError}, - storage::{StorageBool, StorageMap, StorageU256, TopLevelStorage}, + storage::{StorageBool, StorageMap, StorageU256}, }; use crate::utils::{ @@ -194,11 +194,6 @@ pub struct Erc1155 { StorageMap>, } -/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when -/// calling other contracts and not `&mut (impl TopLevelStorage + -/// BorrowMut)`. Should be fixed in the future by the Stylus team. -unsafe impl TopLevelStorage for Erc1155 {} - /// Required interface of an [`Erc1155`] compliant contract. #[interface_id] pub trait IErc1155 { @@ -562,7 +557,7 @@ impl Erc1155 { self._update(from, to, ids.clone(), values.clone())?; if !to.is_zero() { - self._check_on_erc1155_received( + Erc1155::_check_on_erc1155_received( msg::sender(), from, to, @@ -772,7 +767,6 @@ impl Erc1155 { /// /// # Arguments /// - /// * `&mut self` - Write access to the contract's state. /// * `operator` - Generally the address that initiated the token transfer /// (e.g. `msg::sender()`). /// * `from` - Account of the sender. @@ -791,7 +785,6 @@ impl Erc1155 { /// interface id or returned with error, then the error /// [`Error::InvalidReceiver`] is returned. fn _check_on_erc1155_received( - &mut self, operator: Address, from: Address, to: Address, @@ -803,7 +796,7 @@ impl Erc1155 { } let receiver = IERC1155Receiver::new(to); - let call = Call::new_in(self); + let call = Call::new(); let result = match details.transfer { Transfer::Single { id, value } => receiver .on_erc_1155_received(call, operator, from, id, value, data), diff --git a/contracts/src/token/erc20/extensions/permit.rs b/contracts/src/token/erc20/extensions/permit.rs index 28d7bcf4..2135b2a5 100644 --- a/contracts/src/token/erc20/extensions/permit.rs +++ b/contracts/src/token/erc20/extensions/permit.rs @@ -17,7 +17,6 @@ use alloy_sol_types::SolType; use stylus_sdk::{ block, prelude::{storage, StorageType}, - storage::TopLevelStorage, stylus_proc::{public, SolidityError}, }; @@ -82,11 +81,6 @@ pub struct Erc20Permit { pub eip712: T, } -/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when -/// calling other contracts and not `&mut (impl TopLevelStorage + -/// BorrowMut)`. Should be fixed in the future by the Stylus team. -unsafe impl TopLevelStorage for Erc20Permit {} - #[public] impl Erc20Permit { /// Returns the current nonce for `owner`. @@ -177,7 +171,7 @@ impl Erc20Permit { let hash: B256 = self.eip712.hash_typed_data_v4(struct_hash); - let signer: Address = ecdsa::recover(self, hash, v, r, s)?; + let signer: Address = ecdsa::recover(hash, v, r, s)?; if signer != owner { return Err(ERC2612InvalidSigner { signer, owner }.into()); diff --git a/contracts/src/token/erc20/utils/safe_erc20.rs b/contracts/src/token/erc20/utils/safe_erc20.rs index 20bb84e9..1bb611e7 100644 --- a/contracts/src/token/erc20/utils/safe_erc20.rs +++ b/contracts/src/token/erc20/utils/safe_erc20.rs @@ -18,7 +18,6 @@ use stylus_sdk::{ evm::gas_left, function_selector, prelude::storage, - storage::TopLevelStorage, stylus_proc::{public, SolidityError}, types::AddressVM, }; @@ -88,11 +87,6 @@ mod token { #[storage] pub struct SafeErc20 {} -/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when -/// calling other contracts and not `&mut (impl TopLevelStorage + -/// BorrowMut)`. Should be fixed in the future by the Stylus team. -unsafe impl TopLevelStorage for SafeErc20 {} - /// Required interface of a [`SafeErc20`] utility contract. pub trait ISafeErc20 { /// The error type associated to this trait implementation. diff --git a/contracts/src/token/erc721/extensions/consecutive.rs b/contracts/src/token/erc721/extensions/consecutive.rs index c0c458fa..a1297b32 100644 --- a/contracts/src/token/erc721/extensions/consecutive.rs +++ b/contracts/src/token/erc721/extensions/consecutive.rs @@ -30,7 +30,7 @@ use alloy_primitives::{uint, Address, U256}; use stylus_sdk::{ abi::Bytes, evm, msg, - prelude::{storage, TopLevelStorage}, + prelude::storage, stylus_proc::{public, SolidityError}, }; @@ -140,8 +140,6 @@ pub enum Error { ForbiddenBatchBurn(ERC721ForbiddenBatchBurn), } -unsafe impl TopLevelStorage for Erc721Consecutive {} - // ************** ERC-721 External ************** #[public] diff --git a/contracts/src/token/erc721/mod.rs b/contracts/src/token/erc721/mod.rs index 2747366c..917bf5d1 100644 --- a/contracts/src/token/erc721/mod.rs +++ b/contracts/src/token/erc721/mod.rs @@ -207,11 +207,6 @@ pub struct Erc721 { StorageMap>, } -/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when -/// calling other contracts and not `&mut (impl TopLevelStorage + -/// BorrowMut)`. Should be fixed in the future by the Stylus team. -unsafe impl TopLevelStorage for Erc721 {} - /// Required interface of an [`Erc721`] compliant contract. #[interface_id] pub trait IErc721 { @@ -1104,7 +1099,7 @@ impl Erc721 { /// /// # Arguments /// - /// * `&mut self` - Write access to the contract's state. + /// * `&self` - Read access to the contract's state. /// * `operator` - Account to add to the set of authorized operators. /// * `from` - Account of the sender. /// * `to` - Account of the recipient. @@ -1118,7 +1113,7 @@ impl Erc721 { /// interface id or returned with error, then the error /// [`Error::InvalidReceiver`] is returned. pub fn _check_on_erc721_received( - &mut self, + &self, operator: Address, from: Address, to: Address, @@ -1130,7 +1125,7 @@ impl Erc721 { } let receiver = IERC721Receiver::new(to); - let call = Call::new_in(self); + let call = Call::new(); let result = receiver.on_erc_721_received( call, operator, diff --git a/contracts/src/utils/cryptography/ecdsa.rs b/contracts/src/utils/cryptography/ecdsa.rs index 5f8c6bf6..9830defc 100644 --- a/contracts/src/utils/cryptography/ecdsa.rs +++ b/contracts/src/utils/cryptography/ecdsa.rs @@ -8,7 +8,6 @@ use alloy_primitives::{address, uint, Address, B256, U256}; use alloy_sol_types::SolType; use stylus_sdk::{ call::{self, Call, MethodError}, - storage::TopLevelStorage, stylus_proc::SolidityError, }; @@ -77,7 +76,6 @@ impl MethodError for ecdsa::Error { /// /// # Arguments /// -/// * `storage` - Write access to storage. /// * `hash` - Hash of the message. /// * `v` - `v` value from the signature. /// * `r` - `r` value from the signature. @@ -93,16 +91,10 @@ impl MethodError for ecdsa::Error { /// # Panics /// /// * If the `ecrecover` precompile fails to execute. -pub fn recover( - storage: &mut impl TopLevelStorage, - hash: B256, - v: u8, - r: B256, - s: B256, -) -> Result { +pub fn recover(hash: B256, v: u8, r: B256, s: B256) -> Result { check_if_malleable(&s)?; // If the signature is valid (and not malleable), return the signer address. - _recover(storage, hash, v, r, s) + _recover(hash, v, r, s) } /// Calls `ecrecover` EVM precompile. @@ -112,7 +104,6 @@ pub fn recover( /// /// # Arguments /// -/// * `storage` - Write access to storage. /// * `hash` - Hash of the message. /// * `v` - `v` value from the signature. /// * `r` - `r` value from the signature. @@ -128,13 +119,7 @@ pub fn recover( /// # Panics /// /// * If the `ecrecover` precompile fails to execute. -fn _recover( - storage: &mut impl TopLevelStorage, - hash: B256, - v: u8, - r: B256, - s: B256, -) -> Result { +fn _recover(hash: B256, v: u8, r: B256, s: B256) -> Result { let calldata = encode_calldata(hash, v, r, s); if v == 0 || v == 1 { @@ -145,9 +130,8 @@ fn _recover( return Err(ECDSAInvalidSignature {}.into()); } - let recovered = - call::static_call(Call::new_in(storage), ECRECOVER_ADDR, &calldata) - .expect("should call `ecrecover` precompile"); + let recovered = call::static_call(Call::new(), ECRECOVER_ADDR, &calldata) + .expect("should call `ecrecover` precompile"); let recovered = Address::from_slice(&recovered[12..]); diff --git a/examples/ecdsa/src/lib.rs b/examples/ecdsa/src/lib.rs index f94e0a5d..3c4fb31c 100644 --- a/examples/ecdsa/src/lib.rs +++ b/examples/ecdsa/src/lib.rs @@ -20,7 +20,7 @@ impl ECDSAExample { r: B256, s: B256, ) -> Result> { - let signer = ecdsa::recover(self, hash, v, r, s)?; + let signer = ecdsa::recover(hash, v, r, s)?; Ok(signer) } } diff --git a/lib/motsu/README.md b/lib/motsu/README.md index 3356e203..f7f10674 100644 --- a/lib/motsu/README.md +++ b/lib/motsu/README.md @@ -13,7 +13,7 @@ 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` +This trait is typically implemented by default with `stylus_proc::sol_storage` or `stylus_proc::storage` macros. ```rust