Why Choose Sophia?
FUNCTIONAL PROGRAMMING PARADIGM
Strong Static Typing and Security
oracles, names, state channels
Getting started
Try Sophia Without Setup – In ÆStudio
If you want to try Sophia without installing any tools, head over to ÆStudio, the web-based IDE for writing and testing smart contracts in real time.
Tutorials
Explore tutorials designed to guide you through the core concepts and practical uses of Sophia.
AEX-9 Fungible Token
@compiler >= 5
include "Option.aes"
include "String.aes"
contract FungibleToken =
// Define state of type record encapsulating the contract's mutable state
record state =
{ owner : address // the smart contract's owner address
, total_supply : int // total token supply
, balances : balances // balances for each account
, meta_info : meta_info } // token meta info (name, symbol, decimals)
// This is the meta-information record type
record meta_info =
{ name : string
, symbol : string
, decimals : int }
// This is a type alias for the balances map
type balances = map(address, int)
// Declaration and structure of datatype event
// and events that will be emitted on changes
datatype event = Transfer(address, address, int)
entrypoint init(name: string, decimals : int, symbol : string, initial_balance : option(int)) =
require(String.length(name) >= 1, "STRING_TOO_SHORT_NAME")
require(String.length(symbol) >= 1, "STRING_TOO_SHORT_SYMBOL")
require_non_negative_value(decimals)
// If negative initial owner balance is passed, abort the execution
let initial_supply = Option.default(0, initial_balance)
require_non_negative_value(initial_supply)
let owner = Call.caller
{ owner = owner,
total_supply = initial_supply,
balances = Option.match({}, (balance) => {[owner] = balance}, initial_balance),
meta_info = { name = name, symbol = symbol, decimals = decimals } }
// Get balance for owner's address, returns option(int) or None
entrypoint get_balance(account: address) : option(int) =
Map.lookup(account, state.balances)
// Transfer `value` from `Call.caller` to `to_account` account
stateful entrypoint transfer(to_account: address, value: int) =
internal_transfer(Call.caller, to_account, value)
Summary
In this example we created AEX 9 Fungible Token contract in Sophia, which can be used to create and manage fungible tokens on the Aeternity blockchain.
The contract includes functions for transferring tokens between accounts, checking account balances, and retrieving metadata about the token. The contract also defines and enforces example rules to ensure that transfers are valid and that account balances are maintained correctly.
DO NEVER USE THIS WITHOUT SECURITY AUDIT FIRST!
What’s next?
Explore more examples and complete tutorials:
function require_owner() =
require(Call.caller == state.owner, "ONLY_OWNER_CALL_ALLOWED")
function require_non_negative_value(value : int) =
require(value >= 0, "NON_NEGATIVE_VALUE_REQUIRED")
function require_balance(account : address, value : int) =
switch( get_balance(account))
Some(balance) =>
require(balance >= value, "ACCOUNT_INSUFFICIENT_BALANCE")
None => abort("BALANCE_ACCOUNT_NOT_EXISTENT")
stateful function internal_transfer(from_account: address, to_account: address, value: int) =
require_non_negative_value(value)
require_balance(from_account, value)
put(state{ balances[from_account] @ b = b - value })
put(state{ balances[to_account = 0] @ b = b + value })
Chain.event(Transfer(from_account, to_account, value))
// Getters
entrypoint get_meta_info() : meta_info =
state.meta_info
entrypoint get_total_supply() : int =
state.total_supply
entrypoint get_owner_address() : address =
state.owner
entrypoint get_balances() : balances =
state.balances
CHANGELOG — v8.0.0
— Added
Bitwise operations for integers: band, bor, bxor, bnot, << and >>.
Int.mulmod – combined builtin operation for multiplication and modulus.
Crypto.poseidon – a ZK/SNARK-friendly hash function (over the BLS12-381 scalar field).
Address.to_bytes – convert an address to its binary representation (for hashing, etc.).
(…)
— Changed
Crypto.verify_sig is changed to have msg : bytes(). I.e. the
signed data can be of any length (used to be limited to bytes(32)/hash).
System aliases are handled explicitly when converting to a Sophia value, this is only
observable for signature where a value of type signature is now represented as a
(…)