Patterns
No inheritance: traits & composition
Rust has no contract inheritance. Shared behavior comes from traits (with default methods) and shared state from composition.
Solidity leans on inheritance — contract Token is Ownable, Pausable. Rust has no implementation inheritance at all. You reuse code two other ways: traits for shared behavior (they can carry default methods) and composition for shared state (embed a struct).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
abstract contract Ownable {
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_;
}
}
// inherit owner + onlyOwner
contract Token is Ownable {
uint256 public supply;
}use near_sdk::{near, env, require, AccountId};
// shared BEHAVIOR as a trait with a default method
trait Ownable {
fn owner(&self) -> &AccountId;
fn assert_owner(&self) {
require!(env::predecessor_account_id() == *self.owner(), "not owner");
}
}
// shared STATE by composition — embed the owner field
#[near(contract_state)]
pub struct Token {
owner: AccountId,
supply: u128,
}
// implement the one required method; get assert_owner for free
impl Ownable for Token {
fn owner(&self) -> &AccountId {
&self.owner
}
}contract Token is Ownable ↔ impl Ownable for Token. A trait with default methods (assert_owner) is the closest thing to inheriting a base function or modifier — you implement the small required piece and get the rest.
Shared *state* is composition, not inheritance: you embed the fields (or a whole sub-struct) you need. There is no diamond problem and no super — just fields and trait methods.
For the token standards, near-contract-standards gives you structs to embed plus macros that generate the trait impls — that is how you "inherit" NEP-141/171 behavior in practice.