Skip to content

Commit 43e6c42

Browse files
authored
Merge pull request #3413 from OffchainLabs/stylus-docs-getting-started
Update Stylus quickstart, intro and troubleshooting
2 parents ba166df + 32e0ad5 commit 43e6c42

3 files changed

Lines changed: 31 additions & 27 deletions

File tree

docs/stylus/gentle-introduction.mdx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Stylus is an upgrade to Arbitrum Nitro [(ArbOS 32)](/run-arbitrum-node/arbos-rel
2424

2525
This second virtual machine executes WebAssembly (WASM) rather than EVM bytecode. WASM is a binary format used in web standards and browsers for efficient computation. Its design is to be portable and human-readable, with sandboxed execution environments for security. Working with WASM is nothing new for Arbitrum chains. Ever since the [Nitro upgrade](https://medium.com/offchainlabs/arbitrum-nitro-one-small-step-for-l2-one-giant-leap-for-ethereum-bc9108047450), WASM has been a fundamental component of Arbitrum's fraud proofs.
2626

27-
With a WASM VM, any programming language compilable to WASM is within Stylus's scope. While many popular programming languages can compile to WASM, some compilers are better suited to smart contract development than others, such as Rust, C, and C++. Other languages like Go, Sway, Move, and Cairo are also supported. Languages that include their own runtimes, like Python and JavaScript, are more complex for Stylus to support, although not impossible. WASM programs tend to be more efficient than EVM bytecode for memory-intensive applications. This efficiency comes from mature compiler toolchains for languages like Rust and C, which have benefited from decades of optimization work. The WASM runtime also executes faster than the EVM interpreter. Third-party contributions in the form of libraries for new and existing languages are welcome.
27+
With a WASM VM, any programming language compilable to WASM is within Stylus's scope. In practice, some compilers are better suited to smart contract development than others. Rust has the first-class, fully supported SDK, and C and C++ are also supported. Any other language that compiles to WASM is theoretically possible, but support for those is experimental rather than officially maintained. Languages that include their own runtimes, like Python and JavaScript, are more complex for Stylus to support, although not impossible. WASM programs tend to be more efficient than EVM bytecode for memory-intensive applications. This efficiency comes from mature compiler toolchains for languages like Rust and C, which have benefited from decades of optimization work. The WASM runtime also executes faster than the EVM interpreter. Third-party contributions in the form of libraries for new and existing languages are welcome.
2828

2929
## How Stylus works
3030

@@ -44,9 +44,11 @@ To make your contract callable, it must undergo an [activation process](/stylus/
4444

4545
Stylus measures computational costs using ink instead of gas. Ink works like gas but is thousands of times smaller. WASM executes faster than the EVM, so a single EVM operation takes as long as thousands of WASM operations. A finer-grained unit makes pricing more precise.
4646

47-
:::note
48-
Stylus contracts need to be reactivated once per year (365 days) or after any Stylus upgrade. You can do this using [`cargo-stylus`](/stylus/cli-tools/commands-reference) or the [ArbWasm precompile](/arbitrum-essentials/precompiles/reference#common-precompiles). If a contract isn't reactivated, it becomes uncallable.
49-
:::
47+
<VanillaAdmonition type="note">
48+
49+
Stylus contracts need to be reactivated once per year (365 days) or after any Stylus upgrade. You can do this using [`cargo-stylus`](/stylus/cli-tools/commands-reference) or the [ArbWasm precompile](/arbitrum-essentials/precompiles/reference#common-precompiles). If a contract isn't reactivated, it becomes uncallable. The 365-day expiry and a minimum age of about 31 days before a contract can be kept alive are both configurable chain parameters; these are the current defaults.
50+
51+
</VanillaAdmonition>
5052

5153
### Execution
5254

docs/stylus/quickstart.mdx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,11 @@ At this point, you can move on to the next step of this guide or develop your fi
154154

155155
By running `cargo stylus check` against your first contract, you can check if your program can be successfully **deployed and activated** onchain.
156156

157-
:::warning Important
157+
<VanillaAdmonition type="warning" title="Important">
158+
158159
Ensure your Docker service runs so this command works correctly.
159-
:::
160+
161+
</VanillaAdmonition>
160162

161163
```shell
162164
cargo stylus check
@@ -285,15 +287,14 @@ Our contract is a counter; in its initial state, it should store a counter value
285287
You can call your contract so it returns its current counter value by sending it the following command:
286288

287289
```shell title="Call to the function: number()(uint256)"
288-
cast call --rpc-url 'http://localhost:8547' --private-key 0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 \
290+
cast call --rpc-url 'http://localhost:8547' \
289291
[deployed-contract-address] "number()(uint256)"
290292
```
291293

292294
Let's break down the command:
293295

294-
- `cast call` command sends a call to your contract
296+
- `cast call` command sends a read-only call to your contract (no transaction is sent, so no private key is needed)
295297
- The `--rpc-url` option is the `RPC URL` endpoint of our testnode: http://localhost:8547
296-
- The `--private-key` option is the private key of our pre-funded development account. It corresponds to the address `0x3f1eae7d46d88f08fc2f8ed27fcb2ab183eb2d0e`
297298
- The [deployed-contract-address] is the address we want to interact with, it's the address that was returned by `cargo stylus deploy`
298299
- `number()(uint256)` is the function we want to call in Solidity-style signature. The function returns the counter's current value
299300

@@ -347,26 +348,24 @@ to test the counter contract:
347348
#[cfg(test)]
348349
mod test {
349350
use super::*;
350-
use alloy_primitives::address;
351351
use stylus_sdk::testing::*;
352352

353353
#[test]
354354
fn test_counter_operations() {
355-
// Set up test environment
355+
// Set up the test VM and instantiate the contract
356356
let vm = TestVM::default();
357-
// Initialize your contract
358357
let mut contract = Counter::from(&vm);
359358

360-
// Test initial state
361-
assert_eq!(contract.number().unwrap(), U256::ZERO);
359+
// Initial state: the counter starts at zero
360+
assert_eq!(contract.number(), U256::ZERO);
362361

363-
// Test increment
364-
contract.increment().unwrap();
365-
assert_eq!(contract.number().unwrap(), U256::from(1));
362+
// increment() updates storage
363+
contract.increment();
364+
assert_eq!(contract.number(), U256::from(1));
366365

367-
// Test set number
368-
contract.set_number(U256::from(5)).unwrap();
369-
assert_eq!(contract.number().unwrap(), U256::from(5));
366+
// set_number() overwrites the stored value
367+
contract.set_number(U256::from(5));
368+
assert_eq!(contract.number(), U256::from(5));
370369
}
371370
}
372371
```

docs/stylus/troubleshooting/common-issues.mdx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,18 @@ strip = true # Remove debug symbols
102102
panic = "abort" # Smaller panic handling
103103
```
104104

105-
2. **Use wasm-opt**:
105+
2. **Run `wasm-opt` on the compiled binary**:
106106

107107
```shell
108-
cargo stylus check --wasm-opt
108+
wasm-opt -Oz target/wasm32-unknown-unknown/release/your_contract.wasm \
109+
-o optimized.wasm
109110
```
110111

111112
3. **Remove unused dependencies**:
112113

113114
```toml
114115
# Remove unnecessary features
115-
stylus-sdk = { version = "0.8", default-features = false }
116+
stylus-sdk = { version = "0.10.7", default-features = false }
116117
```
117118

118119
4. **Check binary size**:
@@ -259,7 +260,9 @@ pub fn divide(&self, a: U256, b: U256) -> U256 {
259260

260261
// ✅ Good: Returns error
261262
pub fn divide(&self, a: U256, b: U256) -> Result<U256, Vec<u8>> {
262-
ensure!(!b.is_zero(), "Division by zero");
263+
if b.is_zero() {
264+
return Err(b"Division by zero".to_vec());
265+
}
263266
Ok(a / b)
264267
}
265268
```
@@ -363,7 +366,7 @@ mod tests {
363366
let mut contract = MyContract::from(&vm);
364367

365368
// Configure test environment
366-
vm.set_caller(address!("0x0000000000000000000000000000000000000001"));
369+
vm.set_sender(address!("0x0000000000000000000000000000000000000001"));
367370

368371
// Run tests
369372
assert_eq!(contract.get_value().unwrap(), U256::ZERO);
@@ -580,12 +583,12 @@ Include:
580583
| ------------------------------------------ | ------------------------- | ------------------------------------------ |
581584
| "target not found: wasm32-unknown-unknown" | WASM target not installed | `rustup target add wasm32-unknown-unknown` |
582585
| "Cannot connect to Docker daemon" | Docker not running | Start Docker Desktop |
583-
| "Program too large" | Binary exceeds size limit | Add optimization flags, use `--wasm-opt` |
586+
| "Program too large" | Binary exceeds size limit | Add optimization flags, run `wasm-opt` |
584587
| "Insufficient funds" | Not enough ETH for gas | Fund account from faucet |
585588
| "Nonce too low" | Nonce mismatch | Let tooling manage nonces |
586589
| "Out of gas" | Gas limit exceeded | Increase gas limit or optimize code |
587590
| "Storage not initialized" | Missing TestVM setup | Initialize `TestVM::default()` in tests |
588-
| "Division by zero" | Unchecked arithmetic | Use `ensure!()` or `checked_div()` |
591+
| "Division by zero" | Unchecked arithmetic | Return an error or use `checked_div()` |
589592

590593
## Next steps
591594

0 commit comments

Comments
 (0)