Skip to main content

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?

StepEVM (Solidity)SVM (Rust/Anchor)Move (Sui)
1. InstallNode + Foundry (2 min)Rust + Solana CLI + Anchor (10 min)Rust + Sui CLI (5 min)
2. IDEHardhat LSP, Foundry extensionrust-analyzer (excellent)Move Analyzer VSCode extension
3. Browser IDERemix (zero install)Solana PlaygroundNone (CLI required)
4. First contractforge init → edit .solforge testanchor init → edit lib.rsanchor testsui move new → edit .movesui move test
5. Mental modelGlobal state + msg.senderAccounts + PDAs + CPIsObjects + ownership + capabilities
6. Deployforge script --broadcastanchor deploysui client publish
7. Frontendethers.js / viem + wagmi@solana/web3.js + wallet-adapter@mysten/sui + dApp Kit
8. Wallet connectMetaMask / WalletConnectPhantom / wallet-adapter-reactSui Wallet + zkLogin (seedless)
9. Test in contract languageYes (Foundry)No (TypeScript separate)Yes (Move #[test])
10. Time to "it works"HoursDaysHours (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
ToolPurpose
Sui CLIBuild, test, publish, interact
Move AnalyzerVSCode LSP for Move syntax
sui move testBuilt-in test runner (tests written in Move)
Move ProverFormal verification of contracts
SuiScanBlock explorer (suiscan.xyz)

Compared To

ConcernEVMSVMSui
Package managerFoundry remappings / npmCargo + Anchor.tomlMove.toml (built-in)
Local networkAnvil (fork mainnet)solana-test-validatorsui start (local network)
Formal verificationCertora, HalmosTrident (early)Move Prover (mature)

Core Concepts

Objects vs Accounts

The fundamental difference. EVM and Solana use account-based models. Sui uses objects.

ConceptEVMSVMSui
State unitStorage slot in contractAccount (data + owner)Object (ID + type + owner + data)
OwnershipImplicit (mapping balances)Program-derived (PDA)Explicit (object field)
TransferUpdate balance mappingChange account ownerMove object to new address
ParallelismSequential (global state)Implicit (Sealevel)Explicit (disjoint object sets)
Identitymsg.senderSigner accounttx_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

StandardEVMSVMSui
FungibleERC-20 (interface)SPL Token / Token-2022sui::coin (module)
Non-fungibleERC-721 (interface)Metaplex NFT standardAny object with key ability
Semi-fungibleERC-1155SPL Token-2022Composable objects
ApproachStandard interface, any implementationProgram accountsObjects 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 concernEVMSVMSui
Unit testsFoundry (Solidity)Rust #[test] + BanksClientMove #[test] + test_scenario
IntegrationFork tests (Anvil)TypeScript + anchor testPTB simulation (dry-run)
FuzzingFoundry built-in, EchidnaTrident (early)Move Prover, Belobog
Formal verificationCertora (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

ConcernEVMSVMSui
SDKethers.js / viem@solana/web3.js@mysten/sui
React hookswagmiwallet-adapter-react@mysten/dapp-kit
Wallet connectWalletConnect / MetaMaskPhantom adapterSui Wallet + zkLogin
Seedless onboardingERC-4337 (complex)None (native)zkLogin (protocol-level)
Sponsored transactionsERC-4337 paymasterNone (native)Built-in gas sponsorship
Transaction previewSimulation via RPCSimulation via RPCPTB 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:

VulnerabilityEVMSVMSui
Re-entrancyYou prevent (guards)Runtime prevents (CPI depth)Compiler prevents (no recursive calls)
Asset duplicationYou prevent (accounting)Runtime prevents (slot checks)Compiler prevents (linear types)
Access controlYou prevent (modifiers)You prevent (signer checks)Compiler prevents (capabilities)
OverflowAuto-checked (0.8+)Debug: panic, Release: wrapAlways checked (bytecode verifier)
Dangling referencesN/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 concernEVMSVMSui
Deploy costGas-dependent (can be expensive)~2 SOL rentLow (storage fund model)
UpgradeabilityProxy pattern (complex)anchor upgradesui client upgrade (policy-controlled)
Finality~15 min (mainnet)~13s economic~390ms (Mysticeti)
ImmutabilityOptional (proxy defeats it)Upgradeable by defaultConfigurable 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

PackageObjectsPattern Proved
identityIdentity (4 entity types), AttestationProof-of-personhood, provider-based verification, confidence scoring
linkLink, AttributionRuleProvenance chains, 4 decay functions (none/linear/exponential/step), value distribution
loyaltyLoyaltyAccount, PointsTransactionCross-module composition (identity + link → loyalty)
device_registryDevice, DeviceCapability, LocationIoT registration, 5 device types, 4 states, owner/operator/agent separation
depin_coreProtocolConfig, ProtocolStatsAdmin-controlled pause/resume, global metrics, protocol lifecycle
governanceDAOProposal framework
collisionCollisionEventAttribution duplicate detection
incentivesRewardPoolReward distribution integrated with device registry
mandateMandateDelegation/permission system
precision_agricultureAgriDeviceVertical-specific IoT
smart_cityCityInfraUrban infrastructure coordination
cross_chain_bridgeBridgeMessageInter-blockchain messaging
tokenomics_validationEconomicModelEconomic model correctness proofs
test_frameworkTestUtilsProperty-based testing utilities

TypeScript Clients

ClientOperations
IdentityClientCreate/update identity, add attestations, query by type
LinksClientCreate links, track attribution chains, compute decay
LoyaltyClientEarn/redeem points, query transaction history
DeviceRegistryClientRegister/transfer devices, update firmware, query by type
CollisionClientDetect attribution collisions

React Safety Components

ComponentWhat It Prevents
ZkLoginConnectWallet installation friction (OAuth → Sui address)
DestructiveOpGateAccidental irreversible actions (countdown + typed confirmation + nuclear warning)
TransferPreviewBlind signing (PTB dry-run shows exact mutations)
CooldownTransferPanic-click transfers (time-gated)
PreDestructionInventoryHidden asset loss (enumerate before destroy)
ValueAtRiskUnaware exposure (balance summary dashboard)
GasEstimateGas surprise (PTB cost preview)
SponsoredSessionGas barrier for new users (app covers gas)

See Wallet Safety Benchmarks for the 5-dimension certification framework these components implement.

Learning Path

StepResourceTime
1. Move basicsMove Book1-2 days
2. Sui objectsSui Docs — Object Model1 day
3. First packageCreate Sui dAppHalf day
4. PTBsSui Docs — PTBsHalf day
5. TestingSui Move Test1 day
6. FrontenddApp Kit1 day
7. DeployTestnet → MainnetHalf day

Context