The Stylus Rust SDK provides a way to define state variables that are stored on the blockchain, similar but not the same to how state variables work in Solidity. These variables persist across contract calls and represent the contract's persistent storage. In Stylus, you define these storage variables within a struct annotated with #[storage].
In summary, state variables in the Stylus Rust SDK have the following types:
StorageBoolStorageAddressStorageUintStorageSignedStorageFixedBytesStorageVecStorageStringStorageBytesStorageMapStorageArrayStorageString is essentially a wrapper around StorageBytes, providing convenient methods for working with UTF-8 encoded strings.
StorageMap and StorageArray will be discussed in separate sections due to their more complex nature. So this section focuses on the first 8 types.
1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4use stylus_sdk::{
5 prelude::*,
6 alloy_primitives::{I256, U256, Address, FixedBytes},
7 storage::*,
8};
9
10#[storage]
11#[entrypoint]
12pub struct Data {
13 my_bool: StorageBool,
14 my_address: StorageAddress,
15 my_uint: StorageU256,
16 my_signed: StorageI256,
17 my_fixed_bytes: StorageFixedBytes<4>,
18 my_bytes: StorageBytes,
19 my_string: StorageString,
20 my_vec: StorageVec<StorageU256>,
21}
22
23#[public]
24impl Data {
25 //... (Getters and Setters as shown below)
26}1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4use stylus_sdk::{
5 prelude::*,
6 alloy_primitives::{I256, U256, Address, FixedBytes},
7 storage::*,
8};
9
10#[storage]
11#[entrypoint]
12pub struct Data {
13 my_bool: StorageBool,
14 my_address: StorageAddress,
15 my_uint: StorageU256,
16 my_signed: StorageI256,
17 my_fixed_bytes: StorageFixedBytes<4>,
18 my_bytes: StorageBytes,
19 my_string: StorageString,
20 my_vec: StorageVec<StorageU256>,
21}
22
23#[public]
24impl Data {
25 //... (Getters and Setters as shown below)
26}The #[storage] attribute on the Data struct tells Stylus that the fields within this struct represent the contract's state storage.
StorageBool stores a boolean value (true or false).
1//... inside the #[public] impl Data block
2
3 pub fn get_bool(&self) -> bool {
4 self.my_bool.get()
5 }
6
7 pub fn set_bool(&mut self, value: bool) {
8 self.my_bool.set(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_bool(&self) -> bool {
4 self.my_bool.get()
5 }
6
7 pub fn set_bool(&mut self, value: bool) {
8 self.my_bool.set(value);
9 }StorageAddress stores an Ethereum address (alloy_primitives::Address).
1//... inside the #[public] impl Data block
2
3 pub fn get_address(&self) -> Address {
4 self.my_address.get()
5 }
6
7 pub fn set_address(&mut self, value: Address) {
8 self.my_address.set(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_address(&self) -> Address {
4 self.my_address.get()
5 }
6
7 pub fn set_address(&mut self, value: Address) {
8 self.my_address.set(value);
9 }StorageU256 stores an unsigned 256-bit integer (alloy_primitives::U256).
1//... inside the #[public] impl Data block
2
3 pub fn get_uint(&self) -> U256 {
4 self.my_uint.get()
5 }
6
7 pub fn set_uint(&mut self, value: U256) {
8 self.my_uint.set(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_uint(&self) -> U256 {
4 self.my_uint.get()
5 }
6
7 pub fn set_uint(&mut self, value: U256) {
8 self.my_uint.set(value);
9 }StorageU256 is an alias of StorageUint, you can also define StorageU128 or other byte length uint.
StorageI256 stores a signed 256-bit integer (alloy_primitives::I256).
1//... inside the #[public] impl Data block
2
3 pub fn get_signed(&self) -> I256 {
4 self.my_signed.get()
5 }
6
7 pub fn set_signed(&mut self, value: I256) {
8 self.my_signed.set(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_signed(&self) -> I256 {
4 self.my_signed.get()
5 }
6
7 pub fn set_signed(&mut self, value: I256) {
8 self.my_signed.set(value);
9 }StorageI256 is an alias of StorageSigned, you can also define StorageI128 or other byte length int.
StorageFixedBytes<N> stores a fixed-size byte array of N bytes (alloy_primitives::FixedBytes<N>).
1//... inside the #[public] impl Data block
2
3 pub fn get_fixed_bytes(&self) -> FixedBytes<4> {
4 self.my_fixed_bytes.get()
5 }
6
7 pub fn set_fixed_bytes(&mut self, value: FixedBytes<4>) {
8 self.my_fixed_bytes.set(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_fixed_bytes(&self) -> FixedBytes<4> {
4 self.my_fixed_bytes.get()
5 }
6
7 pub fn set_fixed_bytes(&mut self, value: FixedBytes<4>) {
8 self.my_fixed_bytes.set(value);
9 }StorageBytes stores a dynamic byte array (Vec<u8>).
1//... inside the #[public] impl Data block
2
3 pub fn get_bytes(&self) -> Vec<u8> {
4 self.my_bytes.get_bytes()
5 }
6
7 pub fn get_byte_from_bytes(&self, index: U256) -> u8 {
8 self.my_bytes.get(index).unwrap()
9 }
10
11 pub fn set_bytes(&mut self, value: Vec<u8>) {
12 self.my_bytes.set_bytes(value);
13 }
14
15 pub fn push_byte_to_bytes(&mut self, value: u8) {
16 self.my_bytes.push(value);
17 }1//... inside the #[public] impl Data block
2
3 pub fn get_bytes(&self) -> Vec<u8> {
4 self.my_bytes.get_bytes()
5 }
6
7 pub fn get_byte_from_bytes(&self, index: U256) -> u8 {
8 self.my_bytes.get(index).unwrap()
9 }
10
11 pub fn set_bytes(&mut self, value: Vec<u8>) {
12 self.my_bytes.set_bytes(value);
13 }
14
15 pub fn push_byte_to_bytes(&mut self, value: u8) {
16 self.my_bytes.push(value);
17 }StorageString stores a UTF-8 encoded string (String).
1//... inside the #[public] impl Data block
2
3 pub fn get_string(&self) -> String {
4 self.my_string.get_string()
5 }
6
7 pub fn set_string(&mut self, value: String) {
8 self.my_string.set_str(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_string(&self) -> String {
4 self.my_string.get_string()
5 }
6
7 pub fn set_string(&mut self, value: String) {
8 self.my_string.set_str(value);
9 }StorageVec<T> stores a dynamically sized vector (array) of primitive data type T (For example, T can be alloy_primitives::U256).
1//... inside the #[public] impl Data block
2
3 pub fn get_vec(&self, index: U256) -> U256 {
4 self.my_vec.get(index).unwrap()
5 }
6
7 pub fn push_vec(&mut self, value: U256) {
8 self.my_vec.push(value);
9 }1//... inside the #[public] impl Data block
2
3 pub fn get_vec(&self, index: U256) -> U256 {
4 self.my_vec.get(index).unwrap()
5 }
6
7 pub fn push_vec(&mut self, value: U256) {
8 self.my_vec.push(value);
9 }1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4use stylus_sdk::{
5 prelude::*,
6 alloy_primitives::{I256, U256, Address, FixedBytes},
7 storage::*,
8};
9
10#[storage]
11#[entrypoint]
12pub struct Data {
13 my_bool: StorageBool,
14 my_address: StorageAddress,
15 my_uint: StorageU256,
16 my_signed: StorageI256,
17 my_fixed_bytes: StorageFixedBytes<4>,
18 my_bytes: StorageBytes,
19 my_string: StorageString,
20 my_vec: StorageVec<StorageU256>,
21}
22
23#[public]
24impl Data {
25 // Getters
26 pub fn get_bool(&self) -> bool {
27 self.my_bool.get()
28 }
29
30 pub fn get_address(&self) -> Address {
31 self.my_address.get()
32 }
33
34 pub fn get_uint(&self) -> U256 {
35 self.my_uint.get()
36 }
37
38 pub fn get_signed(&self) -> I256 {
39 self.my_signed.get()
40 }
41
42 pub fn get_fixed_bytes(&self) -> FixedBytes<4> {
43 self.my_fixed_bytes.get()
44 }
45
46 pub fn get_bytes(&self) -> Vec<u8> {
47 self.my_bytes.get_bytes()
48 }
49
50 pub fn get_byte_from_bytes(&self, index: U256) -> u8 {
51 self.my_bytes.get(index).unwrap()
52 }
53
54 pub fn get_string(&self) -> String {
55 self.my_string.get_string()
56 }
57
58 pub fn get_vec(&self, index: U256) -> U256 {
59 self.my_vec.get(index).unwrap()
60 }
61
62 // Setters
63 pub fn set_bool(&mut self, value: bool) {
64 self.my_bool.set(value);
65 }
66
67 pub fn set_address(&mut self, value: Address) {
68 self.my_address.set(value);
69 }
70
71 pub fn set_uint(&mut self, value: U256) {
72 self.my_uint.set(value);
73 }
74
75 pub fn set_signed(&mut self, value: I256) {
76 self.my_signed.set(value);
77 }
78
79 pub fn set_fixed_bytes(&mut self, value: FixedBytes<4>) {
80 self.my_fixed_bytes.set(value);
81 }
82
83 pub fn set_bytes(&mut self, value: Vec<u8>) {
84 self.my_bytes.set_bytes(value);
85 }
86
87 pub fn push_byte_to_bytes(&mut self, value: u8) {
88 self.my_bytes.push(value);
89 }
90
91 pub fn set_string(&mut self, value: String) {
92 self.my_string.set_str(value);
93 }
94
95 pub fn push_vec(&mut self, value: U256) {
96 self.my_vec.push(value);
97 }
98}1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4use stylus_sdk::{
5 prelude::*,
6 alloy_primitives::{I256, U256, Address, FixedBytes},
7 storage::*,
8};
9
10#[storage]
11#[entrypoint]
12pub struct Data {
13 my_bool: StorageBool,
14 my_address: StorageAddress,
15 my_uint: StorageU256,
16 my_signed: StorageI256,
17 my_fixed_bytes: StorageFixedBytes<4>,
18 my_bytes: StorageBytes,
19 my_string: StorageString,
20 my_vec: StorageVec<StorageU256>,
21}
22
23#[public]
24impl Data {
25 // Getters
26 pub fn get_bool(&self) -> bool {
27 self.my_bool.get()
28 }
29
30 pub fn get_address(&self) -> Address {
31 self.my_address.get()
32 }
33
34 pub fn get_uint(&self) -> U256 {
35 self.my_uint.get()
36 }
37
38 pub fn get_signed(&self) -> I256 {
39 self.my_signed.get()
40 }
41
42 pub fn get_fixed_bytes(&self) -> FixedBytes<4> {
43 self.my_fixed_bytes.get()
44 }
45
46 pub fn get_bytes(&self) -> Vec<u8> {
47 self.my_bytes.get_bytes()
48 }
49
50 pub fn get_byte_from_bytes(&self, index: U256) -> u8 {
51 self.my_bytes.get(index).unwrap()
52 }
53
54 pub fn get_string(&self) -> String {
55 self.my_string.get_string()
56 }
57
58 pub fn get_vec(&self, index: U256) -> U256 {
59 self.my_vec.get(index).unwrap()
60 }
61
62 // Setters
63 pub fn set_bool(&mut self, value: bool) {
64 self.my_bool.set(value);
65 }
66
67 pub fn set_address(&mut self, value: Address) {
68 self.my_address.set(value);
69 }
70
71 pub fn set_uint(&mut self, value: U256) {
72 self.my_uint.set(value);
73 }
74
75 pub fn set_signed(&mut self, value: I256) {
76 self.my_signed.set(value);
77 }
78
79 pub fn set_fixed_bytes(&mut self, value: FixedBytes<4>) {
80 self.my_fixed_bytes.set(value);
81 }
82
83 pub fn set_bytes(&mut self, value: Vec<u8>) {
84 self.my_bytes.set_bytes(value);
85 }
86
87 pub fn push_byte_to_bytes(&mut self, value: u8) {
88 self.my_bytes.push(value);
89 }
90
91 pub fn set_string(&mut self, value: String) {
92 self.my_string.set_str(value);
93 }
94
95 pub fn push_vec(&mut self, value: U256) {
96 self.my_vec.push(value);
97 }
98}1[package]
2name = "stylus_storage_example"
3version = "0.1.7"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
7
8[dependencies]
9alloy-primitives = "=0.7.6"
10alloy-sol-types = "=0.7.6"
11mini-alloc = "0.4.2"
12stylus-sdk = "0.6.0"
13hex = "0.4.3"
14
15[features]
16export-abi = ["stylus-sdk/export-abi"]
17
18[lib]
19crate-type = ["lib", "cdylib"]
20
21[profile.release]
22codegen-units = 1
23strip = true
24lto = true
25panic = "abort"
26opt-level = "s"1[package]
2name = "stylus_storage_example"
3version = "0.1.7"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
7
8[dependencies]
9alloy-primitives = "=0.7.6"
10alloy-sol-types = "=0.7.6"
11mini-alloc = "0.4.2"
12stylus-sdk = "0.6.0"
13hex = "0.4.3"
14
15[features]
16export-abi = ["stylus-sdk/export-abi"]
17
18[lib]
19crate-type = ["lib", "cdylib"]
20
21[profile.release]
22codegen-units = 1
23strip = true
24lto = true
25panic = "abort"
26opt-level = "s"