|
| 1 | +--- |
| 2 | +title: "#[ink::contract_ref]" |
| 3 | +hide_title: true |
| 4 | +slug: /macros-attributes/contract_ref |
| 5 | +--- |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +Defines the interface of a "callee" contract and generates a wrapper type which can be |
| 10 | +used for interacting with the contract. |
| 11 | + |
| 12 | +The interface is defined using a trait, and the macro generates a native Rust type |
| 13 | +(a contract reference) that implements this trait, so it can be used in any Rust |
| 14 | +context that expects types. |
| 15 | + |
| 16 | +:::note |
| 17 | +A key difference between an `#[ink::contract_ref]` and [`#[ink::trait_definition]`][trait-def] |
| 18 | +is that a `#[ink::contract_ref]` dynamically declares the interface of |
| 19 | +an on-chain/"callee" contract with a possibly different ABI from the root/"caller" contract, |
| 20 | +while a [`#[ink::trait_definition]`][trait-def] is an interface that defines shared behavior |
| 21 | +to be implemented (or reused/inherited) by the root contract, where the ABI is |
| 22 | +inferred from the root contract. |
| 23 | +::: |
| 24 | + |
| 25 | +[trait-def]: ../basics/trait-definitions.md |
| 26 | + |
| 27 | +## Example |
| 28 | + |
| 29 | +### Definition |
| 30 | + |
| 31 | +```rust |
| 32 | +#[ink::contract_ref(abi = "sol")] |
| 33 | +pub trait Erc20 { |
| 34 | + Returns the total supply of the ERC-20 smart contract. |
| 35 | + #[ink(message)] |
| 36 | + fn total_supply(&self) -> ink::U256; |
| 37 | + |
| 38 | + Transfers balance from the caller to the given address. |
| 39 | + #[ink(message)] |
| 40 | + fn transfer(&mut self, amount: ink::U256, to: ink::Address) -> bool; |
| 41 | + |
| 42 | + // etc. |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +### Usage |
| 47 | + |
| 48 | +Given the above interface, you can use the generated contract reference in a |
| 49 | +"caller" contract as shown below: |
| 50 | + |
| 51 | +```rust |
| 52 | +#[ink::contract] |
| 53 | +mod erc20_caller { |
| 54 | + use ink::U256; |
| 55 | + |
| 56 | + #[ink(storage)] |
| 57 | + pub struct Erc20Caller { |
| 58 | + callee: ink::Address, |
| 59 | + } |
| 60 | + |
| 61 | + impl Erc20Caller { |
| 62 | + #[ink(constructor)] |
| 63 | + pub fn new(addr: ink::Address) -> Self { |
| 64 | + Self { callee: addr } |
| 65 | + } |
| 66 | + |
| 67 | + #[ink(message)] |
| 68 | + pub fn call_erc20(&self) { |
| 69 | + // Calls the ERC20 contract using the contract ref generated above. |
| 70 | + let total = Erc20Ref::from(self.callee).total_supply(); |
| 71 | + |
| 72 | + // Do some fun stuff! |
| 73 | + } |
| 74 | + } |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +## Header Arguments |
| 79 | + |
| 80 | +The `#[ink::contract_ref]` macro can be provided with some additional |
| 81 | +comma-separated header arguments: |
| 82 | + |
| 83 | +### `abi: String` |
| 84 | + |
| 85 | +Specifies the ABI (Application Binary Interface) of the "callee" contract. |
| 86 | + |
| 87 | +**Usage Example:** |
| 88 | +```rust |
| 89 | +#[ink::contract_ref(abi = "sol")] |
| 90 | +pub trait Callee { |
| 91 | + #[ink(message)] |
| 92 | + fn message1(&self); |
| 93 | + |
| 94 | + #[ink(message, selector = 42)] |
| 95 | + fn message2(&self); |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +**Default value:** Empty. |
| 100 | + |
| 101 | +**Allowed values:** `"ink"`, `"sol"` |
| 102 | + |
| 103 | +**NOTE**: When no value is provided, the generated contract reference will use the |
| 104 | +ABI of the root contract (i.e "ink" in ["ink" and "all" ABI mode][abi-mode] |
| 105 | +and "sol" in ["sol" ABI mode][abi-mode]). |
| 106 | + |
| 107 | +[abi-mode]: ../basics/abi/overview.md |
| 108 | + |
| 109 | +### `env: impl Environment` |
| 110 | + |
| 111 | +Specifies the environment to use for the generated contract reference. |
| 112 | + |
| 113 | +This should be the same environment used by the root contract (if any). |
| 114 | + |
| 115 | +The environment must implement the `Environment` (defined in `ink_env`) |
| 116 | +trait and provides all the necessary fundamental type definitions for `Balance`, |
| 117 | +`AccountId` etc. |
| 118 | + |
| 119 | +**Usage Example:** |
| 120 | + |
| 121 | +Given a custom `Environment` implementation: |
| 122 | +```rust |
| 123 | +#[derive(Clone)] |
| 124 | +pub struct MyEnvironment; |
| 125 | + |
| 126 | +impl ink_env::Environment for MyEnvironment { |
| 127 | + const NATIVE_TO_ETH_RATIO: u32 = 100_000_000; |
| 128 | + type AccountId = [u8; 16]; |
| 129 | + type Balance = u128; |
| 130 | + type Hash = [u8; 32]; |
| 131 | + type Timestamp = u64; |
| 132 | + type BlockNumber = u32; |
| 133 | + type EventRecord = (); |
| 134 | +} |
| 135 | +``` |
| 136 | +A user might define an interface (and generate a contract reference) that uses the |
| 137 | +above custom `Environment` implementation as demonstrated below: |
| 138 | +```rust |
| 139 | +#[ink::contract_ref(env = MyEnvironment)] |
| 140 | +pub trait Callee { |
| 141 | + #[ink(message)] |
| 142 | + fn message(&self); |
| 143 | + |
| 144 | + // ... |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +**Default value:** `DefaultEnvironment` defined in `ink_env` crate. |
0 commit comments