Sui Move Development
What does it feel like to onboard as a developer — and how does that compare to EVM and Solana?
The parent comparison scores the platforms on safety, onboarding, speed, composability, and ecosystem. This page walks the actual onboarding path — environment, first contract, testing, frontend, deployment — so you can feel the difference rather than read about it.
Onboarding Comparison
The same developer journey across three platforms. Where does each one create friction, and where does it disappear?
| Step | EVM (Solidity) | SVM (Rust/Anchor) | Move (Sui) |
|---|---|---|---|
| 1. Install | Node + Foundry (2 min) | Rust + Solana CLI + Anchor (10 min) | Rust + Sui CLI (5 min) |
| 2. IDE | Hardhat LSP, Foundry extension | rust-analyzer (excellent) | Move Analyzer VSCode extension |
| 3. Browser IDE | Remix (zero install) | Solana Playground | None (CLI required) |
| 4. First contract | forge init → edit .sol → forge test | anchor init → edit lib.rs → anchor test | sui move new → edit .move → sui move test |
| 5. Mental model | Global state + msg.sender | Accounts + PDAs + CPIs | Objects + ownership + capabilities |
| 6. Deploy | forge script --broadcast | anchor deploy | sui client publish |
| 7. Frontend | ethers.js / viem + wagmi | @solana/web3.js + wallet-adapter | @mysten/sui + dApp Kit |
| 8. Wallet connect | MetaMask / WalletConnect | Phantom / wallet-adapter-react | Sui Wallet + zkLogin (seedless) |
| 9. Test in contract language | Yes (Foundry) | No (TypeScript separate) | Yes (Move #[test]) |
| 10. Time to "it works" | Hours | Days | Hours (once mental model clicks) |
The bottleneck is step 5. EVM's mental model is familiar (global state, like a database). Solana's account model is genuinely hard (PDAs, account validation, CPI depth limits). Sui's object model is novel but intuitive once you see that objects ARE the things they represent — a coin is an object you own, not a balance in someone else's ledger.
Environment Setup
# Install Sui CLI (requires Rust)
cargo install --locked --git https://github.com/MystenLabs/sui.git --branch devnet sui
# Verify
sui --version
# Create new project
sui move new my_project
cd my_project
# Run tests
sui move test
# Connect to network
sui client new-env --alias devnet --rpc https://fullnode.devnet.sui.io:443
sui client switch --env devnet
sui client faucet # get test tokens
| Tool | Purpose |
|---|---|
| Sui CLI | Build, test, publish, interact |
| Move Analyzer | VSCode LSP for Move syntax |
| sui move test | Built-in test runner (tests written in Move) |
| Move Prover | Formal verification of contracts |
| SuiScan | Block explorer (suiscan.xyz) |
Compared To
| Concern | EVM | SVM | Sui |
|---|---|---|---|
| Package manager | Foundry remappings / npm | Cargo + Anchor.toml | Move.toml (built-in) |
| Local network | Anvil (fork mainnet) | solana-test-validator | sui start (local network) |
| Formal verification | Certora, Halmos | Trident (early) | Move Prover (mature) |
Core Concepts
Objects vs Accounts
The fundamental difference. EVM and Solana use account-based models. Sui uses objects.
| Concept | EVM | SVM | Sui |
|---|---|---|---|
| State unit | Storage slot in contract | Account (data + owner) | Object (ID + type + owner + data) |
| Ownership | Implicit (mapping balances) | Program-derived (PDA) | Explicit (object field) |
| Transfer | Update balance mapping | Change account owner | Move object to new address |
| Parallelism | Sequential (global state) | Implicit (Sealevel) | Explicit (disjoint object sets) |
| Identity | msg.sender | Signer account | tx_context::sender() + zkLogin |
Object Types
Owned Object → Single owner, fast path (no consensus needed)
Shared Object → Multiple writers, full consensus
Immutable Object → Published packages, constants
Programmable Transaction Blocks
One transaction, up to 1024 operations, with data flowing between them. No equivalent in EVM or Solana at this scale.
PTB:
1. Split coin → coin_a, coin_b
2. Transfer coin_a → recipient
3. Deposit coin_b → DeFi pool
4. Mint receipt NFT from pool
→ All atomic. All in ~390ms.
First Contract
Hello World (Counter)
module hello::counter {
/// A counter object owned by a single address
public struct Counter has key, store {
id: UID,
value: u64,
}
/// Create a new counter, transfer to sender
public fun create(ctx: &mut TxContext) {
let counter = Counter {
id: object::new(ctx),
value: 0,
};
transfer::transfer(counter, tx_context::sender(ctx));
}
/// Increment the counter
public fun increment(counter: &mut Counter) {
counter.value = counter.value + 1;
}
/// Read the value
public fun value(counter: &Counter): u64 {
counter.value
}
#[test]
fun test_counter() {
use sui::test_scenario;
let owner = @0xA;
let mut scenario = test_scenario::begin(owner);
// Create counter
test_scenario::next_tx(&mut scenario, owner);
{
create(test_scenario::ctx(&mut scenario));
};
// Increment and verify
test_scenario::next_tx(&mut scenario, owner);
{
let mut counter = test_scenario::take_from_sender<Counter>(&scenario);
increment(&mut counter);
assert!(value(&counter) == 1, 0);
test_scenario::return_to_sender(&scenario, counter);
};
test_scenario::end(scenario);
}
}
Compared To
EVM equivalent: uint256 public counter; function increment() public { counter++; } — simpler syntax, but the counter lives in contract storage, not as an owned object. Anyone can call increment. Access control is opt-in.
Solana equivalent: Define account struct, derive PDA, validate accounts in instruction handler, serialize/deserialize. ~3x more boilerplate for the same result because the account model requires explicit validation at every step.
Sui difference: The counter IS an object. Ownership is structural. Only the owner can pass &mut Counter. The compiler enforces what EVM and Solana enforce at runtime (or don't).
Token Standards
| Standard | EVM | SVM | Sui |
|---|---|---|---|
| Fungible | ERC-20 (interface) | SPL Token / Token-2022 | sui::coin (module) |
| Non-fungible | ERC-721 (interface) | Metaplex NFT standard | Any object with key ability |
| Semi-fungible | ERC-1155 | SPL Token-2022 | Composable objects |
| Approach | Standard interface, any implementation | Program accounts | Objects with abilities |
In Sui, there's no separate "NFT standard" because every object with key is already uniquely identified, owned, and transferable. The object model IS the standard.
/// A Sui coin is just a typed wrapper around a balance
public struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>,
}
Testing
Tests live in the same language as contracts. No context switching.
#[test]
fun test_transfer() {
use sui::test_scenario;
let sender = @0xA;
let recipient = @0xB;
let mut scenario = test_scenario::begin(sender);
// Create and transfer
test_scenario::next_tx(&mut scenario, sender);
{
let coin = coin::mint_for_testing<SUI>(1000, test_scenario::ctx(&mut scenario));
transfer::public_transfer(coin, recipient);
};
// Verify recipient received it
test_scenario::next_tx(&mut scenario, recipient);
{
let coin = test_scenario::take_from_sender<Coin<SUI>>(&scenario);
assert!(coin::value(&coin) == 1000, 0);
test_scenario::return_to_sender(&scenario, coin);
};
test_scenario::end(scenario);
}
| Testing concern | EVM | SVM | Sui |
|---|---|---|---|
| Unit tests | Foundry (Solidity) | Rust #[test] + BanksClient | Move #[test] + test_scenario |
| Integration | Fork tests (Anvil) | TypeScript + anchor test | PTB simulation (dry-run) |
| Fuzzing | Foundry built-in, Echidna | Trident (early) | Move Prover, Belobog |
| Formal verification | Certora (expensive) | None (production) | Move Prover (built-in, free) |
Move Prover is the differentiator. Formal verification is built into the toolchain, not a $50K+ audit add-on.
Frontend Integration
dApp Kit
import { ConnectButton, useCurrentAccount, useSuiClient } from '@mysten/dapp-kit';
import { Transaction } from '@mysten/sui/transactions';
function App() {
const account = useCurrentAccount();
const client = useSuiClient();
const incrementCounter = async () => {
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE_ID}::counter::increment`,
arguments: [tx.object(COUNTER_ID)],
});
// Sign and execute via connected wallet
};
return (
<div>
<ConnectButton />
{account && <button onClick={incrementCounter}>Increment</button>}
</div>
);
}
Compared To
| Concern | EVM | SVM | Sui |
|---|---|---|---|
| SDK | ethers.js / viem | @solana/web3.js | @mysten/sui |
| React hooks | wagmi | wallet-adapter-react | @mysten/dapp-kit |
| Wallet connect | WalletConnect / MetaMask | Phantom adapter | Sui Wallet + zkLogin |
| Seedless onboarding | ERC-4337 (complex) | None (native) | zkLogin (protocol-level) |
| Sponsored transactions | ERC-4337 paymaster | None (native) | Built-in gas sponsorship |
| Transaction preview | Simulation via RPC | Simulation via RPC | PTB dry-run (1024 ops visible) |
zkLogin removes the wallet installation barrier entirely. Users sign in with Google/Apple, a ZK proof maps their OAuth credential to a Sui address. No seed phrase, no extension, no onboarding friction.
Security Patterns
What the compiler prevents vs what you must prevent yourself:
| Vulnerability | EVM | SVM | Sui |
|---|---|---|---|
| Re-entrancy | You prevent (guards) | Runtime prevents (CPI depth) | Compiler prevents (no recursive calls) |
| Asset duplication | You prevent (accounting) | Runtime prevents (slot checks) | Compiler prevents (linear types) |
| Access control | You prevent (modifiers) | You prevent (signer checks) | Compiler prevents (capabilities) |
| Overflow | Auto-checked (0.8+) | Debug: panic, Release: wrap | Always checked (bytecode verifier) |
| Dangling references | N/A (no references) | Borrow checker (Rust) | Borrow checker (Move) |
Capability Pattern
/// Only the holder of AdminCap can call admin functions
public struct AdminCap has key, store {
id: UID,
}
/// This function cannot be called without possessing AdminCap
public fun admin_action(cap: &AdminCap, /* ... */) {
// AdminCap is the proof of authorization
// No runtime check needed — if you have it, you're authorized
}
Compare to Solidity's onlyOwner modifier (convention, not enforcement) or Solana's manual require!(ctx.accounts.authority.key() == expected) (runtime check you might forget).
Deployment
# Build
sui move build
# Publish to devnet (get package ID back)
sui client publish --gas-budget 100000000
# Interact
sui client call \
--package $PACKAGE_ID \
--module counter \
--function create \
--gas-budget 10000000
| Deployment concern | EVM | SVM | Sui |
|---|---|---|---|
| Deploy cost | Gas-dependent (can be expensive) | ~2 SOL rent | Low (storage fund model) |
| Upgradeability | Proxy pattern (complex) | anchor upgrade | sui client upgrade (policy-controlled) |
| Finality | ~15 min (mainnet) | ~13s economic | ~390ms (Mysticeti) |
| Immutability | Optional (proxy defeats it) | Upgradeable by default | Configurable per package |
What We Built
Patterns proven across 15 Move packages, TypeScript SDK clients, and React safety components. Deployed at drmg-design-system.vercel.app.
Move Packages
| Package | Objects | Pattern Proved |
|---|---|---|
| identity | Identity (4 entity types), Attestation | Proof-of-personhood, provider-based verification, confidence scoring |
| link | Link, AttributionRule | Provenance chains, 4 decay functions (none/linear/exponential/step), value distribution |
| loyalty | LoyaltyAccount, PointsTransaction | Cross-module composition (identity + link → loyalty) |
| device_registry | Device, DeviceCapability, Location | IoT registration, 5 device types, 4 states, owner/operator/agent separation |
| depin_core | ProtocolConfig, ProtocolStats | Admin-controlled pause/resume, global metrics, protocol lifecycle |
| governance | DAO | Proposal framework |
| collision | CollisionEvent | Attribution duplicate detection |
| incentives | RewardPool | Reward distribution integrated with device registry |
| mandate | Mandate | Delegation/permission system |
| precision_agriculture | AgriDevice | Vertical-specific IoT |
| smart_city | CityInfra | Urban infrastructure coordination |
| cross_chain_bridge | BridgeMessage | Inter-blockchain messaging |
| tokenomics_validation | EconomicModel | Economic model correctness proofs |
| test_framework | TestUtils | Property-based testing utilities |
TypeScript Clients
| Client | Operations |
|---|---|
| IdentityClient | Create/update identity, add attestations, query by type |
| LinksClient | Create links, track attribution chains, compute decay |
| LoyaltyClient | Earn/redeem points, query transaction history |
| DeviceRegistryClient | Register/transfer devices, update firmware, query by type |
| CollisionClient | Detect attribution collisions |
React Safety Components
| Component | What It Prevents |
|---|---|
| ZkLoginConnect | Wallet installation friction (OAuth → Sui address) |
| DestructiveOpGate | Accidental irreversible actions (countdown + typed confirmation + nuclear warning) |
| TransferPreview | Blind signing (PTB dry-run shows exact mutations) |
| CooldownTransfer | Panic-click transfers (time-gated) |
| PreDestructionInventory | Hidden asset loss (enumerate before destroy) |
| ValueAtRisk | Unaware exposure (balance summary dashboard) |
| GasEstimate | Gas surprise (PTB cost preview) |
| SponsoredSession | Gas barrier for new users (app covers gas) |
See Wallet Safety Benchmarks for the 5-dimension certification framework these components implement.
Learning Path
| Step | Resource | Time |
|---|---|---|
| 1. Move basics | Move Book | 1-2 days |
| 2. Sui objects | Sui Docs — Object Model | 1 day |
| 3. First package | Create Sui dApp | Half day |
| 4. PTBs | Sui Docs — PTBs | Half day |
| 5. Testing | Sui Move Test | 1 day |
| 6. Frontend | dApp Kit | 1 day |
| 7. Deploy | Testnet → Mainnet | Half day |
Context
- Smart Contract Comparison — Safety, onboarding, speed, composability, ecosystem across EVM/SVM/Move
- EVM Development — Solidity onboarding path
- Solana Development — SVM onboarding path
- Sui Technical — Object model, Mysticeti consensus, agent economy primitives
- Sui Dev Resources — SDKs, tooling, learning resources
- Wallet Safety Benchmarks — 5-dimension safety certification framework
- Developer Experience — DX as northstar for crypto adoption