macro_rules! contract_ref {
( $trait_path:path ) => { ... };
( $trait_path:path, $env:ty ) => { ... };
}
Expand description
Generates a wrapper which can be used for interacting with the contract.
This is done by creating a wrapper around the trait defined with the
ink::trait_definition
macro.
The macro returns the native Rust type that implements the corresponding trait, so it can be used in any Rust context that expects types.
§Usage in the #[ink::contract]
context
The macro expects one argument ‒ the path to the trait, in order to create a wrapper around it.
#[ink::contract]
mod trait_caller {
use ink::{
contract_ref,
U256,
};
#[ink::trait_definition]
pub trait Erc20 {
/// Returns the total supply of the ERC-20 smart contract.
#[ink(message)]
fn total_supply(&self) -> U256;
/// Transfers balance from the caller to the given address.
#[ink(message)]
fn transfer(&mut self, amount: U256, to: Address) -> bool;
}
#[ink(storage)]
pub struct Caller {
/// The example of `contract_ref!` as a struct type.
erc20: contract_ref!(Erc20),
}
impl Caller {
/// Example of `contract_ref!` as an argument type.
#[ink(constructor)]
pub fn new(erc20: contract_ref!(Erc20)) -> Self {
Self { erc20 }
}
/// Example of converting `AccountId` into `contract_ref!` implicitly.
#[ink(message)]
pub fn change_account_id_1(&mut self, new_erc20: Address) {
self.erc20 = new_erc20.into();
}
/// Example of converting `AccountId` into `contract_ref!` explicitly.
#[ink(message)]
pub fn change_account_id_2(&mut self, new_erc20: Address) {
let erc20: contract_ref!(Erc20) = new_erc20.into();
self.erc20 = erc20;
}
/// Example of converting `AccountId` into an alias from `contract_ref!`.
#[ink(message)]
pub fn change_account_id_3(&mut self, new_erc20: Address) {
type Erc20Wrapper = contract_ref!(Erc20);
let erc20: Erc20Wrapper = new_erc20.into();
self.erc20 = erc20;
}
/// Example of how to do common calls via fully qualified syntax.
#[ink(message)]
pub fn total_supply_1(&self) -> U256 {
Erc20::total_supply(&self.erc20)
}
/// Example of how to do common calls without fully qualified syntax.
#[ink(message)]
pub fn total_supply_2(&self) -> U256 {
self.erc20.total_supply()
}
/// Example of how to use the call builder with `contract_ref!`.
#[ink(message)]
pub fn total_supply_3(&self) -> U256 {
use ink::codegen::TraitCallBuilder;
// Returns the `CallBuilder` that implements `Erc20` trait.
let erc20_builder = self.erc20.call();
erc20_builder
.total_supply()
.transferred_value(U256::from(0))
.invoke()
}
/// Example of how to do common calls and convert
/// the `contract_ref!` into `AccountId`.
#[ink(message)]
pub fn transfer_to_erc20(&mut self, amount: U256) -> bool {
let erc20_as_account_id = self.erc20.as_ref().clone();
self.erc20.transfer(amount, erc20_as_account_id)
}
}
}
§Usage outside the #[ink::contract]
context
The macro expects two arguments:
- The first argument is the path to the trait, e.g.
Erc20
orerc20::Erc20
. - The second argument is the type of the [
ink_env::Environment
].
If the second argument is not specified, the macro uses the Environment
type alias.
use ink::contract_ref;
use ink_env::DefaultEnvironment;
use ink_primitives::Address;
#[ink::trait_definition]
pub trait Erc20 {
/// Returns the total supply of the ERC-20 smart contract.
#[ink(message)]
fn total_supply(&self) -> u128;
/// Transfers balance from the caller to the given address.
#[ink(message)]
fn transfer(&mut self, amount: u128, to: Address) -> bool;
}
#[derive(Clone)]
pub struct CustomEnv;
impl ink_env::Environment for CustomEnv {
const MAX_EVENT_TOPICS: usize = 3;
type AccountId = [u8; 32];
type Balance = u64;
type Hash = [u8; 32];
type Timestamp = u64;
type BlockNumber = u64;
type ChainExtension = ();
type EventRecord = ();
}
type AliasWithDefaultEnv = contract_ref!(Erc20, DefaultEnvironment);
type AliasWithCustomEnv = contract_ref!(Erc20, CustomEnv);
type AliasWithGenericEnv<E> = contract_ref!(Erc20, E);
fn default(mut contract: contract_ref!(Erc20, DefaultEnvironment)) {
let total_supply = contract.total_supply();
let to: Address = contract.as_ref().clone();
contract.transfer(total_supply, to);
}
fn default_alias(mut contract: AliasWithDefaultEnv) {
default(contract)
}
fn custom(mut contract: contract_ref!(Erc20, CustomEnv)) {
let total_supply = contract.total_supply();
contract.transfer(total_supply, contract.as_ref().clone());
}
fn custom_alias(mut contract: AliasWithCustomEnv) {
custom(contract)
}
fn generic<E, A>(mut contract: contract_ref!(Erc20, E))
where
E: ink_env::Environment<AccountId = A>,
A: Into<Address> + Clone,
{
let total_supply = contract.total_supply();
let to = contract.as_ref().clone();
contract.transfer(total_supply, to.into());
}
fn generic_alias<E, A>(mut contract: AliasWithGenericEnv<E>)
where
E: ink_env::Environment<AccountId = A>,
A: Into<Address> + Clone,
{
generic(contract)
}
type Environment = DefaultEnvironment;
fn contract_ref_default_behaviour(mut contract: contract_ref!(Erc20)) {
let total_supply = contract.total_supply();
let to: Address = contract.as_ref().clone();
contract.transfer(total_supply, to);
}