Arbitrum Stylus logo

Stylus by Example

VM affordances

The Stylus Rust SDK contains several modules for interacting with the Virtual Machine (VM), which can be imported from stylus_sdk.

Let's see an example:

1use stylus_sdk::{msg};
2
3let callvalue = msg::value();
1use stylus_sdk::{msg};
2
3let callvalue = msg::value();

This page lists the modules that are available, as well as the methods within those modules.

block

Allows you to inspect the current block:

  • basefee: gets the basefee of the current block
  • chainid: gets the unique chain identifier of the Arbitrum chain
  • coinbase: gets the coinbase of the current block, which on Arbitrum chains is the L1 batch poster's address
  • gas_limit: gets the gas limit of the current block
  • number: gets a bounded estimate of the L1 block number at which the sequencer sequenced the transaction. See Block gas limit, numbers and time for more information on how this value is determined
  • timestamp: gets a bounded estimate of the Unix timestamp at which the sequencer sequenced the transaction. See Block gas limit, numbers and time for more information on how this value is determined
1use stylus_sdk::{block};
2
3let basefee = block::basefee();
4let chainid = block::chainid();
5let coinbase = block::coinbase();
6let gas_limit = block::gas_limit();
7let number = block::number();
8let timestamp = block::timestamp();
1use stylus_sdk::{block};
2
3let basefee = block::basefee();
4let chainid = block::chainid();
5let coinbase = block::coinbase();
6let gas_limit = block::gas_limit();
7let number = block::number();
8let timestamp = block::timestamp();

contract

Allows you to inspect the contract itself:

  • address: gets the address of the current program
  • args: reads the invocation's calldata. The entrypoint macro uses this under the hood
  • balance: gets the balance of the current program
  • output: writes the contract's return data. The entrypoint macro uses this under the hood
  • read_return_data: copies the bytes of the last EVM call or deployment return result. Note: this function does not revert if out of bounds, but rather will copy the overlapping portion
  • return_data_len: returns the length of the last EVM call or deployment return result, or 0 if neither have happened during the program's execution
1use stylus_sdk::{contract};
2
3let address = contract::address();
4contract::args();
5let balance = contract::balance();
6contract::output();
7contract::read_return_data();
8contract::return_data_len();
1use stylus_sdk::{contract};
2
3let address = contract::address();
4contract::args();
5let balance = contract::balance();
6contract::output();
7contract::read_return_data();
8contract::return_data_len();

crypto

Allows you to access VM-accelerated cryptographic functions:

  • keccak: efficiently computes the keccak256 hash of the given preimage
1use stylus_sdk::{crypto};
2use stylus_sdk::alloy_primitives::address;
3
4let preimage = address!("361594F5429D23ECE0A88E4fBE529E1c49D524d8");
5let hash = crypto::keccak(&preimage);
1use stylus_sdk::{crypto};
2use stylus_sdk::alloy_primitives::address;
3
4let preimage = address!("361594F5429D23ECE0A88E4fBE529E1c49D524d8");
5let hash = crypto::keccak(&preimage);

evm

Allows you to access affordances for the Ethereum Virtual Machine:

  • gas_left: gets the amount of gas remaining. See Ink and Gas for more information on Stylus's compute pricing
  • ink_left: gets the amount of ink remaining. See Ink and Gas for more information on Stylus's compute pricing
  • log: emits a typed alloy log
  • pay_for_memory_grow: this function exists to force the compiler to import this symbol. Calling it will unproductively consume gas
  • raw_log: emits an EVM log from its raw topics and data. Most users should prefer the alloy-typed raw_log
1use stylus_sdk::{evm};
2
3let gas_left = evm::gas_left();
4let ink_left = evm::ink_left();
5evm::log(...);
6evm::pay_for_memory_grow();
7evm::raw_log(...);
1use stylus_sdk::{evm};
2
3let gas_left = evm::gas_left();
4let ink_left = evm::ink_left();
5evm::log(...);
6evm::pay_for_memory_grow();
7evm::raw_log(...);

Here's an example of how to emit a Transfer log:

1sol! {
2    event Transfer(address indexed from, address indexed to, uint256 value);
3    event Approval(address indexed owner, address indexed spender, uint256 value);
4}
5
6fn foo() {
7   ...
8   evm::log(Transfer {
9      from: Address::ZERO,
10      to: address,
11      value,
12   });
13}
1sol! {
2    event Transfer(address indexed from, address indexed to, uint256 value);
3    event Approval(address indexed owner, address indexed spender, uint256 value);
4}
5
6fn foo() {
7   ...
8   evm::log(Transfer {
9      from: Address::ZERO,
10      to: address,
11      value,
12   });
13}

msg

Allows you to inspect the current call

  • reentrant: whether the current call is reentrant
  • sender: gets the address of the account that called the program. For normal L2-to-L2 transactions the semantics are equivalent to that of the EVM's CALLER opcode, including in cases arising from DELEGATE_CALL
  • value: gets the ETH value in wei sent to the program
1use stylus_sdk::{msg};
2
3let reentrant = msg::reentrant();
4let sender = msg::sender();
5let value = msg::value();
1use stylus_sdk::{msg};
2
3let reentrant = msg::reentrant();
4let sender = msg::sender();
5let value = msg::value();

tx

Allows you to inspect the current transaction

  • gas_price: gets the gas price in wei per gas, which on Arbitrum chains equals the basefee
  • gas_to_ink: converts evm gas to ink. See Ink and Gas for more information on Stylus's compute-pricing model
  • ink_price: gets the price of ink in evm gas basis points. See Ink and Gas for more information on Stylus's compute-pricing model
  • ink_to_gas: converts ink to evm gas. See Ink and Gas for more information on Stylus's compute-pricing model
  • origin: gets the top-level sender of the transaction. The semantics are equivalent to that of the EVM's ORIGIN opcode
1use stylus_sdk::{tx};
2
3let gas_price = tx::gas_price();
4let gas_to_ink = tx::gas_to_ink();
5let ink_price = tx::ink_price();
6let ink_to_gas = tx::ink_to_gas();
7let origin = tx::origin();
1use stylus_sdk::{tx};
2
3let gas_price = tx::gas_price();
4let gas_to_ink = tx::gas_to_ink();
5let ink_price = tx::ink_price();
6let ink_to_gas = tx::ink_to_gas();
7let origin = tx::origin();

Learn More