Smart Contract Development on Move (Aptos/Sui)
Move emerged as a response to accumulated EVM vulnerabilities. When The DAO hack in 2016 emptied it for $60M through Solidity reentrancy, it became clear: global mutable state model plus arbitrary external calls — this is fundamental architectural problem. Move solves it differently: resources are not copied and destroyed implicitly, they are moved. Hence the language name.
If you come with Solidity experience, first week on Move will be painful. Not because it's complex — but because much of what Solidity allows by default, Move forbids at system type level.
How Move Differs from Solidity at Security Level
Linear Type System and Resource Model
In Solidity, token is mapping entry: mapping(address => uint256) balances. Nothing prevents writing function that creates tokens from air or "forgets" to subtract balance. Move resource exists in one place simultaneously — guaranteed by bytecode verifier, not auditor.
// Aptos Move: resource can't be copied or lost
struct Coin<phantom CoinType> has store {
value: u64,
}
Abilities copy, drop, store, key are capabilities. If type lacks drop, compiler won't let function finish without using value. Forgotten resource = compilation error, not lost funds.
Proven EVM Attack Vectors, Closed in Move
| Attack Vector (EVM) | Status in Move |
|---|---|
| Reentrancy | Impossible: no arbitrary external calls to unknown contracts |
| Integer overflow | Impossible: arithmetic aborts on overflow by default |
| Improper proxy initialization | Much harder: storage model differs |
| Access control via msg.sender | Replaced with signer — can't be forged |
| Selfdestruct | No analog |
This doesn't mean Move contracts contain no vulnerabilities. Logic errors haven't gone anywhere. But class of attacks consuming 60-70% of EVM audit, simply doesn't exist in Move.
Aptos vs Sui: Architectural Differences Affecting Development
Both chains use Move, but data storage models radically different.
Aptos: Global Storage and Account-Centric Model
In Aptos, resources stored in account: move_to(account, resource). For accessing other account's resource need acquires-annotated call: borrow_global<T>(addr). Similar to EVM pattern with mapping(address => struct), but type-safe.
// Aptos: read resource of specific account
public fun get_balance(owner: address): u64 acquires CoinStore {
borrow_global<CoinStore>(owner).coin.value
}
Parallelism in Aptos implemented via Block-STM — optimistic execution with rollback on conflicts. Works well if transactions touch different accounts, poorly if all write to one resource (e.g., global counter).
Sui: Object Model and True Parallelism
In Sui everything is object with unique ObjectID. Transaction explicitly declares which objects it uses (owned, shared, immutable). Scheduler sees dependency graph in advance — transactions with non-intersecting objects execute parallel without optimistic rollbacks.
// Sui: object exists independent of account
public struct NFT has key, store {
id: UID,
name: String,
// ...
}
public fun transfer_nft(nft: NFT, recipient: address, ctx: &mut TxContext) {
transfer::public_transfer(nft, recipient);
}
For DeFi protocols with high TPS this is fundamental. Shared objects are shared mutex, they serialize transactions. Well-designed Sui contract maximizes owned object usage.
Our Process with Move
Toolchain and Infrastructure
For Aptos use Aptos CLI and Aptos Framework (Move standard library). For Sui — Sui CLI, Move Analyzer (LSP plugin for VS Code). Tests written on Move Test Framework (#[test], #[test_only]) with coverage via aptos move test --coverage or sui move test.
For fork testing Aptos — Aptos Local Testnet via Docker. For Sui — localnet mode of Sui CLI. Full Hardhat mainnet fork equivalent doesn't exist yet, so integration tests with real protocols (Thala, Cetus, Turbos) require testnet deployment.
Typical Problems on First Move Contract
Generic type phantom. Beginners often confuse phantom parameters. Coin<USDC> and Coin<ETH> — different types despite identical structure. This is feature, not bug. But if not mark parameter as phantom, compiler requires its presence in fields, breaking abstraction.
Ability constraints in generic functions. Write generic function for multiple types without providing needed ability-constraints — common mistake. T: store needed for global storage placement, T: copy + drop for value-type behavior.
Event emission in Sui. Unlike Aptos where events stored in EventHandle resource, Sui emits events via event::emit<T>() and doesn't save on-chain. If contract expects reaction to events from other contract — impossible. Need different architecture.
What Typical Project Looks Like
Analytics (1-3 days). Design resource model: what stored where, who has signer, how objects transferred. Often change original architecture — what works in Solidity needs rethinking in Move.
Development (3-10 days depending on complexity). Write contracts, unit tests and integration scenarios. For DeFi protocols — mandatory fuzz testing on edge cases with minimal amounts and u64 boundary values.
Audit. For Aptos use Move Prover — formal verifier, checks specifications. Unique Move capability: write mathematically provable contract invariants. For Sui — Move Analyzer + manual audit.
Deployment. For Aptos: aptos move publish with multi-sig via Aptos Safe. For Sui: sui client publish with explicit upgrade capability management.
Timeline Guidelines
Simple token contract on Aptos (fungible asset standard) — 3-5 days with tests. Lending protocol with price oracles and liquidations — 4-8 weeks. Cross-chain bridge with finality checks — from 2 months. Cost calculated individually after architecture briefing.
Move — young ecosystem with serious technical advantages. Developer infrastructure lags EVM, documentation sometimes updates faster than it ages. But if you need protocol where reentrancy-class attacks excluded at language level — this is it.







