Patterns
Upgrading a contract
No proxy, no delegatecall. You deploy new wasm to the same account; the state stays and an optional migrate reshapes it.
Solidity contracts are immutable per address, so upgrades mean a proxy that delegatecalls to a swappable implementation. NEAR has no such dance: you deploy new code to the same account and it replaces the old code in place. The account id and its stored state are untouched.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// minimal upgradeable proxy: forward every call to `implementation`
contract Proxy {
address public implementation;
fallback() external payable {
address impl = implementation;
assembly {
calldatacopy(0, 0, calldatasize())
let ok := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch ok
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}use near_sdk::{near, env, AccountId, PanicOnDefault};
// v2 of the contract — a new field was added
#[near(contract_state)]
#[derive(PanicOnDefault)]
pub struct Contract {
owner: AccountId,
version: u32,
}
#[near]
impl Contract {
// After deploying the new wasm to the SAME account, call this once to
// reshape the persisted state from the old layout to the new one.
#[private]
#[init(ignore_state)]
pub fn migrate() -> Self {
let old: OldContract = env::state_read().expect("no state");
Self { owner: old.owner, version: 2 }
}
}
// the previous version's state layout, for reading during migration
#[near(serializers = [borsh])]
struct OldContract {
owner: AccountId,
}No proxy, no delegatecall. Deploying new wasm to the account swaps the code; env::current_account_id() and the state survive. There is nothing like an "implementation address" to point at.
If the state *layout* changed, run a one-time migrate marked #[init(ignore_state)] (so it may overwrite existing state) that reads the old struct and writes the new one. #[private] keeps it callable only by the account itself.
Upgradeability is really a governance question: who holds the full-access key that can deploy? Often a DAO or multisig — the same trust question as who controls a proxy admin on the EVM.