Smart Contracts
JOEL supports smart contract development for blockchain platforms.
Contract Declaration
Ethereum (EVM)
[Compiled]
[target evm]
contract Vault {
state let owner: address
state let balance: uint256 = 0
fn constructor() {
owner = tx.sender
}
#[payable]
fn deposit() {
balance += tx.value
}
fn withdraw(amount: uint256) {
require(tx.sender == owner)
require(amount <= balance)
send(owner, amount)
balance -= amount
}
}Solana (WASM)
[Compiled]
[target wasm-solana]
contract Counter {
state let count: u64 = 0
fn increment() {
count += 1
}
fn get() -> u64 {
return count
}
}Contract State
contract Token {
state let total_supply: uint256
state let balances: map[address, uint256]
state let owner: address
}Contract Functions
Public Functions
contract Token {
fn transfer(to: address, amount: uint256) {
# Public function - anyone can call
}
}Private Functions
contract Token {
private fn _mint(to: address, amount: uint256) {
# Internal function
}
}Payable Functions
contract Vault {
#[payable]
fn deposit() {
# Can receive native tokens
balance += tx.value
}
}Access Control
contract Ownable {
state let owner: address
fn only_owner() {
require(tx.sender == owner)
}
fn transfer_ownership(new_owner: address) {
only_owner()
owner = new_owner
}
}Events
# Coming soon
contract Token {
event Transfer(from: address, to: address, amount: uint256)
fn transfer(to: address, amount: uint256) {
# Transfer logic
emit Transfer(tx.sender, to, amount)
}
}Examples
Simple Token
[Compiled]
[target evm]
contract SimpleToken {
state let total_supply: uint256 = 1000000
state let balances: map[address, uint256]
state let owner: address
fn constructor() {
owner = tx.sender
balances[owner] = total_supply
}
fn transfer(to: address, amount: uint256) {
require(balances[tx.sender] >= amount)
balances[tx.sender] -= amount
balances[to] += amount
}
fn balance_of(addr: address) -> uint256 {
return balances[addr]
}
}Vault Contract
[Compiled]
[target evm]
contract Vault {
state let owner: address
state let balance: uint256 = 0
fn constructor() {
owner = tx.sender
}
#[payable]
fn deposit() {
balance += tx.value
}
fn withdraw(amount: uint256) {
require(tx.sender == owner)
require(amount <= balance)
send(owner, amount)
balance -= amount
}
fn get_balance() -> uint256 {
return balance
}
}Security Best Practices
- Check access: Always verify permissions
- Validate inputs: Check all parameters
- Handle overflow: Use safe math operations
- Avoid reentrancy: Use checks-effects-interactions
- Test thoroughly: Write comprehensive tests
Compilation
# Compile for EVM
joel build contract.joel --target evm
# Compile for Solana
joel build contract.joel --target wasm-solana