Skip to content

Commit

Permalink
Merge branch 'master' into less-to-scss
Browse files Browse the repository at this point in the history
  • Loading branch information
symbolpunk authored Sep 14, 2023
2 parents 3ae248c + d2d71fe commit a27545e
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 19 deletions.
8 changes: 6 additions & 2 deletions arbitrum-docs/partials/_glossary-partial.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
### Blockchain {#blockchain}
<p>A distributed digital ledger that is used to record transactions and store data in a secure, transparent, and tamper-resistant way, notably in cryptocurrency protocols. </p>

### BOLD {#bold}
<p>Short for "Bounded Liquidity Delay"; latest version of the Arbitrum <a href="/intro/glossary#challenge-protocol">Challenge protocol</a> designed to eliminate <a href="https://medium.com/offchainlabs/solutions-to-delay-attacks-on-rollups-434f9d05a07a">delay attack vectors</a> (see <a href="https://medium.com/offchainlabs/bold-permissionless-validation-for-arbitrum-chains-9934eb5328cc">here</a> for more). Not currently on mainnet. </p>

### 🧢 CAP Finance {#cap-finance}
<p>Widely considered the most degen community on Arbitrum.<br />
<br />
Expand Down Expand Up @@ -101,8 +104,6 @@
### Data Availability Committee (DAC) {#data-availability-committee-dac}
<p>A permissioned set of parties responsible for enforcing data availability in an <a href="/intro/glossary#arbitrum-anytrust-protocol">Arbitrum AnyTrust Protocol</a> chain. See <em><a href="https://medium.com/offchainlabs/introducing-anytrust-chains-cheaper-faster-l2-chains-with-minimal-trust-assumptions-31def59eb8d7">Introducing AnyTrust Chains: Cheaper, Faster L2 Chains with Minimal Trust Assumptions</a></em> to learn more.</p>

<p></p>



### Defensive Validator {#defensive-validator}
Expand Down Expand Up @@ -235,6 +236,9 @@ If you see any Smol's with giga brains, swole arms or hear the sound of "EEEE" i
<br />
Jump into the world of Elleria and go on adventures.</p>

### Time boost {#time-boost}
<p>A proposed (not currently live) transaction policy in which users can pay a fee to the <a href="/intro/glossary#sequencer">Sequencer</a> for a small ordering advantage. See [here](<a href="https://medium.com/offchainlabs/time-boost-a-new-transaction-ordering-policy-for-arbitrum-5b3066382d62">https://medium.com/offchainlabs/time-boost-a-new-transaction-ordering-policy-for-arbitrum-5b3066382d62</a>) for more. </p>

### 🐸 Toadstoolz {#toadstoolz}
<p>Hidden in the Croakshire, you will find the friendly Toadstoolz. <br />
<br />
Expand Down
155 changes: 139 additions & 16 deletions arbitrum-docs/stylus/reference/rust-sdk-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ impl Contract {
}
```

In the above, `msg::value` is the amount of ETH passed to the contract in wei, which may be used to pay for something depending on the contracts business logic. Note that you have to annotate the method with [`#[payable]`][payable], or else calls to it will revert. This is required as a safety measure since it prevents vulnerabilities based on covertly updating contract balances.
In the above, `msg::value` is the amount of ETH passed to the contract in wei, which may be used to pay for something depending on the contracts business logic. Note that you have to annotate the method with [`#[payable]`][payable], or else calls to it will revert. This is required as a safety measure to prevent users losing funds to methods that didnt intend to accept ether.

### [`#[pure]`][pure], [`#[view]`][view], and `#[write]`

Expand Down Expand Up @@ -314,10 +314,10 @@ fn entrypoint(calldata: Vec<u8>) -> ArbResult {

### Reentrancy

If a contract calls another that then calls the first, it is said to be reentrant. By default, all Stylus programs revert when this happened. However, you can opt out of this behavior by customizing your entrypoint.
If a contract calls another that then calls the first, it is said to be reentrant. By default, all Stylus programs revert when this happened. However, you can opt out of this behavior by enabling the `reentrant` feature flag.

```rust
#[entrypoint(allow_reentrancy = true)]
stylus-sdk = { version = "0.3.0", features = ["reentrant"] }
```

This is dangerous, and should be done only after careful reviewideally by 3rd party auditors. Numerous exploits and hacks have in Web3 are attributable to developers misusing or not fully understanding reentrant patterns.
Expand Down Expand Up @@ -384,7 +384,7 @@ The SDK does this automatically for you via a feature flag called `export-abi` t
cargo run --features export-abi --target <triple>
```

Note that because the above actually generates a `main` function that you need to run, the target cant be `wasm32-unknown-unknown` like normal. Instead youll need to pass in your target triple, which `cargo stylus` figures out for you. This `main` function is also why the following commonly appears in the `[main.rs](http://main.rs)` file of Stylus contracts.
Note that because the above actually generates a `main` function that you need to run, the target cant be `wasm32-unknown-unknown` like normal. Instead youll need to pass in your target triple, which `cargo stylus` figures out for you. This `main` function is also why the following commonly appears in the `main.rs` file of Stylus contracts.

```rust
#![cfg_attr(not(feature = "export-abi"), no_main)]
Expand All @@ -408,29 +408,140 @@ interface Weth is Erc20 {

## Calls

:::caution UNDER CONSTRUCTION

This section is currently under construction, and will be updated soon.

If you're waiting for this content to be completed, click the `Request an update` button at the top of this page to let us know!
Just as with storage and methods, Stylus SDK calls are Solidity ABI equivalent. This means you never have to know the implementation details of other contracts to invoke them. You simply import the Solidity interface of the target contract, which can be auto-generated via the `cargo stylus` [CLI tool][abi_export].

:::tip
You can call contracts in any programming language with the Stylus SDK.
:::

### [`sol_interface!`][sol_interface]

_Coming soon!_
This macro defines a `struct` for each of the Solidity interfaces provided.

```rust
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`][Address] and returns a [`B256`][B256].

```rust
pub fn do_call(&mut self, account: IService, user: Address) -> Result<String, Error> {
account.make_payment(self, user) // note the snake case
}
```

Observe the casing change. [`sol_interface!`][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`.

### Configuring gas and value with [`Call`][Call]

[`Call`][Call] lets you configure a call via optional configuration methods. This is similar to how one would configure opening a [`File`][File] in Rust.

```rust
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)
}
```

By default [`Call`][Call] supplies all gas remaining and zero value, which often means [`Call::new()`][Call_new] may be passed to the method directly. Additional configuration options are available in cases of reentrancy.

### Reentrant calls

Contracts that opt into reentrancy via the `reentrant` feature flag require extra care. When the `storage-cache` feature is enabled, cross-contract calls must [`flush`][StorageCache_flush] or [`clear`][StorageCache_clear] the [`StorageCache`][StorageCache] to safeguard state. This happens automatically via the type system.

```rust
sol_interface! {
interface IMethods {
function pureFoo() pure;
function viewFoo() view;
function writeFoo();
function payableFoo() payable;
}
}

#[external]
impl Contract {
pub fn call_pure(&self, methods: IMethods) -> Result<(), Vec<u8>> {
Ok(methods.pure_foo(self)?) // `pure` methods might lie about not being `view`
}

pub fn call_view(&self, methods: IMethods) -> Result<(), Vec<u8>> {
Ok(methods.view_foo(self)?)
}

pub fn call_write(&mut self, methods: IMethods) -> Result<(), Vec<u8>> {
methods.view_foo(self)?; // allows `pure` and `view` methods too
Ok(methods.write_foo(self)?)
}

#[payable]
pub fn call_payable(&mut self, methods: IMethods) -> Result<(), Vec<u8>> {
methods.write_foo(Call::new_in(self))?; // these are the same
Ok(methods.payable_foo(self)?) // ------------------
}
}
```

### Call contexts
In the above, we’re able to pass `&self` and `&mut self` because `Contract` implements [`TopLevelStorage`][TopLevelStorage], which means that a reference to it entails access to the entirety of the contract’s state. This is the reason it is sound to make a call, since it ensures all cached values are invalidated and/or persisted to state at the right time.

_Coming soon!_
When writing Stylus libraries, a type might not be [`TopLevelStorage`][TopLevelStorage] and therefore `&self` or `&mut self` won’t work. Building a [`Call`][Call] from a generic parameter via [`new_in`][Call_new_in] is the usual solution.

### Calls with inheritance
```rust
pub fn do_call(
storage: &mut impl TopLevelStorage, // can be generic, but often just &mut self
account: IService, // serializes as an Address
user: Address,
) -> Result<String, Error> {

_Coming soon!_
let config = Call::new_in(storage) // take exclusive access to all contract storage
.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
}
```

Note that in the context of an [`#[external]`][external] call, the `&mut impl` argument will correctly distinguish the method as being `write` or [`payable`][payable]. This means you can write library code that will work regardless of whether the reentrant feature flag is enabled.

Note too that [`Call::new_in`][Call_new_in] should be used instead of [`Call::new`][Call_new] since the former provides access to storage. Code that previously compiled with reentrancy disabled may require modification in order to type-check. This is done to ensure storage changes are persisted and that the storage cache is properly managed before calls.

### [`call`][fn_call], [`static_call`][fn_static_call], and [`delegate_call`][fn_delegate_call]

Though [`sol_interface!`][sol_interface] and [`Call`][Call] form the most common idiom to invoke other contracts, their underlying [`call`][fn_call] and [`static_call`][fn_static_call] are exposed for direct access.

```rust
let return_data = call(Call::new(), contract, call_data)?;
```

In each case the calldata is supplied as a [`Vec<u8>`][Vec]. The return result is either the raw return data on success, or a call [`Error`][CallError] on failure.

[`delegate_call`][fn_delegate_call] is also available, though it's `unsafe` and doesn't have a richly-typed equivalent. This is because a delegate call must trust the other contract to uphold safety requirements. Though this function clears any cached values, the other contract may arbitrarily change storage, spend ether, and do other things one should never blindly allow other contracts to do.

### [`transfer_eth`][transfer_eth]

_Coming soon!_
This method provides a convenient shorthand for transferring ether.

Note that this method invokes the other contract, which may in turn call others. All gas is supplied, which the recipient may burn. If this is not desired, the [`call`][fn_call] function may be used instead.

```rust
transfer_eth(recipient, value)?; // these two are equivalent

call(Call::new().value(value), recipient, &[])?; // these two are equivalent
```

### [`RawCall`][RawCall] and `unsafe` calls

Expand All @@ -444,7 +555,7 @@ let data = RawCall::new_delegate() // configure a delegate call
.call(contract, calldata)?; // do the call
```

Note that the [`call`][RawCall_call] method is `unsafe`. This is due to reentrancy, and the fact that the call does not require clearing the storage cache.
Note that the [`call`][RawCall_call] method is `unsafe` when reentrancy is enabled. See [`flush_storage_cache`][RawCall_flush_storage_cache] and [`clear_storage_cache`][RawCall_clear_storage_cache] for more information.

## [`RawDeploy`][RawDeploy] and `unsafe` deployments

Expand Down Expand Up @@ -508,6 +619,8 @@ let callvalue = msg::value();
[Erase]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html
[erase]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html#tymethod.erase
[StorageCache]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html
[StorageCache_flush]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.flush
[StorageCache_clear]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.clear
[EagerStorage]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.EagerStorage.html
[StorageBool]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageBool.html
[StorageAddress]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageAddress.html
Expand All @@ -525,6 +638,7 @@ let callvalue = msg::value();
[StorageGuard]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageGuard.html
[StorageGuardMut]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageGuardMut.html
[Address]: https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.Address.html
[B256]: https://docs.rs/alloy-primitives/latest/alloy_primitives/aliases/type.B256.html
[Uint]: https://docs.rs/ruint/1.10.1/ruint/struct.Uint.html
[Signed]: https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.Signed.html
[FixedBytes]: https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.FixedBytes.html
Expand All @@ -551,8 +665,17 @@ let callvalue = msg::value();
[StorageMap_replace]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageMap.html#method.replace
[Router]: https://docs.rs/stylus-sdk/latest/stylus_sdk/abi/trait.Router.html
[transfer_eth]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/fn.transfer_eth.html
[Call]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.Call.html
[Call_new]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.Call.html#method.new
[Call_new_in]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.Call.html#method.new_in
[CallError]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/enum.Error.html
[fn_call]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/fn.call.html
[fn_static_call]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/fn.static_call.html
[fn_delegate_call]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/fn.delegate_call.html
[RawCall]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.RawCall.html
[RawCall_call]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.RawCall.html#method.call
[RawCall_flush_storage_cache]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.RawCall.html#method.flush_storage_cache
[RawCall_clear_storage_cache]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.RawCall.html#method.clear_storage_cache
[RawDeploy]: https://docs.rs/stylus-sdk/latest/stylus_sdk/deploy/struct.RawDeploy.html
[solidity_storage]: https://docs.rs/stylus-sdk/latest/stylus_sdk/prelude/attr.solidity_storage.html
[sol_storage]: https://docs.rs/stylus-sdk/latest/stylus_sdk/prelude/macro.sol_storage.html
Expand Down
Loading

0 comments on commit a27545e

Please sign in to comment.