Move -> Soroban: the differential cheat sheet
For Aptos Move developers shipping Soroban contracts. Each entry is composed in the following structure:
- What it is in Move
- What it is in Soroban
- Where the analogy breaks.
- The breakage is the payload.
Legend:
- ⚠ FALSE FRIEND: your Move instinct produces compiling, working-looking Soroban code that is wrong.
- ∅ NO ANALOGUE: nothing on the other side, don’t force one.
- 🔧 DIRECT SWAP: mechanical rename, low risk.
Verified against
soroban-sdk27.0.6 · rustc 1.91.1 · Aptos Move 9.4.0 Every Soroban snippet in this document compiles and, where it asserts behaviour, runs green, see Verification, which also records how this was drafted. Move snippets are illustrative and not compiled.
Version note. soroban-sdk major = Stellar protocol version (SDK 27 ↔ protocol 27). Network limits and TTL floors are set by validator vote; the numbers in §6.4 match InvocationResourceLimits::mainnet() as baked into SDK 27.0.6 (a snapshot dated 2026-07-10; the SDK itself notes these are hardcoded and require an SDK update to refresh). Check live values before relying on them: Stellar Lab network limits · stellar network settings --network mainnet · crates.io/soroban-sdk.
Quick map
| # | Concept | Move | Flag | Soroban | § |
|---|---|---|---|---|---|
| 1 | Transaction authority | &signer | ⚠ | Address param + addr.require_auth() | 1.1 |
| 2 | Caller identity | signer::address_of(s) | 🔧 | the Address param itself | 1.1 |
| 3 | Multi-party authorization | multi-agent tx (N signers) | N auth entries in one tx | 1.2 | |
| 4 | Programmatic signing | resource account + SignerCapability | custom account (__check_auth) / invoker auth | 1.4 | |
| 5 | Module-to-module access | friend / public(friend) | ∅ | ∅, auth checks replace visibility | 1.5 |
| 6 | Delegated authority | capability structs (MintCap, AdminCap…) | ⚠ | role Address in storage + require_auth | 2.1 |
| 7 | Composable asset primitive | Aptos object model (Object<T>, refs) | ∅ | ∅, keyed entries or factory instances | 2.2 |
| 8 | Enforced obligation | hot potato (no-ability struct) | ∅ | ∅, runtime checks in one invocation | 2.3 |
| 9 | Storage operations | move_to / borrow_global / exists / move_from | ⚠ | storage().{set,get,has,remove,update} | 3.1 |
| 10 | State ownership | resources under user accounts | all state under the contract | 3.2 | |
| 11 | Mutable state access | borrow_global_mut writes through | ⚠ | get returns a copy; write only on set | 3.3 |
| 12 | Access declaration | acquires (explicit or inferred) | transaction footprint, from simulation | 3.4 | |
| 13 | State lifetime | state persists once paid | ∅ ⚠ | durability tiers + TTL + archival | 3.5 |
| 14 | Type-level guarantees | abilities key/store/copy/drop | ∅ ⚠ | ∅, every value is plain data | 4.1 |
| 15 | Asset representation | Coin<T> value in hand | ⚠ | ∅ value objects; funds move only via token calls | 4.2 |
| 16 | Type-level asset segregation | generic entry fns, phantom params | ⚠ | monomorphic ABI; asset identity = Address | 4.3 |
| 17 | Data modelling | Move 2 enums / positional structs | 🔧 | #[contracttype] enums / tuple structs | 4.4 |
| 18 | Numeric semantics | signed types since Move 2.3, but amounts are u64 | ⚠ | token amount i128 is signed | 4.5 |
| 19 | Code deployment unit | module published at an address | Wasm hash (upload) + instances (deploy) | 5.1 | |
| 20 | Dependency linking | compile-time use other_module | ⚠ | runtime client to an address held in storage | 5.2 |
| 21 | Function visibility | entry / public / private | one exported namespace, all-public | 5.3 | |
| 22 | Initialization | init_module(&signer) | 🔧 | __constructor(env, args…) | 5.4 |
| 23 | Upgradeability | upgrade policy in Move.toml | upgrade entry point compiled in, or immutable by omission | 5.5 | |
| 24 | Transaction composition | scripts compose calls in one tx | ∅ | exactly one invocation per tx | 5.6 |
| 25 | Failure signalling | abort / assert! codes | #[contracterror] + Result / panic_with_error! | 6.1 | |
| 26 | Failure propagation | abort always propagates | ∅ | callee errors catchable via try_ clients | 6.2 |
| 27 | Overflow safety | overflow aborts, always | ⚠ | Rust semantics behind a profile flag | 4.5 |
| 28 | Call dispatch | static dispatch, reentrancy impossible | dynamic dispatch, host blocks reentrancy | 6.3 | |
| 29 | Metering model | gas schedule, no declaration | multidimensional declared resources | 6.4 | |
| 30 | Off-chain observability | #[event] + event::emit | ⚠ | #[contractevent], topics vs data, ~7-day retention | 7 |
| 31 | Fungible token standard | Coin / Fungible Asset standards | ⚠ | SEP-41 + Stellar Asset Contract | 8.1 |
| 32 | Non-fungible token standard | Digital Asset standard (token objects + refs) | ⚠ | SEP-50 (draft), and no SAC-equivalent trustable tier | 8.2 |
| 33 | Unit testing | #[test(a = @0x1)], expected_failure | ⚠ | Env testutils, mock_all_auths | 9 |
| 34 | Formal verification | Move Prover (first-party, in-language spec {}) | ⚠ | no first-party tool; third-party Certora Sunbeam, Komet | 9 |
| 35 | Read-only queries | #[view] + /view endpoint | ∅ ⚠ | ∅ attribute, any fn via simulateTransaction; view is a call mode | 5.7 |
| 36 | Customizing token behaviour | static dispatch + DFA escape hatch (AIP-73) | ⚠ | dynamic dispatch is the only mechanism; the token is the hook | 5.8 |
| 37 | Event access on-chain | reading emitted events on-chain | ∅ ⚠ | ∅ on both; write-only in production, readable in tests only | 7.1 |
| 38 | Compile-time inlining | inline fun (+ lambda params) | 🔧 | ∅ keyword; ordinary private fns + closures | 5.9 |
| 39 | Paying out a share | splitting a Coin<T> is the value moving | ⚠ | arithmetic, plus a token call you can omit | 4.6 |
Contents
- Identity & authorization
- Capabilities & the object model
- State & storage
- Types & abilities
- Modules vs. contracts
- Execution semantics
- Events
- Tokens
- Testing & assurance
- Toolchain quick map
- Porting reflexes, the grep-able checklist
- Verification
- Primary sources
Contributing
Corrections are the most valuable contribution. Missing Move concepts are equally welcome as issues even without an answer. See CONTRIBUTING.md; All Soroban snippets must compile.