Releases: OffchainLabs/stylus-sdk-rs
Stylus SDK 0.6.0
0.6.0 - 2024-08-30
This release contains bugfixes, some breaking changes, and general updates. This is the recommended release for usage at the time of the Stylus release on Arbitrum mainnet.
Breaking Changes
#[selector(id = ...)]
syntax has been removed to avoid misleading contracts
from being implemented.- Several methods in
RawDeploy
which were not fully implemented yet #[pure]
,#[view]
and#[write]
attributes have been removed in favor of
using arguments to infer state mutability.stylus-sdk
now ships withmini-alloc
enabled by default. This means that
a#[global_allocator]
should not be declared in most cases. If a custom
allocator is still needed themini-alloc
should be disabled (enabled by
default).StorageU1
andStorageI1
types have been removed.
Deprecated
- The
#[external]
macro is now deprecated in favor of#[public]
which
provides the same functionality. - The
#[solidity_storage]
macro is now deprecated in favor of#[storage]
which provides the same functionality.
Changed
- Ensure consistency between proc macros when parsing attributes.
- Update
sol_interface!
macro to report errors when using Solidity features
which have not yet been implemented.
Fixed
- Properly encode bytes when calling external contracts.
- Properly encode Bytes and strings in return types.
- Bytes type now works properly in
export-abi
. export-abi
now works for contracts with no functions with returned values.- Off-by-one error when storing strings with length 32.
- Interfaces in
sol_interface!
no longer incorrectly inherit functions from
previous definitions.
Documentation
- Various documentation updates for clarity.
- Cleaned up typos and moved TODOs to the github issue tracker.
Security
- Function signatures which generate the same selector values will now fail
at compile-time to avoid misleading contract calls.
Stylus SDK 0.4.3
This release introduces two quality of life improvements around error handling to the Stylus SDK.
Infallible Methods
External methods may now be infallible. That is, you don't have to write Result
and Ok
unless the code returns an error.
#[external]
impl Counter {
pub fn number(&self) -> U256 {
self.number.get()
}
}
[derive(SolidityError)]
The derive(SolidityError)
macro simplifies the error declaration process.
sol! {
error InsufficientBalance(address from, uint256 have, uint256 want);
error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want);
}
#[derive(SolidityError)]
pub enum Erc20Error {
InsufficientBalance(InsufficientBalance),
InsufficientAllowance(InsufficientAllowance),
}
#[external]
impl Contract {
pub fn fallible_method() -> Result<(), Erc20Error> {
// code that might revert
}
}
The above is abi-compatible with Solidity and will auto-generate interface types.
cargo stylus export-abi
interface IContract {
function fallibleMethod() external;
error InsufficientBalance(address, uint256, uint256);
error InsufficientAllowance(address, address, uint256, uint256);
}
Stylus SDK 0.4.2
This release patches a bug in call::delegate_call
so that it no longer performs normal EVM calls.
RawCall::new_delegate
was unaffected.
Stylus SDK 0.4.1
This release introduces new features and fixes to the Stylus SDK. We've bumped the major version number due to minor backwards-incompatible changes. To adopt the latest version, edit your Cargo.toml
as follows
stylus-sdk = "0.4.1"
Check if address has code
The AddressVM
trait from the prelude
has a new method, has_code
, for detecting if an account has code.
use stylus-sdk::{prelude::*, contract, alloy_primitives::address};
let arbinaut = address!(361594F5429D23ECE0A88E4fBE529E1c49D524d8);
assert!(!arbinaut.has_code());
assert!(contract::address().has_code())
Note that this is insufficient to determine if an address is an EOA. During contract deployment, an account only gets its code at the very end, meaning that this method will return false
while the constructor is executing.
As part of this change, we've updated the method signature of Address::codehash
to return a B256
instead of an Option
. Previously the Option
was supposed to be None
if the account was not a contract. Splitting this out into two methods is a more sensible API.
Configurable Selectors
You may now override method selectors.
impl Contract {
#[selector(name = "otherName")]
pub fn renamed() {
...
}
#[selector(id = "otherFunc(uint64)")]
pub fn other_selector(value: U64) {
...
}
#[selector(id = 0xba5eba11)]
pub fn exact_selector() {
...
}
}
The above will now export
/**
* This file was automatically generated by Stylus and represents a Rust program.
* For more information, please see [The Stylus SDK](https://github.com/OffchainLabs/stylus-sdk-rs).
*/
interface IContract {
function otherName() external pure;
// note: selector was overridden to be 0x7cc01843.
function otherSelector(uint64 value) external pure;
// note: selector was overridden to be 0xba5eba11.
function exactSelector() external pure;
}
Reentrancy Changes
Because Call::new
is never correct in reentrant code, the reentrant
feature flag removes it. This shouldn't affect existing contracts since reentrant calls instead use Call::new_in
.
Stylus SDK 0.3.0
This release introduces large improvements to the Stylus SDK. We've bumped the major version number due to minor backwards-incompatible changes. To adopt the latest version, edit your Cargo.toml
as follows
stylus-sdk = "0.3.0"
Call Other Contracts
The sol_interface!
macro and new Call
type make writing calls to other contracts much easier.
sol_interface! {
interface IService {
function makePayment(address user) payable returns (string);
function getConstant() pure returns (bytes32)
}
interface ITree {
// other interface methods
}
}
The above will define IService
and ITree
for calling the methods of the two contracts.
For example, IService
will have a make_payment
method that accepts an Address
and returns a B256
.
pub fn do_call(account: IService, user: Address) -> Result<String, Error> {
let config = Call::new()
.gas(evm::gas_left() / 2) // limit to half the gas left
.value(msg::value()); // set the callvalue
account.make_payment(config, user) // note the snake case
}
Observe the casing change. sol_interface!
computes the selector based on the exact name passed in, which should almost always be CamelCase
. For aesthetics, the rust functions will instead use snake_case
.
Direct Delegate Call
Doing delegate calls have always been possible, but for added flexibility the new delegate_call
method makes this easier in certain circumstances.
Additional methods exist for calls, static calls, and transfer eth too.
New reentrant
Feature Flag
Most users won't want reentrancy. For this reason we've moved most methods behind the new reentrant
flag. The SDK will always support them and provide protection via the Rust type system, but when disabled certain features become nicer.
In particular, various methods like RawCall::call
that would be unsafe
no longer are. Additionally, the new Call
type will exist for making safe calls in any context.
Fully #[no_std]
The Stylus SDK is now fully #[no_std]
compatible. You can opt-into this in your contract by adding
#![cfg_attr(not(feature = "export-abi"), no_main, no_std)]
100% docs.rs
The Stylus SDK is now fully documented on docs.rs. This includes all types, modules, and macros, including with code examples.
Stylus SDK 0.2.4
This backwards-compatible patch introduces new features, improved documentation, and minor bug fixes.
Import Raw Host I/Os
Using the new hostio
feature flag, users may import the hostio
module for direct access to the VM.
This allows users to opt out of Alloy and other large imports.
use stylus_sdk::hostio;
use stylus_sdk::{alloy_primitives::Address, msg};
let mut sender = Address::ZERO;
unsafe {
hostio::msg_sender(sender.as_mut_ptr());
}
assert_eq!(sender, msg::sender());
Stylus SDK 0.2.2
This backwards-compatible patch release makes documentation improvements, along with one minor feature addition.
StorageKey
You can now implement custom keys for mappings.
impl StorageKey for Key {
fn to_slot(&self, root: B256) -> U256 {
// return a slot
}
}
The above then enables
sol_storage! {
mapping(Key => Value) map; // in solidity
}
#[solidity_storage]
pub struct Contract {
map: StorageMap<Key, Value>, // or in Rust
}
Stylus SDK 0.2.1
This patch includes backward-compatible changes introducing new features.
Fixed Storage Arrays
You may now use fixed-length storage arrays when declaring contract storage.
pub struct Arrays {
string[4] strings;
uint8[2][4] matrix;
int96[4][] vector;
int96[][4] vectors;
Struct[3] structs;
}
Eager Storage Access
You may now opt-out of Stylus's optimal storage-caching algo by disabling the default storage-cache
feature like so.
stylus-sdk = { version = "0.2.1", default-features = false }
This will replace the StorageCache
type with EagerStorage
, which has identical methods but doesn't employ caching. Most users won't want to do this, but it may help in shrinking binary sizes or hand-optimizing.
Host I/O Caching
Repeated access to EVM affordances is now cheaper due to caching. This means msg::value
and similar may be called more than once without paying VM costs.
Cache management for RawCall and RawDeploy
RawCall
and RawDeploy
have new methods for managing the storage cache.
let data = RawCall::new_delegate() // configure a delegate call
.gas(2100) // supply 2100 gas
.limit_return_data(0, 32) // only read the first 32 bytes back
.flush_storage_cache() // flush the storage cache before the call
.call(contract, calldata)?; // do the call
Stylus SDK 0.2.0
This release makes a few improvements based on community feedback. You can upgrade to this release by changing the following in your Cargo.toml
stylus-sdk = "0.2.0"
Alloy FixedBytes
abi::FixedBytes
has been removed in favor of Alloy's FixedBytes. This makes the following much more intuitive
pub fn root(&self) -> Result<B256, Vec<u8>> {
Ok(self.root.get().into())
}
EVM affordances now return better types
Some EVM affordances, like block::basefee
returned B256
. Those likely to be used in math now return U256
.
Interface fixes
Importing interface methods with empty args or methods that are write
caused compile errors. These have now been fixed.
sol_interface! {
interface IClass {
function empty_args();
function write_method(bytes32);
}
}
Stylus SDK 0.1.0
Initial release of the Stylus SDK.