Tsukumogami

Documentation

Learn about the Python subset supported by Tsukumogami, safety guarantees, and how to write transpilable contracts.

Overview

Tsukumogami transpiles a carefully constrained subset of Python into production-ready smart contracts. The subset is designed to ensure:

  • Determinism — Same input always produces same output
  • Auditability — Generated code is readable and reviewable
  • Gas Predictability — Bounded execution costs
  • Safety — Compile-time guarantees prevent common vulnerabilities

Python Subset

Supported Features

Type annotations (mandatory)
Variables, arithmetic, comparisons
Control flow (if, for, bounded while)
Pure functions
Classes with @contract decorator
Mapping[K, V] and Array[T]
Optional[T] for nullable types
Tuple for fixed structs

Not Supported

Recursion(Stack safety)
Unbounded loops(Gas predictability)
Floating-point math(Precision issues)
Dynamic imports(Determinism)
File/network access(Sandboxing)
Generators/yield(State complexity)
Async/await(Not applicable on-chain)
eval/exec(Security)

Decorators

@contractMarks a class as a smart contract
@contract
class MyContract:
    ...
@entryTransaction entry point (state-mutating)
@entry
def transfer(self, to: Address, amount: Uint256) -> bool:
    ...
@viewRead-only function (no state changes)
@view
def get_balance(self, account: Address) -> Uint256:
    return self.balances[account]
@eventDefines an emittable event
@event
class Transfer:
    sender: Address
    recipient: Address
    amount: Uint256
@storageMarks persistent storage
@storage
class State:
    owner: Address
    total: Uint256

Type Mappings

PythonSolidityRustMove
intint256i64u64
boolboolboolbool
strstringStringString
Uint256uint256u128u256
AddressaddressPubkeyaddress
Bytes32bytes32[u8; 32]vector<u8>
Mapping[K, V]mapping(K => V)HashMap<K, V>Table<K, V>
Array[T]T[]Vec<T>vector<T>

Safety Rules

Mandatory Type Annotations

All function parameters, return types, and storage variables must have explicit type annotations. This enables static analysis and deterministic code generation.

No Recursion

Direct or indirect recursion is not allowed. All iterative patterns must use explicit loops with bounded iterations.

No Floating Point

Floating-point numbers are not supported due to non-deterministic behavior across platforms. Use integer arithmetic or fixed-point representations.

Bounded Loops

All loops must have a clear upper bound that can be determined at compile time. This ensures predictable gas costs and prevents infinite loops.

Examples

Simple Counter

Basic state management with increment/decrement

Python Input
class="syntax-decorator">@contract
class Counter:
count: Uint256
class="syntax-decorator">@entry
def increment(self) -> None:
self.count += 1
class="syntax-decorator">@view
def get(self) -> Uint256:
return self.count
Solidity Output
contract Counter {
uint256 public count;
function increment() external {
count += 1;
}
function get() external view returns (uint256) {
return count;
}
}

Access Control

Owner-restricted operations

Python Input
class="syntax-decorator">@contract
class Ownable:
owner: Address
def __init__(self) -> None:
self.owner = msg.sender
class="syntax-decorator">@entry
def restricted_action(self) -> None:
assert msg.sender == self.owner
class=class="syntax-string">"syntax-comment"># ... action
Solidity Output
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
function restrictedAction() external {
require(msg.sender == owner);
class=class="syntax-string">"syntax-comment">// ... action
}
}

Token Balance

Mapping-based balance tracking

Python Input
class="syntax-decorator">@contract
class Token:
balances: Mapping[Address, Uint256]
class="syntax-decorator">@entry
def transfer(self, to: Address, amount: Uint256) -> bool:
assert self.balances[msg.sender] >= amount
self.balances[msg.sender] -= amount
self.balances[to] += amount
return True
Solidity Output
contract Token {
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount)
external returns (bool)
{
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
balances[to] += amount;
return true;
}
}