1843 lines
64 KiB
HTML
1843 lines
64 KiB
HTML
|
||
<!doctype html>
|
||
<html lang="en" class="no-js">
|
||
<head>
|
||
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
||
|
||
|
||
|
||
<link rel="icon" href="favicon.png">
|
||
<meta name="generator" content="mkdocs-1.2.1, mkdocs-material-7.1.9">
|
||
|
||
|
||
|
||
<title>Features - æternity Sophia Language</title>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="assets/stylesheets/main.ca7ac06f.min.css">
|
||
|
||
|
||
<link rel="stylesheet" href="assets/stylesheets/palette.f1a3b89f.min.css">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700%7CRoboto+Mono&display=fallback">
|
||
<style>:root{--md-text-font-family:"Roboto";--md-code-font-family:"Roboto Mono"}</style>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="pink" data-md-color-accent="pink">
|
||
|
||
|
||
<script>function __prefix(e){return new URL(".",location).pathname+"."+e}function __get(e,t=localStorage){return JSON.parse(t.getItem(__prefix(e)))}</script>
|
||
|
||
<script>var palette=__get("__palette");if(null!==palette&&"object"==typeof palette.color)for(var key in palette.color)document.body.setAttribute("data-md-color-"+key,palette.color[key])</script>
|
||
|
||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||
<label class="md-overlay" for="__drawer"></label>
|
||
<div data-md-component="skip">
|
||
|
||
|
||
<a href="#features" class="md-skip">
|
||
Skip to content
|
||
</a>
|
||
|
||
</div>
|
||
<div data-md-component="announce">
|
||
|
||
</div>
|
||
|
||
<header class="md-header" data-md-component="header">
|
||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||
<a href="index.html" title="æternity Sophia Language" class="md-header__button md-logo" aria-label="æternity Sophia Language" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54z"/></svg>
|
||
|
||
</a>
|
||
<label class="md-header__button md-icon" for="__drawer">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
|
||
</label>
|
||
<div class="md-header__title" data-md-component="header-title">
|
||
<div class="md-header__ellipsis">
|
||
<div class="md-header__topic">
|
||
<span class="md-ellipsis">
|
||
æternity Sophia Language
|
||
</span>
|
||
</div>
|
||
<div class="md-header__topic" data-md-component="header-topic">
|
||
<span class="md-ellipsis">
|
||
|
||
Features
|
||
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<form class="md-header__option" data-md-component="palette">
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="pink" data-md-color-accent="pink" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
|
||
|
||
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3 3.19.09m3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95 2.06.05m-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31z"/></svg>
|
||
</label>
|
||
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="pink" data-md-color-accent="pink" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_2">
|
||
|
||
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5c-.84 0-1.65.15-2.39.42L12 2M3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29L3.34 7m.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14L3.36 17M20.65 7l-1.77 3.79a7.023 7.023 0 0 0-2.38-4.15l4.15.36m-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29L20.64 17M12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44L12 22z"/></svg>
|
||
</label>
|
||
|
||
|
||
</form>
|
||
|
||
|
||
|
||
<label class="md-header__button md-icon" for="__search">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
|
||
</label>
|
||
|
||
<div class="md-search" data-md-component="search" role="dialog">
|
||
<label class="md-search__overlay" for="__search"></label>
|
||
<div class="md-search__inner" role="search">
|
||
<form class="md-search__form" name="search">
|
||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active" required>
|
||
<label class="md-search__icon md-icon" for="__search">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
|
||
</label>
|
||
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" tabindex="-1">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
|
||
</button>
|
||
</form>
|
||
<div class="md-search__output">
|
||
<div class="md-search__scrollwrap" data-md-scrollfix>
|
||
<div class="md-search-result" data-md-component="search-result">
|
||
<div class="md-search-result__meta">
|
||
Initializing search
|
||
</div>
|
||
<ol class="md-search-result__list"></ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="md-header__source">
|
||
|
||
<a href="https://github.com/aeternity/aesophia" title="Go to repository" class="md-source" data-md-component="source">
|
||
<div class="md-source__icon md-icon">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||
</div>
|
||
<div class="md-source__repository">
|
||
GitHub
|
||
</div>
|
||
</a>
|
||
</div>
|
||
|
||
</nav>
|
||
</header>
|
||
|
||
<div class="md-container" data-md-component="container">
|
||
|
||
|
||
|
||
|
||
<main class="md-main" data-md-component="main">
|
||
<div class="md-main__inner md-grid">
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
|
||
|
||
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
||
<label class="md-nav__title" for="__drawer">
|
||
<a href="index.html" title="æternity Sophia Language" class="md-nav__button md-logo" aria-label="æternity Sophia Language" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54z"/></svg>
|
||
|
||
</a>
|
||
æternity Sophia Language
|
||
</label>
|
||
|
||
<div class="md-nav__source">
|
||
|
||
<a href="https://github.com/aeternity/aesophia" title="Go to repository" class="md-source" data-md-component="source">
|
||
<div class="md-source__icon md-icon">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||
</div>
|
||
<div class="md-source__repository">
|
||
GitHub
|
||
</div>
|
||
</a>
|
||
</div>
|
||
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="index.html" class="md-nav__link">
|
||
Introduction
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="sophia_syntax.html" class="md-nav__link">
|
||
Syntax
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active">
|
||
|
||
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||
Features
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<a href="sophia_features.html" class="md-nav__link md-nav__link--active">
|
||
Features
|
||
</a>
|
||
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contracts" class="md-nav__link">
|
||
Contracts
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Contracts">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#calling-other-contracts" class="md-nav__link">
|
||
Calling other contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#protected-contract-calls" class="md-nav__link">
|
||
Protected contract calls
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contract-factories-and-child-contracts" class="md-nav__link">
|
||
Contract factories and child contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#mutable-state" class="md-nav__link">
|
||
Mutable state
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Mutable state">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#stateful-functions" class="md-nav__link">
|
||
Stateful functions
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable" class="md-nav__link">
|
||
Payable
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Payable">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable-contracts" class="md-nav__link">
|
||
Payable contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable-entrypoints" class="md-nav__link">
|
||
Payable entrypoints
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#namespaces" class="md-nav__link">
|
||
Namespaces
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#splitting-code-over-multiple-files" class="md-nav__link">
|
||
Splitting code over multiple files
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#standard-library" class="md-nav__link">
|
||
Standard library
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#types" class="md-nav__link">
|
||
Types
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#literals" class="md-nav__link">
|
||
Literals
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arithmetic" class="md-nav__link">
|
||
Arithmetic
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#bit-fields" class="md-nav__link">
|
||
Bit fields
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#type-aliases" class="md-nav__link">
|
||
Type aliases
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#algebraic-data-types" class="md-nav__link">
|
||
Algebraic data types
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#lists" class="md-nav__link">
|
||
Lists
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#maps-and-records" class="md-nav__link">
|
||
Maps and records
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Maps and records">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#constructing-maps-and-records" class="md-nav__link">
|
||
Constructing maps and records
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#accessing-values" class="md-nav__link">
|
||
Accessing values
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#updating-a-value" class="md-nav__link">
|
||
Updating a value
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#map-implementation" class="md-nav__link">
|
||
Map implementation
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#strings" class="md-nav__link">
|
||
Strings
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#chars" class="md-nav__link">
|
||
Chars
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#byte-arrays" class="md-nav__link">
|
||
Byte arrays
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#cryptographic-builtins" class="md-nav__link">
|
||
Cryptographic builtins
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#authorization-interface" class="md-nav__link">
|
||
Authorization interface
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#oracle-interface" class="md-nav__link">
|
||
Oracle interface
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Oracle interface">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#example" class="md-nav__link">
|
||
Example
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sanity-checks" class="md-nav__link">
|
||
Sanity checks
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aens-interface" class="md-nav__link">
|
||
AENS interface
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="AENS interface">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#example_1" class="md-nav__link">
|
||
Example
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#events" class="md-nav__link">
|
||
Events
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Events">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#argument-order" class="md-nav__link">
|
||
Argument order
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#compiler-pragmas" class="md-nav__link">
|
||
Compiler pragmas
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#exceptions" class="md-nav__link">
|
||
Exceptions
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#delegation-signature" class="md-nav__link">
|
||
Delegation signature
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="sophia_stdlib.html" class="md-nav__link">
|
||
Standard library
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="sophia_examples.html" class="md-nav__link">
|
||
Contract examples
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="CHANGELOG.html" class="md-nav__link">
|
||
Changelog
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contracts" class="md-nav__link">
|
||
Contracts
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Contracts">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#calling-other-contracts" class="md-nav__link">
|
||
Calling other contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#protected-contract-calls" class="md-nav__link">
|
||
Protected contract calls
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contract-factories-and-child-contracts" class="md-nav__link">
|
||
Contract factories and child contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#mutable-state" class="md-nav__link">
|
||
Mutable state
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Mutable state">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#stateful-functions" class="md-nav__link">
|
||
Stateful functions
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable" class="md-nav__link">
|
||
Payable
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Payable">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable-contracts" class="md-nav__link">
|
||
Payable contracts
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#payable-entrypoints" class="md-nav__link">
|
||
Payable entrypoints
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#namespaces" class="md-nav__link">
|
||
Namespaces
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#splitting-code-over-multiple-files" class="md-nav__link">
|
||
Splitting code over multiple files
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#standard-library" class="md-nav__link">
|
||
Standard library
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#types" class="md-nav__link">
|
||
Types
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#literals" class="md-nav__link">
|
||
Literals
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arithmetic" class="md-nav__link">
|
||
Arithmetic
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#bit-fields" class="md-nav__link">
|
||
Bit fields
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#type-aliases" class="md-nav__link">
|
||
Type aliases
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#algebraic-data-types" class="md-nav__link">
|
||
Algebraic data types
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#lists" class="md-nav__link">
|
||
Lists
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#maps-and-records" class="md-nav__link">
|
||
Maps and records
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Maps and records">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#constructing-maps-and-records" class="md-nav__link">
|
||
Constructing maps and records
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#accessing-values" class="md-nav__link">
|
||
Accessing values
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#updating-a-value" class="md-nav__link">
|
||
Updating a value
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#map-implementation" class="md-nav__link">
|
||
Map implementation
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#strings" class="md-nav__link">
|
||
Strings
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#chars" class="md-nav__link">
|
||
Chars
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#byte-arrays" class="md-nav__link">
|
||
Byte arrays
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#cryptographic-builtins" class="md-nav__link">
|
||
Cryptographic builtins
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#authorization-interface" class="md-nav__link">
|
||
Authorization interface
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#oracle-interface" class="md-nav__link">
|
||
Oracle interface
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Oracle interface">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#example" class="md-nav__link">
|
||
Example
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sanity-checks" class="md-nav__link">
|
||
Sanity checks
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aens-interface" class="md-nav__link">
|
||
AENS interface
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="AENS interface">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#example_1" class="md-nav__link">
|
||
Example
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#events" class="md-nav__link">
|
||
Events
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Events">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#argument-order" class="md-nav__link">
|
||
Argument order
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#compiler-pragmas" class="md-nav__link">
|
||
Compiler pragmas
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#exceptions" class="md-nav__link">
|
||
Exceptions
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#delegation-signature" class="md-nav__link">
|
||
Delegation signature
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="md-content" data-md-component="content">
|
||
<article class="md-content__inner md-typeset">
|
||
|
||
|
||
|
||
<h1 id="features">Features</h1>
|
||
<h2 id="contracts">Contracts</h2>
|
||
<p>The main unit of code in Sophia is the <em>contract</em>.</p>
|
||
<ul>
|
||
<li>A contract implementation, or simply a contract, is the code for a
|
||
smart contract and consists of a list of types, entrypoints and local
|
||
functions. Only the entrypoints can be called from outside the contract.</li>
|
||
<li>A contract instance is an entity living on the block chain (or in a state
|
||
channel). Each instance has an address that can be used to call its
|
||
entrypoints, either from another contract or in a call transaction.</li>
|
||
<li>A contract may define a type <code>state</code> encapsulating its local
|
||
state. When creating a new contract the <code>init</code> entrypoint is executed and the
|
||
state is initialized to its return value.</li>
|
||
</ul>
|
||
<p>The language offers some primitive functions to interact with the blockchain and contracts.
|
||
Please refer to the <a href="sophia_stdlib.html#chain">Chain</a>, <a href="sophia_stdlib.html#contract">Contract</a>
|
||
and the <a href="sophia_stdlib.html#call">Call</a> namespaces in the documentation.</p>
|
||
<h3 id="calling-other-contracts">Calling other contracts</h3>
|
||
<p>To call a function in another contract you need the address to an instance of
|
||
the contract. The type of the address must be a contract type, which consists
|
||
of a number of type definitions and entrypoint declarations. For instance,</p>
|
||
<div class="highlight"><pre><span></span><code>// A contract type
|
||
contract interface VotingType =
|
||
entrypoint vote : string => unit
|
||
</code></pre></div>
|
||
<p>Now given contract address of type <code>VotingType</code> you can call the <code>vote</code>
|
||
entrypoint of that contract:</p>
|
||
<div class="highlight"><pre><span></span><code>contract VoteTwice =
|
||
entrypoint voteTwice(v : VotingType, alt : string) =
|
||
v.vote(alt)
|
||
v.vote(alt)
|
||
</code></pre></div>
|
||
<p>Contract calls take two optional named arguments <code>gas : int</code> and <code>value : int</code>
|
||
that lets you set a gas limit and provide tokens to a contract call. If omitted
|
||
the defaults are no gas limit and no tokens. Suppose there is a fee for voting:</p>
|
||
<div class="highlight"><pre><span></span><code> entrypoint voteTwice(v : VotingType, fee : int, alt : string) =
|
||
v.vote(value = fee, alt)
|
||
v.vote(value = fee, alt)
|
||
</code></pre></div>
|
||
<p>Named arguments can be given in any order.</p>
|
||
<p>Note that reentrant calls are not permitted. In other words, when calling
|
||
another contract it cannot call you back (directly or indirectly).</p>
|
||
<p>To construct a value of a contract type you can give a contract address literal
|
||
(for instance <code>ct_2gPXZnZdKU716QBUFKaT4VdBZituK93KLvHJB3n4EnbrHHw4Ay</code>), or
|
||
convert an account address to a contract address using <code>Address.to_contract</code>.
|
||
Note that if the contract does not exist, or it doesn't have the entrypoint, or
|
||
the type of the entrypoint does not match the stated contract type, the call
|
||
fails.</p>
|
||
<p>To recover the underlying <code>address</code> of a contract instance there is a field
|
||
<code>address : address</code>. For instance, to send tokens to the voting contract (given that it is payable)
|
||
without calling it you can write</p>
|
||
<div class="highlight"><pre><span></span><code> entrypoint pay(v : VotingType, amount : int) =
|
||
Chain.spend(v.address, amount)
|
||
</code></pre></div>
|
||
<h3 id="protected-contract-calls">Protected contract calls</h3>
|
||
<p>If a contract call fails for any reason (for instance, the remote contract
|
||
crashes or runs out of gas, or the entrypoint doesn't exist or has the wrong
|
||
type) the parent call also fails. To make it possible to recover from failures,
|
||
contract calls takes a named argument <code>protected : bool</code> (default <code>false</code>).</p>
|
||
<p>The protected argument must be a literal boolean, and when set to <code>true</code>
|
||
changes the type of the contract call, wrapping the result in an <code>option</code> type.
|
||
If the call fails the result is <code>None</code>, otherwise it's <code>Some(r)</code> where <code>r</code> is
|
||
the return value of the call.</p>
|
||
<div class="highlight"><pre><span></span><code>contract interface VotingType =
|
||
entrypoint : vote : string => unit
|
||
|
||
contract Voter =
|
||
entrypoint tryVote(v : VotingType, alt : string) =
|
||
switch(v.vote(alt, protected = true) : option(unit))
|
||
None => "Voting failed"
|
||
Some(_) => "Voting successful"
|
||
</code></pre></div>
|
||
<p>Any gas that was consumed by the contract call before the failure stays
|
||
consumed, which means that in order to protect against the remote contract
|
||
running out of gas it is necessary to set a gas limit using the <code>gas</code> argument.
|
||
However, note that errors that would normally consume all the gas in the
|
||
transaction still only uses up the gas spent running the contract.</p>
|
||
<h3 id="contract-factories-and-child-contracts">Contract factories and child contracts</h3>
|
||
<p>Since the version 6.0.0 Sophia supports deploying contracts by other
|
||
contracts. This can be done in two ways:</p>
|
||
<ul>
|
||
<li>Contract cloning via <a href="sophia_stdlib.html#clone"><code>Chain.clone</code></a></li>
|
||
<li>Direct deploy via <a href="sophia_stdlib.html#create"><code>Chain.create</code></a></li>
|
||
</ul>
|
||
<p>These functions take variable number of arguments that must match the created
|
||
contract's <code>init</code> function. Beside that they take some additional named
|
||
arguments – please refer to their documentation for the details.</p>
|
||
<p>While <code>Chain.clone</code> requires only a <code>contract interface</code> and a living instance
|
||
of a given contract on the chain, <code>Chain.create</code> needs a full definition of a
|
||
to-create contract defined by the standard <code>contract</code> syntax, for example</p>
|
||
<div class="highlight"><pre><span></span><code>contract IntHolder =
|
||
type state = int
|
||
entrypoint init(x) = x
|
||
entrypoint get() = state
|
||
|
||
main contract IntHolderFactory =
|
||
stateful entrypoint new(x : int) : IntHolder =
|
||
let ih = Chain.create(x) : IntHolder
|
||
ih
|
||
</code></pre></div>
|
||
<p>In case of a presence of child contracts (<code>IntHolder</code> in this case), the main
|
||
contract must be pointed out with the <code>main</code> keyword as shown in the example.</p>
|
||
<h2 id="mutable-state">Mutable state</h2>
|
||
<p>Sophia does not have arbitrary mutable state, but only a limited form of state
|
||
associated with each contract instance.</p>
|
||
<ul>
|
||
<li>Each contract defines a type <code>state</code> encapsulating its mutable state.
|
||
The type <code>state</code> defaults to the <code>unit</code>.</li>
|
||
<li>The initial state of a contract is computed by the contract's <code>init</code>
|
||
function. The <code>init</code> function is <em>pure</em> and returns the initial state as its
|
||
return value.
|
||
If the type <code>state</code> is <code>unit</code>, the <code>init</code> function defaults to returning the value <code>()</code>.
|
||
At contract creation time, the <code>init</code> function is executed and
|
||
its result is stored as the contract state.</li>
|
||
<li>The value of the state is accessible from inside the contract
|
||
through an implicitly bound variable <code>state</code>.</li>
|
||
<li>State updates are performed by calling a function <code>put : state => unit</code>.</li>
|
||
<li>Aside from the <code>put</code> function (and similar functions for transactions
|
||
and events), the language is purely functional.</li>
|
||
<li>Functions modifying the state need to be annotated with the <code>stateful</code> keyword (see below).</li>
|
||
</ul>
|
||
<p>To make it convenient to update parts of a deeply nested state Sophia
|
||
provides special syntax for map/record updates.</p>
|
||
<h3 id="stateful-functions">Stateful functions</h3>
|
||
<p>Top-level functions and entrypoints must be annotated with the
|
||
<code>stateful</code> keyword to be allowed to affect the state of the running contract.
|
||
For instance,</p>
|
||
<div class="highlight"><pre><span></span><code> stateful entrypoint set_state(s : state) =
|
||
put(s)
|
||
</code></pre></div>
|
||
<p>Without the <code>stateful</code> annotation the compiler does not allow the call to
|
||
<code>put</code>. A <code>stateful</code> annotation is required to</p>
|
||
<ul>
|
||
<li>Use a stateful primitive function. These are</li>
|
||
<li><code>put</code></li>
|
||
<li><code>Chain.spend</code></li>
|
||
<li><code>Oracle.register</code></li>
|
||
<li><code>Oracle.query</code></li>
|
||
<li><code>Oracle.respond</code></li>
|
||
<li><code>Oracle.extend</code></li>
|
||
<li><code>AENS.preclaim</code></li>
|
||
<li><code>AENS.claim</code></li>
|
||
<li><code>AENS.transfer</code></li>
|
||
<li><code>AENS.revoke</code></li>
|
||
<li><code>AENS.update</code></li>
|
||
<li>Call a <code>stateful</code> function in the current contract</li>
|
||
<li>Call another contract with a non-zero <code>value</code> argument.</li>
|
||
</ul>
|
||
<p>A <code>stateful</code> annotation <em>is not</em> required to</p>
|
||
<ul>
|
||
<li>Read the contract state.</li>
|
||
<li>Issue an event using the <code>event</code> function.</li>
|
||
<li>Call another contract with <code>value = 0</code>, even if the called function is stateful.</li>
|
||
</ul>
|
||
<h2 id="payable">Payable</h2>
|
||
<h3 id="payable-contracts">Payable contracts</h3>
|
||
<p>A concrete contract is by default <em>not</em> payable. Any attempt at spending to such
|
||
a contract (either a <code>Chain.spend</code> or a normal spend transaction) will fail. If a
|
||
contract shall be able to receive funds in this way it has to be declared <code>payable</code>:</p>
|
||
<div class="highlight"><pre><span></span><code>// A payable contract
|
||
payable contract ExampleContract =
|
||
stateful entrypoint do_stuff() = ...
|
||
</code></pre></div>
|
||
<p>If in doubt, it is possible to check if an address is payable using
|
||
<code>Address.is_payable(addr)</code>.</p>
|
||
<h3 id="payable-entrypoints">Payable entrypoints</h3>
|
||
<p>A contract entrypoint is by default <em>not</em> payable. Any call to such a function
|
||
(either a <a href="#calling-other-contracts">Remote call</a> or a contract call transaction)
|
||
that has a non-zero <code>value</code> will fail. Contract entrypoints that should be called
|
||
with a non-zero value should be declared <code>payable</code>.</p>
|
||
<div class="highlight"><pre><span></span><code>payable stateful entrypoint buy(to : address) =
|
||
if(Call.value > 42)
|
||
transfer_item(to)
|
||
else
|
||
abort("Value too low")
|
||
</code></pre></div>
|
||
<p>Note: In the æternity VM (AEVM) contracts and entrypoints were by default
|
||
payable until the Lima release.</p>
|
||
<h2 id="namespaces">Namespaces</h2>
|
||
<p>Code can be split into libraries using the <code>namespace</code> construct. Namespaces
|
||
can appear at the top-level and can contain type and function definitions, but
|
||
not entrypoints. Outside the namespace you can refer to the (non-private) names
|
||
by qualifying them with the namespace (<code>Namespace.name</code>).
|
||
For example,</p>
|
||
<div class="highlight"><pre><span></span><code>namespace Library =
|
||
type number = int
|
||
function inc(x : number) : number = x + 1
|
||
|
||
contract MyContract =
|
||
entrypoint plus2(x) : Library.number =
|
||
Library.inc(Library.inc(x))
|
||
</code></pre></div>
|
||
<p>Functions in namespaces have access to the same environment (including the
|
||
<code>Chain</code>, <code>Call</code>, and <code>Contract</code>, builtin namespaces) as function in a contract,
|
||
with the exception of <code>state</code>, <code>put</code> and <code>Chain.event</code> since these are
|
||
dependent on the specific state and event types of the contract.</p>
|
||
<h2 id="splitting-code-over-multiple-files">Splitting code over multiple files</h2>
|
||
<p>Code from another file can be included in a contract using an <code>include</code>
|
||
statement. These must appear at the top-level (outside the main contract). The
|
||
included file can contain one or more namespaces and abstract contracts. For
|
||
example, if the file <code>library.aes</code> contains</p>
|
||
<div class="highlight"><pre><span></span><code>namespace Library =
|
||
function inc(x) = x + 1
|
||
</code></pre></div>
|
||
<p>you can use it from another file using an <code>include</code>:</p>
|
||
<div class="highlight"><pre><span></span><code>include "library.aes"
|
||
contract MyContract =
|
||
entrypoint plus2(x) = Library.inc(Library.inc(x))
|
||
</code></pre></div>
|
||
<p>This behaves as if the contents of <code>library.aes</code> was textually inserted into
|
||
the file, except that error messages will refer to the original source
|
||
locations. The language will try to include each file at most one time automatically,
|
||
so even cyclic includes should be working without any special tinkering.</p>
|
||
<h2 id="standard-library">Standard library</h2>
|
||
<p>Sophia offers <a href="sophia_stdlib.html">standard library</a> which exposes some
|
||
primitive operations and some higher level utilities. The builtin
|
||
namespaces like <code>Chain</code>, <code>Contract</code>, <code>Map</code>
|
||
are included by default and are supported internally by the compiler.
|
||
Others like <code>List</code>, <code>Frac</code>, <code>Option</code> need to be manually included using the
|
||
<code>include</code> directive. For example
|
||
<div class="highlight"><pre><span></span><code>include "List.aes"
|
||
include "Pair.aes"
|
||
-- Map is already there!
|
||
|
||
namespace C =
|
||
entrypoint keys(m : map('a, 'b)) : list('a) =
|
||
List.map(Pair.fst, (Map.to_list(m)))
|
||
</code></pre></div></p>
|
||
<h2 id="types">Types</h2>
|
||
<p>Sophia has the following types:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Type</th>
|
||
<th>Description</th>
|
||
<th>Example</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>int</td>
|
||
<td>A 2-complement integer</td>
|
||
<td><code>-1</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>address</td>
|
||
<td>æternity address, 32 bytes</td>
|
||
<td><code>Call.origin</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bool</td>
|
||
<td>A Boolean</td>
|
||
<td><code>true</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bits</td>
|
||
<td>A bit field</td>
|
||
<td><code>Bits.none</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bytes(n)</td>
|
||
<td>A byte array with <code>n</code> bytes</td>
|
||
<td><code>#fedcba9876543210</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>string</td>
|
||
<td>An array of bytes</td>
|
||
<td><code>"Foo"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>list</td>
|
||
<td>A homogeneous immutable singly linked list.</td>
|
||
<td><code>[1, 2, 3]</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>('a, 'b) => 'c</td>
|
||
<td>A function. Parentheses can be skipped if there is only one argument</td>
|
||
<td><code>(x : int, y : int) => x + y</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>tuple</td>
|
||
<td>An ordered heterogeneous array</td>
|
||
<td><code>(42, "Foo", true)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>record</td>
|
||
<td>An immutable key value store with fixed key names and typed values</td>
|
||
<td><code>record balance = { owner: address, value: int }</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>map</td>
|
||
<td>An immutable key value store with dynamic mapping of keys of one type to values of one type</td>
|
||
<td><code>type accounts = map(string, address)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>option('a)</td>
|
||
<td>An optional value either None or Some('a)</td>
|
||
<td><code>Some(42)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>state</td>
|
||
<td>A user defined type holding the contract state</td>
|
||
<td><code>record state = { owner: address, magic_key: bytes(4) }</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>event</td>
|
||
<td>An append only list of blockchain events (or log entries)</td>
|
||
<td><code>datatype event = EventX(indexed int, string)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>hash</td>
|
||
<td>A 32-byte hash - equivalent to <code>bytes(32)</code></td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>signature</td>
|
||
<td>A signature - equivalent to <code>bytes(64)</code></td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Chain.ttl</td>
|
||
<td>Time-to-live (fixed height or relative to current block)</td>
|
||
<td><code>FixedTTL(1050)</code> <code>RelativeTTL(50)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>oracle('a, 'b)</td>
|
||
<td>And oracle answering questions of type 'a with answers of type 'b</td>
|
||
<td><code>Oracle.register(acct, qfee, ttl)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>oracle_query('a, 'b)</td>
|
||
<td>A specific oracle query</td>
|
||
<td><code>Oracle.query(o, q, qfee, qttl, rttl)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>contract</td>
|
||
<td>A user defined, typed, contract address</td>
|
||
<td><code>function call_remote(r : RemoteContract) = r.fun()</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2 id="literals">Literals</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Type</th>
|
||
<th>Constant/Literal example(s)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>int</td>
|
||
<td><code>-1</code>, <code>2425</code>, <code>4598275923475723498573485768</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>address</td>
|
||
<td><code>ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bool</td>
|
||
<td><code>true</code>, <code>false</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bits</td>
|
||
<td><code>Bits.none</code>, <code>Bits.all</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>bytes(8)</td>
|
||
<td><code>#fedcba9876543210</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>string</td>
|
||
<td><code>"This is a string"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>list</td>
|
||
<td><code>[1, 2, 3]</code>, <code>[(true, 24), (false, 19), (false, -42)]</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>tuple</td>
|
||
<td><code>(42, "Foo", true)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>record</td>
|
||
<td><code>{ owner = Call.origin, value = 100000000 }</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>map</td>
|
||
<td><code>{["foo"] = 19, ["bar"] = 42}</code>, <code>{}</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>option(int)</td>
|
||
<td><code>Some(42)</code>, <code>None</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>state</td>
|
||
<td><code>state{ owner = Call.origin, magic_key = #a298105f }</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>event</td>
|
||
<td><code>EventX(0, "Hello")</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>hash</td>
|
||
<td><code>#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>signature</td>
|
||
<td><code>#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Chain.ttl</td>
|
||
<td><code>FixedTTL(1050)</code>, <code>RelativeTTL(50)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>oracle('a, 'b)</td>
|
||
<td><code>ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>oracle_query('a, 'b)</td>
|
||
<td><code>oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>contract</td>
|
||
<td><code>ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2 id="arithmetic">Arithmetic</h2>
|
||
<p>Sophia integers (<code>int</code>) are represented by 256-bit (AEVM) or arbitrary-sized (FATE) signed words and supports the following
|
||
arithmetic operations:
|
||
- addition (<code>x + y</code>)
|
||
- subtraction (<code>x - y</code>)
|
||
- multiplication (<code>x * y</code>)
|
||
- division (<code>x / y</code>), truncated towards zero
|
||
- remainder (<code>x mod y</code>), satisfying <code>y * (x / y) + x mod y == x</code> for non-zero <code>y</code>
|
||
- exponentiation (<code>x ^ y</code>)</p>
|
||
<p>All operations are <em>safe</em> with respect to overflow and underflow. On AEVM they behave as the corresponding
|
||
operations on arbitrary-size integers and fail with <code>arithmetic_error</code> if the
|
||
result cannot be represented by a 256-bit signed word. For example, <code>2 ^ 255</code>
|
||
fails rather than wrapping around to -2²⁵⁵.</p>
|
||
<p>The division and modulo operations also throw an arithmetic error if the
|
||
second argument is zero.</p>
|
||
<h2 id="bit-fields">Bit fields</h2>
|
||
<p>Sophia integers do not support bit arithmetic. Instead there is a separate
|
||
type <code>bits</code>. See the standard library <a href="sophia_stdlib.html#bits">documentation</a>.</p>
|
||
<p>On the AEVM a bit field is represented by a 256-bit word and reading or writing
|
||
a bit outside the 0..255 range fails with an <code>arithmetic_error</code>. On FATE a bit
|
||
field can be of arbitrary size (but it is still represented by the
|
||
corresponding integer, so setting very high bits can be expensive).</p>
|
||
<h2 id="type-aliases">Type aliases</h2>
|
||
<p>Type aliases can be introduced with the <code>type</code> keyword and can be
|
||
parameterized. For instance</p>
|
||
<div class="highlight"><pre><span></span><code>type number = int
|
||
type string_map('a) = map(string, 'a)
|
||
</code></pre></div>
|
||
<p>A type alias and its definition can be used interchangeably. Sophia does not support
|
||
higher-kinded types, meaning that following type alias is invalid: <code>type wrap('f, 'a) = 'f('a)</code></p>
|
||
<h2 id="algebraic-data-types">Algebraic data types</h2>
|
||
<p>Sophia supports algebraic data types (variant types) and pattern matching. Data
|
||
types are declared by giving a list of constructors with
|
||
their respective arguments. For instance,</p>
|
||
<div class="highlight"><pre><span></span><code>datatype one_or_both('a, 'b) = Left('a) | Right('b) | Both('a, 'b)
|
||
</code></pre></div>
|
||
<p>Elements of data types can be pattern matched against, using the <code>switch</code> construct:</p>
|
||
<div class="highlight"><pre><span></span><code>function get_left(x : one_or_both('a, 'b)) : option('a) =
|
||
switch(x)
|
||
Left(x) => Some(x)
|
||
Right(_) => None
|
||
Both(x, _) => Some(x)
|
||
</code></pre></div>
|
||
<p>or directly in the left-hand side:
|
||
<div class="highlight"><pre><span></span><code>function
|
||
get_left : one_or_both('a, 'b) => option('a)
|
||
get_left(Left(x)) = Some(x)
|
||
get_left(Right(_)) = None
|
||
get_left(Both(x, _)) = Some(x)
|
||
</code></pre></div></p>
|
||
<p><em>NOTE: Data types cannot currently be recursive.</em></p>
|
||
<h2 id="lists">Lists</h2>
|
||
<p>A Sophia list is a dynamically sized, homogenous, immutable, singly
|
||
linked list. A list is constructed with the syntax <code>[1, 2, 3]</code>. The
|
||
elements of a list can be any of datatype but they must have the same
|
||
type. The type of lists with elements of type <code>'e</code> is written
|
||
<code>list('e)</code>. For example we can have the following lists:</p>
|
||
<div class="highlight"><pre><span></span><code>[1, 33, 2, 666] : list(int)
|
||
[(1, "aaa"), (10, "jjj"), (666, "the beast")] : list(int * string)
|
||
[{[1] = "aaa", [10] = "jjj"}, {[5] = "eee", [666] = "the beast"}] : list(map(int, string))
|
||
</code></pre></div>
|
||
<p>New elements can be prepended to the front of a list with the <code>::</code>
|
||
operator. So <code>42 :: [1, 2, 3]</code> returns the list <code>[42, 1, 2, 3]</code>. The
|
||
concatenation operator <code>++</code> appends its second argument to its first
|
||
and returns the resulting list. So concatenating two lists
|
||
<code>[1, 22, 33] ++ [10, 18, 55]</code> returns the list <code>[1, 22, 33, 10, 18, 55]</code>.</p>
|
||
<p>Sophia supports list comprehensions known from languages like Python, Haskell or Erlang.
|
||
Example syntax:
|
||
<div class="highlight"><pre><span></span><code>[x + y | x <- [1,2,3,4,5], let k = x*x, if (k > 5), y <- [k, k+1, k+2]]
|
||
// yields [12,13,14,20,21,22,30,31,32]
|
||
</code></pre></div></p>
|
||
<p>Lists can be constructed using the range syntax using special <code>..</code> operator:
|
||
<div class="highlight"><pre><span></span><code>[1..4] == [1,2,3,4]
|
||
</code></pre></div>
|
||
The ranges are always ascending and have step equal to 1.</p>
|
||
<p>Please refer to the <a href="sophia_stdlib.html#list">standard library</a> for the predefined functionalities.</p>
|
||
<h2 id="maps-and-records">Maps and records</h2>
|
||
<p>A Sophia record type is given by a fixed set of fields with associated,
|
||
possibly different, types. For instance
|
||
<div class="highlight"><pre><span></span><code> record account = { name : string,
|
||
balance : int,
|
||
history : list(transaction) }
|
||
</code></pre></div></p>
|
||
<p>Maps, on the other hand, can contain an arbitrary number of key-value bindings,
|
||
but of a fixed type. The type of maps with keys of type <code>'k</code> and values of type
|
||
<code>'v</code> is written <code>map('k, 'v)</code>. The key type can be any type that does not
|
||
contain a map or a function type.</p>
|
||
<p>Please refer to the <a href="sophia_stdlib.html#map">standard library</a> for the predefined functionalities.</p>
|
||
<h3 id="constructing-maps-and-records">Constructing maps and records</h3>
|
||
<p>A value of record type is constructed by giving a value for each of the fields.
|
||
For the example above,
|
||
<div class="highlight"><pre><span></span><code> function new_account(name) =
|
||
{name = name, balance = 0, history = []}
|
||
</code></pre></div>
|
||
Maps are constructed similarly, with keys enclosed in square brackets
|
||
<div class="highlight"><pre><span></span><code> function example_map() : map(string, int) =
|
||
{["key1"] = 1, ["key2"] = 2}
|
||
</code></pre></div>
|
||
The empty map is written <code>{}</code>.</p>
|
||
<h3 id="accessing-values">Accessing values</h3>
|
||
<p>Record fields access is written <code>r.f</code> and map lookup <code>m[k]</code>. For instance,
|
||
<div class="highlight"><pre><span></span><code> function get_balance(a : address, accounts : map(address, account)) =
|
||
accounts[a].balance
|
||
</code></pre></div>
|
||
Looking up a non-existing key in a map results in contract execution failing. A
|
||
default value to return for non-existing keys can be provided using the syntax
|
||
<code>m[k = default]</code>. See also <code>Map.member</code> and <code>Map.lookup</code> below.</p>
|
||
<h3 id="updating-a-value">Updating a value</h3>
|
||
<p>Record field updates are written <code>r{f = v}</code>. This creates a new record value
|
||
which is the same as <code>r</code>, but with the value of the field <code>f</code> replaced by <code>v</code>.
|
||
Similarly, <code>m{[k] = v}</code> constructs a map with the same values as <code>m</code> except
|
||
that <code>k</code> maps to <code>v</code>. It makes no difference if <code>m</code> has a mapping for <code>k</code> or
|
||
not.</p>
|
||
<p>It is possible to give a name to the old value of a field or mapping in an
|
||
update: instead of <code>acc{ balance = acc.balance + 100 }</code> it is possible to write
|
||
<code>acc{ balance @ b = b + 100 }</code>, binding <code>b</code> to <code>acc.balance</code>. When giving a
|
||
name to a map value (<code>m{ [k] @ x = v }</code>), the corresponding key must be present
|
||
in the map or execution fails, but a default value can be provided:
|
||
<code>m{ [k = default] @ x = v }</code>. In this case <code>x</code> is bound to <code>default</code> if
|
||
<code>k</code> is not in the map.</p>
|
||
<p>Updates can be nested:
|
||
<div class="highlight"><pre><span></span><code>function clear_history(a : address, accounts : map(address, account)) : map(address, account) =
|
||
accounts{ [a].history = [] }
|
||
</code></pre></div>
|
||
This is equivalent to <code>accounts{ [a] @ acc = acc{ history = [] } }</code> and thus
|
||
requires <code>a</code> to be present in the accounts map. To have <code>clear_history</code> create
|
||
an account if <code>a</code> is not in the map you can write (given a function <code>empty_account</code>):
|
||
<div class="highlight"><pre><span></span><code> accounts{ [a = empty_account()].history = [] }
|
||
</code></pre></div></p>
|
||
<h3 id="map-implementation">Map implementation</h3>
|
||
<p>Internally in the VM maps are implemented as hash maps and support fast lookup
|
||
and update. Large maps can be stored in the contract state and the size of the
|
||
map does not contribute to the gas costs of a contract call reading or updating
|
||
it.</p>
|
||
<h2 id="strings">Strings</h2>
|
||
<p>There is a builtin type <code>string</code>, which can be seen as an array of bytes.
|
||
Strings can be compared for equality (<code>==</code>, <code>!=</code>), used as keys in maps and
|
||
records, and used in builtin functions <code>String.length</code>, <code>String.concat</code> and
|
||
the hash functions described below.</p>
|
||
<p>Please refer to the <code>String</code> <a href="sophia_stdlib.html#string">library documentation</a>.</p>
|
||
<h2 id="chars">Chars</h2>
|
||
<p>There is a builtin type <code>char</code> (the underlying representation being an integer),
|
||
mainly used to manipulate strings via <code>String.to_list</code>/<code>String.from_list</code>.</p>
|
||
<p>Characters can also be introduced as character literals (`'x', '+', ...).</p>
|
||
<p>Please refer to the <code>Char</code> <a href="sophia_stdlib.html#char">library documentation</a>.</p>
|
||
<h2 id="byte-arrays">Byte arrays</h2>
|
||
<p>Byte arrays are fixed size arrays of 8-bit integers. They are described in hexadecimal system,
|
||
for example the literal <code>#cafe</code> creates a two-element array of bytes <code>ca</code> (202) and <code>fe</code> (254)
|
||
and thus is a value of type <code>bytes(2)</code>.</p>
|
||
<p>Please refer to the <code>Bytes</code> <a href="sophia_stdlib.html#bytes">library documentation</a>.</p>
|
||
<h2 id="cryptographic-builtins">Cryptographic builtins</h2>
|
||
<p>Libraries <a href="sophia_stdlib.html#crypto">Crypto</a> and <a href="sophia_stdlib.html#string">String</a> provide functions to
|
||
hash objects, verify signatures etc. The <code>hash</code> is a type alias for <code>bytes(32)</code>.</p>
|
||
<h2 id="authorization-interface">Authorization interface</h2>
|
||
<p>When a Generalized account is authorized, the authorization function needs
|
||
access to the transaction and the transaction hash for the wrapped transaction. (A <code>GAMetaTx</code>
|
||
wrapping a transaction.) The transaction and the transaction hash is available in the primitive
|
||
<code>Auth.tx</code> and <code>Auth.tx_hash</code> respectively, they are <em>only</em> available during authentication if invoked by a
|
||
normal contract call they return <code>None</code>.</p>
|
||
<h2 id="oracle-interface">Oracle interface</h2>
|
||
<p>You can attach an oracle to the current contract and you can interact with oracles
|
||
through the Oracle interface.</p>
|
||
<p>For a full description of how Oracle works see
|
||
<a href="https://github.com/aeternity/protocol/blob/master/oracles/oracles.md#oracles">Oracles</a>.
|
||
For a functionality documentation refer to the <a href="sophia_stdlib.html#oracle">standard library</a>.</p>
|
||
<h3 id="example">Example</h3>
|
||
<p>Example for an oracle answering questions of type <code>string</code> with answers of type <code>int</code>:
|
||
<div class="highlight"><pre><span></span><code>contract Oracles =
|
||
|
||
stateful entrypoint registerOracle(acct : address,
|
||
sign : signature, // Signed network id + oracle address + contract address
|
||
qfee : int,
|
||
ttl : Chain.ttl) : oracle(string, int) =
|
||
Oracle.register(acct, signature = sign, qfee, ttl)
|
||
|
||
entrypoint queryFee(o : oracle(string, int)) : int =
|
||
Oracle.query_fee(o)
|
||
|
||
payable stateful entrypoint createQuery(o : oracle_query(string, int),
|
||
q : string,
|
||
qfee : int,
|
||
qttl : Chain.ttl,
|
||
rttl : int) : oracle_query(string, int) =
|
||
require(qfee =< Call.value, "insufficient value for qfee")
|
||
Oracle.query(o, q, qfee, qttl, RelativeTTL(rttl))
|
||
|
||
stateful entrypoint extendOracle(o : oracle(string, int),
|
||
ttl : Chain.ttl) : unit =
|
||
Oracle.extend(o, ttl)
|
||
|
||
stateful entrypoint signExtendOracle(o : oracle(string, int),
|
||
sign : signature, // Signed network id + oracle address + contract address
|
||
ttl : Chain.ttl) : unit =
|
||
Oracle.extend(o, signature = sign, ttl)
|
||
|
||
stateful entrypoint respond(o : oracle(string, int),
|
||
q : oracle_query(string, int),
|
||
sign : signature, // Signed network id + oracle query id + contract address
|
||
r : int) =
|
||
Oracle.respond(o, q, signature = sign, r)
|
||
|
||
entrypoint getQuestion(o : oracle(string, int),
|
||
q : oracle_query(string, int)) : string =
|
||
Oracle.get_question(o, q)
|
||
|
||
entrypoint hasAnswer(o : oracle(string, int),
|
||
q : oracle_query(string, int)) =
|
||
switch(Oracle.get_answer(o, q))
|
||
None => false
|
||
Some(_) => true
|
||
|
||
entrypoint getAnswer(o : oracle(string, int),
|
||
q : oracle_query(string, int)) : option(int) =
|
||
Oracle.get_answer(o, q)
|
||
</code></pre></div></p>
|
||
<h3 id="sanity-checks">Sanity checks</h3>
|
||
<p>When an Oracle literal is passed to a contract, no deep checks are performed.
|
||
For extra safety <a href="sophia_stdlib.html#check">Oracle.check</a> and <a href="sophia_stdlib.html#check_query">Oracle.check_query</a>
|
||
functions are provided.</p>
|
||
<h2 id="aens-interface">AENS interface</h2>
|
||
<p>Contracts can interact with the
|
||
<a href="https://github.com/aeternity/protocol/blob/master/AENS.md">æternity naming system</a>.
|
||
For this purpose the <a href="sophia_stdlib.html#aens">AENS</a> library was exposed.</p>
|
||
<h3 id="example_1">Example</h3>
|
||
<p>In this example we assume that the name <code>name</code> already exists, and is owned by
|
||
an account with address <code>addr</code>. In order to allow a contract <code>ct</code> to handle
|
||
<code>name</code> the account holder needs to create a
|
||
<a href="#delegation-signature">signature</a> <code>sig</code> of <code>addr | name.hash | ct.address</code>.</p>
|
||
<p>Armed with this information we can for example write a function that extends
|
||
the name if it expires within 1000 blocks:
|
||
<div class="highlight"><pre><span></span><code> stateful entrypoint extend_if_necessary(addr : address, name : string, sig : signature) =
|
||
switch(AENS.lookup(name))
|
||
None => ()
|
||
Some(AENS.Name(_, FixedTTL(expiry), _)) =>
|
||
if(Chain.block_height + 1000 > expiry)
|
||
AENS.update(addr, name, Some(RelativeTTL(50000)), None, None, signature = sig)
|
||
</code></pre></div></p>
|
||
<p>And we can write functions that adds and removes keys from the pointers of the
|
||
name:
|
||
<div class="highlight"><pre><span></span><code> stateful entrypoint add_key(addr : address, name : string, key : string,
|
||
pt : AENS.pointee, sig : signature) =
|
||
switch(AENS.lookup(name))
|
||
None => ()
|
||
Some(AENS.Name(_, _, ptrs)) =>
|
||
AENS.update(addr, name, None, None, Some(ptrs{[key] = pt}), signature = sig)
|
||
|
||
stateful entrypoint delete_key(addr : address, name : string,
|
||
key : string, sig : signature) =
|
||
switch(AENS.lookup(name))
|
||
None => ()
|
||
Some(AENS.Name(_, _, ptrs)) =>
|
||
let ptrs = Map.delete(key, ptrs)
|
||
AENS.update(addr, name, None, None, Some(ptrs), signature = sig)
|
||
</code></pre></div></p>
|
||
<p><em>Note:</em> From the Iris hardfork more strict rules apply for AENS pointers, when
|
||
a Sophia contract lookup or update (bad) legacy pointers, the bad keys are
|
||
automatically removed so they will not appear in the pointers map.</p>
|
||
<h2 id="events">Events</h2>
|
||
<p>Sophia contracts log structured messages to an event log in the resulting
|
||
blockchain transaction. The event log is quite similar to <a href="https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events">Events in
|
||
Solidity</a>.
|
||
Events are further discussed in the <a href="https://github.com/aeternity/protocol/blob/master/contracts/events.md">protocol</a>.</p>
|
||
<p>To use events a contract must declare a datatype <code>event</code>, and events are then
|
||
logged using the <code>Chain.event</code> function:</p>
|
||
<div class="highlight"><pre><span></span><code> datatype event
|
||
= Event1(int, int, string)
|
||
| Event2(string, address)
|
||
|
||
Chain.event(e : event) : unit
|
||
</code></pre></div>
|
||
<p>The event can have 0-3 <em>indexed</em> fields, and an optional <em>payload</em> field. A
|
||
field is indexed if it fits in a 32-byte word, i.e.
|
||
- <code>bool</code>
|
||
- <code>int</code>
|
||
- <code>bits</code>
|
||
- <code>address</code>
|
||
- <code>oracle(_, _)</code>
|
||
- <code>oracle_query(_, _)</code>
|
||
- contract types
|
||
- <code>bytes(n)</code> for <code>n</code> ≤ 32, in particular <code>hash</code></p>
|
||
<p>The payload field must be either a string or a byte array of more than 32 bytes.
|
||
The fields can appear in any order.</p>
|
||
<p><em>NOTE:</em> Indexing is not part of the core æternity node.</p>
|
||
<p>Events are emitted by using the <code>Chain.event</code> function. The following function
|
||
will emit one Event of each kind in the example.</p>
|
||
<div class="highlight"><pre><span></span><code> entrypoint emit_events() : () =
|
||
Chain.event(Event1(42, 34, "foo"))
|
||
Chain.event(Event2("This is not indexed", Contract.address))
|
||
</code></pre></div>
|
||
<h3 id="argument-order">Argument order</h3>
|
||
<p>It is only possible to have one (1) <code>string</code> parameter in the event, but it can
|
||
be placed in any position (and its value will end up in the <code>data</code> field), i.e.
|
||
<div class="highlight"><pre><span></span><code>AnotherEvent(string, indexed address)
|
||
|
||
...
|
||
|
||
Chain.event(AnotherEvent("This is not indexed", Contract.address))
|
||
</code></pre></div>
|
||
would yield exactly the same result in the example above!</p>
|
||
<h2 id="compiler-pragmas">Compiler pragmas</h2>
|
||
<p>To enforce that a contract is only compiled with specific versions of the
|
||
Sophia compiler, you can give one or more <code>@compiler</code> pragmas at the
|
||
top-level (typically at the beginning) of a file. For instance, to enforce that
|
||
a contract is compiled with version 4.3 of the compiler you write</p>
|
||
<div class="highlight"><pre><span></span><code>@compiler >= 4.3
|
||
@compiler < 4.4
|
||
</code></pre></div>
|
||
<p>Valid operators in compiler pragmas are <code><</code>, <code>=<</code>, <code>==</code>, <code>>=</code>, and <code>></code>. Version
|
||
numbers are given as a sequence of non-negative integers separated by dots.
|
||
Trailing zeros are ignored, so <code>4.0.0 == 4</code>. If a constraint is violated an
|
||
error is reported and compilation fails.</p>
|
||
<h2 id="exceptions">Exceptions</h2>
|
||
<p>Contracts can fail with an (uncatchable) exception using the built-in function</p>
|
||
<div class="highlight"><pre><span></span><code>abort(reason : string) : 'a
|
||
</code></pre></div>
|
||
<p>Calling abort causes the top-level call transaction to return an error result
|
||
containing the <code>reason</code> string. Only the gas used up to and including the abort
|
||
call is charged. This is different from termination due to a crash which
|
||
consumes all available gas.</p>
|
||
<p>For convenience the following function is also built-in:</p>
|
||
<div class="highlight"><pre><span></span><code>function require(b : bool, err : string) =
|
||
if(!b) abort(err)
|
||
</code></pre></div>
|
||
<h2 id="delegation-signature">Delegation signature</h2>
|
||
<p>Some chain operations (<code>Oracle.<operation></code> and <code>AENS.<operation></code>) have an
|
||
optional delegation signature. This is typically used when a user/accounts
|
||
would like to allow a contract to act on it's behalf. The exact data to be
|
||
signed varies for the different operations, but in all cases you should prepend
|
||
the signature data with the <code>network_id</code> (<code>ae_mainnet</code> for the æternity mainnet, etc.).</p>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</article>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
|
||
<footer class="md-footer">
|
||
|
||
<nav class="md-footer__inner md-grid" aria-label="Footer">
|
||
|
||
|
||
<a href="sophia_syntax.html" class="md-footer__link md-footer__link--prev" aria-label="Previous: Syntax" rel="prev">
|
||
<div class="md-footer__button md-icon">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
|
||
</div>
|
||
<div class="md-footer__title">
|
||
<div class="md-ellipsis">
|
||
<span class="md-footer__direction">
|
||
Previous
|
||
</span>
|
||
Syntax
|
||
</div>
|
||
</div>
|
||
</a>
|
||
|
||
|
||
|
||
<a href="sophia_stdlib.html" class="md-footer__link md-footer__link--next" aria-label="Next: Standard library" rel="next">
|
||
<div class="md-footer__title">
|
||
<div class="md-ellipsis">
|
||
<span class="md-footer__direction">
|
||
Next
|
||
</span>
|
||
Standard library
|
||
</div>
|
||
</div>
|
||
<div class="md-footer__button md-icon">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg>
|
||
</div>
|
||
</a>
|
||
|
||
</nav>
|
||
|
||
<div class="md-footer-meta md-typeset">
|
||
<div class="md-footer-meta__inner md-grid">
|
||
<div class="md-footer-copyright">
|
||
|
||
Made with
|
||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||
Material for MkDocs
|
||
</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
</div>
|
||
<div class="md-dialog" data-md-component="dialog">
|
||
<div class="md-dialog__inner md-typeset"></div>
|
||
</div>
|
||
<script id="__config" type="application/json">{"base": ".", "features": ["content.tabs.link", "search.highlight", "search.share", "search.suggest"], "translations": {"clipboard.copy": "Copy to clipboard", "clipboard.copied": "Copied to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.placeholder": "Type to start searching", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.term.missing": "Missing", "select.version.title": "Select version"}, "search": "assets/javascripts/workers/search.477d984a.min.js", "version": {"provider": "mike"}}</script>
|
||
|
||
|
||
<script src="assets/javascripts/bundle.82b56eb2.min.js"></script>
|
||
|
||
|
||
</body>
|
||
</html> |