Skip to main content

Concepts: Move vs Solidity

If you're coming from Solidity, Move will challenge how you think about blockchain programming.

This comprehensive guide compares every major concept between Ethereum/Solidity and Cedra/Move. You'll discover how Move's design eliminates entire vulnerability classes that require constant vigilance in Solidity, and why this matters for building secure, high-performance decentralized applications.

The Paradigm Shift

Solidity: Contract-Centric Computing

Smart contracts are autonomous programs that hold both logic and state. Think of them as independent computers that manage their own data.

Move: Resource-Oriented Programming

Resources are first-class digital assets that exist independently of the code that manipulates them. Think of them as physical objects that can be owned, transferred, but never duplicated or lost.


Account Architecture

In Ethereum, everything is an account, but accounts don't own their assets. In Cedra, accounts directly own typed resources, fundamentally changing how you think about storage and ownership.

Ethereum

// Account structure
Account {
nonce: Sequential transaction counter
balance: ETH balance in wei
storageRoot: Pointer to contract storage
codeHash: Contract code identifier
}
  • All data lives in contract storage (Patricia Merkle Tree)
  • Contracts are accounts with code
  • Users are accounts without code

Cedra

// Account structure
Account {
sequence_number: Transaction ordering
authentication_key: Cryptographic identity
resources: Type-indexed storage
modules: Deployed code
}
  • Resources live under user accounts
  • Modules (code) are separate from resources (data)
  • Each resource type stored once per account

Storage

Solidity stores all user data inside contracts using numbered slots. Move stores typed resources directly under user accounts. You own your data, not the contract.

Ethereum

contract Token {
// Slot 0: owner
address owner;

// Slot 1: totalSupply
uint256 totalSupply;

// Slot 2+: mapping data
mapping(address => uint256) balances;

}
  • Each contract has isolated storage space
  • Storage organized in 32-byte slots
  • Key-value mappings for complex data

Cedra

// Move module
module cedra::token {
struct Vault has key {
coins: Coin<CedraCoin>
}

// Store resource under account
move_to(account, Vault { coins });

// Access resource by type
let vault = borrow_global<Vault>(address);
}
  • Resources stored globally under addresses
  • Type-safe access via borrow_global
  • Resources indexed by type

Execution Models

Ethereum processes transactions one at a time because any contract can call any other. Move's resource isolation enables parallel execution - 160,000 TPS.

Ethereum

// Transaction 1 and 2 must execute in order
// because they might touch the same state
transfer(alice, 100); // Tx 1
transfer(bob, 50); // Tx 2 (must wait)
  • Contracts can call any other contract
  • Can't predict state access patterns
  • External calls can loop back

Cedra

// These can execute simultaneously
transfer_coin<USDC>(alice, 100); // Tx 1
transfer_coin<CED>(bob, 50); // Tx 2 (parallel)
  • Assume no conflicts, execute in parallel
  • Check if assumptions were correct
  • Retry conflicting transactions
  • Apply all changes atomically

Type Systems and Safety

Solidity offers basic type safety but requires runtime checks for everything. Move's linear type system with abilities prevents entire classes of bugs at compile time.

Ethereum

uint256 amount;  // Cannot assign string
address owner; // 20-byte address type
bool isActive; // Boolean type

// Runtime checks required
require(msg.sender == owner, "Not authorized");
require(balance >= amount, "Insufficient funds");
  • Basic type safety (strings, ints, addresses)
  • Manual validation everywhere
  • No compile-time asset safety
  • Developer must prevent bugs

Cedra

// This coin cannot be copied or dropped
struct Coin has store {
value: u64
}

// This receipt must be used (hot potato pattern)
struct Receipt { // No abilities!
amount: u64
}
  • Linear types prevent duplication/loss
  • Abilities control behavior
  • Compiler enforces asset safety
  • Language prevents bugs

Function Dispatch

Solidity allows calling any contract at runtime with arbitrary data. Move requires all function calls to be known at compile time - no address.call(), no reentrancy.

Ethereum

// Can call any contract dynamically
IContract(contractAddress).someFunction();

// Enables complex patterns but also vulnerabilities
address(target).call(
abi.encodeWithSignature("withdraw()")
);
  • Flexible composition
  • Runtime resolution
  • Enables reentrancy attacks
  • Difficult to analyze statically

Cedra

// All calls resolved at compile time
use cedra::token;
token::transfer(from, to, amount);

// No arbitrary external calls possible
// No address.call() equivalent
  • Compile-time verification
  • No reentrancy possible
  • Better performance
  • Easier formal verification

Security Models

Solidity requires developers to follow security patterns correctly. Move's language design makes entire vulnerability classes impossible by construction.

Ethereum

// Reentrancy Guard
modifier nonReentrant() {
require(!locked, "Reentrant call");
locked = true;
_;
locked = false;
}

// Checks-Effects-Interactions
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount); // Check
balances[msg.sender] -= amount; // Effect
msg.sender.transfer(amount); // Interaction
}
  • Manual security patterns required
  • Easy to forget or misimplement
  • SafeMath for overflow protection
  • Access control via modifiers

Cedra

// Reentrancy impossible - no recursive calls
public fun withdraw(account: &signer, amount: u64) {
let coin = coin::withdraw(account, amount);
// No way to call back into this function
}

// Integer overflow auto-aborts
public fun add(a: u64, b: u64): u64 {
a + b // No SafeMath needed
}

// Access control via capability types
public fun admin_only(_cap: &AdminCapability) {
// Must have capability to call
}
  • Security enforced by language
  • Impossible to write vulnerable patterns
  • Automatic overflow checking
  • Type-based capabilities

Transaction Safety Mechanisms

Ethereum's nonces prevent replay attacks but block parallel submission. Cedra's sequence numbers provide the same security without head-of-line blocking.

Ethereum

// Transaction queue - MUST execute in order
Tx1: nonce=4, transfer(alice, 100) // Waiting...
Tx2: nonce=5, transfer(bob, 50) // BLOCKED!
Tx3: nonce=6, transfer(carol, 25) // BLOCKED!

// If Tx1 fails or gets stuck, ALL subsequent
// transactions are blocked (head-of-line blocking)
  • Sequential counter per account
  • Prevents replay attacks
  • Causes issues with parallel submission
  • Stuck transactions block queue

Cedra

// Transactions can be submitted in parallel
Tx1: seq=4, transfer(alice, 100) // Processing
Tx2: seq=5, transfer(bob, 50) // Can proceed!
Tx3: seq=6, transfer(carol, 25) // Can proceed!

// Failed transactions don't block others
// Better handling of transaction ordering
  • Similar to nonces but more flexible
  • Allows parallel transaction submission
  • Better handling of failed transactions
  • No head-of-line blocking

Gas Models

Ethereum's gas price auctions create unpredictable costs from $0.60 to $196+. Cedra's fixed unit pricing delivers consistent ~$0.006 transaction costs.

Ethereum

Auction-Based Pricing:

gasPrice = baseFee + priorityFee
totalCost = gasUsed × gasPrice
  • Variable costs ($0.60 - $196+)
  • Competitive bidding for block space
  • MEV and front-running issues

Cedra

Predictable Pricing:

totalGas = executionUnits + ioUnits + storageBytes
totalCost = totalGas × unitPrice
  • Fixed unit prices (~$0.006)
  • Predictable costs
  • Parallel execution reduces competition
  • Storage fees based on actual bytes

Module Upgradeability

Solidity requires complex proxy patterns with delegatecall risks and storage layout constraints. Move supports native module upgrades with automatic compatibility checks.

Ethereum

// Complex proxy setup required
contract Proxy {
address implementation;

function upgrade(address newImpl) external {
implementation = newImpl;
}

fallback() external {
delegatecall(implementation);
}
}
  • Storage layout must be preserved
  • Complex upgrade patterns
  • Security risks with delegatecall

Cedra

// Modules can be upgraded directly
module cedra::token {
struct UpgradeCapability has key {}

public fun upgrade(
cap: &UpgradeCapability,
code: vector<u8>
) {
// Direct code replacement
}
}
  • Native upgrade support
  • Compatibility checking
  • Simpler governance

Token Standards

Ethereum requires deploying a new contract for every token (ERC-20, ERC-721). Move uses one generic framework with type parameters - infinite tokens, zero deployments.

Ethereum

// Each token needs its own contract
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MTK") {
_mint(msg.sender, 1000000);
}
}

// Deploy again for another token
contract AnotherToken is ERC20 {
constructor() ERC20("Another", "ATK") {
_mint(msg.sender, 5000000);
}
}
  • Contract per token
  • Deployment costs for each
  • Inconsistent implementations

Cedra

// One framework, infinite tokens
module cedra::fungible_asset {
use cedra::fungible_asset;
use cedra::primary_fungible_store;
use cedra::object::Object;

// Same code for all tokens
public fun transfer(
from: &signer,
metadata: Object<Metadata>,
to: address,
amount: u64
) {
let fa = primary_fungible_store::withdraw(from, metadata, amount);
primary_fungible_store::deposit(to, fa);
}
}
  • Type parameters for tokens
  • No deployment needed
  • Guaranteed consistency

Mental Model Shifts: from Solidity to Move

The transition from Solidity to Move requires rethinking fundamental blockchain programming patterns. Move's language design eliminates entire classes of vulnerabilities by construction:

Solidity ThinkingMove ThinkingLearn More
"How do I prevent double-spending?""Resources can't be duplicated"Resource Types
"Check, then update state""Take resource, then give it"Ownership & Borrowing
"Add reentrancy guard""Static dispatch prevents it"Module System
"Pack structs for gas""Use natural data layout"Data Types
"Deploy new contract per token""Use type parameters"Generics
"Implement access control""Use capability tokens"Capability Pattern
Programming Model: Contract-centricResource-oriented programmingIntroduction to Move
Asset Representation: Numbers in mappingsPhysical resources with typesResource Safety
Ownership Model: Contracts own assetsUsers own resourcesAccount Architecture
Safety Approach: Developer vigilanceLanguage-enforced invariantsType System
Execution Model: Sequential by necessityParallel by design (160k TPS)Blockchain Architecture
Type System: Basic types + structsLinear types with abilitiesAbilities System

Ready to build with Move? Here's your learning path:

🎯 Start Building

📚 Deep Dive into Move

🏗️ Advanced Patterns