From 608a293703b22245f69a93bb729f49b90709301e Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Sat, 4 Oct 2025 12:52:54 +0300 Subject: [PATCH 1/4] Add `#[ink::contract_ref]` attribute docs --- docs/macros-attributes/contract_ref.md | 137 +++++++++++++++++++++++++ sidebars.js | 1 + 2 files changed, 138 insertions(+) create mode 100644 docs/macros-attributes/contract_ref.md diff --git a/docs/macros-attributes/contract_ref.md b/docs/macros-attributes/contract_ref.md new file mode 100644 index 0000000000..6dffd20d2c --- /dev/null +++ b/docs/macros-attributes/contract_ref.md @@ -0,0 +1,137 @@ +--- +title: "#[ink::contract_ref]" +hide_title: true +slug: /macros-attributes/contract_ref +--- + +![Text/contract Title Picture](/img/title/text/contract.svg) + +Defines the interface of a "callee" contract and generates a wrapper type which can be +used for interacting with the contract. + +The interface is defined using a trait, and the macro generates a native Rust type +(a contract reference) that implements this trait, so it can be used in any Rust +context that expects types. + +## Example + +### Definition + +```rust +#[ink::contract_ref(abi = "sol")] +pub trait Erc20 { + Returns the total supply of the ERC-20 smart contract. + #[ink(message)] + fn total_supply(&self) -> ink::U256; + + Transfers balance from the caller to the given address. + #[ink(message)] + fn transfer(&mut self, amount: ink::U256, to: ink::Address) -> bool; + + // etc. +} +``` + +### Usage + +Given the above interface, you can use the generated contract reference in a +"caller" contract as shown below: + +```rust +#[ink::contract] +mod erc20_caller { + use ink::U256; + + #[ink(storage)] + pub struct Erc20Caller { + callee: ink::Address, + } + + impl Erc20Caller { + #[ink(constructor)] + pub fn new(addr: ink::Address) -> Self { + Self { callee: addr } + } + + #[ink(message)] + pub fn call_erc20(&self) { + // Calls the ERC20 contract using the contract ref generated above. + let total = Erc20Ref::from(self.callee).total_supply(); + + // Do some fun stuff! + } + } +} +``` + +## Header Arguments + +The `#[ink::contract_ref]` macro can be provided with some additional +comma-separated header arguments: + +### `abi: String` + +Specifies the ABI (Application Binary Interface) of the "callee" contract. + +**Usage Example:** +```rust +#[ink::contract_ref(abi = "sol")] +pub trait Callee { + #[ink(message)] + fn message1(&self); + + #[ink(message, selector = 42)] + fn message2(&self); +} +``` + +**Default value:** Empty. + +**Allowed values:** `"ink"`, `"sol"` + +**NOTE**: When no value is provided, the generated contract reference will use the +ABI of the root contract (i.e "ink" in ["ink" and "all" ABI mode][abi-mode] +and "sol" in ["sol" ABI mode][abi-mode]). + +[abi-mode]: ../basics/abi/overview.md + +### `env: impl Environment` + +Specifies the environment to use for the generated contract reference. + +This should be the same environment used by the root contract (if any). + +The environment must implement the `Environment` (defined in `ink_env`) +trait and provides all the necessary fundamental type definitions for `Balance`, +`AccountId` etc. + +**Usage Example:** + +Given a custom `Environment` implementation: +```rust +#[derive(Clone)] +pub struct MyEnvironment; + +impl ink_env::Environment for MyEnvironment { + const NATIVE_TO_ETH_RATIO: u32 = 100_000_000; + type AccountId = [u8; 16]; + type Balance = u128; + type Hash = [u8; 32]; + type Timestamp = u64; + type BlockNumber = u32; + type EventRecord = (); +} +``` +A user might define an interface (and generate a contract reference) that uses the +above custom `Environment` implementation as demonstrated below: +```rust +#[ink::contract_ref(env = MyEnvironment)] +pub trait Callee { + #[ink(message)] + fn message(&self); + + // ... +} +``` + +**Default value:** `DefaultEnvironment` defined in `ink_env` crate. diff --git a/sidebars.js b/sidebars.js index cd82e96aef..89bd451c79 100644 --- a/sidebars.js +++ b/sidebars.js @@ -73,6 +73,7 @@ module.exports = { "Macros & Attributes": [ "macros-attributes/overview", "macros-attributes/contract", + "macros-attributes/contract_ref", "macros-attributes/anonymous", "macros-attributes/constructor", "macros-attributes/default", From 88d97998f519810cdf145a6367b71f24cbd70712 Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Sat, 4 Oct 2025 12:24:28 +0300 Subject: [PATCH 2/4] migration: Add `ink::contract_ref` rename --- docs/faq/migrating-from-ink-5-to-6.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/faq/migrating-from-ink-5-to-6.md b/docs/faq/migrating-from-ink-5-to-6.md index d14eb1b618..38f5bce478 100644 --- a/docs/faq/migrating-from-ink-5-to-6.md +++ b/docs/faq/migrating-from-ink-5-to-6.md @@ -255,6 +255,14 @@ and have your contract invoke either a cross-contract call or a delegate call in This is also the migration path recommended for Chain Extensions. +### Renamed `ink::contract_ref!` to `ink::contract_ref_from_path!` + +This was necessary because we introduced a new [`#[ink::contract_ref]` attribute][contract-ref-attr]. +The PR [#2648](https://github.com/use-ink/ink/pull/2648) contains more information +about the motivation and benefits of this change. + +[contract-ref-attr]: ../macros-attributes/contract_ref.md + ## Interesting New Features ### Solidity ABI compatible ink! contracts From 709ccf766c37ea6a1fcd2b3ee87d3e3bcd3b7e17 Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Sat, 4 Oct 2025 14:17:31 +0300 Subject: [PATCH 3/4] note: `#[ink::contract_ref]` and `#[ink::trait_definition]` differences --- docs/macros-attributes/contract_ref.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/macros-attributes/contract_ref.md b/docs/macros-attributes/contract_ref.md index 6dffd20d2c..5641c5066e 100644 --- a/docs/macros-attributes/contract_ref.md +++ b/docs/macros-attributes/contract_ref.md @@ -13,6 +13,17 @@ The interface is defined using a trait, and the macro generates a native Rust ty (a contract reference) that implements this trait, so it can be used in any Rust context that expects types. +:::note +A key difference between an `#[ink::contract_ref]` and [`#[ink::trait_definition]`][trait-def] +is that a `#[ink::contract_ref]` dynamically declares the interface of +an on-chain/"callee" contract with a possibly different ABI from the root/"caller" contract, +while a [`#[ink::trait_definition]`][trait-def] is an interface that defines shared behavior +to be implemented (or reused/inherited) by the root contract, where the ABI is +inferred from the root contract. +::: + +[trait-def]: ../basics/trait-definitions.md + ## Example ### Definition From 31893c8f65d0cea18ab23b018d72b2a7967e3562 Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Sat, 4 Oct 2025 14:32:49 +0300 Subject: [PATCH 4/4] title image --- docs/macros-attributes/contract_ref.md | 2 +- static/img/title/text/contract_ref.svg | 124 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 static/img/title/text/contract_ref.svg diff --git a/docs/macros-attributes/contract_ref.md b/docs/macros-attributes/contract_ref.md index 5641c5066e..0d9025b03d 100644 --- a/docs/macros-attributes/contract_ref.md +++ b/docs/macros-attributes/contract_ref.md @@ -4,7 +4,7 @@ hide_title: true slug: /macros-attributes/contract_ref --- -![Text/contract Title Picture](/img/title/text/contract.svg) +![Text/contract_ref Title Picture](/img/title/text/contract_ref.svg) Defines the interface of a "callee" contract and generates a wrapper type which can be used for interacting with the contract. diff --git a/static/img/title/text/contract_ref.svg b/static/img/title/text/contract_ref.svg new file mode 100644 index 0000000000..e77d9c4952 --- /dev/null +++ b/static/img/title/text/contract_ref.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +