from solidity

From Solidity to Cudo

Everything you know still applies — contracts, state, events, access control. Cudo just moves the safety checks from runtime to compile time. This guide maps every Solidity concept to its Cudo equivalent.

01 Concept map

Every Solidity concept has a Cudo equivalent. Some get stricter, some get simpler, some disappear entirely (because the compiler handles them).

Solidity
Cudo
contract
contract
mapping / state variables
state { } block
function (external/public)
operation
view / pure functions
view
event + emit
event + emits: clause
modifier / require()
requires: clause
onlyOwner / role checks
capability + has
ReentrancyGuard / nonReentrant
nothing — impossible in grammar
SafeMath / unchecked blocks
checked by default, +% -% *% for wrapping
no equivalent
contention: (parallelism model)
no equivalent
invariant (compiler-proven properties)
no equivalent
resource (linear types)
02 Side by side

The same contracts, written in both languages. Notice what disappears.

ERC-20 Token

Token.sol solidity
pragma solidity ^0.8.20;

contract Token {
    mapping(address => uint256) public balances;
    uint256 public totalSupply;

    event Transfer(
        address indexed from,
        address indexed to,
        uint256 amount
    );

    function transfer(
        address to,
        uint256 amount
    ) external {
        require(
            balances[msg.sender] >= amount,
            "insufficient"
        );
        balances[msg.sender] -= amount;
        balances[to] += amount;
        emit Transfer(
            msg.sender, to, amount
        );
    }
}
token.cudo cudo
contract Token {
    version: 1
    contention: per<address>

    state {
        total_supply: u256,
        balances: Map<address, u256>,
    }

    invariant conservation:
        self.total_supply
        == self.balances.values().sum()

    operation transfer(
        to: address,
        amount: u256
    )
        requires: self.balances[caller]
                  >= amount
        mutates:  self.balances[caller],
                  self.balances[to]
        emits:    Transfer
    {
        self.balances[caller] -= amount;
        self.balances[to] += amount;
        emit Transfer {
            from: caller, to, amount
        };
    }
}
What's different? The Cudo version adds a conservation invariant the compiler proves, a contention model that enables parallel transfers, and mutates: clauses that prevent undeclared side effects. Reentrancy? Not possible — there's no callback mechanism.

Access Control

Ownable.sol solidity
contract Ownable {
    address public owner;
    mapping(address => bool) admins;

    modifier onlyOwner() {
        require(
            msg.sender == owner,
            "not owner"
        );
        _;
    }

    modifier onlyAdmin() {
        require(
            admins[msg.sender],
            "not admin"
        );
        _;
    }

    function addAdmin(
        address a
    ) external onlyOwner {
        admins[a] = true;
    }

    function doThing()
        external onlyAdmin
    {
        // admin logic
    }
}
managed.cudo cudo
contract Managed {
    version: 1
    contention: global

    capability Owner;
    capability Admin;

    state {
        admin_set: Set<address>,
    }

    operation add_admin(
        a: address
    )
        requires: caller has Owner
        mutates:  self.admin_set
    {
        self.admin_set.insert(a);
    }

    operation do_thing()
        requires: caller has Admin
    {
        // admin logic
    }
}
No modifiers, no inheritance. Capabilities are type-level constraints. A caller without Owner can't even attempt to call add_admin — the transaction is rejected before execution.

Vault (the reentrancy problem)

Vault.sol solidity
import "ReentrancyGuard.sol";

contract Vault is ReentrancyGuard {
    mapping(address => uint256)
        deposits;

    function withdraw(
        uint256 amount
    ) external nonReentrant {
        require(
            deposits[msg.sender] >= amount
        );
        // CEI pattern (easy to forget)
        deposits[msg.sender] -= amount;

        // external call — reentrancy
        // risk if guard is missing
        (bool ok, ) = msg.sender
            .call{value: amount}("");
        require(ok);
    }
}
vault.cudo cudo
contract Vault {
    version: 1
    contention: per<address>

    state {
        deposits: Map<address, u256>,
    }

    operation withdraw(
        amount: u256
    )
        requires:
            self.deposits[caller]
            >= amount
        mutates:
            self.deposits[caller]
    {
        self.deposits[caller]
            -= amount;
        send(amount, caller);
    }
    // no callbacks exist.
    // reentrancy is a syntax error.
    // no guard needed.
}
The DAO hack is a syntax error. Cudo has no callback mechanism in the grammar. Operations can't re-enter. There is no fallback(), no receive(), no way for a called contract to call you back mid-execution.
03 What you lose, what you gain

Gone from Solidity

New in Cudo

04 Interactive transpiler

Paste Solidity or pick a template. See the Cudo equivalent instantly. This is a pattern-based translation — it won't handle every edge case, but it'll get you 80% there.

solidity → cudo transpiler
paste solidity
cudo output
// paste Solidity or pick a template to see the Cudo equivalent
templates:
05 Migration checklist

Moving a Solidity codebase to Cudo, step by step.

  1. Map all mapping and state variables into a single state { } block.
  2. Convert function to operation. Add mutates: clauses listing every field each operation writes.
  3. Convert view/pure functions to view.
  4. Replace modifier + require() with requires: clauses.
  5. Replace role checks (onlyOwner) with capability declarations and has constraints.
  6. Choose a contention: model. If users operate on independent state, use per<K>.
  7. Delete reentrancy guards. They're unnecessary.
  8. Add invariant declarations for any conservation laws or bounds you previously tested for.
  9. If you used token transfers as values, model them as resource types instead.
  10. Run cudo check and fix compiler errors. Each one is a bug that existed silently in your Solidity.