Functions & calls

Initialization (constructors)

When default state is not enough, mark a method #[init]. It runs once, takes arguments, and returns the starting state — the constructor.

The contracts so far used #[derive(Default)] and initialized themselves lazily. When the starting state depends on arguments — an owner, a cap, a token address — you need a real constructor. On NEAR that is a method marked #[init] that returns Self.

A vault with an owner and a cap
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Vault {
    address public owner;
    uint256 public cap;

    constructor(address _owner, uint256 _cap) {
        owner = _owner;
        cap = _cap;
    }
}
Rust
use near_sdk::{near, AccountId};
use near_sdk::json_types::U128;

#[near(contract_state)]
pub struct Vault {
    owner: AccountId,
    cap: u128,
}

#[near]
impl Vault {
    #[init]
    pub fn new(owner: AccountId, cap: U128) -> Self {
        Self { owner, cap: cap.0 }
    }

    pub fn owner(&self) -> AccountId {
        self.owner.clone()
    }
}
Coming from EVM

constructor(...) ↔ a method marked #[init] that returns Self. Note there is no #[derive(Default)] here — a contract has exactly one of the two.

An #[init] method must be called once after deploy, before anything else. Until it runs the contract has no state and every other method panics with "not initialized" — deploy and init are two separate steps.

U128 / U64 (near_sdk::json_types) are string-wrapped integers for method arguments and returns. JSON numbers lose precision above 2^53, so money-sized values cross the ABI as U128 and you read the inner value with .0.