Compare commits
1 Commits
master
...
uw-rename-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b116d77883 |
53
.circleci/config.yml
Normal file
53
.circleci/config.yml
Normal file
@ -0,0 +1,53 @@
|
||||
version: 2.1
|
||||
|
||||
executors:
|
||||
aebuilder:
|
||||
docker:
|
||||
- image: aeternity/builder:bionic-otp24
|
||||
user: builder
|
||||
working_directory: ~/aesophia
|
||||
|
||||
jobs:
|
||||
verify_rebar_lock:
|
||||
executor: aebuilder
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Ensure lock file is up-to-date
|
||||
command: |
|
||||
./rebar3 upgrade
|
||||
git diff --quiet -- rebar.lock || (echo "rebar.lock is not up-to-date" && exit 1)
|
||||
build:
|
||||
executor: aebuilder
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dialyzer-cache-v2-{{ .Branch }}-{{ .Revision }}
|
||||
- dialyzer-cache-v2-{{ .Branch }}-
|
||||
- dialyzer-cache-v2-
|
||||
- run:
|
||||
name: Build
|
||||
command: ./rebar3 compile
|
||||
- run:
|
||||
name: Static Analysis
|
||||
command: ./rebar3 dialyzer
|
||||
- run:
|
||||
name: Eunit
|
||||
command: ./rebar3 eunit
|
||||
- run:
|
||||
name: Common Tests
|
||||
command: ./rebar3 ct
|
||||
- save_cache:
|
||||
key: dialyzer-cache-v2-{{ .Branch }}-{{ .Revision }}
|
||||
paths:
|
||||
- _build/default/rebar3_20.3.8_plt
|
||||
- store_artifacts:
|
||||
path: _build/test/logs
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_test:
|
||||
jobs:
|
||||
- build
|
||||
- verify_rebar_lock
|
@ -1,14 +0,0 @@
|
||||
name: Sophia Tests
|
||||
run-name: ${{ gitea.actor }} testing Sophia
|
||||
on: [push, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: linux_amd64
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
- name: test
|
||||
run: |
|
||||
. /home/act_runner/.erts/27.2.1/activate
|
||||
./rebar3 eunit
|
21
.github/workflows/docs-develop.yml
vendored
Normal file
21
.github/workflows/docs-develop.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Publish development docs
|
||||
on:
|
||||
push:
|
||||
branches: ['master']
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- run: pip3 install -r .github/workflows/requirements.txt -U
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
- run: |
|
||||
cd .docssite
|
||||
mike deploy --push master
|
22
.github/workflows/docs-release.yml
vendored
Normal file
22
.github/workflows/docs-release.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: Publish release docs
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- run: pip3 install -r .github/workflows/requirements.txt -U
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
- run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
- run: |
|
||||
cd .docssite
|
||||
mike deploy --push --update-aliases $RELEASE_VERSION latest
|
5
.github/workflows/requirements.txt
vendored
Normal file
5
.github/workflows/requirements.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
mkdocs==1.4.2
|
||||
mkdocs-simple-hooks==0.1.5
|
||||
mkdocs-material==9.0.9
|
||||
mike==1.1.2
|
||||
pygments==2.17.2
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,7 +18,7 @@ _build
|
||||
rebar3.crashdump
|
||||
*.erl~
|
||||
*.aes~
|
||||
sophia
|
||||
aesophia
|
||||
.qcci
|
||||
current_counterexample.eqc
|
||||
test/contracts/test.aes
|
||||
|
@ -11,12 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
### Removed
|
||||
|
||||
## [9.0.0]
|
||||
### Changed
|
||||
- stdlib dir discovery now works by finding a relative path from the loaded Sophia installation
|
||||
###Removed
|
||||
- Oracles
|
||||
|
||||
## [8.0.1]
|
||||
### Changed
|
||||
- Upgrade aebytecode to v3.4.1 to fix C warnings
|
||||
|
1
LICENSE
1
LICENSE
@ -1,6 +1,5 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2025, QPQ AG
|
||||
Copyright (c) 2017, æternity developers
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
|
16
README.md
16
README.md
@ -1,11 +1,11 @@
|
||||
# The Sophia smart contract language
|
||||
# aesophia
|
||||
|
||||
This is the __sophia__ compiler which compiles contracts written in __sophia__ to [FATE](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts/fate.md) instructions.
|
||||
This is the __sophia__ compiler for the æternity system which compiles contracts written in __sophia__ to [FATE](https://github.com/aeternity/protocol/blob/master/contracts/fate.md) instructions.
|
||||
|
||||
The compiler is currently being used three places
|
||||
- [The command line compiler](https://git.qpq.swiss/QPQ-AG/sophia_cli)
|
||||
- [Desktop wallet](https://git.qpq.swiss/QPQ-AG/GajuDesk)
|
||||
- In the [Gajumaru core node](https://git.qpq.swiss/QPQ-AG/gajumaru) tests
|
||||
- [The command line compiler](https://github.com/aeternity/aesophia_cli)
|
||||
- [The HTTP compiler](https://github.com/aeternity/aesophia_http)
|
||||
- In [æternity node](https://github.com/aeternity/aeternity) tests
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -16,7 +16,7 @@ The compiler is currently being used three places
|
||||
* [Contract examples](docs/sophia_examples.md)
|
||||
* [Contributing](CONTRIBUTING.md)
|
||||
|
||||
Additionally you can check out the [contracts section](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts) of the Gajumaru blockchain specification.
|
||||
Additionally you can check out the [contracts section](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md) of the æternity blockchain specification.
|
||||
|
||||
## Versioning
|
||||
|
||||
@ -31,5 +31,5 @@ Versioning should follow the [semantic versioning](https://semver.org/spec/v2.0.
|
||||
|
||||
The basic modules for interfacing the compiler:
|
||||
|
||||
* [so_compiler: the Sophia compiler](docs/so_compiler.md)
|
||||
* [so_aci: the ACI interface](docs/so_aci.md)
|
||||
* [aeso_compiler: the Sophia compiler](docs/aeso_compiler.md)
|
||||
* [aeso_aci: the ACI interface](docs/aeso_aci.md)
|
||||
|
@ -1,8 +1,8 @@
|
||||
# so_aci
|
||||
# aeso_aci
|
||||
|
||||
### Module
|
||||
|
||||
### so_aci
|
||||
### aeso_aci
|
||||
|
||||
The ACI interface encoder and decoder.
|
||||
|
||||
@ -123,7 +123,7 @@ be included inside another contract.
|
||||
``` erlang
|
||||
1> {ok,Contract} = file:read_file("aci_test.aes").
|
||||
{ok,<<"contract Answers =\n record state = { a : answers }\n type answers() = map(string, int)\n\n stateful function"...>>}
|
||||
2> {ok,JsonACI} = so_aci:contract_interface(json, Contract).
|
||||
2> {ok,JsonACI} = aeso_aci:contract_interface(json, Contract).
|
||||
{ok,[#{contract =>
|
||||
#{functions =>
|
||||
[#{arguments => [],name => <<"init">>,
|
||||
@ -144,7 +144,7 @@ be included inside another contract.
|
||||
vars => []}]}}]}
|
||||
3> file:write_file("aci_test.aci", jsx:encode(JsonACI)).
|
||||
ok
|
||||
4> {ok,InterfaceStub} = so_aci:render_aci_json(JsonACI).
|
||||
4> {ok,InterfaceStub} = aeso_aci:render_aci_json(JsonACI).
|
||||
{ok,<<"contract Answers =\n record state = {a : Answers.answers}\n type answers = map(string, int)\n function init "...>>}
|
||||
5> file:write_file("aci_test.include", InterfaceStub).
|
||||
ok
|
@ -1,8 +1,8 @@
|
||||
# so_compiler
|
||||
# aeso_compiler
|
||||
|
||||
### Module
|
||||
|
||||
### so_compiler
|
||||
### aeso_compiler
|
||||
|
||||
The Sophia compiler
|
||||
|
@ -1,9 +1,12 @@
|
||||
# Introduction
|
||||
Sophia is a functional language designed for smart contract development.
|
||||
It is strongly typed and has restricted mutable state.
|
||||
Sophia is a functional language designed for smart contract development. It is strongly typed and has
|
||||
restricted mutable state.
|
||||
|
||||
Sophia is customized for smart contracts, which can be published to a blockchain.
|
||||
Thus some features of conventional languages (such as floating point arithmetic) are not present in Sophia,
|
||||
and some blockchain specific primitives, constructions and types have been added.
|
||||
Sophia is customized for smart contracts, which can be published
|
||||
to a blockchain. Thus some features of conventional
|
||||
languages, such as floating point arithmetic, are not present in Sophia, and
|
||||
some [æternity blockchain](https://aeternity.com) specific primitives, constructions and types have been added.
|
||||
|
||||
The file extension used for Sophia source files is ".aes", reflecting Sophia's Aeternity heritage.
|
||||
!!! Note
|
||||
- For rapid prototyping of smart contracts check out [AEstudio](https://studio.aepps.com/)!
|
||||
- For playing around and diving deeper into the language itself check out the [REPL](https://repl.aeternity.io/)!
|
||||
|
@ -65,3 +65,9 @@ contract FundMe =
|
||||
amount = state.contributions[to]})
|
||||
put(state{ contributions @ c = Map.delete(to, c) })
|
||||
```
|
||||
|
||||
## Repositories
|
||||
This is a list with repositories that include smart contracts written in Sophia:
|
||||
|
||||
- [aepp-sophia-examples](https://github.com/aeternity/aepp-sophia-examples)
|
||||
- A repository that contains lots of different examples. The functionality of these examples is - to some extent - also covered by tests written in JavaScript.
|
@ -274,6 +274,12 @@ counterpart in `Args1`.
|
||||
- A map type `map(A1, A2)` is a subtype of `map(B1, B2)` if `A1` is a subtype
|
||||
of `B1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- An oracle type `oracle(A1, A2)` is a subtype of `oracle(B1, B2)` if `B1` is
|
||||
a subtype of `A1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- An oracle_query type `oracle_query(A1, A2)` is a subtype of `oracle_query(B1, B2)`
|
||||
if `A1` is a subtype of `B1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- A user-defined datatype `t(Args1)` is a subtype of `t(Args2)`
|
||||
|
||||
- When a user-defined type `t('a)` is covariant in `'a`, then `t(A)` is a
|
||||
@ -334,6 +340,10 @@ Without the `stateful` annotation the compiler does not allow the call to
|
||||
* Use a stateful primitive function. These are
|
||||
- `put`
|
||||
- `Chain.spend`
|
||||
- `Oracle.register`
|
||||
- `Oracle.query`
|
||||
- `Oracle.respond`
|
||||
- `Oracle.extend`
|
||||
- `AENS.preclaim`
|
||||
- `AENS.claim`
|
||||
- `AENS.transfer`
|
||||
@ -546,6 +556,8 @@ Sophia has the following types:
|
||||
| hash | A 32-byte hash - equivalent to `bytes(32)` | |
|
||||
| signature | A signature - equivalent to `bytes(64)` | |
|
||||
| Chain.ttl | Time-to-live (fixed height or relative to current block) | ```FixedTTL(1050)``` ```RelativeTTL(50)``` |
|
||||
| oracle('a, 'b) | And oracle answering questions of type 'a with answers of type 'b | ```Oracle.register(acct, qfee, ttl)``` |
|
||||
| oracle_query('a, 'b) | A specific oracle query | ```Oracle.query(o, q, qfee, qttl, rttl)``` |
|
||||
| contract | A user defined, typed, contract address | ```function call_remote(r : RemoteContract) = r.fun()``` |
|
||||
|
||||
## Literals
|
||||
@ -568,6 +580,8 @@ Sophia has the following types:
|
||||
| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
||||
| signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
||||
| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
|
||||
| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
|
||||
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
|
||||
| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
|
||||
|
||||
## Hole expression
|
||||
@ -877,9 +891,77 @@ wrapping a transaction.) The transaction and the transaction hash is available i
|
||||
`Auth.tx` and `Auth.tx_hash` respectively, they are *only* available during authentication if invoked by a
|
||||
normal contract call they return `None`.
|
||||
|
||||
## Oracle interface
|
||||
You can attach an oracle to the current contract and you can interact with oracles
|
||||
through the Oracle interface.
|
||||
|
||||
For a full description of how Oracle works see
|
||||
[Oracles](https://github.com/aeternity/protocol/blob/master/oracles/oracles.md#oracles).
|
||||
For a functionality documentation refer to the [standard library](sophia_stdlib.md#oracle).
|
||||
|
||||
### Example
|
||||
|
||||
Example for an oracle answering questions of type `string` with answers of type `int`:
|
||||
```sophia
|
||||
contract Oracles =
|
||||
|
||||
stateful entrypoint registerOracle(acct : address,
|
||||
sign : signature, // Signed network id + oracle address + contract address
|
||||
qfee : int,
|
||||
ttl : Chain.ttl) : oracle(string, int) =
|
||||
Oracle.register(acct, signature = sign, qfee, ttl)
|
||||
|
||||
entrypoint queryFee(o : oracle(string, int)) : int =
|
||||
Oracle.query_fee(o)
|
||||
|
||||
payable stateful entrypoint createQuery(o : oracle_query(string, int),
|
||||
q : string,
|
||||
qfee : int,
|
||||
qttl : Chain.ttl,
|
||||
rttl : int) : oracle_query(string, int) =
|
||||
require(qfee =< Call.value, "insufficient value for qfee")
|
||||
Oracle.query(o, q, qfee, qttl, RelativeTTL(rttl))
|
||||
|
||||
stateful entrypoint extendOracle(o : oracle(string, int),
|
||||
ttl : Chain.ttl) : unit =
|
||||
Oracle.extend(o, ttl)
|
||||
|
||||
stateful entrypoint signExtendOracle(o : oracle(string, int),
|
||||
sign : signature, // Signed network id + oracle address + contract address
|
||||
ttl : Chain.ttl) : unit =
|
||||
Oracle.extend(o, signature = sign, ttl)
|
||||
|
||||
stateful entrypoint respond(o : oracle(string, int),
|
||||
q : oracle_query(string, int),
|
||||
sign : signature, // Signed network id + oracle query id + contract address
|
||||
r : int) =
|
||||
Oracle.respond(o, q, signature = sign, r)
|
||||
|
||||
entrypoint getQuestion(o : oracle(string, int),
|
||||
q : oracle_query(string, int)) : string =
|
||||
Oracle.get_question(o, q)
|
||||
|
||||
entrypoint hasAnswer(o : oracle(string, int),
|
||||
q : oracle_query(string, int)) =
|
||||
switch(Oracle.get_answer(o, q))
|
||||
None => false
|
||||
Some(_) => true
|
||||
|
||||
entrypoint getAnswer(o : oracle(string, int),
|
||||
q : oracle_query(string, int)) : option(int) =
|
||||
Oracle.get_answer(o, q)
|
||||
```
|
||||
|
||||
### Sanity checks
|
||||
|
||||
When an Oracle literal is passed to a contract, no deep checks are performed.
|
||||
For extra safety [Oracle.check](sophia_stdlib.md#check) and [Oracle.check_query](sophia_stdlib.md#check_query)
|
||||
functions are provided.
|
||||
|
||||
## AENS interface
|
||||
|
||||
Contracts can interact with the [æternity naming system](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/AENS.md). For this
|
||||
Contracts can interact with the [æternity naming
|
||||
system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this
|
||||
purpose the [AENS](sophia_stdlib.md#aens) and later the
|
||||
[AENSv2](sophia_stdlib.md#aensv2) library was exposed.
|
||||
|
||||
@ -927,9 +1009,10 @@ automatically removed so they will not appear in the pointers map.
|
||||
|
||||
## Events
|
||||
|
||||
Sophia contracts log structured messages to an event log in the resulting blockchain transaction.
|
||||
The event log is quite similar to [Events in Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events).
|
||||
Events are further discussed in the [protocol](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts/events.md).
|
||||
Sophia contracts log structured messages to an event log in the resulting
|
||||
blockchain transaction. The event log is quite similar to [Events in
|
||||
Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events).
|
||||
Events are further discussed in the [protocol](https://github.com/aeternity/protocol/blob/master/contracts/events.md).
|
||||
|
||||
|
||||
To use events a contract must declare a datatype `event`, and events are then
|
||||
@ -949,6 +1032,8 @@ field is indexed if it fits in a 32-byte word, i.e.
|
||||
- `int`
|
||||
- `bits`
|
||||
- `address`
|
||||
- `oracle(_, _)`
|
||||
- `oracle_query(_, _)`
|
||||
- contract types
|
||||
- `bytes(n)` for `n` ≤ 32, in particular `hash`
|
||||
|
||||
@ -1028,15 +1113,34 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
|
||||
|
||||
## Delegation signature
|
||||
|
||||
Some chain operations (`AENSv2.<operation>`) have an
|
||||
Some chain operations (`Oracle.<operation>` and `AENSv2.<operation>`) 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.
|
||||
|
||||
There are five different delegation signatures:
|
||||
### From Ceres
|
||||
|
||||
From the Ceres protocol version the delegation signatures have more structure,
|
||||
including a unique tag, `network_id` and identifiers; there are five different
|
||||
delegation signatures:
|
||||
|
||||
- AENS wildcard - the user signs: `owner account + contract`
|
||||
- `AENS_PRECLAIM` - the user signs: `owner account + contract`
|
||||
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `owner account + name hash + contract`
|
||||
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `owner account + contract`
|
||||
- `ORACLE_RESPOND` - the user signs: `query id + contract`
|
||||
|
||||
See [Serialized signature data](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/serializations.md)
|
||||
See [Serialized signature
|
||||
data](https://github.com/aeternity/protocol/blob/master/contracts/fate.md#from-ceres-serialized-signature-data)
|
||||
for the exact structure used.
|
||||
|
||||
### Before ceres
|
||||
|
||||
The exact data to be signed varies for the different operations, but in all
|
||||
cases you should prepend the signature data with the `network_id` (`ae_mainnet`
|
||||
for the æternity mainnet, etc.).
|
||||
|
||||
There are four different delegation signatures:
|
||||
- `AENS_PRECLAIM` - the user signs: owner `network_id + account + contract`
|
||||
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `network_id + owner account + name hash + contract`
|
||||
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `network_id + owner account + contract`
|
||||
- `ORACLE_RESPOND` - the user signs: `network_id + query id + contract`
|
||||
|
@ -25,6 +25,7 @@ The out-of-the-box namespaces are:
|
||||
- [Crypto](#crypto)
|
||||
- [Int](#int)
|
||||
- [Map](#map)
|
||||
- [Oracle](#oracle)
|
||||
|
||||
The following ones need to be included as regular files with `.aes` suffix, for example
|
||||
```
|
||||
@ -71,6 +72,14 @@ Address.is_contract(a : address) : bool
|
||||
Is the address a contract
|
||||
|
||||
|
||||
#### is_oracle
|
||||
```
|
||||
Address.is_oracle(a : address) : bool
|
||||
```
|
||||
|
||||
Is the address a registered oracle
|
||||
|
||||
|
||||
#### is_payable
|
||||
```
|
||||
Address.is_payable(a : address) : bool
|
||||
@ -90,7 +99,7 @@ Cast address to contract type C (where `C` is a contract)
|
||||
### AENS
|
||||
|
||||
The old AENS namespace, kept in the compiler to be able to interact with
|
||||
contracts from before Ceres, compiled using sophia compiler version 7.x and
|
||||
contracts from before Ceres, compiled using aesophia compiler version 7.x and
|
||||
earlier. Used in [AENSCompat](#aenscompat) when converting between old and new
|
||||
pointers.
|
||||
|
||||
@ -105,9 +114,8 @@ datatype name = Name(address, Chain.ttl, map(string, AENS.pointee))
|
||||
##### pointee
|
||||
|
||||
```
|
||||
datatype pointee = AccountPt(address)
|
||||
| ContractPt(address)
|
||||
| ChannelPt(address)
|
||||
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
| ContractPt(address) | ChannelPt(address)
|
||||
```
|
||||
|
||||
### AENSv2
|
||||
@ -119,7 +127,7 @@ naming system (AENS). If `owner` is equal to `Contract.address` the signature
|
||||
`signature` is ignored, and can be left out since it is a named argument.
|
||||
Otherwise we need a signature to prove that we are allowed to do AENS
|
||||
operations on behalf of `owner`. The [signature is tied to a network
|
||||
id](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/consensus/README.md#transaction-signature),
|
||||
id](https://github.com/aeternity/protocol/blob/iris/consensus/consensus.md#transaction-signature),
|
||||
i.e. the signature material should be prefixed by the network id.
|
||||
|
||||
#### Types
|
||||
@ -133,10 +141,8 @@ datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
|
||||
##### pointee
|
||||
|
||||
```
|
||||
datatype pointee = AccountPt(address)
|
||||
| ContractPt(address)
|
||||
| ChannelPt(address)
|
||||
| DataPt(bytes())
|
||||
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
| ContractPt(address) | ChannelPt(address) | DataPt(bytes())
|
||||
```
|
||||
|
||||
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
|
||||
@ -179,7 +185,8 @@ The [signature](./sophia_features.md#delegation-signature) should be a
|
||||
serialized structure containing `network id`, `owner address`, and
|
||||
`Contract.address`.
|
||||
|
||||
The [signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. containing `network id`, `owner address`, `Contract.address`.
|
||||
|
||||
@ -280,6 +287,7 @@ namespace Chain =
|
||||
datatype ga_meta_tx = GAMetaTx(address, int)
|
||||
datatype paying_for_tx = PayingForTx(address, int)
|
||||
datatype base_tx = SpendTx(address, int, string)
|
||||
| OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
|
||||
| NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
|
||||
| NameRevokeTx(hash) | NameTransferTx(address, string)
|
||||
| ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
|
||||
@ -297,7 +305,7 @@ Auth.tx_hash : option(hash)
|
||||
|
||||
Gets the transaction hash during authentication. Note: `Auth.tx_hash`
|
||||
computation differs between protocol versions (changed in Ceres!), see
|
||||
[aeserialisation](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/serializations.md)
|
||||
[aeserialisation](https://github.com/aeternity/protocol/blob/master/serializations.md)
|
||||
specification for details.
|
||||
|
||||
|
||||
@ -529,6 +537,7 @@ datatype paying_for_tx = PayingForTx(address, int)
|
||||
##### base_tx
|
||||
```
|
||||
datatype base_tx = SpendTx(address, int, string)
|
||||
| OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
|
||||
| NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
|
||||
| NameRevokeTx(hash) | NameTransferTx(address, string)
|
||||
| ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
|
||||
@ -935,6 +944,118 @@ Returns a list containing pairs of keys and their respective elements.
|
||||
Turns a list of pairs of form `(key, value)` into a map
|
||||
|
||||
|
||||
### Oracle
|
||||
|
||||
#### register
|
||||
```
|
||||
Oracle.register(<signature : bytes(64)>, acct : address, qfee : int, ttl : Chain.ttl) : oracle('a, 'b)
|
||||
```
|
||||
|
||||
Registers new oracle answering questions of type `'a` with answers of type `'b`.
|
||||
|
||||
* The `acct` is the address of the oracle to register (can be the same as the contract).
|
||||
* The [signature](./sophia_features.md#delegation-signature) should be a
|
||||
serialized structure containing `network id`, `account address`, and
|
||||
`contract address`. Using the private key of `account address` for signing.
|
||||
Proving you have the private key of the oracle to be. If the address is the same
|
||||
as the contract `sign` is ignored and can be left out entirely.
|
||||
* The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle.
|
||||
* The `ttl` is the Time To Live for the oracle in key blocks, either relative to the current
|
||||
key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`).
|
||||
* The type `'a` is the type of the question to ask.
|
||||
* The type `'b` is the type of the oracle answers.
|
||||
|
||||
Examples:
|
||||
```
|
||||
Oracle.register(addr0, 25, RelativeTTL(400))
|
||||
Oracle.register(addr1, 25, RelativeTTL(500), signature = sign1)
|
||||
```
|
||||
|
||||
|
||||
#### get\_question
|
||||
```
|
||||
Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a
|
||||
```
|
||||
|
||||
Checks what was the question of query `q` on oracle `o`
|
||||
|
||||
|
||||
#### respond
|
||||
```
|
||||
Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit
|
||||
```
|
||||
|
||||
Responds to the question `q` on `o`. Unless the contract address is the same
|
||||
as the oracle address the `signature` (which is an optional, named argument)
|
||||
needs to be provided. Proving that we have the private key of the oracle by
|
||||
[signing](./sophia_features.md#delegation-signature) should be a serialized
|
||||
structure containing `network id`, `oracle query id`, and `contract address`.
|
||||
|
||||
|
||||
#### extend
|
||||
```
|
||||
Oracle.extend(<signature : bytes(64)>, o : oracle('a, 'b), ttl : Chain.ttl) : unit
|
||||
```
|
||||
|
||||
Extends TTL of an oracle.
|
||||
* `singature` is a named argument and thus optional. Must be the same as for `Oracle.register`
|
||||
* `o` is the oracle being extended
|
||||
* `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value.
|
||||
|
||||
#### query\_fee
|
||||
```
|
||||
Oracle.query_fee(o : oracle('a, 'b)) : int
|
||||
```
|
||||
|
||||
Returns the query fee of the oracle
|
||||
|
||||
|
||||
#### query
|
||||
```
|
||||
Oracle.query(o : oracle('a, 'b), q : 'a, qfee : int, qttl : Chain.ttl, rttl : Chain.ttl) : oracle_query('a, 'b)
|
||||
```
|
||||
|
||||
Asks the oracle a question.
|
||||
* The `qfee` is the query fee debited to the contract account (`Contract.address`).
|
||||
* The `qttl` controls the last height at which the oracle can submit a response
|
||||
and can be either fixed or relative.
|
||||
* The `rttl` must be relative and controls how long an answer is kept on the chain.
|
||||
The call fails if the oracle could expire before an answer.
|
||||
|
||||
|
||||
#### get\_answer
|
||||
```
|
||||
Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b)
|
||||
```
|
||||
|
||||
Checks what is the optional query answer
|
||||
|
||||
|
||||
#### expiry
|
||||
|
||||
```
|
||||
Oracle.expiry(o : oracle('a, 'b)) : int
|
||||
```
|
||||
|
||||
Ask the oracle when it expires. The result is the block height at which it will happen.
|
||||
|
||||
|
||||
#### check
|
||||
```
|
||||
Oracle.check(o : oracle('a, 'b)) : bool
|
||||
```
|
||||
|
||||
Returns `true` iff the oracle `o` exists and has correct type
|
||||
|
||||
|
||||
#### check_query
|
||||
```
|
||||
Oracle.check_query(o : oracle('a, 'b), q : oracle_query('a, 'b)) : bool
|
||||
```
|
||||
|
||||
It returns `true` iff the oracle query exist and has the expected type.
|
||||
|
||||
|
||||
## Includable namespaces
|
||||
|
||||
These need to be explicitly included (with `.aes` suffix)
|
||||
@ -1543,7 +1664,7 @@ point where the error would exceed the `loss` value.
|
||||
|
||||
For debugging. If it ever returns false in a code that doesn't call `frac` constructors or
|
||||
accept arbitrary `frac`s from the surface you should report it as a
|
||||
[bug](https://git.qpq.swiss/QPQ-AG/sophia/issues/new)
|
||||
[bug](https://github.com/aeternity/aesophia/issues/new)
|
||||
|
||||
If you expect getting calls with malformed `frac`s in your contract, you should use
|
||||
this function to verify the input.
|
||||
|
@ -28,6 +28,8 @@ interface main using as for hiding
|
||||
- `Char` character literal enclosed in `'` with escape character `\`
|
||||
- `AccountAddress` base58-encoded 32 byte account pubkey with `ak_` prefix
|
||||
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
|
||||
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
|
||||
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
|
||||
- `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix
|
||||
|
||||
Valid string escape codes are
|
||||
@ -44,7 +46,7 @@ Valid string escape codes are
|
||||
| `\xHexDigits` | *HexDigits* | |
|
||||
|
||||
|
||||
See the [identifier encoding scheme](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/node/api/api_encoding.md) for the
|
||||
See the [identifier encoding scheme](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) for the
|
||||
details on the base58 literals.
|
||||
|
||||
## Layout blocks
|
||||
@ -237,6 +239,7 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
|
||||
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
||||
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
|
||||
| AccountAddress | ContractAddress // Chain identifiers
|
||||
| OracleAddress | OracleQueryId // Chain identifiers
|
||||
| Signature // Signature
|
||||
| '???' // Hole expression 1 + ???
|
||||
|
||||
|
@ -3,7 +3,6 @@ namespace AENSCompat =
|
||||
function pointee_to_V2(p : AENS.pointee) : AENSv2.pointee =
|
||||
switch(p)
|
||||
AENS.AccountPt(a) => AENSv2.AccountPt(a)
|
||||
AENS.OraclePt(a) => AENSv2.OraclePt(a)
|
||||
AENS.ContractPt(a) => AENSv2.ContractPt(a)
|
||||
AENS.ChannelPt(a) => AENSv2.ChannelPt(a)
|
||||
|
||||
@ -11,7 +10,6 @@ namespace AENSCompat =
|
||||
function pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee) =
|
||||
switch(p2)
|
||||
AENSv2.AccountPt(a) => Some(AENS.AccountPt(a))
|
||||
AENSv2.OraclePt(a) => Some(AENS.OraclePt(a))
|
||||
AENSv2.ContractPt(a) => Some(AENS.ContractPt(a))
|
||||
AENSv2.ChannelPt(a) => Some(AENS.ChannelPt(a))
|
||||
AENSv2.DataPt(_) => None
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
{erl_opts, [debug_info]}.
|
||||
|
||||
{deps, [ {gmbytecode,
|
||||
{git, "https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
|
||||
{ref, "97cea33be8f3a35d26055664da7aa59531ff5537"}}}
|
||||
{deps, [ {gmbytecode, {git, "https://git.qpq.swiss/QPQ-AG/gmbytecode.git", {ref, "cc4fd04019"}}}
|
||||
, {eblake2, "1.0.0"}
|
||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}
|
||||
]}.
|
||||
@ -15,11 +13,10 @@
|
||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||
]}.
|
||||
|
||||
{relx, [{release, {sophia, "9.0.0"},
|
||||
{relx, [{release, {sophia, "8.0.1"},
|
||||
[sophia, gmbytecode]},
|
||||
|
||||
{dev_mode, true},
|
||||
{include_erts, false},
|
||||
|
||||
{extended_start_script, true}]}.
|
||||
|
||||
|
35
rebar.lock
35
rebar.lock
@ -1,30 +1,31 @@
|
||||
{"1.2.0",
|
||||
[{<<"gmbytecode">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
|
||||
{ref, "97cea33be8f3a35d26055664da7aa59531ff5537"}},
|
||||
0},
|
||||
{<<"gmserialization">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||
{ref,"ac64e01b0f675c1a34c70a827062f381920742db"}},
|
||||
1},
|
||||
{<<"base58">>,
|
||||
[{<<"base58">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
||||
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
|
||||
2},
|
||||
{<<"eblake2">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/eblake2.git",
|
||||
{ref,"b29d585b8760746142014884007eb8441a3b6a14"}},
|
||||
0},
|
||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||
{<<"enacl">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
||||
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
|
||||
2},
|
||||
{<<"getopt">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/getopt.git",
|
||||
{ref,"dbab6262a2430809430deda9d8650f58f9d80898"}},
|
||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1},
|
||||
{<<"gmbytecode">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
|
||||
{ref,"cc4fd0401903e9ce902a99160ac200e64040217f"}},
|
||||
0},
|
||||
{<<"gmserialization">>,
|
||||
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||
{ref,"9d2ecc00d32ea295309563e54a81636ecb597e96"}},
|
||||
1},
|
||||
{<<"jsx">>,
|
||||
{git,"https://github.com/talentdeficit/jsx.git",
|
||||
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
|
||||
0}]}.
|
||||
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
|
||||
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
|
||||
].
|
||||
|
@ -1,14 +1,13 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Robert Virding
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% ACI interface
|
||||
%%% @end
|
||||
%%% Created : 12 Jan 2019
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(so_aci).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([ file/2
|
||||
, file/3
|
||||
|
@ -1,5 +1,4 @@
|
||||
-module(so_ast).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([int/2,
|
||||
line/1,
|
||||
|
@ -1,5 +1,4 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Type checker for Sophia.
|
||||
@ -12,7 +11,6 @@
|
||||
%%% instances of the compiler to be run in parallel.
|
||||
|
||||
-module(so_ast_infer_types).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([ infer/1
|
||||
, infer/2
|
||||
@ -96,10 +94,9 @@
|
||||
| {add_bytes, so_syntax:ann(), concat | split | split_any, utype(), utype(), utype()}.
|
||||
|
||||
-type aens_resolve_constraint() :: {aens_resolve_type, utype()}.
|
||||
-type oracle_type_constraint() :: {oracle_type, so_syntax:ann(), utype()}.
|
||||
|
||||
-type constraint() :: named_argument_constraint() | field_constraint() | byte_constraint()
|
||||
| aens_resolve_constraint() | oracle_type_constraint().
|
||||
| aens_resolve_constraint().
|
||||
|
||||
-record(field_info,
|
||||
{ ann :: so_syntax:ann()
|
||||
@ -572,8 +569,6 @@ global_env() ->
|
||||
Hash = {id, Ann, "hash"},
|
||||
Bits = {id, Ann, "bits"},
|
||||
Bytes = fun(Len) -> {bytes_t, Ann, Len} end,
|
||||
Oracle = fun(Q, R) -> {app_t, Ann, {id, Ann, "oracle"}, [Q, R]} end,
|
||||
Query = fun(Q, R) -> {app_t, Ann, {id, Ann, "oracle_query"}, [Q, R]} end,
|
||||
Unit = {tuple_t, Ann, []},
|
||||
List = fun(T) -> {app_t, Ann, {id, Ann, "list"}, [T]} end,
|
||||
Option = fun(T) -> {app_t, Ann, {id, Ann, "option"}, [T]} end,
|
||||
@ -615,8 +610,7 @@ global_env() ->
|
||||
TxType = {record_t, [FldT(N, T) || {N, T} <- TxFlds ]},
|
||||
Stateful = fun(T) -> setelement(2, T, [stateful|element(2, T)]) end,
|
||||
|
||||
Fee = Int,
|
||||
[A, Q, R, K, V] = lists:map(TVar, ["a", "q", "r", "k", "v"]),
|
||||
[A, K, V] = lists:map(TVar, ["a", "k", "v"]),
|
||||
|
||||
MkDefs = fun(Defs) -> [{X, {Ann, if is_integer(T) -> {builtin, T}; true -> T end}} || {X, T} <- Defs] end,
|
||||
|
||||
@ -639,8 +633,7 @@ global_env() ->
|
||||
{"hash", {[], {alias_t, Bytes(32)}}},
|
||||
{"signature", {[], {alias_t, Bytes(64)}}},
|
||||
{"bits", 0},
|
||||
{"option", 1}, {"list", 1}, {"map", 2},
|
||||
{"oracle", 2}, {"oracle_query", 2}
|
||||
{"option", 1}, {"list", 1}, {"map", 2}
|
||||
]) },
|
||||
|
||||
ChainScope = #scope
|
||||
@ -677,10 +670,6 @@ global_env() ->
|
||||
{"GAMetaTx", Fun([Address, Int], GAMetaTx)},
|
||||
{"PayingForTx", Fun([Address, Int], PayForTx)},
|
||||
{"SpendTx", Fun([Address, Int, String], BaseTx)},
|
||||
{"OracleRegisterTx", BaseTx},
|
||||
{"OracleQueryTx", BaseTx},
|
||||
{"OracleResponseTx", BaseTx},
|
||||
{"OracleExtendTx", BaseTx},
|
||||
{"NamePreclaimTx", BaseTx},
|
||||
{"NameClaimTx", Fun([String], BaseTx)},
|
||||
{"NameUpdateTx", Fun([Hash], BaseTx)},
|
||||
@ -719,24 +708,10 @@ global_env() ->
|
||||
{"gas_left", Fun([], Int)}])
|
||||
},
|
||||
|
||||
OracleScope = #scope
|
||||
{ funs = MkDefs(
|
||||
[{"register", SignFun([Address, Fee, TTL], Oracle(Q, R))},
|
||||
{"expiry", Fun([Oracle(Q, R)], Fee)},
|
||||
{"query_fee", Fun([Oracle(Q, R)], Fee)},
|
||||
{"query", StateFun([Oracle(Q, R), Q, Fee, TTL, TTL], Query(Q, R))},
|
||||
{"get_question", Fun([Oracle(Q, R), Query(Q, R)], Q)},
|
||||
{"respond", SignFun([Oracle(Q, R), Query(Q, R), R], Unit)},
|
||||
{"extend", SignFun([Oracle(Q, R), TTL], Unit)},
|
||||
{"get_answer", Fun([Oracle(Q, R), Query(Q, R)], option_t(Ann, R))},
|
||||
{"check", Fun([Oracle(Q, R)], Bool)},
|
||||
{"check_query", Fun([Oracle(Q,R), Query(Q, R)], Bool)}]) },
|
||||
|
||||
AENSScope = #scope
|
||||
{ funs = MkDefs(
|
||||
[%% AENS pointee constructors
|
||||
{"AccountPt", Fun1(Address, Pointee)},
|
||||
{"OraclePt", Fun1(Address, Pointee)},
|
||||
{"ContractPt", Fun1(Address, Pointee)},
|
||||
{"ChannelPt", Fun1(Address, Pointee)},
|
||||
%% Name object constructor
|
||||
@ -755,7 +730,6 @@ global_env() ->
|
||||
{"lookup", Fun([String], option_t(Ann, AENSNameV2))},
|
||||
%% AENS pointee constructors v2
|
||||
{"AccountPt", Fun1(Address, PointeeV2)},
|
||||
{"OraclePt", Fun1(Address, PointeeV2)},
|
||||
{"ContractPt", Fun1(Address, PointeeV2)},
|
||||
{"ChannelPt", Fun1(Address, PointeeV2)},
|
||||
{"DataPt", Fun1(Bytes(any), PointeeV2)},
|
||||
@ -881,7 +855,6 @@ global_env() ->
|
||||
AddressScope = #scope{ funs = MkDefs([{"to_str", Fun1(Address, String)},
|
||||
{"to_bytes", Fun1(Address, Bytes(32))},
|
||||
{"to_contract", FunC(address_to_contract, [Address], A)},
|
||||
{"is_oracle", Fun1(Address, Bool)},
|
||||
{"is_contract", Fun1(Address, Bool)},
|
||||
{"is_payable", Fun1(Address, Bool)}]) },
|
||||
|
||||
@ -890,7 +863,6 @@ global_env() ->
|
||||
, ["Chain"] => ChainScope
|
||||
, ["Contract"] => ContractScope
|
||||
, ["Call"] => CallScope
|
||||
, ["Oracle"] => OracleScope
|
||||
, ["AENS"] => AENSScope
|
||||
, ["AENSv2"] => AENSv2Scope
|
||||
, ["Map"] => MapScope
|
||||
@ -942,8 +914,6 @@ infer(Contracts, Options) ->
|
||||
ets_insert(type_vars_variance, {"list", [covariant]}),
|
||||
ets_insert(type_vars_variance, {"option", [covariant]}),
|
||||
ets_insert(type_vars_variance, {"map", [covariant, covariant]}),
|
||||
ets_insert(type_vars_variance, {"oracle", [contravariant, covariant]}),
|
||||
ets_insert(type_vars_variance, {"oracle_query", [covariant, covariant]}),
|
||||
|
||||
when_warning(warn_unused_functions, fun() -> create_unused_functions() end),
|
||||
check_modifiers(Env, Contracts),
|
||||
@ -1551,8 +1521,6 @@ check_event_con(Env, {constr_t, Ann, Con, Args}) ->
|
||||
%% Not so nice.
|
||||
is_word_type({id, _, Name}) ->
|
||||
lists:member(Name, ["int", "address", "hash", "bits", "bool"]);
|
||||
is_word_type({app_t, _, {id, _, Name}, [_, _]}) ->
|
||||
lists:member(Name, ["oracle", "oracle_query"]);
|
||||
is_word_type({bytes_t, _, N}) -> N =< 32;
|
||||
is_word_type({con, _, _}) -> true;
|
||||
is_word_type({qcon, _, _}) -> true;
|
||||
@ -1879,14 +1847,6 @@ is_first_order(Ts) when is_list(Ts) -> lists:all(fun is_first_order/1, Ts);
|
||||
is_first_order(Tup) when is_tuple(Tup) -> is_first_order(tuple_to_list(Tup));
|
||||
is_first_order(_) -> true.
|
||||
|
||||
ensure_monomorphic(Type, Err) ->
|
||||
is_monomorphic(Type) orelse type_error(Err).
|
||||
|
||||
is_monomorphic({tvar, _, _}) -> false;
|
||||
is_monomorphic(Ts) when is_list(Ts) -> lists:all(fun is_monomorphic/1, Ts);
|
||||
is_monomorphic(Tup) when is_tuple(Tup) -> is_monomorphic(tuple_to_list(Tup));
|
||||
is_monomorphic(_) -> true.
|
||||
|
||||
check_state_init(Env) ->
|
||||
Top = Env#env.namespace,
|
||||
StateType = lookup_type(Env, {id, [{origin, system}], "state"}),
|
||||
@ -1958,14 +1918,6 @@ infer_expr(_Env, Body={account_pubkey, As, _}) ->
|
||||
{typed, As, Body, {id, As, "address"}};
|
||||
infer_expr(_Env, Body={signature, As, Bin}) when byte_size(Bin) == 64 ->
|
||||
{typed, As, Body, {bytes_t, As, 64}};
|
||||
infer_expr(_Env, Body={oracle_pubkey, As, _}) ->
|
||||
Q = fresh_uvar(As),
|
||||
R = fresh_uvar(As),
|
||||
{typed, As, Body, {app_t, As, {id, As, "oracle"}, [Q, R]}};
|
||||
infer_expr(_Env, Body={oracle_query_id, As, _}) ->
|
||||
Q = fresh_uvar(As),
|
||||
R = fresh_uvar(As),
|
||||
{typed, As, Body, {app_t, As, {id, As, "oracle_query"}, [Q, R]}};
|
||||
infer_expr(_Env, Body={contract_pubkey, As, _}) ->
|
||||
Con = fresh_uvar(As),
|
||||
add_constraint([#is_contract_constraint{ contract_t = Con,
|
||||
@ -2067,9 +2019,6 @@ infer_expr(Env, {app, Ann, Fun, Args0} = App) ->
|
||||
when_warning(warn_negative_spend, fun() -> warn_potential_negative_spend(Ann, NewFun1, NewArgs) end),
|
||||
[ add_constraint({aens_resolve_type, GeneralResultType})
|
||||
|| element(3, FunName) =:= ["AENSv2", "resolve"] ],
|
||||
[ add_constraint({oracle_type, Ann, OType})
|
||||
|| OType <- [get_oracle_type(FunName, ArgTypes, GeneralResultType)],
|
||||
OType =/= false ],
|
||||
add_constraint(
|
||||
#dependent_type_constraint{ named_args_t = NamedArgsVar,
|
||||
named_args = NamedArgs1,
|
||||
@ -2198,10 +2147,6 @@ check_valid_const_expr({account_pubkey, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({signature, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({oracle_pubkey, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({oracle_query_id, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({contract_pubkey, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({id, _, "_"}) ->
|
||||
@ -2775,14 +2720,10 @@ destroy_and_report_unsolved_constraints(Env) ->
|
||||
({add_bytes, _, _, _, _, _}) -> true;
|
||||
(_) -> false
|
||||
end, OtherCs3),
|
||||
{AensResolveCs, OtherCs5} =
|
||||
{AensResolveCs, _OtherCs5} =
|
||||
lists:partition(fun({aens_resolve_type, _}) -> true;
|
||||
(_) -> false
|
||||
end, OtherCs4),
|
||||
{OracleTypeCs, []} =
|
||||
lists:partition(fun({oracle_type, _, _}) -> true;
|
||||
(_) -> false
|
||||
end, OtherCs5),
|
||||
|
||||
check_field_constraints(Env, FieldCs),
|
||||
check_record_create_constraints(Env, CreateCs),
|
||||
@ -2790,19 +2731,9 @@ destroy_and_report_unsolved_constraints(Env) ->
|
||||
check_named_args_constraints(Env, NamedArgCs),
|
||||
check_bytes_constraints(Env, BytesCs),
|
||||
check_aens_resolve_constraints(Env, AensResolveCs),
|
||||
check_oracle_type_constraints(Env, OracleTypeCs),
|
||||
|
||||
destroy_constraints().
|
||||
|
||||
get_oracle_type({qid, _, ["Oracle", "register"]}, _ , OType) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "query"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "get_question"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "get_answer"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "check"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "check_query"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type({qid, _, ["Oracle", "respond"]}, [OType| _], _ ) -> OType;
|
||||
get_oracle_type(_Fun, _Args, _Ret) -> false.
|
||||
|
||||
%% -- Named argument constraints --
|
||||
|
||||
%% True if solved (unified or type error), false otherwise
|
||||
@ -2914,23 +2845,10 @@ check_aens_resolve_constraints(Env, [{aens_resolve_type, Type} | Rest]) ->
|
||||
{id, _, "string"} -> ok;
|
||||
{id, _, "address"} -> ok;
|
||||
{con, _, _} -> ok;
|
||||
{app_t, _, {id, _, "oracle"}, [_, _]} -> ok;
|
||||
{app_t, _, {id, _, "oracle_query"}, [_, _]} -> ok;
|
||||
_ -> type_error({invalid_aens_resolve_type, so_syntax:get_ann(Type), Type2})
|
||||
end,
|
||||
check_aens_resolve_constraints(Env, Rest).
|
||||
|
||||
check_oracle_type_constraints(_Env, []) ->
|
||||
ok;
|
||||
check_oracle_type_constraints(Env, [{oracle_type, Ann, OType} | Rest]) ->
|
||||
Type = unfold_types_in_type(Env, instantiate(OType)),
|
||||
{app_t, _, {id, _, "oracle"}, [QType, RType]} = Type,
|
||||
ensure_monomorphic(QType, {invalid_oracle_type, polymorphic, query, Ann, Type}),
|
||||
ensure_monomorphic(RType, {invalid_oracle_type, polymorphic, response, Ann, Type}),
|
||||
ensure_first_order(QType, {invalid_oracle_type, higher_order, query, Ann, Type}),
|
||||
ensure_first_order(RType, {invalid_oracle_type, higher_order, response, Ann, Type}),
|
||||
check_oracle_type_constraints(Env, Rest).
|
||||
|
||||
%% -- Field constraints --
|
||||
|
||||
check_record_create_constraints(_, []) -> ok;
|
||||
@ -4023,15 +3941,9 @@ mk_error({higher_order_entrypoint, Ann, {id, _, Name}, Thing}) ->
|
||||
mk_error({invalid_aens_resolve_type, Ann, T}) ->
|
||||
Msg = io_lib:format("Invalid return type of `AENSv2.resolve`:\n"
|
||||
"~s`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)",
|
||||
"It must be a `string` or a pubkey type (`address`, etc)",
|
||||
[pp_type(" `", T)]),
|
||||
mk_t_err(pos(Ann), Msg);
|
||||
mk_error({invalid_oracle_type, Why, What, Ann, Type}) ->
|
||||
WhyS = case Why of higher_order -> "higher-order (contain function types)";
|
||||
polymorphic -> "polymorphic (contain type variables)" end,
|
||||
Msg = io_lib:format("Invalid oracle type\n~s`", [pp_type(" `", Type)]),
|
||||
Cxt = io_lib:format("The ~s type must not be ~s", [What, WhyS]),
|
||||
mk_t_err(pos(Ann), Msg, Cxt);
|
||||
mk_error({interface_implementation_conflict, Contract, I1, I2, Fun}) ->
|
||||
Msg = io_lib:format("Both interfaces `~s` and `~s` implemented by "
|
||||
"the contract `~s` have a function called `~s`",
|
||||
|
@ -1,13 +1,13 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Ulf Norell
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Compiler from Sophia language to Fate intermediate code.
|
||||
%%% Compiler from Aeterinty Sophia language to Fate intermediate code.
|
||||
%%% @end
|
||||
%%% Created : 26 Mar 2019
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_ast_to_fcode).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([ast_to_fcode/2, format_fexpr/1]).
|
||||
-export_type([fcode/0, fexpr/0, fun_def/0]).
|
||||
@ -53,6 +53,8 @@
|
||||
| {bytes, binary()}
|
||||
| {account_pubkey, binary()}
|
||||
| {contract_pubkey, binary()}
|
||||
| {oracle_pubkey, binary()}
|
||||
| {oracle_query_id, binary()}
|
||||
| {signature, binary()}
|
||||
| {bool, false | true}
|
||||
| {contract_code, string()} %% for CREATE, by name
|
||||
@ -113,6 +115,8 @@
|
||||
| address
|
||||
| {bytes, non_neg_integer()}
|
||||
| contract
|
||||
| {oracle, ftype(), ftype()} %% Query type, Response type
|
||||
| oracle_query
|
||||
| name
|
||||
| channel
|
||||
| bits
|
||||
@ -301,7 +305,7 @@ builtins() ->
|
||||
{"to_any_size", 1}, {"size", 1}, {"split_any", 2}]},
|
||||
{["Int"], [{"to_str", 1}, {"to_bytes", 2}, {"mulmod", 2}]},
|
||||
{["Address"], [{"to_str", 1}, {"to_bytes", 1}, {"to_contract", 1},
|
||||
{"is_contract", 1}, {"is_payable", 1}]}
|
||||
{"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||
],
|
||||
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
||||
|| {NS, Funs} <- Scopes,
|
||||
@ -329,6 +333,8 @@ init_type_env() ->
|
||||
["address"] => ?type(address),
|
||||
["hash"] => ?type(hash),
|
||||
["signature"] => ?type(signature),
|
||||
["oracle"] => ?type(Q, R, {oracle, Q, R}),
|
||||
["oracle_query"] => ?type(_, _, oracle_query), %% TODO: not in Fate
|
||||
["list"] => ?type(T, {list, T}),
|
||||
["map"] => ?type(K, V, {map, K, V}),
|
||||
["option"] => ?type(T, {variant, [[], [T]]}),
|
||||
@ -596,12 +602,25 @@ expr_to_fcode(_Env, _Type, {string, Ann, S}) -> {lit, to_fann(Ann), {st
|
||||
expr_to_fcode(_Env, _Type, {account_pubkey, Ann, K}) -> {lit, to_fann(Ann), {account_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {signature, Ann, K}) -> {lit, to_fann(Ann), {signature, K}};
|
||||
expr_to_fcode(_Env, _Type, {contract_pubkey, Ann, K}) -> {lit, to_fann(Ann), {contract_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {oracle_pubkey, Ann, K}) -> {lit, to_fann(Ann), {oracle_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {oracle_query_id, Ann, K}) -> {lit, to_fann(Ann), {oracle_query_id, K}};
|
||||
expr_to_fcode(_Env, _Type, {bytes, Ann, B}) -> {lit, to_fann(Ann), {bytes, B}};
|
||||
|
||||
%% Variables
|
||||
expr_to_fcode(Env, _Type, {id, Ann, X}) -> resolve_var(Env, Ann, [X]);
|
||||
expr_to_fcode(Env, Type, {qid, Ann, X}) ->
|
||||
case resolve_var(Env, Ann, X) of
|
||||
{builtin_u, FAnn, B, Ar} when B =:= oracle_query;
|
||||
B =:= oracle_get_question;
|
||||
B =:= oracle_get_answer;
|
||||
B =:= oracle_respond;
|
||||
B =:= oracle_register;
|
||||
B =:= oracle_check;
|
||||
B =:= oracle_check_query ->
|
||||
OType = get_oracle_type(B, Type),
|
||||
{oracle, QType, RType} = type_to_fcode(Env, OType),
|
||||
TypeArgs = [{lit, FAnn, {typerep, QType}}, {lit, FAnn, {typerep, RType}}],
|
||||
{builtin_u, FAnn, B, Ar, TypeArgs};
|
||||
{builtin_u, FAnn, B = aens_resolve, Ar} ->
|
||||
{fun_t, _, _, _, ResType} = Type,
|
||||
AensType = type_to_fcode(Env, ResType),
|
||||
@ -865,6 +884,17 @@ make_tuple_fpat(Ps) -> {tuple, Ps}.
|
||||
strip_singleton_tuples({tuple, _, [T]}) -> strip_singleton_tuples(T);
|
||||
strip_singleton_tuples(T) -> T.
|
||||
|
||||
-spec get_oracle_type(OracleFun, FunT) -> OracleType when
|
||||
OracleFun :: atom(),
|
||||
FunT :: so_syntax:type(),
|
||||
OracleType :: so_syntax:type().
|
||||
get_oracle_type(oracle_register, {fun_t, _, _, _, OType}) -> OType;
|
||||
get_oracle_type(oracle_query, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_get_question, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_get_answer, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_check, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_check_query, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_respond, {fun_t, _, _, [OType | _], _}) -> OType.
|
||||
|
||||
%% -- Pattern matching --
|
||||
|
||||
@ -2421,6 +2451,7 @@ pp_ftype(T) when is_atom(T) -> pp_text(T);
|
||||
pp_ftype(any) -> pp_text("_");
|
||||
pp_ftype({tvar, X}) -> pp_text(X);
|
||||
pp_ftype({bytes, N}) -> pp_call(pp_text("bytes"), [{lit, [], {int, N}}]);
|
||||
pp_ftype({oracle, Q, R}) -> pp_call_t("oracle", [Q, R]);
|
||||
pp_ftype({tuple, Ts}) ->
|
||||
pp_parens(pp_par(pp_punctuate(pp_text(" *"), [pp_ftype(T) || T <- Ts])));
|
||||
pp_ftype({list, T}) ->
|
||||
|
@ -1,13 +1,12 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Happi (Erik Stenman)
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Compiler from Sophia language to FATE.
|
||||
%%% Compiler from Aeterinty Sophia language to FATE.
|
||||
%%% @end
|
||||
%%% Created : 12 Dec 2017
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_compiler).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([ file/1
|
||||
, file/2
|
||||
|
@ -1,5 +1,4 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc ADT for structured error messages + formatting.
|
||||
%%%
|
||||
@ -7,7 +6,6 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(so_errors).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-type src_file() :: no_file | iolist().
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Ulf Norell
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Fate backend for Sophia compiler
|
||||
%%% @end
|
||||
%%% Created : 11 Jan 2019
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_fcode_to_fate).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
|
||||
|
||||
@ -140,6 +140,8 @@ type_to_scode(string) -> string;
|
||||
type_to_scode(address) -> address;
|
||||
type_to_scode({bytes, N}) -> {bytes, N};
|
||||
type_to_scode(contract) -> contract;
|
||||
type_to_scode({oracle, _, _}) -> oracle;
|
||||
type_to_scode(oracle_query) -> oracle_query;
|
||||
type_to_scode(name) -> name;
|
||||
type_to_scode(channel) -> channel;
|
||||
type_to_scode(bits) -> bits;
|
||||
@ -235,6 +237,8 @@ lit_to_fate(Env, L) ->
|
||||
{account_pubkey, K} -> gmb_fate_data:make_address(K);
|
||||
{signature, S} -> gmb_fate_data:make_bytes(S);
|
||||
{contract_pubkey, K} -> gmb_fate_data:make_contract(K);
|
||||
{oracle_pubkey, K} -> gmb_fate_data:make_oracle(K);
|
||||
{oracle_query_id, H} -> gmb_fate_data:make_oracle_query(H);
|
||||
{contract_code, C} -> gmb_fate_data:make_contract_bytearray(serialize_contract_code(Env, C));
|
||||
{typerep, T} -> gmb_fate_data:make_typerep(type_to_scode(T))
|
||||
end.
|
||||
|
@ -1,6 +1,5 @@
|
||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||
%%% @doc Parser combinators for the Sophia parser. Based on
|
||||
%%% Koen Claessen. 2004. Parallel Parsing Processes. J. Functional
|
||||
@ -8,7 +7,6 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_parse_lib).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([parse/2,
|
||||
return/1, fail/0, fail/1, fail/2, map/2, bind/2,
|
||||
|
@ -3,7 +3,6 @@
|
||||
%%% Description :
|
||||
%%% Created : 1 Mar 2018 by Ulf Norell
|
||||
-module(so_parser).
|
||||
-vsn("9.0.0").
|
||||
-compile({no_auto_import,[map_get/2]}).
|
||||
|
||||
-export([string/1,
|
||||
|
@ -1,13 +1,11 @@
|
||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc Pretty printer for Sophia.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_pretty).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]).
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc The Sophia lexer.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_scan).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([scan/1, utf8_encode/1]).
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc A customisable lexer.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_scan_lib).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([compile/1, string/3,
|
||||
token/1, token/2, symbol/0, skip/0,
|
||||
|
@ -1,18 +1,17 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Radosław Rowicki
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Standard library for Sophia
|
||||
%%% @end
|
||||
%%% Created : 6 July 2019
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(so_stdlib).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([stdlib_include_path/0]).
|
||||
|
||||
stdlib_include_path() ->
|
||||
{file, BEAM} = code:is_loaded(?MODULE),
|
||||
filename:join(filename:dirname(filename:dirname(BEAM)), "priv/stdlib").
|
||||
filename:join([code:priv_dir(sophia), "stdlib"]).
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc Sophia abstract syntax types.
|
||||
%%%
|
||||
@ -8,7 +7,6 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(so_syntax).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]).
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Sophia syntax utilities.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_syntax_utils).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([used_ids/1, used_ids/2, used_types/2, used/1]).
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Sophia utility functions.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(so_utils).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([scc/1, canonical_dir/1]).
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2025, QPQ AG
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc Decoding fate data to AST
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(so_vm_decode).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-export([ from_fate/2 ]).
|
||||
|
||||
@ -17,6 +15,8 @@ from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin};
|
||||
from_fate({id, _, "signature"}, ?FATE_BYTES(Bin)) -> {signature, [], Bin};
|
||||
from_fate({id, _, "hash"}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin};
|
||||
from_fate({id, _, "unit"}, ?FATE_UNIT) -> {tuple, [], []};
|
||||
from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin};
|
||||
from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin};
|
||||
from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin};
|
||||
from_fate({bytes_t, _, any}, ?FATE_BYTES(Bin)) -> make_any_bytes(Bin);
|
||||
from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin};
|
||||
|
@ -1,5 +1,4 @@
|
||||
-module(so_warnings).
|
||||
-vsn("9.0.0").
|
||||
|
||||
-record(warn, { pos :: so_errors:pos()
|
||||
, message :: iolist()
|
||||
|
@ -1,6 +1,6 @@
|
||||
{application, sophia,
|
||||
[{description, "Compiler for Sophia language"},
|
||||
{vsn, "9.0.0"},
|
||||
[{description, "Compiler for the Sophia language"},
|
||||
{vsn, "8.0.1"},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
|
@ -2,6 +2,7 @@ contract interface Remote =
|
||||
entrypoint main_fun : (int) => unit
|
||||
|
||||
contract AddrChain =
|
||||
|
||||
entrypoint is_c(a : address) =
|
||||
Address.is_contract(a)
|
||||
|
||||
|
@ -8,14 +8,13 @@ contract interface OldAENSContract =
|
||||
main contract AENSUpdate =
|
||||
stateful entrypoint update_name(owner : address, name : string, b : bytes(2)) =
|
||||
let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller)
|
||||
let p2 : AENSv2.pointee = AENSv2.OraclePt(Call.caller)
|
||||
let p3 : AENSv2.pointee = AENSv2.ContractPt(Call.caller)
|
||||
let p4 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller)
|
||||
let p5 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do"))
|
||||
let p6 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4))
|
||||
let p2 : AENSv2.pointee = AENSv2.ContractPt(Call.caller)
|
||||
let p3 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller)
|
||||
let p4 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do"))
|
||||
let p5 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4))
|
||||
AENSv2.update(owner, name, None, None,
|
||||
Some({ ["account_pubkey"] = p1,
|
||||
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5, ["data2"] = p6 }))
|
||||
["contract_pubkey"] = p2, ["misc"] = p3, ["data"] = p4, ["data2"] = p5 }))
|
||||
|
||||
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
|
||||
let p : AENS.pointee = c.lookup(name, "key1")
|
||||
|
@ -9,7 +9,6 @@
|
||||
// datatype ga_meta_tx = GAMetaTx(address, int)
|
||||
// datatype paying_for_tx = PayingForTx(address, int)
|
||||
// datatype base_tx = SpendTx(address, int, string)
|
||||
// | OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
|
||||
// | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
|
||||
// | NameRevokeTx(hash) | NameTransferTx(address, string)
|
||||
// | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
|
||||
@ -42,10 +41,6 @@ contract BasicAuthTx =
|
||||
fee = 123, ttl = 0, actor = Call.caller }
|
||||
switch(tx0.tx)
|
||||
Chain.SpendTx(receiver, amount, payload) => verify(tx_hash, n, s)
|
||||
Chain.OracleRegisterTx => false
|
||||
Chain.OracleQueryTx => false
|
||||
Chain.OracleResponseTx => false
|
||||
Chain.OracleExtendTx => false
|
||||
Chain.NamePreclaimTx => false
|
||||
Chain.NameClaimTx(name) => false
|
||||
Chain.NameUpdateTx(name) => false
|
||||
|
5
test/contracts/higher_order_query_type.aes
Normal file
5
test/contracts/higher_order_query_type.aes
Normal file
@ -0,0 +1,5 @@
|
||||
contract HigherOrderQueryType =
|
||||
stateful function foo(o) : oracle_query(_, string ) =
|
||||
Oracle.query(o, (x) => x + 1, 100, RelativeTTL(100), RelativeTTL(100))
|
||||
|
||||
entrypoint main_fun() = ()
|
@ -1,5 +1,5 @@
|
||||
// This is a custom test file if you need to run a compiler without
|
||||
// changing so_compiler_tests.erl
|
||||
// changing aeso_compiler_tests.erl
|
||||
|
||||
include "List.aes"
|
||||
|
||||
|
@ -28,11 +28,11 @@ contract C =
|
||||
let c16 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
let c17 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
let c18 = RelativeTTL(50)
|
||||
let c21 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C
|
||||
let c22 = N.nsconst
|
||||
let c23 = c01
|
||||
let c24 = c11.name
|
||||
let c25 : int = 1
|
||||
let c19 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C
|
||||
let c20 = N.nsconst
|
||||
let c21 = c01
|
||||
let c22 = c11.name
|
||||
let c23 : int = 1
|
||||
|
||||
entrypoint f01() = c01
|
||||
entrypoint f02() = c02
|
||||
@ -52,9 +52,9 @@ contract C =
|
||||
entrypoint f16() = c16
|
||||
entrypoint f17() = c17
|
||||
entrypoint f18() = c18
|
||||
entrypoint f19() = c19
|
||||
entrypoint f20() = c20
|
||||
entrypoint f21() = c21
|
||||
entrypoint f22() = c22
|
||||
entrypoint f23() = c23
|
||||
entrypoint f24() = c24
|
||||
entrypoint f25() = c25
|
||||
entrypoint fqual() = C.c01
|
||||
|
@ -97,7 +97,6 @@ compilable_contracts() ->
|
||||
{"funargs", "singleton_rec", ["{x = 1000}"]},
|
||||
{"funargs", "aens_name", ["AENS.Name(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, RelativeTTL(100), {[\"pt1\"] = AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)})"]},
|
||||
{"funargs", "aens_pointee", ["AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
|
||||
{"funargs", "aens_pointee", ["AENS.OraclePt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
|
||||
{"funargs", "aens_pointee", ["AENS.ContractPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
|
||||
{"funargs", "aens_pointee", ["AENS.ChannelPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
|
||||
{"funargs", "chain_ga_meta_tx", ["Chain.GAMetaTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42)"]},
|
||||
@ -105,10 +104,6 @@ compilable_contracts() ->
|
||||
{"funargs", "chain_base_tx", ["Chain.SpendTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42,\"foo\")"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.ContractCreateTx(12234)"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.ContractCallTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 12234)"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.OracleRegisterTx"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.OracleQueryTx"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.OracleResponseTx"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.OracleExtendTx"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.NamePreclaimTx"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.NameClaimTx(\"acoolname.chain\")"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.NameUpdateTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
|
||||
|
@ -464,7 +464,8 @@ failing_contracts() ->
|
||||
[<<?Pos(2, 12)
|
||||
"Nested contracts are not allowed. Contract `Con` is not defined at top level.">>])
|
||||
, ?TYPE_ERROR(bad_address_literals,
|
||||
[<<?Pos(9, 5)
|
||||
[
|
||||
<<?Pos(9, 5)
|
||||
"Cannot unify `address` and `Remote`\n"
|
||||
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
|
||||
"against the expected type `Remote`">>,
|
||||
@ -1051,19 +1052,19 @@ failing_contracts() ->
|
||||
[<<?Pos(4,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `'a`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
"It must be a `string` or a pubkey type (`address`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(bad_aens_resolve,
|
||||
[<<?Pos(6,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `list(int)`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
"It must be a `string` or a pubkey type (`address`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(bad_aens_resolve_using,
|
||||
[<<?Pos(7,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `list(int)`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
"It must be a `string` or a pubkey type (`address`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(var_args_unify_let,
|
||||
[<<?Pos(3,9)
|
||||
|
20
zomp.meta
20
zomp.meta
@ -1,20 +0,0 @@
|
||||
{name,"Sophia Compiler"}.
|
||||
{type,lib}.
|
||||
{modules,[]}.
|
||||
{prefix,none}.
|
||||
{desc,"The Sophia smart contract language for the FATE VM"}.
|
||||
{author,"QPQ AG"}.
|
||||
{package_id,{"otpr","sophia",{9,0,0}}}.
|
||||
{deps,[{"otpr","gmbytecode",{3,4,1}},
|
||||
{"otpr","getopt",{1,0,2}},
|
||||
{"otpr","eblake2",{1,0,0}},
|
||||
{"otpr","zj",{1,1,0}}]}.
|
||||
{key_name,none}.
|
||||
{a_email,[]}.
|
||||
{c_email,[]}.
|
||||
{copyright,"(c) 2024 QPQ AG"}.
|
||||
{file_exts,[]}.
|
||||
{license,skip}.
|
||||
{repo_url,"https://git.qpq.swiss/QPQ-AG/sophia"}.
|
||||
{tags,["gaju","gajumaru","blockchain","sophia","crypto","compiler","puck"]}.
|
||||
{ws_url,[]}.
|
19
zomp_prep
19
zomp_prep
@ -1,19 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
# This is a small pre-packaging source generation and include correction script that should be
|
||||
# run before packaging this project for use with ZX/Zomp.
|
||||
|
||||
rm -rf _build
|
||||
cd src
|
||||
for f in $(ls *.erl)
|
||||
do
|
||||
echo "Updating includes in: $f"
|
||||
sed -i 's/gmbytecode\/include\///g' "$f"
|
||||
sed -i 's/\.\.\/include\///g' "$f"
|
||||
sed -i 's/include_lib/include/g' "$f"
|
||||
done
|
||||
sed -i 's/gmb_opcodes\.hrl/\$gmbytecode_include\/gmb_opcodes\.hrl/' so_compiler.erl
|
||||
sed -i 's/gmb_fate_data\.hrl/\$gmbytecode_include\/gmb_fate_data\.hrl/' so_vm_decode.erl
|
||||
cd ..
|
||||
rm -f ebin/*.beam
|
||||
rm -f rebar*
|
Loading…
x
Reference in New Issue
Block a user