Arbitrum Stylus logo

Stylus by Example

Import interfaces

Interfaces allow you to interact with other contracts from your Stylus contract, regardless of the language used to develop them (Solidity, Rust, ...). This page shows how to declare an Interface using the Stylus Rust SDK.

Declaring interfaces and calling other contracts

To declare an interface in your Rust contract, you can use the sol_interface! macro. This macro defines a struct for each of the Solidity ABI interfaces provided.

Let's see an example:

1sol_interface! {
2    interface IService {
3        function makePayment(address user) payable returns (string);
4        function getConstant() pure returns (bytes32)
5    }
6
7    interface ITree {
8        // other interface methods
9    }
10}
1sol_interface! {
2    interface IService {
3        function makePayment(address user) payable returns (string);
4        function getConstant() pure returns (bytes32)
5    }
6
7    interface ITree {
8        // other interface methods
9    }
10}

The above will define IService and ITree for calling the methods of the two contracts. Notice how Solidity syntax is used to declare the interfaces.

With this example interface, for instance, we can call method make_payment from IService that accepts an Address and returns a B256.

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

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.

Let's finish this section with a different example that directly calls a method from an imported interface:

1sol_interface! {
2    interface IMethods {
3        function viewFoo() external view;
4        function writeFoo() external;
5    }
6}
7
8#[public]
9impl Contract {
10    pub fn call_view(&mut self, contract_address: Address) -> Result<(), Vec<u8>> {
11        let external_contract = IMethods::new(contract_address);
12        let config = Call::new_in(self);
13        Ok(external_contract.view_foo(config)?)
14    }
15
16    pub fn call_write(&mut self, contract_address: Address) -> Result<(), Vec<u8>> {
17        let external_contract = IMethods::new(contract_address);
18        let config = Call::new_in(self);
19        Ok(external_contract.write_foo(config)?)
20    }
21}
1sol_interface! {
2    interface IMethods {
3        function viewFoo() external view;
4        function writeFoo() external;
5    }
6}
7
8#[public]
9impl Contract {
10    pub fn call_view(&mut self, contract_address: Address) -> Result<(), Vec<u8>> {
11        let external_contract = IMethods::new(contract_address);
12        let config = Call::new_in(self);
13        Ok(external_contract.view_foo(config)?)
14    }
15
16    pub fn call_write(&mut self, contract_address: Address) -> Result<(), Vec<u8>> {
17        let external_contract = IMethods::new(contract_address);
18        let config = Call::new_in(self);
19        Ok(external_contract.write_foo(config)?)
20    }
21}