Skip to content

Releases: OffchainLabs/stylus-sdk-rs

Stylus SDK 0.4.3

23 Feb 19:22
bf26cb5
Compare
Choose a tag to compare

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

28 Nov 21:00
d5d2f61
Compare
Choose a tag to compare

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

17 Sep 22:02
6045222
Compare
Choose a tag to compare

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

12 Sep 00:29
f3d8d9d
Compare
Choose a tag to compare

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

07 Sep 19:32
74df668
Compare
Choose a tag to compare

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

07 Sep 00:38
af88573
Compare
Choose a tag to compare

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

06 Sep 21:22
749a709
Compare
Choose a tag to compare

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

01 Sep 23:29
3e8693c
Compare
Choose a tag to compare

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

31 Aug 12:17
Compare
Choose a tag to compare

Initial release of the Stylus SDK.