2142 lines
139 KiB
HTML
2142 lines
139 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="prev" href="../sophia_syntax/">
|
||
|
||
|
||
<link rel="next" href="../sophia_stdlib/">
|
||
|
||
<link rel="icon" href="../favicon.png">
|
||
<meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.0.9">
|
||
|
||
|
||
|
||
<title>Features - æternity Sophia Language</title>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="../assets/stylesheets/main.0d440cfe.min.css">
|
||
|
||
|
||
<link rel="stylesheet" href="../assets/stylesheets/palette.2505c338.min.css">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||
|
||
|
||
|
||
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="pink" data-md-color-accent="pink">
|
||
|
||
|
||
|
||
<script>var palette=__md_get("__palette");if(palette&&"object"==typeof palette.color)for(var key of Object.keys(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>
|
||
|
||
<div data-md-component="outdated" hidden>
|
||
|
||
<aside class="md-banner md-banner--warning">
|
||
<div class="md-banner__inner md-grid md-typeset">
|
||
|
||
You're not viewing the latest version.
|
||
<a href="../..">
|
||
<strong>Click here to go to latest.</strong>
|
||
</a>
|
||
|
||
</div>
|
||
<script>var el=document.querySelector("[data-md-component=outdated]"),outdated=__md_get("__outdated",sessionStorage);!0===outdated&&el&&(el.hidden=!1)</script>
|
||
</aside>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<header class="md-header" data-md-component="header">
|
||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||
<a href=".." 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" 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>
|
||
<nav class="md-search__options" aria-label="Search">
|
||
|
||
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7 0-.24-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91 1.61 0 2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08Z"/></svg>
|
||
</a>
|
||
|
||
<button type="reset" class="md-search__icon md-icon" title="Clear" 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>
|
||
</nav>
|
||
|
||
<div class="md-search__suggest" data-md-component="search-suggest"></div>
|
||
|
||
</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" role="presentation"></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"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><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=".." 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"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><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=".." class="md-nav__link">
|
||
Introduction
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../sophia_syntax/" class="md-nav__link">
|
||
Syntax
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active">
|
||
|
||
<input class="md-nav__toggle md-toggle" 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="./" 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>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contract-interfaces-and-polymorphism" class="md-nav__link">
|
||
Contract interfaces and polymorphism
|
||
</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="#hole-expression" class="md-nav__link">
|
||
Hole expression
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#constants" class="md-nav__link">
|
||
Constants
|
||
</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/" class="md-nav__link">
|
||
Standard library
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../sophia_examples/" class="md-nav__link">
|
||
Contract examples
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../CHANGELOG/" 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>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#contract-interfaces-and-polymorphism" class="md-nav__link">
|
||
Contract interfaces and polymorphism
|
||
</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="#hole-expression" class="md-nav__link">
|
||
Hole expression
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#constants" class="md-nav__link">
|
||
Constants
|
||
</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/#chain">Chain</a>, <a href="../sophia_stdlib/#contract">Contract</a>
|
||
and the <a href="../sophia_stdlib/#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><span class="c1">// A contract type</span>
|
||
<span class="k">contract</span><span class="w"> </span><span class="k">interface</span><span class="w"> </span><span class="nf">VotingType</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">vote</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">unit</span>
|
||
</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><span class="k">contract</span><span class="w"> </span><span class="nf">VoteTwice</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">voteTwice</span><span class="p">(</span><span class="n">v</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">VotingType</span><span class="p">,</span><span class="w"> </span><span class="n">alt</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">vote</span><span class="p">(</span><span class="n">alt</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">vote</span><span class="p">(</span><span class="n">alt</span><span class="p">)</span>
|
||
</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><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">voteTwice</span><span class="p">(</span><span class="n">v</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">VotingType</span><span class="p">,</span><span class="w"> </span><span class="n">fee</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="n">alt</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">vote</span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">fee</span><span class="p">,</span><span class="w"> </span><span class="n">alt</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">vote</span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">fee</span><span class="p">,</span><span class="w"> </span><span class="n">alt</span><span class="p">)</span>
|
||
</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><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">pay</span><span class="p">(</span><span class="n">v</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">VotingType</span><span class="p">,</span><span class="w"> </span><span class="n">amount</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">spend</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">amount</span><span class="p">)</span>
|
||
</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><span class="k">contract</span><span class="w"> </span><span class="k">interface</span><span class="w"> </span><span class="nf">VotingType</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">vote</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">unit</span>
|
||
|
||
<span class="k">contract</span><span class="w"> </span><span class="nf">Voter</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">tryVote</span><span class="p">(</span><span class="n">v</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">VotingType</span><span class="p">,</span><span class="w"> </span><span class="n">alt</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">vote</span><span class="p">(</span><span class="n">alt</span><span class="p">,</span><span class="w"> </span><span class="n">protected</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kc">true</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="kt">unit</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nf">None</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="s2">"Voting failed"</span>
|
||
<span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="s2">"Voting successful"</span>
|
||
</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>
|
||
<p>Any side effects (state change, token transfers, etc.) made by a failing
|
||
protected call is rolled back, just like they would be in the unprotected case.</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/#clone"><code>Chain.clone</code></a></li>
|
||
<li>Direct deploy via <a href="../sophia_stdlib/#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><span class="k">contract</span><span class="w"> </span><span class="nf">IntHolder</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="nb">state</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">int</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">init</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">get</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nb">state</span>
|
||
|
||
<span class="k">main</span><span class="w"> </span><span class="k">contract</span><span class="w"> </span><span class="nf">IntHolderFactory</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">new</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">IntHolder</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">let</span><span class="w"> </span><span class="n">ih</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">create</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">IntHolder</span>
|
||
<span class="w"> </span><span class="n">ih</span>
|
||
</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>
|
||
<h3 id="contract-interfaces-and-polymorphism">Contract interfaces and polymorphism</h3>
|
||
<p>Contracts can implement one or multiple interfaces, the contract has to define
|
||
every entrypoint from the implemented interface and the entrypoints in both
|
||
the contract and implemented interface should have compatible types.</p>
|
||
<div class="highlight"><pre><span></span><code>contract interface Animal =
|
||
entrypoint sound : () => string
|
||
|
||
contract Cat : Animal =
|
||
entrypoint sound() = "Cat sound"
|
||
</code></pre></div>
|
||
<p>Contract interfaces can extend other interfaces. An extended interface has to
|
||
declare all entrypoints from every parent interface. All the declarations in the extended
|
||
interface must have types compatible with the declarations from the parent
|
||
interface.</p>
|
||
<div class="highlight"><pre><span></span><code>contract interface II =
|
||
entrypoint f : () => unit
|
||
|
||
contract interface I : II =
|
||
entrypoint f : () => unit
|
||
entrypoint g : () => unit
|
||
|
||
contract C : I =
|
||
entrypoint f() = ()
|
||
entrypoint g() = ()
|
||
</code></pre></div>
|
||
<p>It is only possible to implement (or extend) an interface that has been already
|
||
defined earlier in the file (or in an included file). Therefore recursive
|
||
interface implementation is not allowed in Sophia.</p>
|
||
<div class="highlight"><pre><span></span><code>// The following code would show an error
|
||
|
||
contract interface X : Z =
|
||
entrypoint x : () => int
|
||
|
||
contract interface Y : X =
|
||
entrypoint x : () => int
|
||
entrypoint y : () => int
|
||
|
||
contract interface Z : Y =
|
||
entrypoint x : () => int
|
||
entrypoint y : () => int
|
||
entrypoint z : () => int
|
||
|
||
contract C : Z =
|
||
entrypoint x() = 1
|
||
entrypoint y() = 1
|
||
entrypoint z() = 1
|
||
</code></pre></div>
|
||
<h4 id="adding-or-removing-modifiers">Adding or removing modifiers</h4>
|
||
<p>When a <code>contract</code> or a <code>contract interface</code> implements another <code>contract interface</code>, the <code>payable</code> and <code>stateful</code> modifiers can be kept or changed, both in the contract and in the entrypoints, according to the following rules:</p>
|
||
<ol>
|
||
<li>A <code>payable</code> contract or interface can implement a <code>payable</code> interface or a non-<code>payable</code> interface.</li>
|
||
<li>A non-<code>payable</code> contract or interface can only implement a non-<code>payable</code> interface, and cannot implement a <code>payable</code> interface.</li>
|
||
<li>A <code>payable</code> entrypoint can implement a <code>payable</code> entrypoint or a non-<code>payable</code> entrypoint.</li>
|
||
<li>A non-<code>payable</code> entrypoint can only implement a non-<code>payable</code> entrypoint, and cannot implement a <code>payable</code> entrypoint.</li>
|
||
<li>A non-<code>stateful</code> entrypoint can implement a <code>stateful</code> entrypoint or a non-<code>stateful</code> entrypoint.</li>
|
||
<li>A <code>stateful</code> entrypoint can only implement a <code>stateful</code> entrypoint, and cannot implement a non-<code>stateful</code> entrypoint.</li>
|
||
</ol>
|
||
<h4 id="subtyping-and-variance">Subtyping and variance</h4>
|
||
<p>Subtyping in Sophia follows common rules that take type variance into account. As described by <a href="https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)">Wikipedia</a>, </p>
|
||
<blockquote>
|
||
<p>Variance refers to how subtyping between more complex types relates to subtyping between their components.</p>
|
||
</blockquote>
|
||
<p>This concept plays an important role in complex types such as tuples, <code>datatype</code>s and functions. Depending on the context, it can apply to positions in the structure of a type, or type parameters of generic types. There are four kinds of variances:</p>
|
||
<ul>
|
||
<li>covariant</li>
|
||
<li>contravariant</li>
|
||
<li>invariant</li>
|
||
<li>bivariant</li>
|
||
</ul>
|
||
<p>A type is said to be on a "covariant" position when it describes output or a result of some computation. Analogously, position is "contravariant" when it is an input, or a parameter. Intuitively, when a part of the type is produced by values of it, it is covariant. When it is consumed, it is contravariant. When a type appears to be simultaneously input and output, it is described as invariant. If a type is neither of those (that is, it's unused) it's bivariant. Furthermore, whenever a complex type appears on a contravariant position, all its covariant components become contravariant and vice versa.</p>
|
||
<p>Variance influences how subtyping is applied. Types on covariant positions are subtyped normally, while contravariant the opposite way. Invariant types have to be exactly the same in order for subtyping to work. Bivariant types are always compatible.</p>
|
||
<p>A good example of where it matters can be pictured by subtyping of function types. Let us assume there is a contract interface <code>Animal</code> and two contracts that implement it: <code>Dog</code> and <code>Cat</code>.</p>
|
||
<div class="highlight"><pre><span></span><code><span class="k">contract</span><span class="w"> </span><span class="k">interface</span><span class="w"> </span><span class="nf">Animal</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">int</span>
|
||
|
||
<span class="k">contract</span><span class="w"> </span><span class="nf">Dog</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">Animal</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">age</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="c1">// ...</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">woof</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"woof"</span>
|
||
|
||
<span class="k">contract</span><span class="w"> </span><span class="nf">Cat</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">Animal</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">age</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="c1">// ...</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">meow</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"meow"</span>
|
||
</code></pre></div>
|
||
<p>The assumption of this exercise is that cats do not bark (because <code>Cat</code> does not define the <code>woof</code> entrypoint). If subtyping rules were applied naively, that is if we let <code>Dog => Dog</code> be a subtype of <code>Animal => Animal</code>, the following code would break:</p>
|
||
<div class="highlight"><pre><span></span><code><span class="k">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="p">(</span><span class="nf">Dog</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">d</span><span class="p">.</span><span class="n">woof</span><span class="p">()</span>
|
||
<span class="k">let</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="p">(</span><span class="nf">Animal</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">f</span>
|
||
<span class="k">let</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nf">Cat</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">create</span><span class="p">()</span>
|
||
<span class="n">g</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="c1">// Cat barking!</span>
|
||
</code></pre></div>
|
||
<p>That is because arguments of functions are contravariant, as opposed to return the type which is covariant. Because of that, the assignment of <code>f</code> to <code>g</code> is invalid - while <code>Dog</code> is a subtype of <code>Animal</code>, <code>Dog => string</code> is <strong>not</strong> a subtype of <code>Animal => string</code>. However, <code>Animal => string</code> <strong>is</strong> a subtype of <code>Dog => string</code>. More than that, <code>(Dog => Animal) => Dog</code> is a subtype of <code>(Animal => Dog) => Animal</code>.</p>
|
||
<p>This has consequences on how user-defined generic types work. A type variable gains its variance from its role in the type definition as shown in the example:</p>
|
||
<div class="highlight"><pre><span></span><code><span class="k">datatype</span><span class="w"> </span><span class="n">co</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Co</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="c1">// co is covariant on 'a</span>
|
||
<span class="k">datatype</span><span class="w"> </span><span class="n">ct</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Ct</span><span class="p">(</span><span class="nv">'a</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">unit</span><span class="p">)</span><span class="w"> </span><span class="c1">// ct is contravariant on 'a</span>
|
||
<span class="k">datatype</span><span class="w"> </span><span class="n">in</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">In</span><span class="p">(</span><span class="nv">'a</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="c1">// in is invariant on 'a</span>
|
||
<span class="k">datatype</span><span class="w"> </span><span class="n">bi</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Bi</span><span class="w"> </span><span class="c1">// bi is bivariant on 'a</span>
|
||
</code></pre></div>
|
||
<p>The following facts apply here:</p>
|
||
<ul>
|
||
<li><code>co('a)</code> is a subtype of <code>co('b)</code> when <code>'a</code> is a subtype of <code>'b</code></li>
|
||
<li><code>ct('a)</code> is a subtype of <code>ct('b)</code> when <code>'b</code> is a subtype of <code>'a</code></li>
|
||
<li><code>in('a)</code> is a subtype of <code>in('b)</code> when <code>'a</code> is equal to <code>'b</code></li>
|
||
<li><code>bi('a)</code> is a subtype of <code>bi('b)</code> always</li>
|
||
</ul>
|
||
<p>That altogether induce the following rules of subtyping in Sophia:</p>
|
||
<ul>
|
||
<li>
|
||
<p>A function type <code>(Args1) => Ret1</code> is a subtype of <code>(Args2) => Ret2</code> when <code>Ret1</code>
|
||
is a subtype of <code>Ret2</code> and each argument type from <code>Args2</code> is a subtype of its
|
||
counterpart in <code>Args1</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>A list type <code>list(A)</code> is a subtype of <code>list(B)</code> if <code>A</code> is a subtype of <code>B</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>An option type <code>option(A)</code> is a subtype of <code>option(B)</code> if <code>A</code> is a subtype of <code>B</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>A map type <code>map(A1, A2)</code> is a subtype of <code>map(B1, B2)</code> if <code>A1</code> is a subtype
|
||
of <code>B1</code>, and <code>A2</code> is a subtype of <code>B2</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>An oracle type <code>oracle(A1, A2)</code> is a subtype of <code>oracle(B1, B2)</code> if <code>B1</code> is
|
||
a subtype of <code>A1</code>, and <code>A2</code> is a subtype of <code>B2</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>An oracle_query type <code>oracle_query(A1, A2)</code> is a subtype of <code>oracle_query(B1, B2)</code>
|
||
if <code>A1</code> is a subtype of <code>B1</code>, and <code>A2</code> is a subtype of <code>B2</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>A user-defined datatype <code>t(Args1)</code> is a subtype of <code>t(Args2)</code></p>
|
||
</li>
|
||
<li>
|
||
<p>When a user-defined type <code>t('a)</code> is covariant in <code>'a</code>, then <code>t(A)</code> is a
|
||
subtype of <code>t(B)</code> when <code>A</code> is a subtype of <code>B</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>When a user-defined type <code>t('a)</code> is contravariant in <code>'a</code>, then <code>t(A)</code> is a
|
||
subtype of <code>t(B)</code> when <code>B</code> is a subtype of <code>A</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>When a user-defined type <code>t('a)</code> is binvariant in <code>'a</code>, then <code>t(A)</code> is a
|
||
subtype of <code>t(B)</code> when either <code>A</code> is a subtype of <code>B</code> or when <code>B</code> is a subtype
|
||
of <code>A</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>When a user-defined type <code>t('a)</code> is invariant in <code>'a</code>, then <code>t(A)</code> can never be
|
||
a subtype of <code>t(B)</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<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><span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">set_state</span><span class="p">(</span><span class="n">s</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nb">state</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nb">put</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
|
||
</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><span class="c1">// A payable contract</span>
|
||
<span class="k">payable</span><span class="w"> </span><span class="k">contract</span><span class="w"> </span><span class="nf">ExampleContract</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">do_stuff</span><span class="p">()</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">...</span>
|
||
</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><span class="k">payable</span><span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">buy</span><span class="p">(</span><span class="n">to</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nc">Call</span><span class="p">.</span><span class="n">value</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">42</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">transfer_item</span><span class="p">(</span><span class="n">to</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">else</span>
|
||
<span class="w"> </span><span class="nb">abort</span><span class="p">(</span><span class="s2">"Value too low"</span><span class="p">)</span>
|
||
</code></pre></div>
|
||
<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><span class="k">namespace</span><span class="w"> </span><span class="nf">Library</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">number</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">int</span>
|
||
<span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">inc</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">number</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">number</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">+</span><span class="w"> </span><span class="mi">1</span>
|
||
|
||
<span class="k">contract</span><span class="w"> </span><span class="nf">MyContract</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">plus2</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">Library</span><span class="p">.</span><span class="n">number</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Library</span><span class="p">.</span><span class="n">inc</span><span class="p">(</span><span class="nc">Library</span><span class="p">.</span><span class="n">inc</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
|
||
</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>
|
||
<p>To avoid mentioning the namespace every time it is used, Sophia allows
|
||
including the namespace in the current scope with the <code>using</code> keyword:
|
||
<div class="highlight"><pre><span></span><code>include "Pair.aes"
|
||
using Pair
|
||
contract C =
|
||
type state = int
|
||
entrypoint init() =
|
||
let p = (1, 2)
|
||
fst(p) // this is the same as Pair.fst(p)
|
||
</code></pre></div></p>
|
||
<p>It is also possible to make an alias for the namespace with the <code>as</code> keyword:
|
||
<div class="highlight"><pre><span></span><code>include "Pair.aes"
|
||
contract C =
|
||
using Pair as P
|
||
type state = int
|
||
entrypoint init() =
|
||
let p = (1, 2)
|
||
P.fst(p) // this is the same as Pair.fst(p)
|
||
</code></pre></div></p>
|
||
<p>Having the same alias for multiple namespaces is possible and it allows
|
||
referening functions that are defined in different namespaces and have
|
||
different names with the same alias:
|
||
<div class="highlight"><pre><span></span><code>namespace Xa = function f() = 1
|
||
namespace Xb = function g() = 2
|
||
contract Cntr =
|
||
using Xa as A
|
||
using Xb as A
|
||
type state = int
|
||
entrypoint init() = A.f() + A.g()
|
||
</code></pre></div></p>
|
||
<p>Note that using functions with the same name would result in an ambiguous name
|
||
error:
|
||
<div class="highlight"><pre><span></span><code>namespace Xa = function f() = 1
|
||
namespace Xb = function f() = 2
|
||
contract Cntr =
|
||
using Xa as A
|
||
using Xb as A
|
||
type state = int
|
||
|
||
// the next line has an error because f is defined in both Xa and Xb
|
||
entrypoint init() = A.f()
|
||
</code></pre></div></p>
|
||
<p>Importing specific parts of a namespace or hiding these parts can also be
|
||
done like this:
|
||
<div class="highlight"><pre><span></span><code>using Pair for [fst, snd] // this will only import fst and snd
|
||
using Triple hiding [fst, snd] // this will import everything except for fst and snd
|
||
</code></pre></div></p>
|
||
<p>Note that it is possible to use a namespace in the top level of the file, in the
|
||
contract level, namespace level, or in the function level.</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><span class="k">namespace</span><span class="w"> </span><span class="nf">Library</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">inc</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">+</span><span class="w"> </span><span class="mi">1</span>
|
||
</code></pre></div>
|
||
<p>you can use it from another file using an <code>include</code>:</p>
|
||
<div class="highlight"><pre><span></span><code><span class="k">include</span><span class="w"> </span><span class="s2">"library.aes"</span>
|
||
<span class="k">contract</span><span class="w"> </span><span class="nf">MyContract</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">plus2</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nc">Library</span><span class="p">.</span><span class="n">inc</span><span class="p">(</span><span class="nc">Library</span><span class="p">.</span><span class="n">inc</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
|
||
</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/">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><span class="k">include</span><span class="w"> </span><span class="s2">"List.aes"</span>
|
||
<span class="k">include</span><span class="w"> </span><span class="s2">"Pair.aes"</span>
|
||
<span class="ow">--</span><span class="w"> </span><span class="nf">Map</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">already</span><span class="w"> </span><span class="n">there</span><span class="ow">!</span>
|
||
|
||
<span class="k">namespace</span><span class="w"> </span><span class="nf">C</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">keys</span><span class="p">(</span><span class="n">m</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="nv">'a</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">list</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">List</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="nc">Pair</span><span class="p">.</span><span class="n">fst</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="nc">Map</span><span class="p">.</span><span class="n">to_list</span><span class="p">(</span><span class="n">m</span><span class="p">)))</span>
|
||
</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="hole-expression">Hole expression</h2>
|
||
<p>Hole expressions, written as <code>???</code>, are expressions that are used as a placeholder. During compilation, the compiler will generate a type error indication the type of the hole expression.</p>
|
||
<div class="highlight"><pre><span></span><code>include "List.aes"
|
||
contract C =
|
||
entrypoint f() =
|
||
List.sum(List.map(???, [1,2,3]))
|
||
</code></pre></div>
|
||
<p>A hole expression found in the example above will generate the error <code>Found a hole of type `(int) => int`</code>. This says that the compiler expects a function from <code>int</code> to <code>int</code> in place of the <code>???</code> placeholder.</p>
|
||
<h2 id="constants">Constants</h2>
|
||
<p>Constants in Sophia are contract-level bindings that can be used in either contracts or namespaces. The value of a constant can be a literal, another constant, or arithmetic operations applied to other constants. Lists, tuples, maps, and records can also be used to define a constant as long as their elements are also constants.</p>
|
||
<p>The following visibility rules apply to constants:
|
||
* Constants defined inside a contract are private in that contract. Thus, cannot be accessed through instances of their defining contract.
|
||
* Constants defined inside a namespace are public. Thus, can be used in other contracts or namespaces.
|
||
* Constants cannot be defined inside a contract interface.</p>
|
||
<p>When a constant is shadowed, it can be accessed using its qualified name:</p>
|
||
<div class="highlight"><pre><span></span><code>contract C =
|
||
let c = 1
|
||
entrypoint f() =
|
||
let c = 2
|
||
c + C.c // the result is 3
|
||
</code></pre></div>
|
||
<p>The name of the constant must be an id; therefore, no pattern matching is allowed when defining a constant:</p>
|
||
<div class="highlight"><pre><span></span><code>contract C
|
||
let x::y::_ = [1,2,3] // this will result in an error
|
||
</code></pre></div>
|
||
<h2 id="arithmetic">Arithmetic</h2>
|
||
<p>Sophia integers (<code>int</code>) are represented by arbitrary-sized signed words and support 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.
|
||
The division and modulo operations throw an arithmetic error if the
|
||
right-hand operand 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/#bits">documentation</a>.</p>
|
||
<p>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><span class="k">type</span><span class="w"> </span><span class="n">number</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">int</span>
|
||
<span class="k">type</span><span class="w"> </span><span class="n">string_map</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nv">'a</span><span class="p">)</span>
|
||
</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><span class="k">datatype</span><span class="w"> </span><span class="n">one_or_both</span><span class="p">(</span><span class="nv">'a</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Left</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="nf">Right</span><span class="p">(</span><span class="nv">'b</span><span class="p">)</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="nf">Both</span><span class="p">(</span><span class="nv">'a</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">)</span>
|
||
</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><span class="k">function</span><span class="w"> </span><span class="n">get_left</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">one_or_both</span><span class="p">(</span><span class="nv">'a</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nf">Left</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nf">Right</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">None</span>
|
||
<span class="w"> </span><span class="nf">Both</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
</code></pre></div>
|
||
<p>or directly in the left-hand side:
|
||
<div class="highlight"><pre><span></span><code><span class="k">function</span>
|
||
<span class="w"> </span><span class="n">get_left</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">one_or_both</span><span class="p">(</span><span class="nv">'a</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="nv">'a</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">get_left</span><span class="p">(</span><span class="nf">Left</span><span class="p">(</span><span class="n">x</span><span class="p">))</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">get_left</span><span class="p">(</span><span class="nf">Right</span><span class="p">(</span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">None</span>
|
||
<span class="w"> </span><span class="n">get_left</span><span class="p">(</span><span class="nf">Both</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
</code></pre></div></p>
|
||
<p><em>NOTE: Data types cannot currently be recursive.</em></p>
|
||
<p>Sophia also supports the assignment of patterns to variables:
|
||
<div class="highlight"><pre><span></span><code><span class="k">function</span><span class="w"> </span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">h1</span><span class="ow">::</span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">h2</span><span class="ow">::</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">(</span><span class="n">h1</span><span class="w"> </span><span class="ow">+</span><span class="w"> </span><span class="n">h2</span><span class="p">)</span><span class="ow">::</span><span class="n">t</span><span class="w"> </span><span class="c1">// same as `h1::h2::k => (h1 + h2)::h2::k`</span>
|
||
<span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="n">x</span>
|
||
|
||
<span class="k">function</span><span class="w"> </span><span class="n">g</span><span class="p">(</span><span class="n">p</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="ow">*</span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="kt">int</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">let</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">b</span><span class="p">)))</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="c1">// o is equal to Pair.snd(p)</span>
|
||
<span class="w"> </span><span class="n">b</span>
|
||
</code></pre></div></p>
|
||
<p>Guards are boolean expressions that can be used on patterns in both switch
|
||
statements and functions definitions. If a guard expression evaluates to
|
||
<code>true</code>, then the corresponding body will be used. Otherwise, the next pattern
|
||
will be checked:</p>
|
||
<div class="highlight"><pre><span></span><code><span class="k">function</span><span class="w"> </span><span class="n">get_left_if_positive</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">one_or_both</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nf">Left</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nf">Both</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="nf">None</span>
|
||
</code></pre></div>
|
||
<div class="highlight"><pre><span></span><code><span class="k">function</span>
|
||
<span class="w"> </span><span class="n">get_left_if_positive</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="n">one_or_both</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nv">'b</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">get_left_if_positive</span><span class="p">(</span><span class="nf">Left</span><span class="p">(</span><span class="n">x</span><span class="p">))</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">get_left_if_positive</span><span class="p">(</span><span class="nf">Both</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="n">get_left_if_positive</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">None</span>
|
||
</code></pre></div>
|
||
<p>Guards cannot be stateful even when used inside a stateful function.</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><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">666</span><span class="p">]</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">list</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span>
|
||
<span class="p">[(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s2">"aaa"</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="s2">"jjj"</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="mi">666</span><span class="p">,</span><span class="w"> </span><span class="s2">"the beast"</span><span class="p">)]</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">list</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="ow">*</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span>
|
||
<span class="p">[{[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"aaa"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"jjj"</span><span class="p">},</span><span class="w"> </span><span class="p">{[</span><span class="mi">5</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"eee"</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="mi">666</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="s2">"the beast"</span><span class="p">}]</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">list</span><span class="p">(</span><span class="kt">map</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="kt">string</span><span class="p">))</span>
|
||
</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><span class="p">[</span><span class="n">x</span><span class="w"> </span><span class="ow">+</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">],</span><span class="w"> </span><span class="k">let</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="ow">*</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">k</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="mi">5</span><span class="p">),</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow"><-</span><span class="w"> </span><span class="p">[</span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="n">k</span><span class="ow">+</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">k</span><span class="ow">+</span><span class="mi">2</span><span class="p">]]</span>
|
||
<span class="c1">// yields [12,13,14,20,21,22,30,31,32]</span>
|
||
</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><span class="p">[</span><span class="mi">1</span><span class="p">..</span><span class="mi">4</span><span class="p">]</span><span class="w"> </span><span class="ow">==</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
|
||
</code></pre></div>
|
||
The ranges are always ascending and have step equal to 1.</p>
|
||
<p>Please refer to the <a href="../sophia_stdlib/#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><span class="w"> </span><span class="k">record</span><span class="w"> </span><span class="n">account</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">history</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">list</span><span class="p">(</span><span class="n">transaction</span><span class="p">)</span><span class="w"> </span><span class="p">}</span>
|
||
</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/#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><span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">new_account</span><span class="p">(</span><span class="n">name</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="p">{</span><span class="n">name</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">history</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[]}</span>
|
||
</code></pre></div>
|
||
Maps are constructed similarly, with keys enclosed in square brackets
|
||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">example_map</span><span class="p">()</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="p">{[</span><span class="s2">"key1"</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="s2">"key2"</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="mi">2</span><span class="p">}</span>
|
||
</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><span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">get_balance</span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">account</span><span class="p">))</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="n">accounts</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">balance</span>
|
||
</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><span class="k">function</span><span class="w"> </span><span class="n">clear_history</span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">account</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">map</span><span class="p">(</span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">account</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="n">accounts</span><span class="p">{</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">history</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">}</span>
|
||
</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><span class="w"> </span><span class="n">accounts</span><span class="p">{</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">empty_account</span><span class="p">()].</span><span class="n">history</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">}</span>
|
||
</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/#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/#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/#bytes">library documentation</a>.</p>
|
||
<h2 id="cryptographic-builtins">Cryptographic builtins</h2>
|
||
<p>Libraries <a href="../sophia_stdlib/#crypto">Crypto</a> and <a href="../sophia_stdlib/#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/#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><span class="k">contract</span><span class="w"> </span><span class="nf">Oracles</span><span class="w"> </span><span class="ow">=</span>
|
||
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">registerOracle</span><span class="p">(</span><span class="n">acct</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">sign</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">,</span><span class="w"> </span><span class="c1">// Signed network id + oracle address + contract address</span>
|
||
<span class="w"> </span><span class="n">qfee</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">ttl</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">ttl</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="n">acct</span><span class="p">,</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sign</span><span class="p">,</span><span class="w"> </span><span class="n">qfee</span><span class="p">,</span><span class="w"> </span><span class="n">ttl</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">queryFee</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">query_fee</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">payable</span><span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">createQuery</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">qfee</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">qttl</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">ttl</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">rttl</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nb">require</span><span class="p">(</span><span class="n">qfee</span><span class="w"> </span><span class="ow">=<</span><span class="w"> </span><span class="nc">Call</span><span class="p">.</span><span class="n">value</span><span class="p">,</span><span class="w"> </span><span class="s2">"insufficient value for qfee"</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">,</span><span class="w"> </span><span class="n">qfee</span><span class="p">,</span><span class="w"> </span><span class="n">qttl</span><span class="p">,</span><span class="w"> </span><span class="nf">RelativeTTL</span><span class="p">(</span><span class="n">rttl</span><span class="p">))</span>
|
||
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">extendOracle</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">ttl</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">ttl</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">unit</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">extend</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">ttl</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">signExtendOracle</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">sign</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">,</span><span class="w"> </span><span class="c1">// Signed network id + oracle address + contract address</span>
|
||
<span class="w"> </span><span class="n">ttl</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">ttl</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">unit</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">extend</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sign</span><span class="p">,</span><span class="w"> </span><span class="n">ttl</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">respond</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">sign</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">,</span><span class="w"> </span><span class="c1">// Signed network id + oracle query id + contract address</span>
|
||
<span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">respond</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">,</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sign</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">getQuestion</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">get_question</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">hasAnswer</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">))</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="nc">Oracle</span><span class="p">.</span><span class="n">get_answer</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nf">None</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kc">false</span>
|
||
<span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="kc">true</span>
|
||
|
||
<span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">getAnswer</span><span class="p">(</span><span class="n">o</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">),</span>
|
||
<span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">oracle_query</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">))</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">option</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Oracle</span><span class="p">.</span><span class="n">get_answer</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">)</span>
|
||
</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/#check">Oracle.check</a> and <a href="../sophia_stdlib/#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/#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><span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">extend_if_necessary</span><span class="p">(</span><span class="n">addr</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">sig</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nf">None</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">()</span>
|
||
<span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="nf">FixedTTL</span><span class="p">(</span><span class="n">expiry</span><span class="p">),</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="ow">=></span>
|
||
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nc">Chain</span><span class="p">.</span><span class="n">block_height</span><span class="w"> </span><span class="ow">+</span><span class="w"> </span><span class="mi">1000</span><span class="w"> </span><span class="ow">></span><span class="w"> </span><span class="n">expiry</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nc">AENS</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="nf">RelativeTTL</span><span class="p">(</span><span class="mi">50000</span><span class="p">)),</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sig</span><span class="p">)</span>
|
||
</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><span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">add_key</span><span class="p">(</span><span class="n">addr</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">pt</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nc">AENS</span><span class="p">.</span><span class="n">pointee</span><span class="p">,</span><span class="w"> </span><span class="n">sig</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nf">None</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">()</span>
|
||
<span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">ptrs</span><span class="p">))</span><span class="w"> </span><span class="ow">=></span>
|
||
<span class="w"> </span><span class="nc">AENS</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">ptrs</span><span class="p">{[</span><span class="n">key</span><span class="p">]</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">pt</span><span class="p">}),</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sig</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="k">stateful</span><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">delete_key</span><span class="p">(</span><span class="n">addr</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">address</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">sig</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">signature</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">switch</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nf">None</span><span class="w"> </span><span class="ow">=></span><span class="w"> </span><span class="p">()</span>
|
||
<span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="nc">AENS</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">ptrs</span><span class="p">))</span><span class="w"> </span><span class="ow">=></span>
|
||
<span class="w"> </span><span class="k">let</span><span class="w"> </span><span class="n">ptrs</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nc">Map</span><span class="p">.</span><span class="n">delete</span><span class="p">(</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">ptrs</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="nc">AENS</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="nf">None</span><span class="p">,</span><span class="w"> </span><span class="nf">Some</span><span class="p">(</span><span class="n">ptrs</span><span class="p">),</span><span class="w"> </span><span class="kt">signature</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">sig</span><span class="p">)</span>
|
||
</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><span class="w"> </span><span class="k">datatype</span><span class="w"> </span><span class="kt">event</span>
|
||
<span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">Event1</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="ow">|</span><span class="w"> </span><span class="nf">Event2</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">address</span><span class="p">)</span>
|
||
|
||
<span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="n">e</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">event</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">unit</span>
|
||
</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><span class="w"> </span><span class="k">entrypoint</span><span class="w"> </span><span class="n">emit_events</span><span class="p">()</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="nf">Event1</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span><span class="w"> </span><span class="mi">34</span><span class="p">,</span><span class="w"> </span><span class="s2">"foo"</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="nc">Chain</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="nf">Event2</span><span class="p">(</span><span class="s2">"This is not indexed"</span><span class="p">,</span><span class="w"> </span><span class="nc">Contract</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
|
||
</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><span class="nf">AnotherEvent</span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="k">indexed</span><span class="w"> </span><span class="kt">address</span><span class="p">)</span>
|
||
|
||
<span class="p">...</span>
|
||
|
||
<span class="nc">Chain</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="nf">AnotherEvent</span><span class="p">(</span><span class="s2">"This is not indexed"</span><span class="p">,</span><span class="w"> </span><span class="nc">Contract</span><span class="p">.</span><span class="n">address</span><span class="p">))</span>
|
||
</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><span class="ow">@</span><span class="n">compiler</span><span class="w"> </span><span class="ow">>=</span><span class="w"> </span><span class="mi">4</span><span class="p">.</span><span class="mi">3</span>
|
||
<span class="ow">@</span><span class="n">compiler</span><span class="w"> </span><span class="ow"><</span><span class="w"> </span><span class="mi">4</span><span class="p">.</span><span class="mi">4</span>
|
||
</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><span class="nb">abort</span><span class="p">(</span><span class="n">reason</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nv">'a</span>
|
||
</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><span class="k">function</span><span class="w"> </span><span class="nb">require</span><span class="p">(</span><span class="n">b</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="n">err</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="ow">!</span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="nb">abort</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
|
||
</code></pre></div>
|
||
<p>Aside from that, there is an almost equivalent function <code>exit</code></p>
|
||
<div class="highlight"><pre><span></span><code><span class="n">exit</span><span class="p">(</span><span class="n">reason</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="ow">:</span><span class="w"> </span><span class="nv">'a</span>
|
||
</code></pre></div>
|
||
<p>Just like <code>abort</code>, it breaks the execution with the given reason. The difference
|
||
however is in the gas consumption — while <code>abort</code> returns unused gas, a call to
|
||
<code>exit</code> burns it all.</p>
|
||
<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>
|
||
|
||
|
||
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var tab,labels=set.querySelector(".tabbed-labels");for(tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
|
||
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<footer class="md-footer">
|
||
|
||
<div class="md-footer-meta md-typeset">
|
||
<div class="md-footer-meta__inner md-grid">
|
||
<div class="md-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"], "search": "../assets/javascripts/workers/search.db81ec45.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"provider": "mike"}}</script>
|
||
|
||
|
||
<script src="../assets/javascripts/bundle.a00a7c5e.min.js"></script>
|
||
|
||
|
||
</body>
|
||
</html> |