# Quick Start

Obyte is cryptocurrency platform, which is written with NodeJS. This site is for developers and should help developers to get started using Obyte platform in their projects.

To begin developing any app which is based on headless-obyte, first thing to do is to set up your machine, install Node.js and tools. [Complete guide of preparing your blank Debian-based machine for Obyte development](/tutorials-for-newcomers/setting-up-headless-wallet). You can skip this step if you are familiar with Node.js development and already know how to do it in your way.

Create a new node.js package for your chatbot: `npm init`. You will definitely need modules from `ocore` and if you are going to send payments, you will also need `headless-obyte`. Your `package.json` should list these dependencies:

{% code title="package.json" %}

```javascript
"dependencies": {
    "headless-obyte": "git+https://github.com/byteball/headless-obyte.git",
    "ocore": "git+https://github.com/byteball/ocore.git"
}
```

{% endcode %}

Now run `npm install` to fetch dependencies.

Full configuration options are described in [Configuration](/configuration) section. As for now, in your configuration file (conf.js in project folder or conf.json in user folder) switch your app to light node and add hub URL:

{% code title="conf.js" %}

```javascript
exports.bLight = true;
exports.hub = process.env.testnet ? 'obyte.org/bb-test' : 'obyte.org/bb';
```

{% endcode %}

If you want to connect to testnet network instead of spamming mainnet for development then you can do that by adding `.env` file, which should contain just one line:

```
testnet=1
```

## Sending / receiving txs:

{% code title="index.js" %}

```javascript
var headlessWallet = require('headless-obyte');
var eventBus = require('ocore/event_bus.js');

function onReady() {
    let amount = 1; //in bytes
    let user_address = "62SU7724ME5MWB7VEP64VURYZHDRSDWN"; // account address
    let user_device_address = null; // device address
    headlessWallet.issueChangeAddressAndSendPayment(
        null /*asset, null for bytes*/,
        amount,
        user_address,
        user_device_address,
    (err, unit) => {
        if (err){
            return console.error(err);
        }
        // handle successful payment
    });

    // received new payment
    eventBus.on('new_my_transactions', (arrUnits) => {
        // handle new unconfirmed units here
        // at this stage, payment is not yet confirmed
    });

    // payment is confirmed
    eventBus.on('my_transactions_became_stable', (arrUnits) => {
        // handle payments becoming confirmed
    });
};
eventBus.once('headless_wallet_ready', onReady);
```

{% endcode %}

Go ahead and run the code: `node index.js`. You'll see initialization lines printed by ocore in console, which contain your wallet first address printed and an error saying that `There are no funded addresses`. This is our failed attempt to `issueChangeAddressAndSendPayment()`, as you don't have any bytes in your wallet yet.

We wrapped all of our code in 'headless\_wallet\_ready' event handler, at this point the private keys of your wallet are decrypted and are ready for use.

Find out in console output your first address.

```
====== my first address: 2PJHQKMP7NH6MUYUQPZ4S46C2Q7CQI32
```

You can deposit some bytes on it to be able to make outbound transactions. Right after ocore is done with initialization (`onReady function`), we send one byte to some address. First argument is an `asset`, its the asset you are paying in (`null` for bytes), `amount` is payment amount in the smallest units. If the payment was successful, you get its `unit` in the callback and can save it or watch further events on this unit.

There are many other functions for sending payments, for example sending multiple payments in multiple assets at the same time, see `exports` of <https://github.com/byteball/headless-obyte/blob/master/start.js>.

The `new_my_transactions` and `my_transactions_became_stable` event handlers are to be invoked after any new transaction received to any of your wallet addresses and when this transactions become stable, respectively. `arrUnits` is an array of units (more accurately, unit hashes) that contained any transaction involving your addresses. The event `new_my_transactions` is triggered for outgoing transactions too, you should check if the new transaction credits one of the addresses you are expecting payments to.

The above events work in both full and light nodes. If your node is full, you can alternatively subscribe to event `mci_became_stable` which is emitted each time a new main chain index (MCI) becomes stable:

{% code title="index.js" %}

```javascript
eventBus.on('mci_became_stable', function(mci){
    // check if there are any units you are interested in 
    // that had this MCI and react to their becoming stable
});
```

{% endcode %}

## Simple chat bot

Every Obyte wallet can be paired with any other Obyte wallet, because every wallet has it's unique pairing code. Headless wallet will print it's pairing code to console right after the launch. Depending on what kind of app you want to build, you will or will not need this pairing code. Simplest operations on Obyte platform require no chat bot (like sending/receiving txs, for example).

For more handy interaction with your userbase, you mostly surely need to write a chat bot, to set up direct interaction between your clients Obyte apps and your wallet (this process is called 'pairing'). Chat bot is Obyte wallet which can receive chat messages and react to them. Clients can pair and chat with your chat bot inside their Obyte wallet app, your task is to handle incoming messages and act accordingly. Through chat, users can provide to your chat bot their addresses, KYC profiles, or any other information with couple of clicks.

You can use `bot-example` repository as a starting point for your chat bot. You can also use the module from previous step, but it will require you to add some more config lines, so its better to `git clone git@github.com:byteball/bot-example.git`, remove .git folder `rm -fr bot-example/.git` and tweak some default configs there (remember to give a name to your bot, switch to light node, set up a pairing secret, etc.)

When you start your node, it will print its full pairing code:

```
====== my pairing code: A2WMb6JEIrMhxVk+I0gIIW1vmM3ToKoLkNF8TqUV5UvX@obyte.org/bb#0000
```

The pairing code consists of your node's public key (device public key), hub address, and pairing secret (after #).

Publish this pairing code anywhere as a link with `byteball:` scheme, users will be able to open a chat with your bot by clicking your link (the link opens in their Obyte app and starts a chat):

```markup
<a href="byteball:A2WMb6JEIrMhxVk+I0gIIW1vmM3ToKoLkNF8TqUV5UvX@obyte.org/bb#0000">Chat with my test bot</a>
```

You also need this pairing code to add your bot to the [Bot Store](https://medium.com/byteball/byteball-bot-store-has-launched-c546e9e38ab5).

When a user pairs his device with your bot (e.g. by clicking the link to your bot), you receive a pairing notification and can welcome the user:

{% code title="index.js" %}

```javascript
eventBus.on('paired', function(from_address, pairing_secret){
    var device = require('ocore/device.js');
    device.sendMessageToDevice(from_address, 'text', 'Hi! I am bot.');
});
```

{% endcode %}

The behavior of your event handler can depend on `pairing_secret`, the second argument of the event handler. For example, you can have a one-time (non-permanent) pairing secret equal to session ID on your website; after the user clicks the pairing link and opens chat, you can link his chat session with his web session, see [Authenticating users on websites](/tutorials-for-newcomers/log-in-on-website-with-byteball).

### Receiving chat messages

To receive chat messages, subscribe to 'text' events on event bus:

{% code title="index.js" %}

```javascript
eventBus.on('text', function(from_address, user_message){
    // your code here
});
```

{% endcode %}

`from_address` is user's device address (not to be confused with payment addresses), `user_message` is their message.

### Sending chat messages

Messages to user's device can be sent with `sendMessageToDevice` function in `device` module:

{% code title="index.js" %}

```javascript
var device = require('ocore/device.js');
var message_to_user = 'Message from bot to user';
device.sendMessageToDevice(from_address, 'text', message_to_user);
```

{% endcode %}

So, in case we want to echo back what user wrote, we could combine those two above examples into this:

{% code title="index.js" %}

```javascript
var eventBus = require('ocore/event_bus.js');
var device = require('ocore/device.js');

eventBus.on('text', function(from_address, user_message){
    device.sendMessageToDevice(from_address, 'text', user_message);
});
```

{% endcode %}

Great success, we now have a bot, which is like a parrot (repeating everything you wrote to it).

### Predefined chat commands

To give access to predefined commands, format your responses this way:

```
click this link: [Command name](command:command code)
```

The user will see the text in square brackets "Command name", it will be highlighted as a link, and when the user clicks it, his app will send `command code` text to your bot. ![](/files/-LgUzMyU8ojMVrbXZoln)

### Command suggestion

Sometimes you might want to suggest the command without actually sending it immediately, so user could have the possibility to edit the command before sending, this could be done like this:

```
Example command: we suggest to [buy (number) apples](suggest-command:buy 5 apples)
```

Here is how the result looks like:\
![](/files/-LgUzMyW0g1KydTHmcdU)

## Next step

That's it. You've completed your first chat bot on Obyte platform. You can check other chat bot examples provided by our team:

* [Bot example](https://github.com/byteball/bot-example): start from here
* [Faucet](https://github.com/byteball/obyte-faucet): sending payments
* [ICO bot](https://github.com/byteball/ico-bot): sending and receiving payments
* [Merchant](https://github.com/byteball/obyte-merchant): receiving payments without storage of private keys
* [Flight delay insurance](https://github.com/byteball/flight-delays-insurance): offering contracts
* [Internal asset exchange](https://github.com/byteball/obyte-exchange): offering contracts
* [GUI wallet](https://github.com/byteball/obyte-gui-wallet): not a bot, but you'll find code for offering contracts

Now you are ready to make something useful, go ahead to our Tutorials section and carefully read all of them to get better understanding of Obyte code API. [Tutorials for newcomers](/tutorials-for-newcomers).


# Configuration

These settings are applicable to most Obyte nodes projects that have 'headless-obyte' or 'ocore' library as dependency.

The default settings are in the core library's `conf.js` file, they can be overridden in your project root's `conf.js` and then in `conf.json` in the app data folder. The app data folder is:

* macOS: `~/Library/Application Support/<appname>`
* Linux: `~/.config/<appname>`
* Windows: `%LOCALAPPDATA%\<appname>`

`<appname>` is `name` in your `package.json`, e.g. `headless-obyte`.

## Database location

At some point you'll surely want to have a peek into the database, or even make a modification in it. Default SQLite database file and RocksDB folder are located near the config file, you can find the correct paths for each platform above.

## Testnet network

Most bot repositories have example `.env.testnet` file in their root folder. In order to connect use testnet network, just run `cp .env.testnet .env`. Backup and delete the database if you already ran it on MAINNET. Wallet app for [TESTNET can be downloaded from Obyte.org](https://obyte.org/testnet.html) website.

If you don't have `.env.testnet` example file then just create a `.env` file that contains this row:

```
testnet=1
```

## Settings

This is the list of some of the settings that the library understands (your app can add more settings that only your app understands):

### conf.port

The port to listen on. If you don't want to accept incoming connections at all, set port to `null`, which is the default. If you do want to listen, you will usually have a proxy, such as nginx, accept websocket connections on standard port 443 and forward them to your Obyte daemon that listens on port 6611 on the local interface.

### conf.storage

Storage backend -- mysql or sqlite, the default is sqlite. If sqlite, the database files are stored in the app data folder. If mysql, you need to also initialize the database with [initial .sql file](https://github.com/byteball/ocore/tree/master/initial-db) and set connection params:

{% code title="conf.json" %}

```javascript
{
    "storage": "mysql",
    "database": {
        "host"     : "localhost",
        "user"     : "DATABASE_USER",
        "password" : "DATABASE_PASSWORD",
        "name"     : "DATABASE_NAME"
    }
}
```

{% endcode %}

#### MySQL conf for faster syncing

To lower disk load and increase sync speed, you can optionally disable flushing to disk every transaction, instead doing it once a second. This can be done by setting `innodb_flush_log_at_trx_commit=0` in your MySQL server config file (my.ini)

### conf.bLight

Work as light node (`true`) or full node (`false`). The default is full client. Light node only holds data that is relevant to your wallet, full node sync all the data in public database. Benefit of light node is that you can start using it immediately, but the downside is that you might not get updates about new transactions and confirmations as fast as full node does.

### conf.bServeAsHub

Whether to serve as hub on the Obyte network (store and forward e2e-encrypted messages for devices that connect to your hub). The default is `false`.

### conf.myUrl

If your node accepts incoming connections, this is its URL. The node will share this URL with all its outgoing peers so that they can reconnect in any direction in the future. By default the node doesn't share its URL even if it accepts connections.

### conf.bWantNewPeers

Whether your node wants to learn about new peers from its current peers (`true`, the default) or not (`false`). Set it to `false` to run your node in stealth mode so that only trusted peers can see its IP address (e.g. if you have online wallets on your server and don't want potential attackers to learn its IP).

### conf.socksHost, conf.socksPort, and conf.socksLocalDNS

Settings for connecting through optional SOCKS5 proxy. Use them to connect through TOR and hide your IP address from peers even when making outgoing connections. This is useful and highly recommended when you are running an online wallet on your server and want to make it harder for potential attackers to learn the IP address of the target to attack. Set `socksLocalDNS` to `false` to route DNS queries through TOR as well.

## Email notifications

Most bots out there expect user's machine to have UNIX sendmail and by default `sendmail` function in `mail` module will try to use that, but it is possible to configure your node to use SMTP relay. This way you could use Gmail or Sendmail SMTP server or even something like Mailtrap.io (excellent for testing purposes if you don't want the actual email recipient to receive your test messages). This is how the configuration would look:

{% code title="conf.json" %}

```javascript
{
    "smtpTransport": "relay",
    "smtpRelay": "smtp.mailtrap.io",
    "smtpUser": "MAILTRAP_INBOX_USER",
    "smtpPassword": "MAILTRAP_INBOX_PASSWORD",
    "smtpSsl": false,
    "smtpPort": 2525,
    "admin_email": "admin@example.com",
    "from_email": "bot@example.com"
}
```

{% endcode %}

`smtpTransport` can take one of three values:

* `local`: send email using locally installed `sendmail`. Normally, `sendmail` is not installed by default and when installed, it needs to be properly configured to actually send emails. If you choose this option, no other conf settings are required for email. This is the default option.
* `direct`: send email by connecting directly to the recipient's SMTP server. This option is not recommended.
* `relay`: send email through a relay server, like most email apps do. You need to also configure the server's host `smtpRelay`, its port `smtpPort` if it differs from the default port 25, and `smtpUser` and `smtpPassword` for authentication to the server.

## Accepting incoming connections

Obyte network works over secure WebSocket protocol wss\://. To accept incoming connections, you'll need a valid TLS certificate (you can get a free one from [letsencrypt.org](https://letsencrypt.org)) and a domain name (you can get a free domain from [Freenom](http://www.freenom.com/)). Then you accept connections on standard port 443 and proxy them to your locally running Obyte daemon.

This is an example configuration for nginx to accept websocket connections at wss\://obyte.one/bb and forward them to locally running daemon that listens on port 6611:

If your server doesn't support IPv6, comment or delete the two lines containing \[::] or nginx won't start

```
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate "/etc/letsencrypt/live/obyte.one/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/obyte.one/privkey.pem";

    if ($host != "obyte.one") {
        rewrite ^(.*)$ https://obyte.one$1 permanent;
    }
    if ($https != "on") {
        rewrite ^(.*)$ https://obyte.one$1 permanent;
    }

    location = /bb {
        proxy_pass http://localhost:6611;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    root /var/www/html;
    server_name _;
}
```

By default Node limits itself to 1.76GB the RAM it uses. If you accept incoming connections, you will likely reach this limit and get this error after some time:

```
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [node]
...
...
12: 0x3c0f805c7567
Out of memory
```

To prevent this, increase the RAM limit by adding `--max_old_space_size=<size>` to the launch command where size is the amount in MB you want to allocate.

For example `--max-old-space-size=4096`, if your server has at least 4GB available.

## Checking if the node is running

### Sending the notification to admin when node stops

Many bots have a file named [check\_daemon.js](https://github.com/byteball/bot-example/blob/master/check_daemon.js) included in the repository, which looks like this

```javascript
const check_daemon = require('ocore/check_daemon.js');
check_daemon.checkDaemonAndNotify('node start.js');
```

This can be executed with crontab with the command mentioned in [crontab.txt](https://github.com/byteball/bot-example/blob/master/crontab.txt) and when the email is properly configured on the server and the node crashes, this script will notify you that the node went down.

If you are executing your node with `node start.js --max-old-space-size=4096` command then you should also change the `checkDaemonAndNotify` parameter.

### Restarting the node automatically when it stops

If you are running a wallet-less node (Hub, Relay or Explorer) or password-less headless wallet (`conf.bNoPassphrase=true`) then you can restart the node automatically when it stops. In order to do that, you could use `checkDaemonAndRestart` function, instead of `checkDaemonAndNotify`.

```javascript
const check_daemon = require('ocore/check_daemon.js');
check_daemon.checkDaemonAndRestart('node start.js', 'node start.js 1>log 2>>err');
```

The first parameter in `checkDaemonAndRestart` is the process that gets searched from `ps x` command response, the second parameter is a command that will get executed when node has stopped.

Above example is for wallet-less node, which will log the `stdout` and `stderr` (>> for appending) to file ([headless wallet has logging built-in](/tutorials-for-newcomers/setting-up-headless-wallet#monitoring-logs)). If the command uses parameters like `--max-old-space-size=4096` then these should be added to both parameters, but output directing (`1>log` and `2>>err`) should not be added to first parameter.

If you are using NVM to manage your Node.js versions then you might need to add `PATH` and `LD_LIBRARY_PATH` to your crontab configuration as well, otherwise crontab might not be able to restart the node.


# Tutorials for newcomers

Step by step tutorials to get started with example bots.

## Type of repositories on Obyte Github page

Obyte Github page is located there <https://github.com/byteball>

![Obyte repository dependency graph](/files/-Ls2ZaTGRUMG3UMzO8z4)

### ocore - main core library

* syncs full database if full node.
* relays storage units if full node.

### obyte-gui-wallet - wallet apps with GUI

* inherits `ocore` library.
* light node or full node.
* wallet functionality.
* graphical user interface for Windows, MacOS, Linux, Android and iOS.

### headless-obyte - wallet for server without GUI

* inherits `ocore` library.
* light node or full node.
* wallet functionality.
* can be controlled via chat.
* can be controlled via [JSON-RPC service](/json-rpc/running-rpc-service).

### obyte-witness - nodes that determine the main chain

* inherits `headless-obyte` and `ocore` library.
* only full node.
* recommended to be behind TOR.
* post new units (moves itself funds or posts oracle data) serially.

### obyte-relay - peer that can be connected directly

* inherits `ocore` library.
* only full node.
* accepts incoming connections.
* provides new units, stable units, balances & suitable parents to light nodes.
* notifies wallet apps about new witnesses.

### obyte-hub - hub that relays chat messages

* inherits `obyte-relay` and `ocore` library.
* relays encrypted chat messages between devices.
* notifies wallet apps about new app version.
* shows list of chat bots that are available to pair with.
* shows metadata about assets.

### bot-example - template for new projects

* inherits `headless-obyte` and `ocore` library.
* customized [chat messages handling](/list-of-events#a-new-message-string-type-message-has-been-received) can be added.
* customized actions on [new transactions](/list-of-events#new-unstable-unit) and [stable transactions](/list-of-events#stable-unit) can be added.
* can be used as a base of any new project that needs Obyte wallet functionality.

## Tutorials to setup a node

* [Setting up headless wallet (Debian/Ubuntu Linux)](/tutorials-for-newcomers/setting-up-headless-wallet)
* [Setting up headless wallet with Docker image](https://github.com/byteball/headless-obyte#docker-image)
* [Setting up headless wallet on Raspberry Pi](https://medium.com/obyte-help/running-obyte-wallet-on-headless-raspberrypi-3-56007da32739)

## Examples of using these libraries

* [Ping-poing payments](/tutorials-for-newcomers/ping-pong-paymets)
* [Logging into website](/tutorials-for-newcomers/log-in-on-website-with-byteball)
* [Weather oracle](/tutorials-for-newcomers/weather-oracle)
* [Bet on weather bot](/tutorials-for-newcomers/bet-on-weather-bot)


# Setting up headless wallet

Instructions how to set up headless wallet on a blank Debian machine.

Setting up a Headless wallet is required for those wanting to build their own chat bots. That is, if they want to host the bot on their own server, at least. This guide will take you through the installation in a step by step process but won’t venture into how to build the chat bot itself. There are several possibilities to rent a Virtual Private Server (VPS) and apart from a fairly fast SSD storage there are not a lot of requirements.

The first thing you should consider, is whether you want to run your bot on a full node or a light node. When setting up the server, the choice to run on a full node will mean you need to make sure to have enough disk space available. The installation is the same whether you run a full node or a light node, but running a full node will allow your bot to have access to all units ever posted to the DAG and thereby be able to perform more complex tasks. If light wallet is enough for you and have no interest in renting a VPS then you can run a light [Obyte headless wallet also on Raspberry Pi 3+](https://medium.com/@alvarlaigna/running-obyte-wallet-on-headless-raspberrypi-3-56007da32739).

Most VPS providers allow you to choose an operating system, and since this guide will be based on Debian 9, you might want to find a provider that offers this as one of their options. Since I will be running a full node, I also must make sure to have enough disk space available and that it is on SSD, since HDD will be too slow.

* 1 server (with Debian in this case)
* At least 140-150 GB of fast SSD disk space (HDD is too slow for initial syncing)
* 1 GB RAM (hubs/relays that accept incoming connections might need up to 4GB)

## Setting up the server.

Having created the server, I need to connect to the server. I use a super lightweight SSH terminal called “putty” from my Windows laptop.(available on <https://www.putty.org>)

![](/files/-LSSyosOP4mDDrKfvsI3)

First time you log on, you will see a notice that you have not connected to this host before. Click “Yes” to save the key.

![](/files/-LSSyvt_3B8PrKghOaHo)

You are now logged on to your server:

![](/files/-LSSyynCNbrRG0GNLFlC)

Running the headless wallet as root is not recommended, so the first thing I do, is create the user we will run the hub as. I chose the username “obyte”.

`adduser obyte`

I will be installing all prerequisites as root for this guide. Only the actual headless wallet stuff will be installed from the user we just created. For now, stay logged in as root.

## The fundamentals

First, we need some basic tools. To make sure we get the newest versions, first run an update of the apt tool:\
`apt update`

Then install following software:\
`apt-get install -y git curl software-properties-common`

To make sure all binaries build properly, we need the build-essentials as well:\
`apt-get install -y build-essential`

Now log on with the user we initially created (`obyte` in this example)\
`su -l obyte`

The headless wallet is based on nodejs, and one of the easiest way to control node versions is by the script called “nvm”. Just fire these three commands, and you’re all set (make sure not to miss any of the backticks in the above):\
`` nvm_version=`curl --silent -L https://api.github.com/repos/nvm-sh/nvm/releases/latest | /usr/bin/awk '/tag_name/ { print $2 }' | /bin/sed 's/[",]//g'` ``\
`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/$nvm_version/install.sh | bash`

(thanks to <http://blog.mobnia.com/installing-node-with-nvm-on-a-debian-server/> for the above two commands)

Then exit user, log in again and install version 14 of nodejs:\
`exit`\
`su -l obyte`\
`nvm install 14`

Build tools for Windows can be installed with following command (you need to run PowerShell or CMD.exe as Administrator to install this):\
`npm install --global --production windows-build-tools`

You will also need [node-gyp](https://github.com/nodejs/node-gyp#installation) for cases where the pre-built binaries (secp256k1, sqlite, rocksdb) are not available for your system configuration. That you can install with this command:\
`npm install -g node-gyp`

## Installing the Headless Wallet

So far so good - we’re now almost ready to start actually installing the headless wallet. But first. We need to find the repository that we want to clone. Go to [https://github.com/byteball/headless-obyte](https://github.com/byteball/headless-byteball) and click the “Clone or download” button:

![](/files/-LSSz51lITzwDhAgYZ_K)

Copy the URL from there and clone the repository

`git clone https://github.com/byteball/headless-obyte.git`

It creates a directory called headless-obyte.

`cd headless-obyte`

Then install it

`npm install`

## Configuring and starting your headless wallet

In your .config folder, you should create a file called conf.json and edit it. It will contain values that is used by the headless wallet. They override the values that you can find in the file called conf.js located in your headless-obyte folder.

`mkdir -p ~/.config/headless-obyte`\
`nano ~/.config/headless-obyte/conf.json`

I will briefly explain each of the entries, you should put in the file (if you’re not familiar with the structure of a json object, you could check out sites such as jsoneditoronline.org)

There is also a detailed explanation of the values on <https://github.com/byteball/headless-obyte> at the section called “Customize”.

### deviceName config

This is pretty much self explanatory. The name of your device. This is the name that others will see when they pair with your bot. It’s not to be confused with the bot’s name, which you will have to have the Obyte hub-operator create for you.

### permanent\_pairing\_secret config

This is the part that goes after the # in your pairing invitation that you will use from your control device - usually a GUI wallet.

### control\_addresses config

This is one of the two most important settings. This is an array of device addresses (not wallet addresses) that are allowed to control your headless wallet and request payments from it. You will most likely want to control the headless wallet from a GUI wallet on a phone or desktop. You find the device address by clicking the burger-menu and clicking “Settings” and then scrolling down to the section saying “Device Address” on the wallet(s) you want to be able to connect to the headless wallet from.

![](/files/-LSSzGykqr_ONWgBuAww)

### payout\_address config

The other important setting is the payout\_address which is the wallet address that the bot is allowed to send funds to. When a device with the correct device address requests the bot to send a payment of X bytes, the bot automatically pays it to the wallet you specify here. If you are installing the bot to allow users to send funds to it or to be part of smart contracts that it will potentially withdraw from, you might want to periodically send funds away from the headless wallet and into another wallet you control.

### bLight config

This setting determines whether your headless wallet will run as a full node or a light node. If your bot needs access to all transactions on the DAG, you will need to run a full node. Therefore, in most cases, this should be set to `false`.

The final file would look something like this:

{% code title="conf.json" %}

```javascript
{
  "deviceName": "Obyte Denmark",
  "permanent_pairing_secret": "0000",
  "control_addresses": [
    "DEVICE_ADDRESS_1",
    "DEVICE_ADDRESS_2",
    "DEVICE_ADDRESS_3"
  ],
  "payout_address": "YOUR_WALLET_ADDRESS",
  "bLight": false
}
```

{% endcode %}

## Wallet is ready to be started

That’s it, your headless wallet is now ready to be started. If you set bLight = false; your wallet will start synchronizing the entire DAG. This can take a long time depending on the speed of your server and particularly the SSD disk.

To make sure the process doesn’t run out of memory (which can cause crashes) you should manually assign additional memory to the nodejs process:

`node --max-old-space-size=4096 start.js`

### Run on background using "bg" and "fg"

#### Send to background

`ctrl+z`\
`bg`

#### Stop the headless wallet

`fg`\
`ctrl+c`

### Run on background using “screen”

It might just be me, but I always found that a better way to leave processes running even after I log off the server, is to use the program `screen`. It’s super easy to use. So I suggest, that even though the bot say you can send the process to the background by using `ctrl+z` and `bg`, i have a harder time separating the various background processes. So I suggest you simply do this:

`sudo apt-get install screen`

This allows you to start, detach and re-attach screens as you please.

#### Start a new screen

`screen` - run it when you have detached from screen and want to start a totally new screen.

#### Send screen to background

`ctrl+a and d` - this detaches from screens and sends it to background (be careful not to miss pressing `a` before `d`.

#### Resuming a screen from background

`screen -r` - this reattaches to most recently started screen. If you have started multiple then use `screen -list` to get a list of all started screens and then reattached with `screen -r PPID`

#### Stop the headless wallet

`ctrl+d` - while attached to screen, this terminates the screen and stops the headless wallet

### Run on background non-interactively

If you are unable to enter a passphrase every time the wallet starts and/or are willing to accept the security risks, set `bNoPassphrase` to `true` and daemonize the app when starting:

#### Starting the daemon

```
node start.js 1>log 2>errlog &
```

#### Stopping the daemon

Checking if `node` runs

`ps -ef | { head -1; grep node; }` or `ps -fp $(pgrep -d, -x node)`

`kill PID` - sends SIGTERM command to stop the process by PID number.

If you want to automatically stop all node processes then use `pkill node`

## Useful extras

Since Obyte runs on an SQLite database by default, which is [located in user data folder](/configuration), you might want to be able to explore the data stored yourself, thereby making it easier to create the logic for the bot if you need to access data in the databases. If you wish to [setup Obyte to use MySQL database instead](/configuration#conf-storage) then that can be changed with a configuration file.\
`apt-get install sqlite3`

### Monitoring logs

Checking the log to see if things are running (by default, log file is in [same folder as configuration](/configuration)):

`tail -f ~/headless-obyte/log.txt`

### Disabling logs

By default, headless wallets are set to write logs into a file, but you make them to write to console instead by setting `logToSTDOUT` configuration to `true`.

If don't wish to get the logs to console and you also would like to disable writing the log file then this can be done by adding a variable like this to the configuration file:

{% code title="conf.json" %}

```javascript
{
    "logToSTDOUT": false,
    "LOG_FILENAME": "/dev/null"
}
```

{% endcode %}

## Documentation

Full documentation for headless Obyte node can be found there\
<https://byteball.github.io/headless-obyte/>


# Ping-pong paymets

Hello. I’m starting a series of tutorials about creating projects on Obyte. Today we will consider the creation of ping-pong payment bot. First we will need Linux or MacOS, node.js, [Obyte wallet for testnet](https://byteball.org/testnet.html) and [bot-example](https://github.com/byteball/bot-example). So, let's clone it and run

```bash
git clone https://github.com/byteball/bot-example
cd bot-example 
npm install
cp .env.testnet .env
node start.js
```

\
We run `cp .env.testnet .env` for changing it configuration to testnet network. When you starting bot at first, he will ask you passphrase(don’t forget it, since you need to enter each time you start). When starting bot in console you will see “my pairing code”. It looks like this: Copy this pairing code.

![image3.png](https://cdn.steemitimages.com/DQmPAGJos8Rr46zEUXokatvKRQH5CQZDeyxH7b41ArW1mtr/image3.png)

Now add our bot, open the Obyte wallet and go to Chat (below) > Add a new device > Accept invitation from the other device then insert your pairing code (instead of an asterisk any word, for example, test) and click "PAIR”

![](/files/-LQm_g3SbP-5DlmeVylf)

After that you will have a chat with your bot, write to him and he will answer you with your message. All right, now let's teach the bot to give us our money back.

Opening the start.js file we see 5 events:

**headless\_wallet\_ready** - Triggered when the bot is running and ready to work

**paired** - Triggered when someone adds our bot

**text** - Triggered when we receive a message

**new\_my\_transactions** - Triggered when we receive a transaction(but it is not stable)

**my\_transactions\_became\_stable** - Triggered when the transaction has become stable

First, let's create variables where the associations for addresses will be stored. We will learn how to work with the database in the following lessons.

```javascript
let assocDeviceAddressToPeerAddress = {};
let assocDeviceAddressToMyAddress = {};
let assocMyAddressToDeviceAddress = {};
```

\
Now, lets teach the bot to send a request to send us your address:

```javascript
eventBus.on('paired', (from_address, pairing_secret) => {
  const device = require('ocore/device.js');
  device.sendMessageToDevice(from_address, 'text', "Please send me your address");
});

eventBus.on('text', (from_address, text) => {
  text = text.trim();

  const device = require('ocore/device.js');
  device.sendMessageToDevice(from_address, 'text', "Please send me your address");
});
```

Here we see the function **sendMessageToDevice**, we will use it whenever we want to send a message to the user.

The function takes 3 parameters

1. device address
2. subject - for now we will use only ‘text’
3. our text message

In order to send bot our address we need to go to our chat and click "Insert my address”:

![](/files/-LQmaC696nmvZiN50Ncx)

Great, now we will teach our bot to check and save the user's address, and also create an address for accepting payments and request 5000 bytes from the user.

```javascript
eventBus.on('text', (from_address, text) => {
  const device = require('ocore/device.js');
  text = text.trim();
  if (validationUtils.isValidAddress(text)) {
     assocDeviceAddressToPeerAddress[from_address] = text;
     device.sendMessageToDevice(from_address, 'text', 'Saved your wallet address');
     headlessWallet.issueNextMainAddress((address) => {
        assocMyAddressToDeviceAddress[address] = from_address;
        assocDeviceAddressToMyAddress[from_address] = address;
        device.sendMessageToDevice(from_address, 'text', '[balance](byteball:' + address + '?amount=5000)');
     })
  } else if (assocDeviceAddressToMyAddress[from_address]) {
     device.sendMessageToDevice(from_address, 'text', '[balance](byteball:' + assocDeviceAddressToMyAddress[from_address] + '?amount=5000)');
  } else {
     device.sendMessageToDevice(from_address, 'text', "Please send me your address");
  }
});
```

This time we used **issueNextMainAddress**, this function creates a new wallet address. We need it to distinguish between payments.

Now the most important thing! First, we need to inform the user that we have received the payment and waiting until it becomes stable.

```javascript
eventBus.on('new_my_transactions', (arrUnits) => {
  const device = require('ocore/device.js');
  db.query("SELECT address, amount, asset FROM outputs WHERE unit IN (?)", [arrUnits], rows => {
     rows.forEach(row => {
        let deviceAddress = assocMyAddressToDeviceAddress[row.address];
        if (row.asset === null && deviceAddress) {
           device.sendMessageToDevice(deviceAddress, 'text', 'I received your payment: ' + row.amount + ' bytes');
           return true;
        }
     })
  });
});
```

After that, we send the user his payment minus the payment fee:

```javascript
eventBus.on('my_transactions_became_stable', (arrUnits) => {
  const device = require('ocore/device.js');
  db.query("SELECT address, amount, asset FROM outputs WHERE unit IN (?)", [arrUnits], rows => {
     rows.forEach(row => {
        let deviceAddress = assocMyAddressToDeviceAddress[row.address];
        if (row.asset === null && deviceAddress) {
           headlessWallet.sendAllBytesFromAddress(row.address, assocDeviceAddressToPeerAddress[deviceAddress], deviceAddress, (err, unit) => {
              if(err) device.sendMessageToDevice(deviceAddress, 'text', 'Oops, there\'s been a mistake. : ' + err);

              device.sendMessageToDevice(deviceAddress, 'text', 'I sent back your payment! Unit: ' + unit);
              return true;
           })
        }
     })
  });
});
```

\
\
Here, we use **sendAllBytesFromAddress**, as the name implies, we just send all the funds(minus the payment fee) from one address to another.

That's it. Now let's test it. To do this you need to add faucet bot: AxBxXDnPOzE/AxLHmidAjwLPFtQ6dK3k70zM0yKVeDzC\@byteball.org/bb-test#0000

And send him your address, wait until it becomes stable(this can be seen on the main screen), that's all. Send payments to the bot and get them back.

![](/files/-LQm_p1bxtoeTZeQ-7Ws)

All code you can find on [github](https://github.com/xJeneKx/Tutorial-1). In the next lessons we will continue, but for now I recommend to read the official [wiki](https://github.com/byteball/byteballcore/wiki/Byteball-Developer-Guides). Did you like the lesson? Any questions? What topics have caused you difficulties and it is worth talking about them? Write in the comments and I will help you. Also, join my chat in telegram - [@obytedev](https://t.me/devbyteball).


# Logging into website

Hey guys! Today we will learn how to log in using a Obyte wallet, and also make paid access to the article. To do this, we need project that i have prepared for you [Tutorial-2-source](https://github.com/xJeneKx/Tutorial-2-source). Install it.

```bash
git clone https://github.com/xJeneKx/Tutorial-2-source
cd Tutorial-2-source
npm install
```

If you run project you will see a blog with articles. After opening any article you will see a request to log in. Let’s create an authorization. First we need a pairing code, you could see it on startup

![](https://lh4.googleusercontent.com/UB0mdQRYTSrDVgC2UTEFQub1-vGYV25q4fcnZnWivCVwn7-Gh8QNTgMSDtRTkgPEO5y5lF9KD_W19WgqMGCg5Phd2i9JVjSSLHI3JHz5Qg-QqnyqFjJNzI_P3p_2bU4IKzPNoJBZ)

Copy it and change our code a bit

```javascript
pairingCode = 'Aly99HdWoCFaxJiIHs1ldREAN/sMDhGsRHNQ2RYU9gCj@byteball.org/bb#' + code;
```

```javascript
eventBus.on('paired', (from_address, pairing_secret) => {
  console.error('paired', from_address, pairing_secret);
});
```

Run and see the link. Сlick on it and bot will be added. Now let’s look at the console.

![](https://lh3.googleusercontent.com/CoHNgrayZGvQFYDFzwREmddk4ghl3BTq4AiJFjS0ApNqltnBTuqJTPWiZJEs6wG6OCFg8M2IKwOWoypRgYkXktt2A5j_IsIJLpEsa7uW5PjZgjUG2DfQNVtikCwnb1mhruSMNpeT)

Add the link

```javascript
b = '<br>Please login using this pairing code: <a href="obyte:' + pairingCode + '">' + pairingCode + '</a>';
```

And QR

```javascript
let dataURL = await QRCode.toDataURL("obyte:" + pairingCode);
b = '<br>Please login using this pairing code: <a href="obyte:' + pairingCode + '">' + pairingCode + '</a><br><img src="' + dataURL + '">';
```

Save our device address, we will need it later.

```javascript
eventBus.on('paired', (from_address, pairing_secret) => {
  let device = require('ocore/device');
  assocCodeToDeviceAddress[pairing_secret] = from_address;
  device.sendMessageToDevice(from_address, 'text', 'ok');
});
```

Now we need to tell the browser that we are logged in\
To implement this, we add function in start.js

```javascript
async function amILogged(ctx) {
  let url = ctx.request.url;
  let match = url.match(/code=([0-9]+)/);
  if (match && assocCodeToDeviceAddress[match[1]]) {
     ctx.cookies.set('ac', match[1]);
     ctx.body = 'true';
  } else {
     ctx.body = 'false';
  }
}
```

And also one more routing

```javascript
app.use(mount('/amilogged', amILogged));
```

In article.html we will add a request to check

```javascript
var step = '<%= step %>';
var code = '<%= code %>';
if (step === 'login') {
  setInterval(() => {
     fetch('/amilogged?code=' + code)
        .then((response) => {
           return response.text();
        }).then(result => {
        if (result === 'true') {
           location.reload(true);
        }
     })
        .catch(alert);
  }, 5000);
}
```

What’s going on here? The user scans the QR code, adds our bot. Bot associates code with his device\_address. In the browser, we knock and ask: did we logged in? and adding cookies.

Now we need to create an address and associate it with the user and the article.\
Add a variable

```javascript
let assocCodeAndNumberToAddress = {};
```

Add the address and display it

```javascript
step = 'paid';
let address = await getAssocAddress(assocCode, 1);
let dataURL = await QRCode.toDataURL("obyte:" + address + '?amount=100');
b = '<br>Please pay for the article. <br>Address: ' + address + '<br>Amount: 100<br><img src="' + dataURL + '"><br>' +
  '<a href="obyte:' + address + '?amount=100">Pay</a>';
```

And finally the function getAssocAddress

```javascript
function getAssocAddress(assocCode, number) {
  return new Promise(resolve => {
     let name = assocCode + '_' + number;
     if (assocCodeAndNumberToAddress[name]) {
        return resolve(assocCodeAndNumberToAddress[name]);
     } else {
        headlessWallet.issueNextMainAddress(address => {
           assocCodeAndNumberToAddress[name] = address;
           return resolve(address);
        });
     }
  });
}
```

This time we will not wait for the stabilization of the unit and immediately open access.\
Add a variable

```javascript
let assocCodeToPaid = {};
```

Add a check that the user has paid for

```javascript
async function amIPaid(ctx) {
  let code = ctx.cookies.get('ac');
  ctx.body = (code && itPaid(code)) ? 'true' : 'false';
}

function itPaid(code) {
  return !!assocCodeToPaid[code];
}
```

Add a routing

```javascript
app.use(mount('/amipaid', amIPaid));
```

And payment processing

```javascript
eventBus.on('new_my_transactions', (arrUnits) => {
  const device = require('ocore/device.js');
  db.query("SELECT address, amount, asset FROM outputs WHERE unit IN (?)", [arrUnits], rows => {
     rows.forEach(row => {
        if (row.amount === 100 && row.asset === null) {
           for (let key in assocCodeAndNumberToAddress) {
              if (assocCodeAndNumberToAddress[key] === row.address) {
                 let assocCode = key.split('_')[0];
                 assocCodeToPaid[assocCode] = true;
                 device.sendMessageToDevice(assocCodeToDeviceAddress[assocCode], 'text', 'I received your payment');
                 return;
              }
           }
        }
     })
  });
});
```

That’s all, make a working second article - will be your homework:) You should get this:\
<https://www.youtube.com/watch?v=vvB6A1wBecQ>

All the code you can find on [github](https://github.com/xJeneKx/Tutorial-2-full). Did you like the lesson? Any questions? What topics have caused you difficulties and it is worth talking about them? Write in the comments and I will help you. Also join my telegram chat - [@obytedev](https://t.me/obytedev).


# Weather oracle

Hi, everybody. Today we will create our own oracle. To do this, we need a bot-example. Let’s install it.

```bash
git clone https://github.com/byteball/bot-example
cd bot-example
npm install
cp .env.testnet .env
```

Our oracle will accept a message like City: timestamp, where timestamp is the time to publish.\
Let’s write a message handler

```javascript
headlessWallet.readSingleAddress(address => {
  my_address = address;
  console.error('my_address', address)
});

eventBus.on('text', (from_address, text) => {
  text = text.trim();
  const device = require('ocore/device.js');
  const args = text.toLowerCase().split(':');
  if (args.length === 2){
     switch (args[0]) {
        case 'berlin':
        case 'moscow':
        case 'helsinki':
        case 'washington':
           if(parseInt(args[1]) <= Date.now()){
              console.error('dateNow', Date.now());
              device.sendMessageToDevice(from_address, 'text', "Incorrect time");
           }else {
              arrQueue.push({city: args[0], time: args[1], device_address: from_address});
              device.sendMessageToDevice(from_address, 'text', "ok");
           }
           break;
        default:
           device.sendMessageToDevice(from_address, 'text', "City not support");
           break;
     }
  }else {
     device.sendMessageToDevice(from_address, 'text', "Incorrect command");
  }
});
```

Add a variable to store the queue

```javascript
let arrQueue = [];
```

Now add to the queue

```javascript
if(parseInt(args[1]) <= Date.now()){
  device.sendMessageToDevice(from_address, 'text', "Incorrect time");
}else {
  arrQueue.push({city: args[0], time: args[1], device_address: from_address});
  device.sendMessageToDevice(from_address, 'text', "ok");
}
```

Now we need to check the queue once a minute

```javascript
function checkQueue(){
  arrQueue.forEach((el, index) => {
     if(el.time <= Date.now()){
        let result = JSON.parse(body);
        postDataFeed(el.city, el.time, result.current.temp_c);
     }
  });
}
setTimeout(checkQueue, 60000);
```

Now we come to the main point. We need to publish data\_feed

```javascript
function postDataFeed(city, time, temp){
  const network = require('ocore/network.js');
  const composer = require('ocore/composer.js');

  let data_feed = {};
  data_feed[city + '_' + time] = temp;
  let params = {
     paying_addresses: [my_address],
     outputs: [{address: my_address, amount: 0}],
     signer: headlessWallet.signer,
     callbacks: composer.getSavingCallbacks({
        ifNotEnoughFunds: console.error,
        ifError: console.error,
        ifOk: function(objJoint){
           network.broadcastJoint(objJoint);
        }
     })
  };
  let objMessage = {
     app: "data_feed",
     payload_location: "inline",
     payload: data_feed
  };
  params.messages = [objMessage];
  composer.composeJoint(params);
}
```

What is happening?

1\) We create an object in data\_feed and keep the temperature in it.

```javascript
let data_feed = {};
data_feed[city + '_' + time] = temp;
```

2\) We send the payment to ourselves as we only need to publish data\_feed

```javascript
paying_addresses: [my_address],
outputs: [{address: my_address, amount: 0}]
```

3\) Create a message with data and signature

```javascript
let objMessage = {
     app: "data_feed",
     payload_location: "inline",
     payload: data_feed
  };
```

4\) Publish

```javascript
composer.composeJoint(params);
```

That’s all. Your first oracle is ready. For the experiment, you can add more cities or make paid access. All code is available on [github](https://github.com/xJeneKx/tutorial-3).Did you like the lesson? Any questions? What topics have caused you difficulties and it is worth talking about them? Write in the comments and I will help you. Also join my telegram chat - [@obytedev](https://t.me/obytedev).


# Bet on weather bot

Hello, everybody. Today we will learn how to create our first contract. We will do this on the example of a bot that accepts a bet on the weather.

We will need [bot-example](https://github.com/byteball/bot-example). Let’s install it.

```bash
git clone https://github.com/byteball/bot-example
cd bot-example
npm install
cp .env.testnet .env
```

First, let’s create variables.

```javascript
const request = require('request');
const correspondents = require('./correspondents');

let steps = {}; // store user steps
let assocDeviceAddressToCurrentCityAndTemp = {}; 
let assocDeviceAddressToAddress = {};
let bets = [];
let KEY_API = '50ace22603c84daba1780432180111'; // apixu.com
let my_address;
```

Save our address for use in the contract

```javascript
headlessWallet.readSingleWallet(walletId => {
  db.query("SELECT address FROM my_addresses WHERE wallet=?", [walletId], function (rows) {
     if (rows.length === 0)
        throw Error("no addresses");
     my_address = rows[0].address;
  });
});
```

Let’s add a text handler and analyze what happens:

```javascript
eventBus.on('text', (from_address, text) => {
     text = text.trim().toLowerCase();
     if (!steps[from_address]) steps[from_address] = 'start';
     let step = steps[from_address];
     const device = require('ocore/device.js');
     if (validationUtils.isValidAddress(text.toUpperCase())) { // If address sent to us - save it.
        assocDeviceAddressToAddress[from_address] = text.toUpperCase();
        return device.sendMessageToDevice(from_address, 'text', 'I saved your address. Send me the name of the city');
     } else if (!assocDeviceAddressToAddress[from_address]) { // If we do not know the address - asking it to send for us.
        return device.sendMessageToDevice(from_address, 'text', 'Please send me your byteball address(... > Insert my address)');
     } else if (step === 'city' && (text === 'more' || text === 'less')) { // Create a contract and ask to pay for it
        let time = Date.now() + 20 * 60 * 1000;
        let name = assocDeviceAddressToCurrentCityAndTemp[from_address].city + '_' + time;
        let operator = text === 'more' ? '>=' : '<=';
        let value = assocDeviceAddressToCurrentCityAndTemp[from_address].temp;
        createContract(my_address, assocDeviceAddressToAddress[from_address], 2001, 2000, from_address, name, operator, value, time,
           (err, paymentRequestText, shared_address, timeout) => {
              if (err) throw err;
              findOracleAndSendMessage(assocDeviceAddressToCurrentCityAndTemp[from_address].city + ':' + time, () => {
                 bets.push({
                    myAmount: 2001,
                    peerAmount: 2000,
                    myAddress: my_address,
                    peerAddress: assocDeviceAddressToAddress[from_address],
                    sharedAddress: shared_address,
                    peerDeviceAddress: from_address,
                    name,
                    operator,
                    value,
                    timeout
                 });
                 device.sendMessageToDevice(from_address, 'text', paymentRequestText);
                 setTimeout(() => { // If the payment was not made for 10 minutes-we take the money
                    headlessWallet.sendAllBytesFromAddress(shared_address, my_address, from_address, (err, unit) => {
                       if (!err) console.error('unit:: ', unit);
                    });
                 }, 15 * 60 * 1000);
              });
           });
     } else if (step === 'start') { // Check the weather and specify what rate the user wants to make
        switch (text) {
           case 'berlin':
           case 'moscow':
           case 'helsinki':
           case 'washington':
              request('https://api.apixu.com/v1/current.json?key=' + KEY_API + '&q=' + text, function (error, response, body) {
                 if (error) {
                    console.error(error);
                    device.sendMessageToDevice(from_address, 'text', 'An error occurred. Try again later.');
                 } else {
                    let result = JSON.parse(body);
                    let temp = result.current.temp_c;
                    device.sendMessageToDevice(from_address, 'text', 'Want to bet that in an hour the weather in ' + text + ' will be\n[more ' + temp + 'c](command:more) or [less ' + temp + 'c](command:less)?');
                    steps[from_address] = 'city';
                    assocDeviceAddressToCurrentCityAndTemp[from_address] = {city: text, temp};
                 }
              });
              break;
           default:
              device.sendMessageToDevice(from_address, 'text', "City not support");
              break;
        }
     } else {
        device.sendMessageToDevice(from_address, 'text', "unknown command");
     }
  });
});
```

Now let’s talk about contract creation.\
We need a separate function

```javascript
function createContract(myAddress, peerAddress, myAmount, peerAmount, peerDeviceAddress, name, operator, value, time, cb) {
  const device = require('ocore/device');
  let timeout = Date.now() + 10 * 60 * 1000;
  let inverseOperator = operator === '>=' ? '<' : '>';
  let arrSeenConditionPeer = ['seen', {
     what: 'output',
     address: 'this address',
     asset: 'base',
     amount: peerAmount
  }];
  let arrSeenConditionMyInput = ['seen', {
     what: 'input',
     address: 'this address',
     asset: 'base'
  }];
  let arrDefinition = ['or', [
     ['or', [
        ['and', [
           ['address', peerAddress],
           arrSeenConditionPeer,
           arrSeenConditionMyInput
        ]],
        ['or', [
           ['and', [
              ['address', peerAddress],
              ['in data feed', [[conf.oracle_address], name, operator, value]],
           ]],
           ['and', [
              ['address', myAddress],
              ['in data feed', [[conf.oracle_address], name, inverseOperator, value]]
           ]]
        ]],
     ]],
     ['and', [
        ['address', myAddress],
        ['not', arrSeenConditionPeer],
        ['in data feed', [[conf.TIMESTAMPER_ADDRESS], 'timestamp', '>', timeout]]
     ]]
  ]];
  let assocSignersByPath = {
     'r.0.0.0': {
        address: peerAddress,
        member_signing_path: 'r',
        device_address: peerDeviceAddress
     }, 'r.0.1.0.0': {
        address: peerAddress,
        member_signing_path: 'r',
        device_address: peerDeviceAddress
     },
     'r.1.0': {
        address: myAddress,
        member_signing_path: 'r',
        device_address: device.getMyDeviceAddress()
     },
     'r.0.1.1.0': {
        address: myAddress,
        member_signing_path: 'r',
        device_address: device.getMyDeviceAddress()
     }
  };
 
  let walletDefinedByAddresses = require('ocore/wallet_defined_by_addresses.js');
  walletDefinedByAddresses.createNewSharedAddress(arrDefinition, assocSignersByPath, {
     ifError: (err) => {
        cb(err);
     },
     ifOk: (shared_address) => {
        headlessWallet.issueChangeAddressAndSendPayment('base', myAmount, shared_address, peerDeviceAddress, (err, unit) => {
           if (err) return cb(err);
           let arrPayments = [{
              address: shared_address,
              amount: peerAmount,
              asset: 'base'
           }];
           let assocDefinitions = {};
           assocDefinitions[shared_address] = {
              definition: arrDefinition,
              signers: assocSignersByPath
           };
           let objPaymentRequest = {payments: arrPayments, definitions: assocDefinitions};
           let paymentJson = JSON.stringify(objPaymentRequest);
           let paymentJsonBase64 = Buffer.from(paymentJson).toString('base64');
           let paymentRequestCode = 'payment:' + paymentJsonBase64;
           let paymentRequestText = '[...](' + paymentRequestCode + ')';
           cb(null, paymentRequestText, shared_address, timeout);
        });
     }
  });
}
```

Let’s analyze what happens\
**arrSeenConditionPeer** - watching if there was a payment in the contract with the amount same of the user.\
**arrSeenConditionMyInput** - сhecking, did we withdraw bytes? If yes, then allow the user to pick up their bytes.

**arrDefinition** - this is what our contract looks like, let’s look at it in details.\
When we need some address to subscribe we use \[‘address’, address]\
When we need to check the publication data\_feed we use\
\[‘in data feed’, \[\[conf.oracle\_address], name, operator, value]]

**assocSignersByPath** - in this object, we prescribe the path in the array of the contract before you need to sign and who should sign it. In our example, we sign all ‘address’. The path starts with r-this is the first element in the array, in our case ‘or’ construction. Other examples with signatures will be discussed in the following lessons.

**walletDefinedByAddresses.createNewSharedAddress** - we create a contract address\
**headlessWallet.issueChangeAddressAndSendPayment** - we add the address of the contract and make a payment to it

```javascript
let arrPayments = [{
              address: shared_address,
              amount: peerAmount,
              asset: 'base'
           }];
           let assocDefinitions = {};
           assocDefinitions[shared_address] = {
              definition: arrDefinition,
              signers: assocSignersByPath
           };
           let objPaymentRequest = {payments: arrPayments, definitions: assocDefinitions};
           let paymentJson = JSON.stringify(objPaymentRequest);
           let paymentJsonBase64 = Buffer(paymentJson).toString('base64');
           let paymentRequestCode = 'payment:' + paymentJsonBase64;
           let paymentRequestText = '[your share of payment to the contract](' + paymentRequestCode + ')';
```

This is how we create a message that contains a contract and a payment request.

Create correspondents.js

```javascript
const db = require('ocore/db');

exports.addCorrespondent = (code, name, cb) => {
  let device = require('ocore/device');
 
  function handleCode(code) {
     let matches = code.match(/^([\w\/+]+)@([\w.:\/-]+)#([\w\/+-]+)$/);
     if (!matches)
        return cb("Invalid pairing code");
     let pubkey = matches[1];
     let hub = matches[2];
     let pairing_secret = matches[3];
     if (pubkey.length !== 44)
        return cb("Invalid pubkey length");
    
     acceptInvitation(hub, pubkey, pairing_secret, cb);
  }
 
  function acceptInvitation(hub_host, device_pubkey, pairing_secret, cb) {
     if (device_pubkey === device.getMyDevicePubKey())
        return cb("cannot pair with myself");
     if (!device.isValidPubKey(device_pubkey))
        return cb("invalid peer public key");
     // the correspondent will be initially called 'New', we'll rename it as soon as we receive the reverse pairing secret back
     device.addUnconfirmedCorrespondent(device_pubkey, hub_host, name, (device_address) => {
        device.startWaitingForPairing((reversePairingInfo) => {
           device.sendPairingMessage(hub_host, device_pubkey, pairing_secret, reversePairingInfo.pairing_secret, {
              ifOk: () =>{
                 cb(null, device_address);
              },
              ifError: cb
           });
        });
     });
  }
 
  handleCode(code);
};

exports.findCorrespondentByPairingCode = (code, cb) => {
  let matches = code.match(/^([\w\/+]+)@([\w.:\/-]+)#([\w\/+-]+)$/);
  if (!matches)
     return cb("Invalid pairing code");
  let pubkey = matches[1];
  let hub = matches[2];
 
  db.query("SELECT * FROM correspondent_devices WHERE pubkey = ? AND hub = ?", [pubkey, hub], (rows) => {
     return cb(rows.length ? rows[0] : null);
  });
};
```

We need to tell the oracle to check and publish the weather at the specified time, for this we use this feature.

```javascript
function findOracleAndSendMessage(value, cb) {
  const device = require('ocore/device');
  correspondents.findCorrespondentByPairingCode(conf.oracle_pairing_code, (correspondent) => {
     if (!correspondent) {
        correspondents.addCorrespondent(conf.oracle_pairing_code, 'flight oracle', (err, device_address) => {
           if (err)
              throw new Error(err);
           device.sendMessageToDevice(device_address, 'text', value);
           cb();
        });
     } else {
        device.sendMessageToDevice(correspondent.device_address, 'text', value);
        cb();
     }
  });
}
```

We check whether there is an oracle in our correspondents and if it is not - we add.

That’s all. I also have a homework for you. Complete the oracle and our bot so that oracle informs us that he published and the publication has become stable. After oracle message, notify the user that he lost or won. And if he lost then take the money out of the contract. All code is available on [github](https://github.com/xJeneKx/tutorial-4). Did you like the lesson? Any questions? What topics have caused you difficulties and it is worth talking about them? Write in the comments and I will help you. Also join my telegram chat - [@obytedev](https://t.me/obytedev).


# Payments and transactions

One of the core features that almost every existing Obyte chatbot has is sending and receiving payments. This enables bot developers immediately add payment to the service they could be providing with

## Requesting payments

When you include a valid Obyte address anywhere in the text of your response to the user, the address will be automatically highlighted in the user's chat window, and after clicking it the user will be able to pay arbitrary amount of arbitrary asset to this address.

When you want to request a specific amount of a specific asset, format your payment request this way:

```
Any text before [payment description, will be ignored](obyte:ACCOUNT_ADDRESS?amount=123000&asset=base) any text after
```

Example: ![](/files/-LgUzMuwHl55QB-6n8C4)

Amount is in the smallest units, such as bytes. If you omit `&asset=...` part, base asset (bytes) is assumed. If you want to request payment in another asset, indicate its identifier such as `oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=` for blackbytes (don't forget to url-encode it).

You will likely want to generate a unique payment address per user, per transaction. This code sample might help:

```javascript
var headlessWallet = require('headless-obyte');

eventBus.once('headless_wallet_ready', () => {

    eventBus.on('text', function(from_address, text) {
        const device = require('ocore/device.js');
        
        if (text === 'resend') {
            headlessWallet.issueNextMainAddress((deposit_address) => {
                // send it over to the user
                device.sendMessageToDevice(from_address, 'text',
                    '[...](obyte:'+ deposit_address +'?amount=123000&asset=base)');
                });
            });
        }
    });
});
```

### Payments from single address wallet

It is possible to request that the payment would be done from any single address wallet or specific single address wallet. This works only in chat messages.

```
[...](obyte:ACCOUNT_ADDRESS?amount=1&single_address=1)
[...](obyte:ACCOUNT_ADDRESS?amount=1&single_address=1&from_address=UEPO3OD2TUUJUOECVMKVSRHRDJ4ST2FS)
```

## Requesting multiple payments

To request the user to pay multiple payments at once, create the below Javascript object `objPaymentRequest` which can contain multiple addresses and multiple assets, encode the object in base64, and send it over to the user:

```javascript
var payments = [
    {address: address1, amount: amount1, asset: asset1},
    {address: address1, amount: amount2, asset: asset2},
    {address: address2, amount: amount3, asset: asset1}
];
var objPaymentRequest = {payments};
var paymentJson = JSON.stringify(objPaymentRequest);
var paymentJsonBase64 = Buffer.from(paymentJson).toString('base64');
var paymentRequestCode = 'payment:'+paymentJsonBase64;
var paymentRequestText = '[...]('+paymentRequestCode+')';

device.sendMessageToDevice(from_address, 'text', paymentRequestText);
```

The user's wallet will parse this message, display the multiple payments in a user-readable form, and offer the user to pay the requested amounts. Your payment-waiting code will be called when the payment is seen on the DAG.

## Waiting for payments

If you include a headless wallet

```javascript
var headlessWallet = require('headless-obyte');
```

you can get notified when any of your addresses receives a payment

```javascript
eventBus.on('new_my_transactions', function(arrUnits){
	// fetch more data about my addresses
	db.query("SELECT outputs.address, amount, asset FROM outputs \
			JOIN my_addresses USING (address) \
			WHERE unit IN(?);", [arrUnits], (rows) => {
		if (rows.length === 0) return;
		rows.forEach((row) => {
		    // react to each unconfirmed payment
		});
	});
});
```

`arrUnits` is an array of units (more accurately, unit hashes) that contained any transaction involving your addresses. The event `new_my_transactions` is triggered for outgoing transactions too, you should check if the new transaction credits one of the addresses you are expecting payments to.

## Waiting for finality of payments

To get notified when any of your transactions become stable (confirmed), subscribe to `my_transactions_became_stable` event:

```javascript
eventBus.on('my_transactions_became_stable', function(arrUnits){
	// fetch more data about my addresses
	db.query("SELECT outputs.address, amount, asset FROM outputs \
			JOIN my_addresses USING (address) \
			WHERE unit IN(?);", [arrUnits], (rows) => {
		if (rows.length === 0) return;
		rows.forEach((row) => {
		    // react to each confirmed payment
		});
	});
});
```

`arrUnits` is again the array of units that just became stable and they contained at least one transaction involving your addresses.

The above events work in both full and light nodes. If your node is full, you can alternatively subscribe to event `mci_became_stable` which is emitted each time a new main chain index (MCI) becomes stable:

```javascript
eventBus.on('mci_became_stable', function(mci){
    // check if there are any units you are interested in 
    // that had this MCI and react to their becoming stable
});
```

## Sending payments from chat bot

To send payments, you need to include a headless wallet

```javascript
var headlessWallet = require('headless-obyte');
```

and use this function after the headless wallet becomes ready:

```javascript
eventBus.once('headless_wallet_ready', () => {
    headlessWallet.issueChangeAddressAndSendPayment(asset, amount, account_address, from_address, (err, unit) => {
        if (err){
            // something went wrong, maybe put this payment on a retry queue
            return;
        }
        // handle successful payment
    });
});
```

`asset` is the asset you are paying in (`null` for bytes), `amount` is payment amount in the smallest units. If the payment was successful, you get its `unit` in the callback and can save it or watch further events on this unit.

There are many other functions for sending payments, for example sending multiple payments in multiple assets at the same time, see `exports` of [https://github.com/byteball/headless-obyte/blob/master/start.js](https://github.com/byteball/headless-byteball/blob/master/start.js).


# Textcoins

Textcoins are a handy way of transfering money and asset to other people, in a text form.

Textcoin is a payment sent though email or other text based media, such as chat apps. Textcoins can also be printed on paper, scratch cards, or PIN envelopes and passed on like paper wallets.

### Sending textcoins with bot

Sending textcoins from server-side (headless) wallets is easy: you use the same functions you normally use to send to Obyte addresses but instead of the recipient's Obyte address you write:

* `textcoin:userEmailAddress` for sending to email, or
* `textcoin:someUniqueIdentifierOtherThanEmail` for sending via any other text based media

Examples: `textcoin:pandanation@wwfus.org` or `textcoin:ASDFGHJKL`.

Sample code:

```javascript
var headlessWallet = require('headless-obyte');

let opts = {
    asset: null, 
    amount: 1000, // bytes
    to_address: "textcoin:pandanation@wwfus.org",
    email_subject: "Payment in textcoin"
};

headlessWallet.issueChangeAddressAndSendMultiPayment(opts, (err, unit, assocMnemonics) => {
    ....
});
```

### Sending textcoin emails

The `opts` object has an optional field `email_subject` which is the subject of the email sent to the user. To send emails, you need to set the following fields in your [configuration files](https://github.com/byteball/byteballcore#configuring):

* `from_email`: the address your emails are sent from. Must be on your domain, otherwise the emails are likely to be non-delivered or labeled as spam
* `smtpTransport`: type of SMTP transport used to deliver emails:
  * `local`: (this is the default) use `/usr/sbin/sendmail`
  * `direct`: connect directly to the recipient's MX server, this minimizes the number of intermediaries who are able to see and potentially steal the textcoin, but this method is not reliable as there are no retries
  * `relay`: send through a relay server. In this case, you need to also set its host name in `smtpRelay`. If it requires authentication, you need to also set `smtpUser` and `smtpPassword`.

### Callback response

The callback of `issueChangeAddressAndSendMultiPayment` and all similar functions has an optional 3rd parameter `assocMnemonics` which is an associative array of all generated textcoins (BIP39 mnemonics) indexed by the `address` from the input parameters.

```javascript
{
    "textcoin:pandanation@wwfus.org": "barely-album-remove-version-endorse-vocal-weasel-kitten-when-fit-elbow-crop"
}
```

All the keys of the array have a `textcoin:` prefix, like in input parameters.

If you are sending though any media other than email, you use `assocMnemonics` to find mnemonics generated for each output address (in the example above, you would find it by the key `textcoin:ASDFGHJKL`) and then deliver them yourself.

For example, if you are writing a Telegram bot that rewards users for certain actions, you create a clickable link by prefixing the mnemonic with `https://obyte.org/#textcoin?`:

```
https://obyte.org/#textcoin?barely-album-remove-version-endorse-vocal-weasel-kitten-when-fit-elbow-crop
```

and send it in chat.

### More resources

If you are going to print a paper wallet from an ATM, you just print the mnemonic and optionally [encode textcoin words](/byteball-protocol-uri#receiving-textcoins-via-link) in the QR code. You could create your own [QR code generator on website](/byteball-protocol-uri#using-protocol-uri-in-qr-code) too with jQuery.

More about textcoins in Obyte blog\
<https://medium.com/obyte/sending-cryptocurrency-to-email-5c9bce22b8a9>

Example code in a Telegram bot that sends users textcoins for passing a quiz: <https://github.com/byteball/telegram-quiz/blob/master/src/wallet.js>

Example code that creates a list of textcoins for subsequent mass sending (e.g. [via MailChimp](https://medium.com/byteball-help/using-mailchimp-to-mass-send-payments-as-textcoins-5c1db06342e3)): <https://github.com/byteball/headless-obyte/blob/master/tools/create_textcoins_list.js>


# Sending data to DAG

You can store arbitrary data (any sequence of bytes) in Obyte public DAG. Some special types of data also supported, like 'text', 'profile', 'poll', etc.

## Data with any structure

To send `data` to DAG database, code below is a minimal that you can use. Since the `opts.messages` is array, it means that all the examples on this page can be changed to multi-message transactions.

```javascript
const headlessWallet = require('headless-obyte');
const eventBus       = require('ocore/event_bus.js');

function postData() {
    let json_data = {
        age: 78.90,
        props: {
            sets: [
                '0bbb',
                'zzz',
                1/3
            ]
        }
    };
    let objMessage = {
        app: 'data',
        payload_location: 'inline',
        payload: json_data
    };
    let opts = {
        messages: [objMessage]
    };

    ​headlessWallet.issueChangeAddressAndSendMultiPayment(opts, (err, unit) => {
        if (err){
            /*
            something went wrong,
            maybe put this transaction on a retry queue
            */
            return;
        }
        // handle successful payment
    });
}

eventBus.on('headless_wallet_ready', postData);
```

AAs can be [triggered with data](/autonomous-agents/getting-started-guide#passing-data-to-aa) by manually entering the key/value pairs to GUI wallet, [prompting users to submit pre-filled Send screen](/byteball-protocol-uri#requesting-to-send-data-to-aa), making the [AA to trigger another AA](/autonomous-agents/getting-started-guide#sending-data) or with the [script from headless wallet](https://github.com/byteball/headless-obyte/blob/master/tools/send_data_to_aa.js).

## Key-value data feed

Previous example shows how to send any data to DAG, but if you would want to store data that is searchable and can be used in [smart-contracts](/contracts/smart-contracts) or [autonomous agents](/autonomous-agents/getting-started-guide) then you would need to post it as key-value pairs and with app type `data_feed`. If we also send it always from the same first address in our wallet then we have basically become an oracle.

```javascript
const headlessWallet = require('headless-obyte');
const eventBus = require('ocore/event_bus.js');

function postDataFeed(first_address) {
    let json_data = {
        time: new Date().toString(), 
        timestamp: Date.now()
    };
    let objMessage = {
        app: 'data_feed',
        payload_location: 'inline',
        payload: json_data
    };
    let opts = {
        paying_addresses: [first_address],
        messages: [objMessage]
    };

    ​headlessWallet.issueChangeAddressAndSendMultiPayment(opts, (err, unit) => {
        if (err){
            /*
            something went wrong,
            maybe put this transaction on a retry queue
            */
            return;
        }
        // handle successful payment
    });
}

eventBus.once('headless_wallet_ready', () => {
    headlessWallet.readFirstAddress(postDataFeed);
});
```

## Profile about yourself

Anybody on Obyte network can post some data about themselves, which will be linked to their address. This app type is called `profile`. Payload for that message can contain any keys. For example, [obyte.io](https://obyte.io/edit-profile) web service lets you post a profile with keys like this:

```javascript
let json_data = {
    name:     'a', 
    about:    'b',
    location: 'c',
    website:  'd',
    email:    'e'        
};
let objMessage = {
    app: 'profile',
    payload_location: 'inline',
    payload: json_data
};
```

## Attestation profile

Attestation profile is similar to previous one with one difference that `attestation` type message are posted by somebody and they describe somebody else. These profiles are used to do KYC by [asking user to provide data about themselves from trusted attestor](/private-profiles#requesting-private-profile).

### Private/Public attestations

[Real Name Attestation](https://github.com/byteball/real-name-attestation) bot creates an `attestation` profile, which keeps all the data private on user device while makes it possible for the others to recognize unique users by `user_id` (it's a salted hash of `first_name`, `last_name`, `dob` and `country`) and also makes it possible to validate with `profile_hash` if user provides them a private profile.

```javascript
const conf = require('ocore/conf.js');
const objectHash = require('ocore/object_hash.js');

let bPublic = false; // ask user if they want public or private profile

function hideProfile(profile, bPublic = false){
    const composer = require('ocore/composer.js');
    let hidden_profile = {};
    let src_profile = {};
    for (let field in profile){
        let value = profile[field];
        let blinding = composer.generateBlinding();
        let hidden_value = objectHash.getBase64Hash([value, blinding], true);
        hidden_profile[field] = hidden_value;
        src_profile[field] = [value, blinding];
    }
    let shortProfile = {
        first_name: profile.first_name,
        last_name:  profile.last_name,
        dob:        profile.dob,
        country:    profile.country,
    };
    let public_profile;
    if (bPublic) {
        public_profile = profile;
        public_profile.user_id = objectHash.getBase64Hash([shortProfile, conf.salt]);
        return [public_profile, null];
    }
    else {
        public_profile = {
            profile_hash: objectHash.getBase64Hash(hidden_profile, true),
            user_id: objectHash.getBase64Hash([shortProfile, conf.salt])
        };
        return [public_profile, src_profile];
    }
}

let profile = {
    first_name: "", // required
    last_name:  "", // required
    dob:        "", // required
    country:    "", // required
    us_state:   "", // optional
    id_type:    ""  // optional
};
for (let field in profile){
    if (typeof profile[field] === 'undefined' || profile[field] === null || profile[field] === '') {
        // remove negative values, except number 0
        delete profile[field];
    }
    else {
        // convert everything else to string
        profile[field] = String(profile[field]);
    }
}
let [public_data, src_profile] = hideProfile(profile, bPublic);
let json_data = {
    address: 'ABCDEF...',
    profile: public_data
};
let objMessage = {
    app: 'attestation',
    payload_location: 'inline',
    payload: json_data
};
```

In case user would want to make their profile public like with [Email Attestation](https://github.com/byteball/email-attestation) and [Steem Attestation](https://github.com/byteball/steem-attestation), `true` could be sent as a second parameter of `hideProfile()` function. To avoid people doxxing themselves, the possibility to make public attestation with Real Name Attestation has not been included. This choice is only on Email Attestation and Steem Attestation.

In order for the user to share private profile with others, your bot should also [send the private profile to user's wallet](/private-profiles#sending-private-profile).

### Public only attestations

If there is no plan to provide private attestations and all the attestation will always be public then there is no need for `user_id`. Then the attestation profile can be as simple as this, but the attestator needs to make sure that the same username attestation is not done to multiple users. One example of that kind is [Username Attestation bot](https://github.com/byteball/username-attestation).

```javascript
let json_data = {
    address: 'ABCDEF...',
    profile: {
        username: ""
    }    
};
let objMessage = {
    app: 'attestation',
    payload_location: 'inline',
    payload: json_data
};
```

For public attestation, there is not private profile to send to user's wallet because the bots who need information about the user could simply just [retrieve the attestation profile from the DAG](/private-profiles#retrieving-public-attestation).

## Poll question and choices

Anybody can post a poll and let others vote on it, this can be done like this data and it will also appear on [obyte.io](https://obyte.io/polls) web service from where it will direct users to [Poll chat bot](https://github.com/byteball/poll-bot).

```javascript
let json_data = {
    question: 'abc?', 
    choices: [
        'a',
        'b',
        'c',
    ]        
};
let objMessage = {
    app: 'poll',
    payload_location: 'inline',
    payload: json_data
};
```

## Plain text data

And last and not the least, it is possible to post plain text to DAG too.

```javascript
let text_data = '';
let objMessage = {
    app: 'text',
    payload_location: 'inline',
    payload: text_data
};
```

## More examples

Shorter code examples using composer library are available in ["/tools" folder of headless-wallet](https://github.com/byteball/headless-obyte/tree/master/tools).

If you wish to send data to DAG database periodically then full code examples for [price oracle](https://github.com/byteball/byteball-data-feed), [bitcoin oracle](https://github.com/byteball/btc-oracle) or [sports oracle](https://github.com/byteball/sports-oracle) can be found on Github.


# Contracts

Obyte provides users with the ability to create Smart Contracts as well as simple prosaic contracts.

There are two ways of making a contract between two Obyte users: either to agree on some conditions and formalize them in our Smart Contract Language, which later can be evaluated by machine code and decide who spends the money from the contract ([Smart Contracts](/contracts/smart-contracts)), or just publish a hash of simple prosaic text of a contract into DAG ([Prosaic Contracts](/contracts/prosaic-contracts)).

If you are looking to build more complex dApps that are as capable as Ethereum smart-contracts, then you need to use [Autonomous Agents](/autonomous-agents).


# Smart contracts

Smart contracts on Obyte are expressions that evaluate to true or false, the money stored on the contract can be spent only when it evaluates to true.

The smart contract language is declarative, meaning that it expresses **what** conditions must be met to allow movement of money, rather than **how** the decisions are made. This makes it easy to see that the implementation of the contract matches its intent, and hard to make mistakes (which cannot be undone in distributed ledgers).

However, the language is not as powerful as Ethereum’s Solidity, it is not Turing-complete, it doesn’t allow to code any program, rather it is a domain specific language for money on the distributed ledger. They are more like [Discreet Log Contracts](https://adiabat.github.io/dlc.pdf) for Bitcoin. If you are looking to build more complex dApps that are as capable as Ethereum smart-contracts, then you need to use [Autonomous Agents](/autonomous-agents).

Money on Obyte is stored on addresses. Address is just a hash (plus checksum) of an [address definition](/contracts/reference), and the address definition is an expression in the Obyte smart contract language that evaluates to either `true` or `false`.

## Offering smart contracts

When you want to create a new smart contract with a user, your sequence is usually as follows:

* you ask the user to send his payment address (it will be included in the contract)
* you define a new contract using the user's address and your address as parties of the contract
* you pay your share to the contract
* at the same time, you send a specially formatted payment request (different from the payment request above) to the user to request his share. You start waiting for the user's payment
* the user views the contract definition in his wallet and agrees to pay
* you receive the payment notification and wait for it to get confirmed
* after the payment is confirmed, the contract is fully funded

We'll discuss creating and offering contracts below. These two steps are similar to what happens in the GUI wallet when a user designs a new contract.

### Creating contract definition

Create a JSON object that defines the contract:

```javascript
var arrDefinition = ['or', [
    ['and', [
        ['address', user_address],
        // conditions when user can unlock the contract
    ]],
    ['and', [
        ['address', bot_address],
        // conditions when I can unlock the contract
    ]]
]];
```

Create another object that describes the positions of your and user addresses in the above definition:

```javascript
var device = require('ocore/device.js');
var assocSignersByPath = {
    'r.0.0': {
        address: user_address,
        member_signing_path: 'r', // unused, should be always 'r'
        device_address: from_address
    },
    'r.1.0': {
        address: bot_address,
        member_signing_path: 'r', // unused, should be always 'r'
        device_address: device.getMyDeviceAddress()
    }
};
```

The keys of this object are `r` (from "root") followed by indexes into arrays in the definition's `or`and `and` conditions. Since the conditions can be nested, there can be many indexes, they are separated by dot.

Then you create the smart contract address:

```javascript
var walletDefinedByAddresses = require('ocore/wallet_defined_by_addresses.js');
walletDefinedByAddresses.createNewSharedAddress(arrDefinition, assocSignersByPath, {
    ifError: function(err){
        // handle error
    },
    ifOk: function(shared_address){
        // new shared address created
    }
});
```

If the address was successfully created, it was also already automatically sent to the user, so the user's wallet will know it.

Example of vesting contracts: [Real Name Attestation](https://github.com/byteball/real-name-attestation/blob/master/modules/contract.js), [Steem Attestation](https://github.com/byteball/steem-attestation/blob/master/modules/contract.js), [Bitcointalk attestation](https://github.com/byteball/bitcointalk-attestation/blob/master/modules/contract.js).\
Examples with oracles: [Flight Delays Insurance](https://github.com/byteball/flight-delays-insurance/blob/master/offerContract.js), [GUI wallet](https://github.com/byteball/obyte-gui-wallet/blob/master/src/js/controllers/correspondentDevice.js).\
Examples with tokens: [Condiitonal token sale](https://github.com/byteball/conditional-token-sale/blob/master/offerContractReversePayment.js), [Exchange bot](https://github.com/byteball/obyte-exchange/blob/master/book.js).

More definition examples can be seen on [smart contracts definitions page](/contracts/reference).

### Sending a request for contract payment

To request the user to pay his share to the contract, create the below Javascript object `objPaymentRequest` which contains both the payment request and the definition of the contract, encode the object in base64, and send it over to the user:

```javascript
var payments = [
    {address: shared_address, amount: peer_amount, asset: peerAsset}
];
var definitions = {};
definitions[shared_address] = {
    definition: arrDefinition,
    signers: assocSignersByPath
};
var objPaymentRequest = {payments, definitions};
var paymentJson = JSON.stringify(objPaymentRequest);
var paymentJsonBase64 = Buffer.from(paymentJson).toString('base64');
var paymentRequestCode = 'payment:'+paymentJsonBase64;
var paymentRequestText = '[...]('+paymentRequestCode+')';

device.sendMessageToDevice(from_address, 'text', paymentRequestText);
```

The user's wallet will parse this message, display the definition of the contract in a user-readable form, and offer the user to pay the requested amount. Your payment-waiting code will be called when the payment is seen on the DAG.

## Re-sending lost smart-contracts

Since smart-contracts are private until they have been spent, users might loose them if they probably didn't backup their wallet or restored from seed words. Some attestation bots lock user's reward for months or years into smart-contracts and it would be more user-friendly if users could still restore the smart-contract even after they have lost it. Since all parties (2 or more) have the definition of the smart-contract in their wallet, one could ask to resend it from the other. With chat bots, this could be done like this:

```javascript
const eventBus = require('ocore/event_bus.js');

eventBus.on('text', function(from_address, text) {
	const device = require('ocore/device.js');

	if (text === 'resend') {
		const walletDefinedByAddresses = require('ocore/wallet_defined_by_addresses');
		walletDefinedByAddresses.sendToPeerAllSharedAddressesHavingUnspentOutputs(from_address, 'base', {
			ifFundedSharedAddress: function(numberOfContracts) {
				device.sendMessageToDevice(from_address, "text",
					`Found and resent ${numberOfContracts} smart contracts that have Bytes on them to your wallet.`
				);
			},
			ifNoFundedSharedAddress: function() {
				device.sendMessageToDevice(from_address, "text",
					`No smart contracts with Bytes on it were found.`
				);
			}
		});
	}
});
```


# Smart contract language reference

## Authentication

These clauses authenticate the author(s) of the unit.

### sig

Here is an example of the simplest address definition that defines an address controlled by a single private key:

```javascript
["sig", {"pubkey": "Ald9tkgiUZQQ1djpZgv2ez7xf1ZvYAsTLhudhvn0931w"}]
```

The pubkey above is base64-encoded public key. The `sig` expression evaluates to `true` if the signature provided with the transaction is valid and produced by the private key that corresponds to the above public key. The address (checksummed hash in base32) corresponding to this definition is A2WWHN7755YZVMXCBLMFWRSLKSZJN3FU.

### hash

This clause evaluates to `true` if the author supplies a preimage of the hash specified in the address definition.

```javascript
["hash", {"hash": "value of sha256 hash in base64"}]
```

## Logical operators

These clauses allow to combine other conditions with logical operators.

### and, or

All expressions in this language evaluate to a boolean value, and multiple boolean subexpressions can be combined using boolean operators `and` and `or`. For example, this is a definition that requires two signatures:

```javascript
["and", [
    ["sig", {pubkey: "one pubkey in base64"}],
    ["sig", {pubkey: "another pubkey in base64"}]
]]
```

To spend funds from the address equal to the hash of the above definition, one would need to provide two signatures.

As you noticed, we use JSON to construct the language expressions. This is an unusual choice but allows to use existing well-debugged, well-supported, and well-optimized JSON parsers rather than invent our own.

“Or” condition can be used to require signatures by any one of the listed public keys:

```javascript
["or", [
    ["sig", {pubkey: "laptop pubkey"}],
    ["sig", {pubkey: "smartphone pubkey"}],
    ["sig", {pubkey: "tablet pubkey"}]
]]
```

The above is useful when you want to control the same address from any of the 3 devices: your laptop, your phone, and your tablet.

The conditions can be nested:

```javascript
["and", [
    ["or", [
        ["sig", {pubkey: "laptop pubkey"}],
        ["sig", {pubkey: "tablet pubkey"}]
    ]],
    ["sig", {pubkey: "smartphone pubkey"}]
]]
```

### r of set

A definition can require a minimum number of conditions to be true out of a larger set, for example, a 2-of-3 signature:

```javascript
["r of set", {
    required: 2,
    set: [
        ["sig", {pubkey: "laptop pubkey"}],
        ["sig", {pubkey: "smartphone pubkey"}],
        ["sig", {pubkey: "tablet pubkey"}]
    ]
}]
```

(“r” stands for “required”) which features both the security of two mandatory signatures and the reliability, so that in case one of the keys is lost, the address is still usable and can be used to change its definition and replace the lost 3rd key with a new one, or to move the funds to another address.

### weighted and

Also, different conditions can be given different weights, of which a minimum is required:

```javascript
["weighted and", {
    required: 50,
    set: [
        {weight: 40, value: ["sig", {pubkey: "CEO pubkey"}] },
        {weight: 20, value: ["sig", {pubkey: "COO pubkey"}] },
        {weight: 20, value: ["sig", {pubkey: "CFO pubkey"}] },
        {weight: 20, value: ["sig", {pubkey: "CTO pubkey"}] }
    ]
}]
```

### not

Subsequent conditions can be negated with `not` clause:

```javascript
["not", ["in data feed", [["NOAA ADDRESS"], "wind_speed", ">", "200"]]]
```

Since it is legal to select very old parents (that didn’t see the newer data feed posts), one usually combines negative conditions such as the above with the requirement that the timestamp is after a certain date.

`sig`, `hash`, `address`, `cosigned by`, and `in merkle` cannot be negated.

## References

These clauses redirect the evaluation of the subdefinition to something else.

### address

A definition can contain reference to another address using `address` clause:

```javascript
["and", [
    ["address", "ADDRESS 1 IN BASE32"],
    ["address", "ADDRESS 2 IN BASE32"]
]]
```

which delegates signing to another address and is useful for building shared control addresses (addresses controlled by several users in contracts). This syntax gives the users the flexibility to change definitions of their own component addresses whenever they like, without bothering the other user.

### definition template

A definition can reference a definition template:

```javascript
["definition template", [
    "hash of unit where the template was defined",
    {param1: "value1", param2: "value2"}
]]
```

The parameters specify values of variables to be replaced in the template. The template needs to be saved before (and as usual, be stable before use) with a special message type app=“definition\_template”, the template itself is in message payload, and the template looks like normal definition but may include references to variables in the syntax @param1, @param2. Definition templates enable code reuse. They may in turn reference other templates.

## Extrospection

These clauses inspect data **outside** of the current unit.

### in data feed

`in data feed` clause can be used to make queries about data previously stored on Obyte:

```javascript
["in data feed", [
    ["ADDRESS1", "ADDRESS2", …], 
    "data feed name", 
    "=", 
    "expected value"
]]
```

This condition evaluates to `true` if there is at least one previous message stored in Obyte database that has “data feed name” equal to “expected value”. Instead of `=`, you can also use `>`, `<`, `>=`, `<=`, or `!=` The data feed must be posted to Obyte decentralized database by one of the oracles whose addresses are “ADDRESS1”, “ADDRESS2”, … Since oracles post to the common database, we call them on-chain oracles.

On-chain oracles are a very powerful thing indeed. For example, this address definition represents a binary option:

```javascript
["or", [
    ["and", [
        ["address", "ADDRESS 1"],
        ["in data feed", [["EXCHANGE ADDRESS"], "EURUSD", ">", "1.2500"]]
    ]],
    ["and", [
        ["address", "ADDRESS 2"],
        ["timestamp", [">", Math.round(Date.now()/1000 + timeout_seconds)]]
    ]]
]]
```

Initially, the two parties fund the address defined by this definition by sending their respective stakes to the address. Then if the EUR/USD exchange rate published by the exchange address ever exceeds 1.2500, the first party can sweep the funds. If this doesn’t happen before timeout period, the second party can sweep all the funds stored on this address.

Another example would be a customer who buys goods from a merchant but he doesn’t quite trust that merchant and wants his money back in case the goods are not delivered. The customer pays to a shared address defined by:

```javascript
["or", [
    ["and", [
        ["address", "MERCHANT ADDRESS"],
        ["in data feed", [["FEDEX ADDRESS"], "tracking", "=", "123456"]]
    ]],
    ["and", [
        ["address", "BUYER ADDRESS"],
        ["timestamp", [">", Math.round(Date.now()/1000 + timeout_seconds)]]
    ]]
]]
```

The definition depends on the FedEx oracle that posts tracking numbers of all successfully delivered shipments. If the shipment is delivered, the merchant will be able to unlock the money using the first condition. If it is not delivered before the specified timeout period, the customer can take his money back. This example is somewhat crazy because it requires FedEx to post each and every shipment. See `in merkle` clause below for a more practical way to achieve the same result.

### in merkle

`in merkle` is a more economical way to query the presence of a particular data entry in a large data set. Instead of posting every data entry in a `data_feed` message, only the merkle root of the large data set is posted as a `data_feed`, and the signer has to provide the data entry and its merkle path:

```javascript
["in merkle", [
    ["ADDRESS1", "ADDRESS2", ...],
    "data feed name",
    "expected value"
]]
```

### seen address

```javascript
["seen address", "ANOTHER ADDRESS IN BASE32"]
```

This clause evaluates to `true` if the specified address was seen as author in at least one past unit included in the last stable unit.

### seen

```javascript
["seen", {
    what: "output",
    address: "ADDRESS",
    asset: "asset or base",
    amount: 12345
}]
```

This clause evaluates to `true` if there was an input or output in the past (before last stable unit) that satisfies the specified condition. The syntax for the search condition is the same as for `has` clause below.

### seen definition change

```javascript
["seen definition change", ["ADDRESS", "NEW DEFINITION CHASH"] ]
```

This clause evaluates to `true` if there was a definition change of the specified address and the c-hash (checksummed hash) of the new definition is equal to the specified value.

### age

```javascript
["age", [">", 1234]]
```

This clause evaluates to `true` if the age of all inputs spent from this address satisfies the specified condition. The age is the difference between last ball mci and the input’s mci.

### attested

```javascript
["attested", ["ADDRESS", ["ATTESTOR1", "ATTESTOR2", ...]]]
```

This clause evaluates to `true` if the specified address is attested by one of the listed attestors. The address can also be “this address”.

## Introspection

These clauses inspect data **within** the current unit

### cosigned by

A subdefinition may require that the transaction be cosigned by another address:

```javascript
["cosigned by", "ANOTHER ADDRESS IN BASE32"]
```

### has, has one

A definition can also include queries about the transaction itself, which can be used for example to code limit orders on a trustless exchange. Assume that a user wants to buy 1,200 units of some asset for which he is willing to pay no more than 1,000 bytes (the native currency of Obyte). Also, he is not willing to stay online all the time while he is waiting for a seller. He would rather just post an order at an exchange and let it execute when a matching seller comes along. He can create a limit order by sending 1,000 bytes to an address defined by this definition, which makes use of `has` clause:

```javascript
["or", [
    ["address", "USER ADDRESS"],
    ["and", [
        ["address", "EXCHANGE ADDRESS"],
        ["has", {
            what: "output", 
            asset: "ID of alternative asset", 
            amount_at_least: 1200, 
            address: "USER ADDRESS"
        }]
    ]]
]]
```

The first or-alternative lets the user take back his bytes whenever he likes, thus cancelling the order. The second alternative delegates the exchange the right to spend the funds, provided that another output on the same transaction pays at least 1,200 units of the other asset to the user’s address. The exchange would publicly list the order, a seller would find it, compose a transaction that exchanges assets, and sign it together with the exchange. Note that the exchange does not receive arbitrary control over the user’s funds, it can spend them only if it simultaneously pays the alternative asset to the user, while the user retains full control over his funds and can withdraw them from the contract when he likes.

The `has` clause evaluates to `true` if the transaction has at least one input or output that satisfies all the set conditions:

* `what`: `input` or `output`, required
* `asset`: ID of asset (44-character string) or `base` for bytes
* `type`: for inputs only, `transfer` or `issue`. If specified, it searches only transfers or only issues
* `amount_at_least`, `amount_at_most`, `amount`: amount must be at least, at most, or exactly equal to the specified value
* `address`: address where the output is sent to or the input is spent from, can be literal address or “this address” or “other address”

Similar clause `has one` has exactly the same syntax but evaluates to true if there is exactly one input or output that satisfies the search conditions.

### has equal, has one equal

The following requirement can also be included in a subdefinition:

```javascript
["has equal", {
    equal_fields: ["address", "amount"],
    search_criteria: [
        {what: "output", asset: "asset1", address: "ADDRESS IN BASE32"},
        {what: "input", asset: "asset2", type: "issue", address: "ANOTHER ADDRESS IN BASE32"}
    ]
}]
```

It evaluates to `true` if there is at least one pair of inputs or outputs that satisfy the search criteria and the fields specified in `equal_fields` are equal. The first element of the pair is searched by the first set of filters, the second by the second, and the syntax for the search conditions is the same as in `has` clause.

A similar condition `has one equal` requires that there is exactly one such pair.

### sum

This clause evaluates to `true` if the sum of inputs or outputs that satisfy the filter is equal, at least, or at most the target value.

```javascript
["sum", {
    filter: {
        what: "input"|"output", asset: "asset or base", type: "transfer"|"issue",
        address: "ADDRESS IN BASE32"
    },
    at_least: 120,
    at_most: 130,
    equals: 123
}]
```

The syntax for the filter is the same as for `has` clause.

### has definition change

```javascript
["has definition change", ["ADDRESS", "NEW DEFINITION CHASH"] ]
```

This clause evaluates to `true` if the unit has a definition change of the specified address and the c-hash (checksummed hash) of the new definition is equal to the specified value.

### mci

```javascript
["mci", ">", 123456]
```

This clause evaluates to `true` if `last_ball_mci` of the current unit is greater than (other possible comparisons: `>=`, `<`, `<=`, `=`) than the specified value. It can be useful to make the address spendable only after some point in the future and not rely on any timestamp oracles.

### timestamp

```javascript
['timestamp', ['>', Math.round(Date.now() / 1000 + 2 * 3600)]]
```

This clause evaluates to `true` If the time is longer than the specified time. You can also use `"=", "<", ">=", "<=", "!="`. This example returns true 2 hours after the deployment.


# Prosaic contracts

Prosaic contracts are the feature of Obyte platform that helps people to make an agreement on, basically, anything, as text of contracts is a simple text. The benefit of using Obyte prosaic contracts is that after both sides of the contract sign it, a unit, which in fact is a public proof of contract agreement, is posted into DAG, which contains a hash of contract text, while being signed by both peers of the contract. So anyone can check the fact of agreement on the exact same text by those two contract peers. The contract text itself is not revealed but stored in peers wallets.

To offer a prosaic contract from your bot, you have to follow these steps:

* user pairs with your bot.
* you ask the user to send his payment address (it will be included in the contract) in the chat.
* you [send the user the private profile](/private-profiles#sending-private-profile) of the other side of the contract.
* you create a new prosaic contract using the user's address and your address as parties of the contract (also defining contract's title, text and how long the offer is valid).
* you send specially formatted chat message with the contract to the user and wait for the response on it ('accept' or 'decline').
* the user views the contract in his wallet and agrees or declines it.
* on receiving 'accepted' response, you generate new shared address with special definition ('and' between two addresses).
* then you top up this shared address to compensate fees.
* you initiate posting a 'data' message from this shared address, containing contract text hash. User will then be asked to sign this transaction from the same shared address (as he is a part of its definition).
* after getting the user's signature for the 'data' unit, you post it into DAG. Mission accomplished.

We have a special wrapper API for all of these steps in `ocore/prosaic_contract_api.js`, which in turn is calling `ocore/prosaic_contract.js` methods. For simplicity, here is an example of using `*_api.js`, you can check it's code to get a better understanding of what's going on.

{% code title="start.js" %}

```javascript
"use strict";
const headlessWallet = require('headless-obyte');
const eventBus = require('ocore/event_bus.js');
const prosaic_contract = require('headless-obyte/prosaic_contract_api.js');

function onReady() {
    prosaic_contract.listenForPendingContracts(headlessWallet.signWithLocalPrivateKey);

    let contract_text = "I pay Tom $20, if he sends me a pair of his Air Jordans.";
    let contract_title = "Air Jordans Purchase from Tom";
    let contract_is_valid_until = 24; //hours

    headlessWallet.readFirstAddress(my_address => {
        let peer_address = "62SU7724ME5MWB7VEP64VURYZHDRSDWN";
        let peer_device_address = "0PUQK5HOEKS4NONGL2ITJI3HMJ76P3LKI";
        prosaic_contract.offer(contract_title,
                                contract_text,
                                my_address,
                                peer_address,
                                peer_device_address,
                                contract_is_valid_until,
                                [],
                                headlessWallet.signWithLocalPrivateKey, {
            onOfferCreated: function(objContract) {
                console.log("on offer created", objContract);
            },
            onResponseReceived: function(accepted) {
                console.log("on response received", accepted);
            },
            onSigned: function(objContract) {
                console.log("on signed", objContract);
            },
            onError: function(error) {
                console.log("on error", error);
            }
        });
    });
};
eventBus.once('headless_wallet_ready', onReady);
```

{% endcode %}

`callbacks` object consists of four optional callback functions, which called in following sequence:

* `onOfferCreated` is called right after the contract was created and sent to peer. Always called.
* `onResponseReceived` is called when peer respond to the contract, supplying the response in `accepted` bool argument.
* `onSigned` indicates that the contract was successfully signed and unit with contract's hash was posted into DAG.
* `onError` can only happen when handling the response, if your bot did receive any response, either `onError` or `onSigned` will be called.

The core module for prosaic contracts is [ocore/prosaic\_contract.js](https://github.com/byteball/ocore/blob/master/prosaic_contract.js). You can directly use it's exported methods, so check the content of it first.


# Contracts with arbitration

Contracts with arbitration are peer-to-peer free-form textual contracts coupled with simple smart contracts that safely lock the money for the duration of the contract and allow disputes to be resolved by mutually agreed arbiters. In other words, a contract with arbitration is a [prosaic contract](/contracts/prosaic-contracts) plus a smart contract that guarantees that the parties faithfully follow the contract.

If you are developing a bot that makes contract offers, here is an outline of the contract's lifecycle:

* Your bot (offerer) receives a user's address in chat from a user.
* The bot then sends a contract with arbitration offer to the user. In the offer, it sets the user's address as the other party of the contract, amount of the contract, and an arbiter's address of your choosing. You can also choose the role for your bot in this contract (buyer or seller).
* The user reviews the offer in their wallet and accepts the contract.
* Your bot receives the user's acceptance, generates a new shared address with smart contract definition, and initiates signing and posting of a special `data` unit with the hash of the agreed contract text. The unit is to be signed by the shared address (shared between the bot and the user) and each party's signature means that they agree with the contract's text. Your bot signs first, then waits for the user to sign the transaction.
* After the unit has been posted, the buyer side of the contract should pay to this contract's address the full amount that was specified in the contract.
* As soon as the funds are locked on the contract, the seller of the goods/services starts fulfilling their obligations.
* When all the work is done and the buyer is satisfied with the result, they can release the funds from the contract sending them to the seller's address. Also at any time the seller can refund the full amount back to the buyer. The smart contract ensures that in the absence of any arbiter decision each party can send the contract's funds only to the other party: buyer to the seller to release the funds after the work is done, or seller to the buyer to refund. Either outcome completes the contract.
* In case of a disagreement, the user can open a dispute and invoke the arbiter by clicking the corresponding button in their wallet, or your bot can call an API method to open a dispute. The plaintiff has to pay for the arbiter's service before the arbiter starts looking into the case. After the contract status becomes `in_dispute`, both parties have to wait for the arbiter to post a resolution unit. After the arbiter has studied the contract and the evidence provided by the parties, they make a decision and post the resolution unit. Then, the winning side can claim the funds from the contract.

Note that in order to open a dispute from the bot, your bot should implement the corresponding API (see below). After you open a dispute, the arbiter will set a fee for their service and the arbstore will send a payment request to your bot. Your bot should be able to handle such requests and decide about paying them, either autonomously, or forward them to a human operator.

All the API methods available for your bot are located in [ocore/arbiter\_contract.js](https://github.com/byteball/ocore/blob/master/arbiter_contract.js) file.

#### Example

There is an example script for a part of the API functionality in [tools/arbiter\_contract\_example.js](https://github.com/byteball/headless-obyte/blob/master/tools/arbiter_contract_example.js) inside `headless-wallet` repository, you can start by modifying it to your needs:

```javascript
"use strict";
const headlessWallet = require('../start.js');
const eventBus = require('ocore/event_bus.js');
const arbiter_contract = require('ocore/arbiter_contract.js');
const device = require('ocore/device.js');
const validationUtils = require('ocore/validation_utils');

function onReady() {
	let contract_text = "Bill pays Tom $20, if Tom sends Bill a pair of his Air Jordans.";
	let contract_title = "Air Jordans Purchase from Tom";
	let amount = 10000; // in bytes, min 10000
	let asset = null;
	let ttl = 24; //hours
	let arbiter_address = "VYDZPZABPIYNNHCPQKTMIKAEBHWEW3SQ";
	let my_contacts = `Email me at: bill@example.com`;
	let me_is_payer = true;

	let my_address;
	headlessWallet.readFirstAddress(address => {
		my_address = address;
	});

	eventBus.on('paired', from_address => {
		device.sendMessageToDevice(from_address, 'text', `My address: ${my_address}, now send me your's.`);
	});

	/* ================ OFFER ================ */
	eventBus.on('text', (from_address, text) => {
		text = text.trim();
		if (!validationUtils.isValidAddress(text))
			return device.sendMessageToDevice(from_address, 'text', `does not look like an address`);
		let contract = {
			title: contract_title,
			text: contract_text,
			arbiter_address: arbiter_address,
			amount: amount,
			asset: asset,
			peer_address: text,
			my_address: my_address,
			me_is_payer: me_is_payer,
			peer_device_address: from_address,
			ttl: ttl,
			cosigners: [],
			my_contact_info: my_contacts
		};

		arbiter_contract.createAndSend(contract, contract => {
			console.log('contract offer sent', contract);
		});
	});

	/* ================ OFFER ACCEPTED ================ */
	eventBus.on("arbiter_contract_response_received", contract => {
		if (contract.status != 'accepted') {
			console.warn('contract declined');
			return;
		}
		arbiter_contract.createSharedAddressAndPostUnit(contract.hash, headlessWallet, (err, contract) => {
			if (err)
				throw err;
			console.log('Unit with contract hash was posted into DAG\nhttps://explorer.obyte.org/#' + contract.unit);

	/* ================ PAY TO THE CONTRACT ================ */
			if (contract.me_is_payer) {
				arbiter_contract.pay(contract.hash, headlessWallet, [],	(err, contract, unit) => {
					if (err)
						throw err;
					console.log('Unit with contract payment was posted into DAG\nhttps://explorer.obyte.org/#' + unit);

					setTimeout(() => {completeContract(contract)}, 3 * 1000); // complete the contract in 3 seconds
				});
			}
		});
	});

	/* ================ CONTRACT FULFILLED - UNLOCK FUNDS ================ */
	function completeContract(contract) {
		arbiter_contract.complete(contract.hash, headlessWallet, [], (err, contract, unit) => {
			if (err)
				throw err;
			console.log(`Contract completed. Funds locked on contract with hash ${contract.hash} were sent to peer, unit: https://explorer.obyte.org/#${unit}`);
		});
	}

	/* ================ CONTRACT EVENT HANDLERS ================ */
	eventBus.on("arbiter_contract_update", (contract, field, value, unit) => {
		if (field === "status" && value === "paid") {
			// do something usefull here
			console.log(`Contract was paid, unit: https://explorer.obyte.org/#${unit}`);
		}
	});
};
eventBus.once('headless_wallet_ready', onReady);
```

Basically, all you need to do is calling the exported methods of `arbiter_contract.js` module and reacting to `arbiter_contract_*` events on the event bus.

#### API reference:

1. `createAndSend(contractObj, callback(contract){})`

   This method creates a contract from the provided object and sends it to the peer. `contractObj` should contain all the fields needed to assemble a new contract offer. The function is then sends the offer to the `contractObj.peer_device_address` via chat. The `contract` received in the callback function has `hash` field, it is the contract's hash which acts as the primary key when referencing contracts.

   `contractObj` required fields:

   1. `title` - contract title, `string`
   2. `text` - contract text, `string`
   3. `arbiter_address` - the address of the picked arbiter, `string`
   4. `amount` - amount in `asset` to be paid to the seller, `int`
   5. `asset` - asset in which the payment should be done, can be `null` or `"base"` for Bytes, or any other asset ID, `string`
   6. `peer_address` - address of the other side of the contract, `string`
   7. `my_address` - your address, `string`
   8. `me_is_payer` - flag specifying if you are the buyer or seller, `bool`
   9. `peer_device_address` - the device address of the other side of the contract, `string`
   10. `ttl` - Time-To-Live, in hours, till which the contract can be accepted, then it expires, `float`
   11. `cosigners` - array of your wallet cosigners that would be used when posting contract signature unit, leave empty if not multi-sig or when you want to use all of the cosigners, `array of device addresses`
   12. `my_contact_info` - free-form text with your contact info so the peer and arbiter can contact you, it is important to note that if you are sending contract offers from a bot, then arbiter can only pair with your bot and not you, therefore you should put your own wallet's pairing code here or other contacts by which you (as a human) can be reached,`string`

   `contract` object supplied to your callback will mostly be identical to the contractObj that you provided to this function, but with some additional fields populated, such as `hash, creation_date, my_pairing_code.`\\
2. `createSharedAddressAndPostUnit(contract_hash, walletInstance, callback(error, contract){})`

   This method is used to react to the peer accepting your offer. It creates a new shared address with smart contract definition and posts the unit into the DAG. `walletInstance` is a reference to wallet that has `sendMultiPayment()` method with an appropriate signer inside. For bots, it is usually the main `headlessWallet` module. If the `error` argument for the callback is `null`, it means that the unit was posted successfully, the `contract` object is returned with the updated fields.\\
3. `pay(contract_hash, walletInstance, arrSigningDeviceAddresses, callback(error, contract, unit){})`

   This method pays to the contract if you are the buyer side. If you use a multi-signature wallet, then fill the `arrSigningDeviceAddresses` array with signing device addresses, otherwise provide an empty array. The `unit` argument in the callback function is the unit ID in case the payment succeeded.\\
4. `complete(contract_hash, walletInstance, arrSigningDeviceAddresses, callback(error, contract, unit){})`

   This method sends the funds locked on the contract to the peer. Depending on your role, this action performs either a successful completion (you are a buyer), or a refund (you are the seller).\\
5. `respond(contract_hash, status, signedMessageBase64, signer, callback(error, contract){})`

   If you allow users to make offers, use this function after receiving a contract offer, usually as a reaction to the event `arbiter_contract_offer`. To get a better idea how to construct `signedMessageBase64` and `signer` arguments for this function, you can take a look at an example of how GUI wallet is invoking it: <https://github.com/byteball/obyte-gui-wallet/blob/95d3354de9f9156fd06ccc63c0a4cac8c94f2510/src/js/services/correspondentService.js#L669>\\
6. `openDispute(contract_hash, callback(error, response, contract){})`

   This function raises a dispute by making an HTTPS request to the contract arbiter's current ArbStore web address. Callback is provided with an error, if any, http response and the updated contract object.\\
7. `appeal(contract_hash, callback(error, response, contract){})`

   This method is similar to the previous one, but is used when you are not satisfied with the arbiter's decision. Also makes an HTTPS request to the ArbStore, but this time calls to ArbStore moderator, who can penalize the arbiter, in case they find the arbiter's decision / actions inappropriate.\\
8. `getByHash(contract_hash, callback(contract){})` / `getBySharedAddress(address, callback(contract){})` / `getAllBy*()`

   These are all similar functions to retrieve one or many contracts by specific criteria. To get a detailed overview of all the methods you can look at exported methods of `arbiter_contract.js` module.

#### Event reference

Almost every event is supplied with additional arguments that you can use in your event handler functions. For examples, see the code snippet above.

1. `arbiter_contract_offer : (contract_hash)` - this event is fired when core received new contract with arbitration offer from any correspondent.
2. `arbiter_contract_response_received : (contract)` - fired when user responds to your contract offer. To get their response, check the `status` field of the contract, it should be either `"accepted"` or `"declined"`.
3. `arbiter_contract_update : (contract, field, value, unit, winner, isPrivate)` - this is the most common event that you will react to. It is raised in many situations, like:
   * changed status of a contract: `field = "status"` (contract was `revoked`, or put `in_dispute`, `in_appeal`, was `paid`, `completed`, etc.). This is the full list of the contract statuses: `'pending', 'revoked', 'accepted', 'signed', 'declined', 'paid', 'in_dispute', 'dispute_resolved', 'in_appeal', 'appeal_approved', 'appeal_declined', 'cancelled', 'completed'`
   * unit with contract hash was posted: `field = "unit"`


# Autonomous Agents

An Autonomous Agent (AA) is a special address (account) on the ledger that acts according to a program associated with it. Its behavior is similar to that of a vending machine that receives coins and data entered on a keypad and in response, releases a cup of coffee, plays a song, or does whatever it was programmed to do.

[Getting started developer guide](/autonomous-agents/getting-started-guide)

[Introduction to Autonomous Agents](https://medium.com/obyte/introducing-autonomous-agents-6fe12fb12aa3) (announcement post on Medium)

## Oscript — the language of autonomous agents

Autonomous Agents are written in Oscript — a new programming language developed specifically for this purpose. The language is very simple and any developer who has experience in curly-brace languages such as JavaScript, PHP, Java, C/C++, etc should not have any difficulty learning it.

Some of the features of the language:

* convenient access to variables that describe the state of the ledger and the triggering (requesting, activating) transaction received. That’s what makes the language domain-specific. In particular, the following variables are available:
* amounts received in the triggering transaction;
* data received in the triggering transaction;
* who sent the triggering transaction;
* state variables of the current and other AAs;
* data feeds;
* attestations;
* balances of this and other AAs;
* information about assets;
* arithmetic operations;
* logical operations (AND, OR, etc);
* comparisons;
* concatenations;
* some math functions;
* some cryptography functions for calculating hashes and validating signatures created off-chain;
* branching with if/else;
* no loops (just iteration methods for objects and arrays);
* no recursive functions;
* scalar and object data types;
* generation of deterministic pseudo-random number from seed.

[Oscript language reference for Autonomous Agents](/autonomous-agents/oscript-language-reference)

![](/files/-Lk6IKWtce5vWRQYV4qm)

AA code can be deployed with [Oscript](https://oscript.org)[ (mainnet)](https://oscript.org)[ editor](https://oscript.org) and [Oscript](https://testnet.oscript.org/)[ (testnet)](https://testnet.oscript.org/)[ editor](https://testnet.oscript.org/). There is also a [extension for VS Code](https://marketplace.visualstudio.com/items?itemName=obyte.oscript-vscode-plugin) and [Autonomous Agent testkit](https://github.com/valyakin/aa-testkit).


# Getting started guide

Autonomous agents allow to quickly create decentralized finance applications on a distributed ledger.

They operate based on code that is deployed on the ledger once and can never be changed. The code is open and is executed by all nodes on the network.

Anybody can activate an AA just by sending a transaction to its address. Here is an example of a simple AA:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.output[[asset=base]] - 1000}"
                    }
                ]
            }
        }
    ]
}]
```

`messages` is a template of the response transaction that will be generated by the AA. It follows the structure of a regular Obyte transaction but its sections between curly braces {} contain code that makes the resulting transaction dependent on the triggering (activating) transaction. This is similar to how PHP code can be inserted into HTML to make the resulting page dependent on the request. The language autonomous agents are written in is called Oscript.

The above example of an AA just sends the received money less 1000 bytes back to the sender. `trigger.address` is the address of the sender who activated the AA. `trigger.output` allows to find the amounts in different currencies sent to the AA, `trigger.output[[asset=base]]` is the amount in the base asset -- bytes.

Another example that sells tokens for bytes at 1.5 tokens per byte:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                // this is the token being sold
                asset: "n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{ round(trigger.output[[asset=base]] * 1.5) }"
                    }
                ]
            }
        }
    ]
}]
```

This code needs to be deployed on the ledger before it can be used. Visit [oscript.org](https://oscript.org), copy/paste the above code, and click "Deploy". You'll then get the address of your new autonomous agent. Anybody can now send money to this address to trigger execution of this AA's code.

## Passing data to AA

AA's response can also depend on data it receives in the triggering transaction.

In Obyte, any transaction can contain one or more *messages* of different types. These types are called *apps*. The most common app is `payment`. At least one payment is mandatory in every transaction, it is necessary to at least pay fees. Another app is `data`. This type of message delivers an arbitrary json object that can contain any data:

```javascript
{
    app: "data",
    payload: {
        withdrawal_amount: 25000,
        nested_array: [
            99,
            {another_field: 44}
        ],
        nested_object: {yet_another_field: "value2"}
    },
     ...
}
```

The object in `payload` is the data this message delivers.

When an AA receives a data message (along with a payment message, of course) in the triggering transaction, it can access the data through `trigger.data` and its action can depend on the data received:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.data.withdrawal_amount}"
                    }
                ]
            }
        }
    ]
}]
```

The above AA tries to send `trigger.data.withdrawal_amount` bytes back to the sender. `withdrawal_amount` is a field in the data message of the triggering transaction:

```javascript
{
    withdrawal_amount: 3000
}
```

AAs can be triggered with data by manually entering the key/value pairs to GUI wallet, [prompting users to submit pre-filled Send screen](/byteball-protocol-uri#requesting-to-send-data-to-aa), making the [AA to trigger another AA](#sending-data) or with the [script from headless wallet](https://github.com/byteball/headless-obyte/blob/master/tools/send_data_to_aa.js).

## Handling errors

In the above example, if the `withdrawal_amount` is greater than the balance that the AA has (including the amount received from the triggering transaction), the AA's response will fail. When an AA fails to handle a trigger transaction for any reason, it rolls back all changes and attempts to send back to sender all the received funds, in all assets, less the bounce fees. By default, the bounce fees are 10000 bytes for "base" asset and 0 for all other assets. This is also the minimum. The default can be overridden by adding a `bounce_fees` field in the autonomous agent definition:

```javascript
["autonomous agent", {
    bounce_fees: {
        base: 20000,
        "n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=": 100
    },
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.data.withdrawal_amount}"
                    }
                ]
            }
        }
    ]
}]
```

The above AA will charge 20000 bytes and 100 units of the asset `"n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY="` if it has to bounce back a triggering transaction. Sending less than 20000 bytes to the AA will result in the AA silently eating the coins (they are not enough even for the bounce fees). When non-zero amount of asset `"n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY="` is sent to the AA, it should also be at least 100, otherwise the AA eats the coins.

## Sending data messages

As said above, `payment` is the most common message but other messages can be sent as well by any address, AA included.

### Sending data feeds

AA can act as an oracle by sending a data feed:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "data_feed",
            payload: {
                "{trigger.data.feed_name}": "{trigger.data.feed_value}"
            }
        }
    ]
}]
```

This example shows that object keys can also be parameterized through Oscript, like object values.

The above AA doesn't have a payment message, it will be added automatically just to pay for the fees.

### Sending data

An AA can also send any structured data:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "data",
            payload: {
                forwarded: 1,
                initial_data: "{trigger.data}"
            }
        },
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY",
                        amount: "{trigger.output[[asset=base]] - 1000}"
                    }
                ]
            }
        }
    ]
}]
```

Unlike `data_feed` messages, `data` messages:

* can have any structure with any nesting depth (data feeds are flat key-value pairs);
* are not indexed for search;
* can be used to pass data to other AAs.

The above AA forwards the received money (less 1000 bytes) to another address, which might be an AA. It also passes data, which includes the initially received data parameters. The value of `trigger.data` will be expanded into an object and added as value of `initial_data` field.

If the secondary recipient (`JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY`) happens to be an AA, its execution will start only after the execution of the current AA is finished. There is no reentrancy issue.

### Sending texts

```javascript
["autonomous agent", {
    messages: [
        {
            app: "text",
            payload: "{'Hello, ' || trigger.data.name || '!'}"
        }
    ]
}]
```

This AA will create a simple text message and store it on the DAG. `||` is the operator for string concatenation.

### Defining new assets

```javascript
["autonomous agent", {
    messages: [
        {
            app: "asset",
            payload: {
                cap: "{trigger.data.cap otherwise ''}",
                is_private: false,
                is_transferrable: true,
                auto_destroy: "{!!trigger.data.auto_destroy}",
                fixed_denominations: false,
                issued_by_definer_only: "{!!trigger.data.issued_by_definer_only}",
                cosigned_by_definer: false,
                spender_attested: false,
                attestors: [
                    "{trigger.data.attestor1 otherwise ''}",
                    "{trigger.data.attestor2 otherwise ''}",
                    "{trigger.data.attestor3 otherwise ''}",
                ]
            }
        }
    ]
}]
```

The above AA creates a definition of a new asset based on parameters passed in `data`.

Some syntax elements that we see here for the first time:

* `!` is a logical `NOT` operator;
* `otherwise` is an operator that returns the first operand if it is truthy (anything except false, 0, and empty string) or the second operand otherwise;
* when an object or array value evaluates to an empty string, the corresponding object/array element is removed. This means that if `cap` parameter is not passed then `cap` in `payload` evaluates to an empty string, therefore `cap` is removed from asset definition and an asset with infinite supply will be defined;
* fields whose value is an empty array/object are also removed. Therefore, if none of the `attestor1`, `attestor2`, `attestor3` fields was set, the `attestors` array becomes empty and will be excluded from the final definition.

## Querying state

The AA's behavior can also depend on various state variables that describe the ledger as a whole.

### Balance

```javascript
["autonomous agent", {
	messages: [
		{
			app: "payment",
			payload: {
				asset: "base",
				outputs: [
					{
						address: "{trigger.address}",
						amount: "{ round(balance[base]/2) }"
					}
				]
			}
		}
	]
}]
```

Balance of other AAs (but not regular addresses) can also be queried:

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{ (balance['JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY'][base] < 1e6) ? 'JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY' : trigger.address }",
                        amount: "{ trigger.output[[asset=base]] - 1000 }"
                    }
                ]
            }
        }
    ]
}]
```

The above AA forwards any received payment (less 1000 bytes) to another AA JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY if its balance is less than 1,000,000 bytes, or returns to sender otherwise.

### Data feeds

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{(data_feed[[oracles='TKT4UESIKTTRALRRLWS4SENSTJX6ODCW', feed_name='BROOKLYNNETS_CHARLOTTEHORNETS_2019-07-21']] == 'CHARLOTTEHORNETS') ? '7XZSBB32I5XPIAVWUYCABKO67TZLHKZW' : 'FDZVVIOJZZVFAP6FLW6GMPDYYHI6W4JG'}"
                    }
                ]
            }
        }
    ]
}]
```

The above AA pays to `7XZSBB32I5XPIAVWUYCABKO67TZLHKZW` if Charlotte Hornets won and to `FDZVVIOJZZVFAP6FLW6GMPDYYHI6W4JG` otherwise `TKT4UESIKTTRALRRLWS4SENSTJX6ODCW` is the address of a sports oracle that posts the results of sports events.

Before the data feed is posted, any attempt to evaluate it will fail the AA and bounce the triggering transaction.

Note that the `amount` field in the output is omitted, which means that the entire AA balance will be paid out.

### Attestations

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{ (attestation[[attestors='JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725', address=trigger.address]].reputation >= 50) ? 50000 : 0 }"
                    }
                ]
            }
        }
    ]
}]
```

The above AA pays to the triggering user 50000 bytes if his address is attested by Steem attestation bot `JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725` and his Steem reputation is at least 50. Otherwise, it "pays" 0 bytes. Trying to pay 0 amount results in the output being removed. Since it is the only output in this case and it is removed, the resulting response transaction would produce no effect, therefore it is not created at all.

## Variables

### State variables

An autonomous agent can have its own state saved between invocations. Use `var` to access and assign state variables:

```javascript
["autonomous agent", {
    messages: [
        {
            if: "{ var['previous_address'] }",
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{ var['previous_address'] }",
                        amount: "{ trigger.output[[asset=base]] - 1000 }"
                    }
                ]
            }
        },
        {
            app: "state",
            state: `{
                var['previous_address'] = trigger.address;
            }`
        }
    ]
}]
```

The above AA saves the address that sent the previous triggering transaction, waits for the next invocation, and sends the received money less 1000 bytes to the previous user.

Assigning state variables is only allowed in the special message with app set to `state`. This message must have a single other field called `state` which is a set of Oscript statements. These statements are allowed to assign state variables. The state message is not included in the final response transaction, it can only affect state by modifying the state variables.

When an uninitialized `var` is accessed, it evaluates to `false`.

The above example has an `if` field in the first message. When `var['previous_address']` is not initialized yet (first call), the `if` oscript evaluates to `false` and the entire first message is excluded from the transaction.

State variables of other AAs can also be read, but not assigned:

```javascript
var['JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY']['var_name']
```

### Local constants

Use local constants to save intermediate results during script execution.

```javascript
["autonomous agent", {
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{ trigger.address }",
                        amount: `{
                            $amount1 = trigger.output[[asset=base]] - 5000;
                            $amount2 = round(balance[base] * 0.9);
                            max($amount1, $amount2)
                        }`
                    }
                ]
            }
        }
    ]
}]
```

Local constant names are prefixed with $. Unlike state variables, they are not saved between invocations.

To make it easier to argue about a local constant's value, there is one restriction that is not common in other languages: single-assignment rule. A local constant can be assigned a value only once and that value remains constant until the end of the script. An attempt to re-assign a value will fail the script and make the AA bounce.

## Conditional sections

As we've seen in the State variables example before, some parts of the response transaction generated by the AA can be excluded by adding an `if` field. If the Oscript in the `if` evaluates to true or any truthy value (anything except false, 0, and empty string), the enclosing object is included in the final response, otherwise, it is excluded.

The `if` field itself is of course always removed from the final response.

## Initialization code

Along with `if`, any object can have an `init` field that includes initialization code:

```javascript
["autonomous agent", {
    messages: [
        {
            if: "{ trigger.data.pay }",
            init: `{
                $amount1 = trigger.output[[asset=base]] - 5000;
                $amount2 = round(balance[base] * 0.9);
            }`,
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{ trigger.address }",
                        amount: "{max($amount1, $amount2)}"
                    }
                ]
            }
        }
    ]
}]
```

The init code contains only statements, it does not return any value unlike most other Oscripts. The other exception is state message described in State variables above, it is also statements-only. All other Oscripts can contain 0 or more statements but must end with an expression (without a `;`) whose value becomes the value of the Oscript.

Init code is evaluated immediately after `if` (if it is present and evaluated to `true` of course) and before everything else. It is often used to set local constants that are used later.

## Local constants in if and init

Local constants that are set in `if` and `init` are also available in all other Oscripts of the current and nested objects. In the above example, `$amount1` and `$amount2` were set in `init` of the message object, and they are used in payload/outputs/output-0/amount of this message.

Local constants set in `if` are also available in the corresponding `init`.

## Statements-only vs return-value Oscripts

As said above, there are two types of Oscripts: those that contain only statements and those that return a value.

There are only two statements-only Oscripts: init and state script. Here is an example of an init script that we've seen before:

```javascript
{
    init: `{
        $amount1 = trigger.output[[asset=base]] - 5000;
        $amount2 = round(balance[base] * 0.9);
    }`,
     ...
}
```

All other Oscripts return a value. They either contain a single expression:

```javascript
{
    address: "{ trigger.address }",
     ...
}
```

or a set of statements and an expression at the end:

```javascript
{
    amount: `{
        $amount1 = trigger.output[[asset=base]] - 5000;
        $amount2 = round(balance[base] * 0.9);
        max($amount1, $amount2)
    }`,
     ...
}
```

The value of the last expression is the value of the Oscript.

## Cases

When you need to route the code execution along several mutually exclusive paths depending on input and environment parameters, use `cases`:

```javascript
["autonomous agent", {
    messages: {
        cases: [
            {
                if: "{trigger.data.define}",
                messages: [
                    // first version of messages
                    ....
                ]
            },
            {
                if: "{trigger.data.issue}",
                init: "{$amount = trigger.output[[asset=base]];}",
                messages: [
                    // second version of messages
                    ....
                ]
            },
            {
                messages: [
                    // default version of messages
                    ....
                ]
            }
        ]
    }
}]
```

The regular `messages` array is replaced with an object with a single element called `cases`. `cases` is an array that lists several mutually exclusive alternatives. Every alternative except the last must have an `if` field. The first alternative whose `if` evaluates to `true` defines the `messages` that will take the place of the higher-level `messages` field.

The conditions in the `if`s may not be mutually exclusive but the alternative that is listed earlier in the list takes precedence. Only one alternative is always taken.

In the above example, if `trigger.data` has no `define` field but has a truthy `issue` field, the 2nd alternative is selected, and the original object folds into:

```javascript
["autonomous agent", {
    messages: [
        // second version of messages
        ....
    ]
}]
```

Cases can be nested. Everything said above about `if`, `init`, and local constants, applies to `cases` as well.

## if else

The above examples showed how execution can be branched along different parts of json template.

Oscript code itself can be branched as well by using if/else:

```javascript
if (var['started']){
    $amount = balance[base];
    $current_winner = var['current_winner'];
}
else{
    $amount = trigger.output[[asset=base]];
    $current_winner = trigger.address;
}
```

## return

If you want to interrupt a script's execution and return from it, with or without a value, use `return`.

Here is an example of `return` in a return-value Oscript, it must return a value:

```javascript
$amount = trigger.output[[asset=base]];
if ($amount > 1e6)
    return $amount;
// here comes some other code that will not be executed if $amount > 1e6
```

A `return` in a statements-only Oscript, such as init, doesn't return any value, it just interrupts the script:

```javascript
$amount = trigger.output[[asset=base]];
if ($amount > 1e6)
    return;
// here comes some other code that will not be executed if $amount > 1e6
```

## bounce/require

If you find an error condition and want to prematurely stop the AA execution and bounce, use `bounce`:

```javascript
$maturity = var['maturity_timestamp'];
if (timestamp < $maturity) {
    bounce("too early");
}
```

or `require`:

```javascript
$maturity = var['maturity_timestamp'];
require(timestamp >= $maturity, "too early");
```

In this example, `timestamp` is roughly the current timestamp (number of seconds since Jan 1, 1970 00:00:00 UTC).

All applied changes will be rolled back and any received coins will be bounced back to the sender less the bounce fees.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

This was a quick introduction to programming of autonomous agents. Read the full [language reference](/autonomous-agents/oscript-language-reference) to learn more, and enjoy your journey through decentralized finance and beyond!


# Oscript language reference

## Autonomous agents

Autonomous agents (AA) are special addresses (accounts) on the ledger that do not belong to anybody. An AA can send transactions only in response to a triggering transaction sent to it and strictly according to a program associated with the AA. This program is open and known in advance, it specifies the AA's reaction to triggering transactions. The reaction depends on:

* coins sent by the triggering transaction: how much of which asset were sent;
* data sent by the triggering transaction;
* environment that exists in the ledger when the trigger is received: balances, data posted by oracles, attestations, state variables.

The AA's reaction can be one or a combination of:

* sending some other coins back to the sender or to a third party (which can be another AA);
* changing the environment of the ledger by posting data feeds, attestations, updating state variables, etc.

The behavior of autonomous agents is similar to vending machines: they accept coins and data entered on a keypad (the triggering action), and in response they release a cup of coffee or play a song, or do whatever they are programmed to do. What's common between them, their behavior is predictable, known in advance.

There are no private/public keys associated with AAs. Their transactions do not have signatures. Their transactions are created by all (full) nodes just by following the common protocol rules and executing the code associated with the AA. All nodes always come to the same result and produce exactly the same transaction that should be sent on behalf of the AA. As one comes to expect from a DAG, all nodes arrive at the same view of the ledger state just by following the rules, without any votings, proof-of competitions, or leaders.

The AA-generated transactions are not broadcast to peers as peers are expected to generate the same transactions on their own.

The language used to specify the AA behavior is a domain specific language that we call Oscript. It was designed specifically for AAs to make it easy to write an autonomous agent behavior, make it easy to argue about what is going on in the AA code, and make it hard to make difficult-to-track errors.

To control the resource consumption, the language does not support loops. Resource usage is controlled by setting a cap on the complexity of the program -- too resource heavy programs are simply not allowed. However, the resource caps provide enough room for the vast majority of practical applications.

AAs can "call" other AAs by sending coins to them. All the scripts in the calling AA are finished and all changes committed before passing control on to the next AA, this avoids completely the reentrancy problem common in other smart contract platforms.

## Autonomous agent definition

Addresses of autonomous agents follow the same general rules as all other Obyte addresses: their definitions are two-element arrays and the address is a checksummed hash of the array encoded in base32.

AA address is defined as:

```javascript
["autonomous agent", {
    // here goes the AA code
}]
```

The second element of the above array is an object that defines a template for future units created by the AA. The template's structure follows the structure of a regular unit in general, with some elements dynamic and dependent upon the input and state parameters. The dynamic elements are designated with special markup and include code in a domain specific language called Oscript:

```javascript
{
    address: "{trigger.address}",
    amount: "{trigger.output[[asset=base]] - 1000}"
}
```

The concept is similar to how such languages as PHP, ASP, and JSP work. For example, a PHP script is a HTML file interspersed with fragments of PHP code enclosed between `<?php` and `?>` tags. These fragments make the HTML page dynamic while keeping its HTML structure. While this mix can quickly become messy when PHP is used to generate HTML code, the ease of creating dynamic web pages by just inserting small pieces of code into HTML was one of the main selling points of these programming languages in the early days of the web. And it enabled quick prototyping, iteration, experimentation, and eventually led to the creation of some of the biggest pieces of the modern Internet (wordpress and facebook, to name a few).

Transactions, or storage units as we call them in Obyte, are similarly the basic building units of distributed ledgers. They are usually represented as JSON objects, which are the counterparts of HTML pages on the web. Now, to make it easy to create dynamic, parameterized JSON objects representing transactions, we allow to inject some code into JSON and invite the developers to apply their creativity and do the rest.

|       | Document format | Scripting language |
| ----- | --------------- | ------------------ |
| Web   | HTML            | PHP                |
| Obyte | JSON            | Oscript            |

This is an example of autonomous agent definition:

```javascript
["autonomous agent", {
    bounce_fees: { base: 10000 },
    doc_url: "https://example.com/doc_urls/{{aa_address}}.json",
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.output[[asset=base]] - 1000}"
                    }
                ]
            }
        }
    ]
}]
```

Here `messages` is a template for the AA's response transaction. It has only one message -- a payment message that will send the received amount less 1000 bytes back to sender. Omitting the `amount` entirely would send everything back (minus the fees). There are code fragments in strings enclosed in curly braces "{}", they are evaluated and the result is inserted in place of the code.

Before sending the resulting response transaction, the nodes on the network will also enhance it with change outputs (if necessary) and add other necessary fields in order to attach the transaction to the DAG: parents, last stable unit, authors, timestamp, fees, etc.

Below is a specification of the unit template format.

## JSON format

### bounce\_fees

```javascript
["autonomous agent", {
    bounce_fees: {
        base: 10000,
        "n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=": 100
    },
    ...
}]
```

This is an optional field of the unit template that specifies the fees charged from sender if the AA execution fails. In this case, all the received money in all assets is automatically bounced back to sender, less the bounce fees. The fees are keyed by asset ID (`base` for bytes).

The minimum and default bounce fee for bytes is 10000 bytes. The minimum and default bounce fee for all other assets is 0. Non-base bounce fees apply only to those assets that were actually received by the autonomous agent.

Sending to an autonomous agent anything less than the bounce fees will result in no response and the AA silently eating the coins. However this rule applies only to money sent from regular addresses. Bounce fees are not checked when the money is received from another AA.

`bounce_fees` field is removed from the final unit.

### doc\_url

Each deployed autonomous agent can have a URL that points to a JSON formatted documentation file, which content will be shown to users in wallet app. URL can contain `{{aa_address}}` placeholder, which will be replaced with actual AA address before fetching the JSON file. The structure of the JSON file should look like this:

```javascript
{
	"version": "1.0",
	"description": "Description shown to users",
	"homepage_url": "https://example.com",
	"source_url": "https://github.com/byteball/ocore",
	"field_descriptions": {
		"some_field_name": "Description how to use this parameter",
		"some_other_field_name": "Description how to use this other parameter",
		...
	}
}
```

Keys in `field_descriptions` object should match all the keys in `trigger.data` that users can use with this AA, wallet app will add value of that fields as an explanation what it does. The value of `version` should be as shown above (`"1.0"`) - it should NOT used as version of AA.

### messages

This is the main field of autonomous agent definition. It specifies templates for the messages to be generated, and the templates are parameterized with oscript code.

The messages can be of any type (called `app`) that Obyte supports. The most common app is `payment`, it is used to send payments in any asset back to sender or to a third party. Other apps are:

* `asset`: used to define a new asset. Different parameters that can be used are documented on [Issuing assets page](/issuing-assets-on-byteball#defining-a-new-asset);
* `data`: used to send data, this includes sending data parameters to other (secondary) AAs;
* `data_feed`: used to send data feeds. By doing this, the AA becomes an oracle;
* `profile`: used to send one's own profile. Maybe an AA wants to say something to the world about itself;
* `text`: used to save arbitrary text to the DAG;
* `definition`: used to post a definition of a new AA;
* `asset_attestors`: used to change the attestor list of an asset previously defined by this AA;
* `attestation`: used to post information about some other address. By doing this, the AA becomes an attestor;
* `definition_template`: used to post a template for smart contract definition;
* `poll`: used to create a poll;
* `vote`: used to vote in a poll. Every AA has voting rights after all.

Structure of those messages types is documented on [Sending data messages section](/autonomous-agents/getting-started-guide#sending-data-messages) and [Sending data to DAG page](/payments/data).

There is also another, special, app called `state`, which is not possible in regular units but is used only in AAs to produce state changes. More about it in a separate chapter.

### base\_aa

It is possible to create parameterized Autonomous Agents, which are based on previously deployed templates. Their structure for that kind of Autonomous Agent would look like this:

```javascript
["autonomous agent", {
    base_aa: "ADDRESS_OF_BASE_AA",
    params: {
        name1: "value1",
        name2: "value2",
        ...
    }
}]
```

The base AA template would need to reference these parameters as `params.name1` and `params.name2`.

## Oscript replacements

Any string, number, or boolean in the template can be calculated by a script. The script is evaluated and the result is inserted in place of the script, the type is preserved. For example, if 20000 bytes were sent from address `2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7` to an AA, then this code

```javascript
{
    address: "{trigger.address}",
    amount: "{trigger.output[[asset=base]] - 1000}"
}
```

would be replaced with

```javascript
{
    address: "2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7",
    amount: 19000
}
```

Object keys can also be parameterized with Oscript:

```javascript
{
    "{trigger.data.key}": "value"
}
```

See the Oscript language reference below.

### cases - template objects

JSON has scalars (strings, numbers, booleans) and objects (objects and arrays). Scalars can be parameterized through Oscript. Objects, on the other hand, are parameterized differently. They can have several alternative versions in the AA template, and only one version is selected based on input parameters and state. The versions and their selection criteria are specified using an object in `cases` array:

```javascript
{
    messages: {
        cases: [
            {
                if: "{trigger.data.define}",
                messages: [
                    // first version of messages
                    ....
                ]
            },
            {
                if: "{trigger.data.issue}",
                init: "{$amount = trigger.output[[asset=base]];}",
                messages: [
                    // second version of messages
                    ....
                ]
            },
            {
                messages: [
                    // default version of messages
                    ....
                ]
            }
        ]
    }
}
```

The regular value of an object/array is replaced with an object whose single element is an array `cases`. Each element of the `cases` array is an object with up to 3 elements:

* `if`: an Oscript expression. If the result of its evaluation is truthy then this `case` is selected. All other `case`s are not evaluated. `if` is required for all `case`s except the last, the last one may or may not have an `if`. If all previous `case`s evaluated to a falsy value and the last one is without an `if`, the last one is selected;
* `init`: an optional statements-only Oscript that is evaluated immediately after `if` if this `case` is selected;
* a mandatory element that is named the same as the original field (`messages` in the above example). If this `case` is selected, the original (3 levels higher) field is replaced with the value of this element.

In the above example, if the 2nd `case` were selected, the original object would fold into:

```javascript
{
    messages: [
        // second version of messages
        ....
    ]
}
```

Cases can be nested.

Cases can be used for any non-scalar value inside `messages`, not just `messages` themselves.

### if - conditional objects

Similar to the `cases` above, any object can have an additional `if` field. It is evaluated first, and if it is falsy, the entire object is removed from the enclosing object or array. Its internal Oscripts are not evaluated in this case.

```javascript
{
    messages: [
        {
            app: "data",
            payload: {
                timestamp: "{timestamp}",
                subscriber: "{trigger.address}"
            }
        },
        {
            if: "{trigger.data.withdrawal_amount > 0}",
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.data.withdrawal_amount}"
                    }
                ]
            }
        }
   ]
}
```

In the above example, the `payment` message will be generated only if `trigger.data.withdrawal_amount` is a number greater than 0.

The `if` field itself is removed from the object.

### init - statements object

Similar to the `cases` above, any object can have an additional `init` field. It is evaluated immediately after `if` when `if` is present and truthy. If there is no `if`, `init` is unconditionally evaluated first.

`init` must be a statements-only Oscript, it does not return a value.

Example:

```javascript
{
    messages: [
        {
            init: "{ $addr = trigger.address; }",
            app: "data",
            payload: {
                timestamp: "{timestamp}",
                subscriber: "{$addr}"
            }
        },
        {
            if: "{trigger.data.withdrawal_amount > 1000}",
            init: "{ $amount = trigger.data.withdrawal_amount - 1000; }",
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{$amount}"
                    }
                ]
            }
        }
   ]
}
```

The `init` field itself is removed from the object.

### Conditional object fields and array elements

If the value of any object field or array value evaluates to an empty string, this field or element is removed.

For example, object

```javascript
{
    field1: "{ (1 == 2) ? 'value1' : '' }",
    field2: "value2"
}
```

will become

```javascript
{
    field2: "value2"
}
```

Array

```javascript
[ `{ (1 == 2) ? "value1" : "" }`, "value2" ]
```

will become

```javascript
[ "value2" ]
```

### Sending all coins

If the `amount` field in an output within a payment message is omitted or evaluates to an empty string (which results in its removal per the above rules), this output receives all the remaining coins.

```javascript
{
    messages: [
        {
            if: "{trigger.data.send_all}",
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7",
                        amount: 1000
                    },
                    {
                        address: "{trigger.address}"
                    }
                ]
            }
        }
   ]
}
```

In the above example, 1000 bytes are sent to `2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7`, the rest of the AA's balance in bytes is sent to the address that triggered the AA.

### Empty objects and arrays

If an object or array becomes empty as a result of various removals, it is also removed from the enclosing object or array.

### State message

A state message is a special message in the `messages` array that performs state changes. It is the only oscript where state variables are assigned. Unlike regular messages that always have `payload`, state message has a field named `state` instead that contains a state changing script:

```javascript
{
    messages: [
        {
            app: "payment",
            payload: {
                asset: "base",
                outputs: [
                    {
                        address: "{trigger.address}",
                        amount: "{trigger.output[[asset=base]] - 1000}"
                    }
                ]
            }
        },
        {
            app: "state",
            state: `{
                var['responded'] = 1;
                var['total_balance_sent_back'] += trigger.output[[asset=base]] - 1000;
                var[trigger.address || '_response_unit'] = response_unit;
            }`
        }
    ]
}
```

The state message must always be the last message in the `messages` array. It is not included in the final response unit and its script (state script) is evaluated **after** the response unit is already prepared. It is the only oscript where response\_unit variable is available. State script contains only statements, it is not allowed to return any value.

## Constants/Variables

### Local constants

```php
$name1 = 1;
$name2 = 'value';
${'name' || 3} = $name1 + 10;
```

Local constant names are always prefixed with `$`. If the constant name itself needs to be calculated, the expression is enclosed in curly braces.

Local constants exist only during AA evaluation. Each constant can be assigned a value only once (single-assignment rule).

Each local constant is visible only in its own oscript after it was assigned. If it was assigned in `if` block, it is also available in all adjacent and enclosed oscripts. If it was assigned in `init` block, it is also available in all adjacent oscripts except `if` and in all oscripts enclosed in the same object.

```javascript
[
    {
        if: `{
            $amount = trigger.output[[asset=base]];
            // the result of the last expression is the result of if
            $amount == 10000
        }`,
        init: `{
            // here we can reference $amount set in if
            $half_amount = round($amount / 2); 
        }`,
        messages: [
            {
                app: "payment",
                payload: {
                    asset: "base",
                    outputs: [
                        {
                            address: "{ trigger.address }",
                            amount: `{
                                // we are in an enclosed oscript
                                // and can reference $half_amount set in init
                                $half_amount
                            }`
                        }
                    ]
                }
            },
            {
                app: "state",
                state: `{
                    // we are in an enclosed oscript
                    // and can reference $amount set in if
                    var['received'] = $amount;
                    // we are in an enclosed oscript
                    // and can reference $half_amount set in init
                    var['sent_back'] = $half_amount;
                }`
            }
        ]
    },
    {
        if: "{trigger.data.payout}",
        init: `{
            // here we cannot reference $amount nor $half_amount from the above
            // we can even assign other values to them without breaking the single-assignment rule
            $amount = 10;
        }`,
        ...
    }
]
```

If an unassigned local constant is referenced, it is taken as `false`.

If-else blocks in curly braces do not create separate scopes for local constants:

```javascript
if (trigger.data.deposit){
    $amount = trigger.output[[asset=base]];
}
$fee = round($amount * 0.01); // we can reference the $amount from above
```

Local constants can hold values of any type: string, number, boolean, or object (including array).

### Objects and arrays

When a local constant holds an object, individual fields of the object can be accessed through dot or \[] selector:

```javascript
$data = trigger.data;
$action = $data.params.action;
$player_score = $data.params[$player_name || '_score'];
```

If the specified object field does not exist, the value is taken as `false`.

Objects and arrays can be initialized using familiar syntax as in other languages:

```javascript
$obj = {a: 3, b: 7 };
$arr = [7, 2, 's', {a: 6}];
```

Although all local constants are single-assignment, objects and arrays can be mutated by modifying, adding, or deleting their fields:

```javascript
$obj = {a: 3, b: 7 };
$obj.a = 4; // modifies an existing field
$obj.c = 10; // adds a new field
delete($obj, 'b'); // deletes a field
freeze($obj); // prohibits further mutations of the object

$arr = [7, 2, 's', {a: 6}];
$arr[0] = 8; // modifies an existing element
$arr[] = 5; // adds a new element
delete($arr, 1); // removes element 1
freeze($arr); // prohibits further mutations of the array
```

The left-hand selectors can be arbitrarily long `.a.b[2].c.3.d[].e`. If some elements do not exist, an empty object or array is created automatically. `[]` adds to the end of an array. Array indexes cannot be skipped, i.e. if an array has length 5, you cannot assign to element 7. Once you are done mutating an object, can call `freeze()` to prevent further accidental mutations.

### Local functions

```javascript
$f = ($x) => {
	 $a = var['a'];
	 $x * $a
};

// one-line syntax for functions that have only one expression
$sq = $x => $x^2;

$res = $f(2);
$nine = $sq(3);
```

Functions are local constants and the same rules apply to them.

The return value is the value of the last expression or a return statement.

A function sees all other local constants and functions declared *before* it. Because of this, recursion is impossible.

Constants declared before the function cannot be shadowed by its arguments or other local constants declared within the function.

Complexity of a function is the sum of complexities of all operations within it. Every time a function is called, its complexity is added to the total complexity of the AA. If a function is declared but never called, its complexity doesn't affect the complexity of the AA.

### Remote functions (getters)

Getters are read-only functions available to other AAs and non-AA code.

They are meant to extract information about an AA state that is not directly available through state vars. E.g. in order to fetch this information one needs to perform some calculation over state vars or access several state vars and have good knowledge about the way information is stored in the AA.

**Examples:**

* oswap could expose functions that would calculate the price of a future exchange. Otherwise, clients would have to do non-trivial math themselves.
* the token registry could expose a single getter `$getTokenDescription($asset)` for reading a token description, and a similar one for decimals. Otherwise, one has to read first `$desc_hash = var['current_desc_' || $asset]`, then `var['description_' || $desc_hash]`.

Getters are declared in a top-level `getters` section which is evaluated before everything else.

```javascript
['autonomous agent', {
	getters: `{
		$sq = $x => $x^2;
		$g = ($x, $y) => $x + 2*$y;
		$h = ($x, $y) => $x||$y;
		$r = ($acc, $x) => $x + $acc;
	}`,
	init: `{
		// uncomment if the AA serves as library only
		// bounce("library only");
		...
	}`,
	...
}]
```

The code in `getters` section can contain only function declarations and constants. Request-specific information such as `trigger.data`, `trigger.outputs`, etc is not available in getters.

In the AA which declares them, getters can be accessed like normal functions.

Other AAs can call them by specifying the remote AA address before the function name using this syntax:

```javascript
$nine = MXMEKGN37H5QO2AWHT7XRG6LHJVVTAWU.$sq(3);
```

or

```javascript
$remote_aa = "MXMEKGN37H5QO2AWHT7XRG6LHJVVTAWU";
$nine = $remote_aa.$sq(3);
```

If `$remote_aa` is a variable that cannot be evaluated at deploy time, you need to indicate the max complexity of the remote call either explicitly, after a #:

```javascript
$nine = $remote_aa#5.$sq(3);
```

or as a variable that can be evaluated at deploy time:

```javascript
$max_complexity = 5;
$nine = $remote_aa#$max_complexity.$sq(3);
```

or by indicating a base AA that the `$remote_aa` is a parameterized AA of:

```javascript
$base_aa = '3DGWRKKWWSC6SV4ZQDWEHYFRYB4TGPKX';
$nine = $remote_aa#$base_aa.$sq(3);
```

The complexity of a remote call is the complexity of its function, plus one.

All functions declared in the `getters` section are publicly available. If some of them are not meant for public use, one can indicate this by a naming convention, e.g. by starting their names with an underscore `$_callPrivateFunction()` but information hiding cannot be really enforced since all getters operate on public data anyway.

Getters can also be conveniently called from non-AAs. In node.js code:

```javascript
const { executeGetter } = require('ocore/formula/evaluation.js');
const db = require('ocore/db.js');

const args = ["arg1", "arg2"];
const res = await executeGetter(db, aa_address, getter, args);
```

For remote clients, there is a `light/execute_getter` command in WebSocket API, hopefully it will be shortly available through obyte.js.

### State variables

State variables are persisted across invocations of autonomous agents.

Accessing state variables:

```javascript
// assigning current AAs state variable to local constant
$my_var_name1 = var['var_name1'];

// assigning other AAs state variable to local constant
$their_var_name1 = var['JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY']['var_name1'];
```

Assigning state variables:

```javascript
var['var_name1'] = 'var_value';
var['var_name2'] = 10;
var['var_name3'] += 10;
var['var_name4'] = false;
var['var_name5'] = {a:8, b:2};
var['var_name5'] ||= {c:6};  // concat an object
```

`var['var_name']` reads the value of state variable `var_name` stored under current AA.

`var['AA_ADDRESS']['var_name']` reads the value of state variable `var_name` stored under AA `AA_ADDRESS`. `AA_ADDRESS` is a valid address or `this_address` to refer to the current AA.

If there is no such variable, `false` is returned.

State variables can be accessed in any oscripts, but can be assigned only in [state message](#state-message) script. Only state vars of the current AA can be assigned, state vars of other AAs are read-only. State vars can be reassigned multiple times but only the final value will be saved to the database and only if the AA finishes successfully. All changes are committed atomically. If the AA fails, all changes to state vars are rolled back.

State vars can temporarily hold strings, numbers, objects, and booleans but when persisting, `true` values are converted to 1 and `false` values result in removal of the state variable from storage. AAs are required to hold a minimum balance in bytes equal to the size of their storage (length of var names + length of var values). This will also incentivize them to free up unused storage. The size of AA’s storage occupied before the current invocation is in variable `storage_size`.

Internally, objects are stored as JSON strings and their length is limited. Don't try to store a structure in a state var if this structure can grow indefinitely.

In addition to regular assignment `=`, state variables can also be modified in place using the following operators:

* `+=`: increment by;
* `-=`: decrement by;
* `*=`: multiply by;
* `/=`: divide by;
* `%=`: remainder of division by;
* `||=`: concatenate string/object/array.

For concatenation, the existing value of the var is converted to string.

For `+=`, `-=`, `*=`, `/=`, `%=`, the existing boolean value is converted to 1 or 0, strings result in error.

If the variable didn't exist prior to one of these assignments, it is taken as `false` and converted to number or string accordingly.

Each read or write operation on a state variable adds +1 to complexity. Assignment with modification also costs 1 in complexity.

Examples:

```javascript
var['sent_back'] = $half_amount;
var['count_investors'] += 1;
var['amount_owed'] += trigger.output[[asset=base]];
var['pending'] = false;
$x = var['JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY']['var_name1'];
```

### Response variables

```javascript
response['key'] = 'text';
```

Adds a key to the response object. Response variables do not affect state, they are meant to only inform the caller, and other interested parties, about the actions performed by the AA.

Response vars can only be assigned, never read. Response vars can be assigned and reassigned multiple times in any oscript. They can hold values of types: string, number, boolean. Attempting to assign an object would result in `true` being assigned.

Example: assigning these response variables

```javascript
response['message'] = "set exchange rate to 0.123 tokens/byte";
response['deposit'] = 2250000;
```

will result in the following response object:

```javascript
{
    "responseVars": {
        "message": "set exchange rate to 0.123 tokens/byte",
        "deposit": 2250000
    }
}
```

## Responses

The AAs are activated and responses are generated when the triggering unit gets stabilized. If the triggering unit triggers several AAs or there are several triggers that are included in the same MC unit and therefore get stabilized at the same time, the triggers are handled in deterministic order to ensure reproducibility on all nodes.

The first response unit has one or two parents:

* the MC unit that just got stabilized and which includes the triggering unit;
* the previous AA-generated unit (meaning, generated by any AA, not just the current one) if it is not already included in the first parent.

Any subsequent responses (generated by secondary AAs and in response to other triggers at the same MCI) are chained after the first response and then one after another.

After every response, 4 events are emitted:

* `aa_response`
* `aa_response_to_unit-` + trigger\_unit
* `aa_response_to_address-` + trigger\_address
* `aa_response_from_aa-` + aa\_address

Applications, which are based on a full node can subscribe to these events to receive information about responses they are interested in, e.g.:

```javascript
var trigger_address = '';

const eventBus = require('ocore/event_bus.js');
eventBus.on('aa_response_to_address-' + trigger_address, (objAAResponse) => {
    // handle event
});
```

Applications, which are based on light node will also need to add the address to their watched list in order to subscribe to these events:

```javascript
var aa_address = '';

const walletGeneral = require('ocore/wallet_general.js');
const eventBus = require('ocore/event_bus.js');
walletGeneral.addWatchedAddress(aa_address, () => {
    eventBus.on('aa_response_from_aa-' + aa_address, (objAAResponse) => {
        // handle event
    });
});
```

All 4 event handlers receive `objAAResponse` object as a single argument:

```javascript
{ 
    mci: 2385,
    trigger_address: '2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7',
    trigger_unit: 'f2S6Q3ufjzDyl9YcB51JUj2z9nE1sL4XL2VoYOrVRgQ=',
    aa_address: 'JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY',
    bounced: false,
    response_unit: 'JCJ1ZGkl2BtUlYoeu6U2yshp97pen/fIkTHvaKYjZa4=',
    objResponseUnit: {
        version: '2.0dev',
        alt: '3',
        timestamp: 1560939440,
        messages: [ ... ],
        authors: [ ... ],
        last_ball_unit: 'cxjDfHzWWgW8LqsC8yoDhgCYmwThmFfkdygGnDrxiFg=',
        last_ball: 'gjg8W2cE4WGFAIIsU2BvLOQKOpH/03Oo1SDS3/2SQDs=',
        witness_list_unit: '3gLI9EnI2xe3WJVPwRg8s4CB24ruetuddS0wYa2EI3c=',
        parent_units: [ 'f2S6Q3ufjzDyl9YcB51JUj2z9nE1sL4XL2VoYOrVRgQ=' ],
        headers_commission: 267,
        payload_commission: 157,
        unit: 'JCJ1ZGkl2BtUlYoeu6U2yshp97pen/fIkTHvaKYjZa4='
    },
    response: {} 
}
```

The object has the following fields:

* `mci`: the MCI of the triggering unit. The response unit is attached to the NC unit with the same MCI;
* `trigger_address`: the address that sent coins to the AA and thus triggered it;
* `aa_address`: AA address
* `bounced`: `true` if the trigger was bounced, `false` otherwise;
* `response_unit`: hash of the response unit or null if there is no response;
* `objResponseUnit`: response unit object or null if there is no response;
* `response`: response from the script. The object can have up to two fields: `error` for error message and `responseVars` for response variables set by scripts.

## Secondary AAs

The generated response unit may contain outputs to other AAs. In this case, the receiving AAs are triggered too. They receive the outputs from the previous AA and the data (if any) from its generated `data` message.

Secondary AAs behave like the primary ones except that they may receive less than the minimum bounce fees.

If there are several secondary AAs triggered by a previous AA, they are handled in a deterministic order to make sure that the results are reproducible on all nodes. If a secondary AA triggers a ternary one in turn, it is handled before going on to the next secondary AA.

If any of the secondary AAs fails, the entire chain fails, all the changes produced by its AAs are rolled back, and the primary AA bounces.

The total number of secondary AAs stemming from a single primary AA cannot exceed 10, otherwise the primary AA fails and bounces.

## Failures

If an AA fails for any reason (bad formula, attempt to send an invalid response, attempt to send more money than it has, etc), and attempt is made to bounce all the received coins back to sender, less bounce fees. All state changes are rolled back.

If creation of the bouncing transaction fails too, no transaction is created in response, i.e. the AA eats the coins.

The response object, which is not saved to the ledger, contains an error message explaining the reasons for failure.

## Semicolon

Every variable assignment must be terminated by a semicolon `;`. return and bounce statements are also terminated with a semicolon.

```javascript
$amount = trigger.output[[asset=base]];
var['sent_back'] = round($half_amount/2);
response['message'] = "set exchange rate to 0.123 tokens/byte";
if ($amount >= 42000)
    bounce("amount too large");
if (balance[base] < 20000)
    return;
```

## Two types of Oscripts

There are two types of Oscripts that can be used in AAs:

* statements-only scripts that consist only of statements (such as assignments) and don't return any value. init script and state message are the only two allowed statements-only scripts;
* scripts that return a value. They can have 0 or more statements but the last evaluated expression must not be a statement and its result is the result of the script.

Example of a statements-only script:

```javascript
$amount = trigger.output[[asset=base]];
$action = trigger.data.action;
```

Example of a script that returns a value:

```javascript
$amount = trigger.output[[asset=base]];
$action = trigger.data.action;
$amount*2
```

The result of evaluation of the last expression `$amount*2` is returned.

### Non-scalar return values

Usually, the return value of oscript is a scalar: string, number, or boolean. It is just inserted in place of the oscript.

If the return value is an object, it is similarly expanded and inserted in place of the original oscript. This can be used to send prepared objects through `trigger.data`.

For example, if `trigger.data` is

```javascript
{
    output: {address: "BSPVULUCOVCNXQERIHIBUDLD7TIBIUHU", amount: 2e5}
}
```

and an AA has this message

```javascript
{
    app: "payment",
    payload: {
        asset: "base",
        outputs: [
            `{trigger.data.output}`
        ]
    }
}
```

The resulting message will be

```javascript
{
    app: "payment",
    payload: {
        asset: "base",
        outputs: [
            {
                address: "BSPVULUCOVCNXQERIHIBUDLD7TIBIUHU",
                amount: 2e5
            }
        ]
    }
}
```

## Flow control

### return

```javascript
return expr;
```

Interrupts the script's execution and returns the value of `expr`. This syntax can be used only in oscripts that are supposed to return a value.

```javascript
return;
```

Interrupts the script's execution without returning any value. This syntax can be used only in statements-only oscripts: `init` and `state`.

### if else

```javascript
if (condition){
    $x = 1;
    $y = 2 * $x;
}
else{
    $x = 2;
    $z = $x^3;
}
```

Evaluates the first block of statements if the `condition` is truthy, the second block otherwise. The `else` part is optional.

If the block includes only one statement, enclosing it in {} is optional:

```javascript
if (condition)
    $x = 1;
```

## Complexity

Like other smart contract definitions, AAs have a capped complexity which cannot exceed 100. Some operations involve complex computation or access to the database, such operations are counted and add to the total complexity count. Other operations such as `+`, `-`, etc, are relatively inexpensive and do not add to the complexity count. The language reference indicates which operations count towards complexity.

Total complexity is the sum of complexities of all oscripts. It is calculated and checked only during deployment and includes the complexity of all branches even though some of them might not be activated at run time.

If the complexity exceeds 100, validation fails and the AA cannot be deployed.

## Operators

#### Arithmetic operators +, -, \*, /, %, ^

```javascript
$amount - 1000
$amount^2 / 4
```

Operands are numbers or converted to numbers if possible.

Additional rules for power operator `^`:

* `e^x` is calculated with exact (not rounded) value of `e`,
* an exponent greater or equal to MAX\_SAFE\_INTEGER will cause an error,
* for non-integer exponents, the result is calculated as `x^y = e^(y * ln(x))` with rounding of the intermediary result, which causes precision loss but guaranties reproducible results;
* this operator adds +1 to complexity count.

### Concatenation operator ||

```javascript
'abc' || 'def'              // 'abcdef'
[4, 6] || [3, 1]            // [4, 6, 3, 1]
{x: 1, y: 7} || {y: 8, a:9} // {x: 1, y: 8, a:9}
```

If the same key is found in both objects, the value from the right-hand one prevails.

Trying to concat an array with object results in error.

If either operand is a scalar (strings, numbers, booleans), both are converted to strings and concatenated as strings. Objects/arrays become "true".

### Binary logical operators AND, OR

Lowercase names `and`, `or` are also allowed.

Non-boolean operands are converted to booleans.

The result is a boolean.

If the first operand evaluates to `true`, second operand of `OR` is not evaluated.

If the first operand evaluates to `false`, second operand of `AND` is not evaluated.

### Unary logical operator NOT

Lowercase name `not` is also allowed. The operator can be also written as `!`.

Non-boolean operand is converted to boolean.

The result is a boolean.

### Operator OTHERWISE

Lowercase name `otherwise` is also allowed.

```javascript
expr1 OTHERWISE expr2
```

If `expr1` is truthy, its result is returned and `expr2` is not evaluated. Otherwise, `expr2` is evaluated and its result returned.

### Comparison operators ==, !=, >, >=, <, <=

If both operands are booleans or both operands are numbers, the result is straightforward.

If both operands are strings, they are compared in lexicographical order.

If both operands are objects, only `==` and `!=` are allowed, other operators will cause an error.

If operands are of different types:

* if any of them is an object or boolean, it causes an error,
* if any of them is a string, only `==` and `!=` are allowed and non-string operand will be converted to string before comparison, other operators will cause an error,
* all other combinations of types cause an error.

### Ternary operator ? :

```javascript
condition ? expr1 : expr2
```

If `condition` is truthy, `expr1` is evaluated and returned, otherwise `expr2` is evaluated and returned.

## Operator precedence

Operators have the following precedence in the order of decreasing "stickiness":

* `^`
* `!`
* `*`, `/`, `%`
* `+`, `-`, `||`
* `==`, `!=`, `>`, `>=`, `<`, `<=`
* `AND`
* `OR`
* `?:`
* `OTHERWISE`

## Global constants

#### pi

Pi constant rounded to 15 digits precision: `3.14159265358979`.

#### e

Euler's number rounded to 15 digits precision: `2.71828182845905`.

## Built-in functions

### Type of variable

```javascript
typeof(anything)
```

Returns `"string"`, `"number"`, `"boolean"` or `"object"`.

### Square root and natural logarithm

```javascript
sqrt(number)
ln(number)
```

These functions add +1 to complexity count.

Negative numbers cause an error. Non-number inputs are converted to numbers or result in error.

### Absolute value

```javascript
abs(number)
```

Returns absolute value of a number. Non-number inputs are converted to numbers or result in error.

### Rounding (round, ceil, floor)

```javascript
round(number [, decimal_places])
ceil(number [, decimal_places])
floor(number [, decimal_places])
```

Rounds the input number to the specified number of decimal places (0 if omitted). `round` uses `ROUND_HALF_EVEN` rules. Non-number inputs are converted to numbers or result in error. Negative or non-integer `decimal_places` results in error. `decimal_places` greater than 15 results in error.

### Minimum and maximum

```javascript
min(number1, [number2[, number3[, ...]]])
max(number1, [number2[, number3[, ...]]])
```

Returns minimum or maximum among the set of numbers. Non-number inputs are converted to numbers or result in error.

### Square root of the sum of squares

```javascript
hypot(number1, [number2[, number3[, ...]]])
```

Returns the square root of the sum of squares of all arguments. Boolean parameters are converted to 1 and 0, objects are taken as 1, all other types result in error. The function returns a non-infinity result even if some intermediary results (squares) would overflow.

This function adds +1 to complexity count.

### Get part of a string

```javascript
substring(string, start_index)
substring(string, start_index, length)
```

Returns part of the string. If length is not set then returns rest of the string from start index. If `start_index` is negative then `substring` uses it as a character index from the end of the string. If `start_index` is negative and absolute of `start_index` is larger than the length of the string then `substring` uses 0 as the `start_index`.

### Find starting index of searched string

```javascript
index_of(string, search_string)
```

Returns integer index (starting from 0) of searched string position in string. If searched string is not found then -1 is returned. Use `contains` if you don't need to know the index of the searched string.

### String search within string

```javascript
starts_with(string, prefix)
ends_with(string, suffix)
contains(string, search_string)
```

Returns boolean `true` if the string starts, ends or contains searched string.

### Uppercase/Lowercase string

```javascript
to_upper(string)
to_lower(string)
```

Returns the string with changed case.

### Replace string

```javascript
replace(str, search_str, replacement)
```

Replaces all occurrences of `search_str` in `str` with `replacement` and returns the new string.

### Validate string

```javascript
has_only(str, allowed_chars)
```

Returns `true` if `str` consists only of characters in `allowed_chars`. `allowed_chars` is a group of characters recognized by regular expressions, examples: `a-z0-9`, `\w`. `has_only` adds +1 to complexity.

### Seconds until specified date

```javascript
parse_date(ISO8601_date)
parse_date(ISO8601_datetime)
```

Attempts to parse string of date or date + time and returns timestamp. If you need to get seconds from UNIX Epoch of a current unit then use [timestamp](#timestamp).

### Convert seconds to date + time, date or time

```javascript
timestamp_to_string(timestamp)
timestamp_to_string(timestamp, 'datetime')
timestamp_to_string(timestamp, 'date')
timestamp_to_string(timestamp, 'time')
```

Returns string format of date + time (default), date or time from [timestamp](#timestamp). Timezone is UTC.

### Parse a JSON string into object

```javascript
json_parse(string)
```

Attempts to parse the input JSON string. If the result of parsing is an object, the object is returned. If the result is a scalar (boolean, string, number), the scalar is returned.

This function adds +1 to complexity count.

If parsing fails, `false` is returned.

Non-string input is converted to string.

### Serialize an object into JSON string

```javascript
json_stringify(object)
```

Stringifies the input parameter into JSON. The parameter can also be a number, boolean, or string. If it is a number outside the IEEE754 range, the formula fails. Objects in the returned JSON are sorted by keys.

### Iteration methods (map, reduce, foreach, filter)

```javascript
$ar = [2, 5, 9];
$ar2 = map($ar, 3, $x => $x^2);
```

The function for `map`, `foreach`, and `filter` accepts 1 or 2 arguments. If it accepts 1 argument, the value of each element is passed to it. If it accepts 2 arguments, key and value for objects or index and element for arrays are passed.

The second argument is the maximum number of elements that an array or object can have. If it is larger, the script fails. This number must be a constant so that it can be known at deploy time, and the complexity of the entire operation is the complexity of the callback function times maximum number of elements. If the function has 0 complexity, the total complexity of map/reduce/foreach/filter is assumed to be 1 independently of the max number of elements. Max number of elements cannot exceed 100.

A function is executed over each element of an array or object. The callback function can be anonymous like in the example above, or referenced by name:

```javascript
$f = $x => $x^2;
$ar = [2, 5, 9];
$ar2 = map($ar, 3, $f);
```

Callback for `map` and `filter` can also be a [remote getter](#remote-functions-getters):

```javascript
$ar2 = map($ar, 3, $remote_aa.$f);
```

`reduce` has one additional argument for initial value:

```javascript
$c = 3;
$ar = [2, 5, 9];

// sums all elements, will return 16
$acc = reduce($ar, $c, ($acc, $x) => $acc + $x, 0);
```

The callback function for `reduce` accepts 2 or 3 arguments: accumulator and value or accumulator, key, and value (accumulator, index, and element for arrays).

All these 4 functions are similar to their Javascript counterparts but unlike Javascript they can also operate on objects, not just arrays.

### split, join

```javascript
split("let-there-be-light", "-")  // ["let", "there", "be", "light"]
join(["let", "there", "be", "light"], "-")  // "let-there-be-light"

split("let-there-be-light", "-", 2)  // ["let", "there"]
```

The functions are similar to their counterparts in other languages. `join` can be applied to objects too, in this case the elements are sorted by key and their values are joined.

### Reverse array

```javascript
reverse([4, 8, 3])  // [3, 8, 4]
```

The function reverses an array and returns a new one. Deep copies of all elements are created.

Passing a non-array to this function results in error.

### Keys of an object

```javascript
keys({b: 3, a: 8}) // ['a', 'b']
```

Returns the keys of an object. The keys are sorted. Passing anything but an object results in error.

### Length of any variable

```javascript
length(string|number|object|array)
```

Returns the length of string. number, object or array. When passed an object or array, it returns the number of elements in object or array. Scalar types are converted to strings and the length of the string is returned.

### Length of an array

```javascript
array_length(object)
```

Returns number of elements if the object is an array. Have to use [`is_array`](#is_array) to determine if object is an array. Use [`length`](#length-of-any-variable) instead.

### Number from seed string

```javascript
number_from_seed(string)
number_from_seed(string, max)
number_from_seed(string, min, max)
```

Generates a number from a seed string. The same seed always produces the same number. The numbers generated from different seed strings are uniformly distributed in the specified interval.

The first form returns a fractional number from 0 to 1.

The second form returns an integer number from 0 to max inclusive.

The third form returns an integer number from min to max inclusive.

This function is useful for generating pseudo-random numbers from a seed string. It adds +1 to complexity count.

### SHA-256 hash

```javascript
sha256(string|number|boolean|object)
sha256(string|number|boolean|object, 'base64')
sha256(string|number|boolean|object, 'base32')
sha256(string|number|boolean|object, 'hex')
```

Returns SHA-256 hash of input string/object in Base64 encoding (default), Base32 or Hex encoding. Non-string inputs are converted to strings. This function adds +1 to complexity count.

### Checksummed 160-bit hash

```javascript
$definition = ["sig", {
  "pubkey": "Ald9tkgiUZQQ1djpZgv2ez7xf1ZvYAsTLhudhvn0931w"
}];
$address = chash160($definition);

$aa_definition = ['autonomous agent', {
  ...
}];
$aa_address = chash160($aa_definition);
```

Returns a 160-bit checksummed hash of an object, it is most useful for calculating an address when you know its definition, e.g. if you programmatically define a new AA and want to know its address in order to immediately trigger it.

### Check trigger data existence

```javascript
exists(trigger.data.param)
```

Returns boolean `true` if the trigger data parameter with name `param` exists.

### is\_integer

```javascript
is_integer(number)
```

Returns boolean `true` if the number is without fractionals.

### is\_array

```javascript
is_array(object)
```

Returns boolean `true` if the object is an array.

### is\_assoc

```javascript
is_assoc(object)
```

Returns boolean `true` if the object is an associative array (dictionary).

### is\_valid\_address

```javascript
is_valid_address(string)
```

Returns boolean `true` if the string is valid Obyte wallet address.

### is\_aa

```javascript
is_aa(string)
```

Returns boolean `true` if the string is Autonomous Agent address.

### is\_valid\_amount

```javascript
is_valid_amount(number)
```

Returns boolean `true` if number is positive, integer, and below MAX\_CAP (maximum cap that any token can have on Obyte platform).

### is\_valid\_signed\_package

```javascript
is_valid_signed_package(signedPackage, address)
```

Returns `true` if `signedPackage` object is a valid signed package signed by address `address`, returns `false` otherwise (the formula doesn't fail even if `signedPackage` doesn't have the correct format). `address` must be a valid address, otherwise the expression fails with an error. This function adds +1 to complexity count.

`signedPackage` object is usually passed through the trigger and has the following structure:

```javascript
{
    "signed_message": {
        "field1": "value1",
        "field2": "value2",
        ...
    },
    "authors": [
        {
            "address": "2QHG44PZLJWD2H7C5ZIWH4NZZVB6QCC7",
            "authentifiers": {
                "r": "MFZ0eFJeLAgAmm6BJdvbEzNt7x0H2Fb5RQBBpMSmyVFMLM2r2SX5chU9hbEWXExkz/T2hXAk1qHmxkAbbpZw8w=="
            }
        }
    ],
    "last_ball_unit": "izgjyn9bpbJjwpKQV7my0Dq1VUHbzrLpWLrdR0fDydw=",
    "version": "2.0"
}
```

Here:

* `signed_message` is the message being signed, it can be an object, an array, or scalar;
* `authors` is an array of authors who signed the message (usually one), it has the same structure as unit authors and includes the signing address, authentifiers (usually signatures) and optionally definitions;
* `last_ball_unit`: optional unit of last ball that indicates the position on the DAG at which the message was signed. If definition is not included in `author`, it must be known at this point in the ledger history. If there is no `last_ball_unit` in `signedPackage`, including address definition as part of each `author` is required;
* `version`: always `2.0`.

Usually, `signedPackage` is created by calling `signMessage` function from `signed_message` module:

```javascript
var headlessWallet = require('headless-obyte');
var signed_message = require('ocore/signed_message.js');

signed_message.signMessage(message, address, headlessWallet.signer, true, function (err, signedPackage) {
    // handle result here
    trigger.data.signedPackage = signedPackage;
});
```

The function creates a correctly structured `signedPackage` object which can be added to `trigger.data`.

### is\_valid\_sig

```javascript
is_valid_sig(message, public_key, signature)
```

Returns `true` if `signature` is a correct ECDSA signature of `message` by the private key corresponding to `public_key`, returns `false` otherwise.

* `message` is a string corresponding to the message being signed, the function will hash the message with SHA-256 before verifying the signature. In case `message` is not a string, the formula will fail.
* `public_key` is a string containing the public key in a PEM format. For example:

  ```
  -----BEGIN PUBLIC KEY-----
  MEowFAYHKoZIzj0CAQYJKyQDAwIIAQEEAzIABG7FrdP/Kqv8MZ4A097cEz0VuG1P\n\ebtdiWNfmIvnMC3quUpg3XQal7okD8HuqcuQCg==
  -----END PUBLIC KEY-----
  ```

  `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` can be omitted, spaces or carriage returns will be ignored. If `public_key` is not a string, is not for a supported curve, or doesn't have the required length then the formula will fail.
* `signature` is a string containing the signature in Base64 or hexadecimal format. In case signature is not a string or is not Base64 nor hexadecimal format, the formula will fail.

Supported algorithms:

ECDSA

`brainpoolP160r1, brainpoolP160t1, brainpoolP192r1, brainpoolP192t1, brainpoolP224r1, brainpoolP224t1, brainpoolP256r1, brainpoolP256t1, prime192v1, prime192v2, prime192v3, prime239v1, prime239v2, prime239v3, prime256v1, secp112r1, secp112r2, secp128r1, secp128r2, secp160k1, secp160r1, secp160r2, secp192k1, secp224k1, secp224r1, secp256k1, secp384r1, sect113r1, sect113r2, sect131r1, sect131r2, wap-wsg-idm-ecid-wtls1, wap-wsg-idm-ecid-wtls4, wap-wsg-idm-ecid-wtls6, wap-wsg-idm-ecid-wtls7, wap-wsg-idm-ecid-wtls8, wap-wsg-idm-ecid-wtls9`

RSA

`PKCS #1 - 512 to 4096 bits`

### vrf\_verify

```javascript
vrf_verify(seed, proof, pubkey)
```

Returns `true` if `proof` is valid, return false otherwise.

* `seed` is a string from which is derived a proof unique for this RSA key. The formula will fail in case `seed` is not a string or is empty.
* `proof` is an hexadecimal string value from 128 to 1024 characters (depending of RSA key size). Can be used with `number_from_seed` to obtain a verifiable random number.
* `pubkey` is a string containing the RSA public key in a PEM spki format. For example:

  ```
  -----BEGIN PUBLIC KEY-----
  MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANOJ1Y6/6uzcHDa7Q1gLO9z0KGOM51sO
  Pc2nfBF4RTobSVVpFnWtZF92r8iWCebwgSRSS9dEX6YIMIWNg11LbQ8CAwEAAQ==
  -----END PUBLIC KEY-----
  ```

  `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` can be omitted, spaces or carriage returns will be ignored. If `public_key` is not a string, is not for a supported curve, or doesn't have the required length then the formula will fail.

Supported algorithm: `RSAPKCS #1 - 512 to 4096 bits`

### is\_valid\_merkle\_proof

```javascript
is_valid_merkle_proof(element, proof);
```

Check if a given element is included in a merkle tree. The `proof` has the following structure `{root: string, siblings: array, index: number}` and would normally come from `trigger.data`. One should check `is_valid_merkle_proof` and look up the merkle hash `root` from a data feed.

### bounce

```javascript
bounce(string);
```

Aborts the script's execution with error message passed as the function's argument. The received money will be bounced to sender (less bounce fees).

### require

```javascript
require(condition, error_message);
```

Aborts the script's execution with error message `error_message` if the `condition` evaluates to a falsy value. The received money will be bounced to the sender (less bounce fees).

This is equivalent to

```javascript
if (!condition) {
    bounce(error_message);
}
```

### log

```javascript
log(expr1, expr2, ...);
```

Use this function for debugging your AA. Its arguments are evaluated and are available in a `logs` array within the AA response object. You can access this object and inspect the logs while running tests through [AA Testkit](https://github.com/valyakin/aa-testkit). It is available even if the script bounced. The logs are not saved anywhere in the DAG but the expressions are still evaluated and might add to your script's complexity. Remove all `log()` calls after debugging.

## Ocore functions

These functions are to be used in conjunction with `is_valid_sig` and `vrf_verify`.

### **signMessageWithEcPemPrivKey**

```javascript
const sig = require(‘ocore/signature.js’)
var signature = sig.signMessageWithEcPemPrivKey(message, encoding, pem_key)
```

Returns a signature that can be verified with is\_valid\_sig

`message` is a string to be signed.

`encoding`is either 'base64 or 'hex'

`pem_key` is a string containing ECDSA private key in PEM format

### **signMessageWithRsaPemPrivKey**�

```javascript
const sig = require(‘ocore/signature.js’)
var signature = sig.signMessageWithRsaPemPrivKey(message, encoding, pem_key)
```

Returns a signature that can be verified with is\_valid\_sig.

`message` is a string to be signed.

`encoding`is either 'base64 or 'hex'

`pem_key` is a string containing RSA private key in PEM format

### **vrfGenerate**

```javascript
const sig = require(‘ocore/signature.js’)
var proof = vrfGenerate(seed, pem_key)
```

\_\*\*\_Returns a proof that can verified with vrf\_verify.

`seed` is a string from which is derived the unique proof

`pem_key` \_\*\*\_is a string containing RSA private key in PEM format�

**Key generation with openssl**

Keys for the functions above can be generated with openssl.

RSA (mandatory for vrfGenerate and vrf\_verify):

private key

`openssl genrsa -out priv_key.pem 2048`

Replace 2048 by any key length from 512 to 4096.

public key

`openssl rsa -in priv_key.pem -outform PEM -pubout -out pub_key.pem`

ECDSA:

private key

openssl ecparam -name prime256v1 -genkey -noout -out priv\_key.pem\
�Replace prime256v1 by any curve identifier listed above

public key

`openssl ec -in priv_key.pem -pubout -out pub_key.pem`

## Conversions

### To-string conversion

Some functions and operators that expect strings as inputs need to convert non-string inputs to strings:

* numbers are converted to strings using their decimal representation. For numbers whose exponent is greater than or equal to 21 or less than or equal to -7, exponential representation is used.
* booleans are converted to strings `true` and `false`.
* objects become strings `true`.

### To-number conversion

Some functions and operators that expect numbers as inputs need to convert non-number inputs to numbers:

* booleans `true` and `false` are converted to numbers `1` and `0` respectively.
* objects become 1.
* strings become numbers, `+` can be used to force the conversion, e.g. `+'3'` becomes `3`, `+false` becomes `0`.

### To-boolean conversion

0 and empty string become `false`, all other values become `true`. Any value that would convert to `true` is called truthy, otherwise falsy.

## Comments

Line comments

```javascript
// this is a comment line
$x = 1; // this part of line is a comment
```

as well as block comments are supported:

```javascript
/*
A comment block
*/
```

## References to external variables

### trigger.address

The address of the sender who sent money to this AA. If the sending unit was signed by several addresses, the first one is used.

### trigger.initial\_address

The address of the sender who sent money to the initial AA of a chain of AAs. Same as `trigger.address` if there was no chain. When an AA sends money to another AA, `trigger.initial_address` remains unchanged.

### trigger.unit

The unit that sent money to this AA.

### trigger.initial\_unit

The trigger unit that started a chain of AA calls. Same as `trigger.unit` if there was no chain. When an AA sends money to another AA, `trigger.initial_unit` remains unchanged.

### trigger.output

```javascript
trigger.output[[asset=assetID]].field
trigger.output[[asset!=assetID]].field
```

Output sent to the AA address in the specified asset.

`assetID` can be `base` for bytes or any expression that evaluates to asset ID.

`field` can be `amount` or `asset` or omitted. If omitted, `amount` is assumed. If the trigger unit had several outputs in the same asset to this AA address, their amounts are summed.

The search criteria can only be `=` (`asset=$assetID`) or `!=` (`asset!=$assetID`).

Examples:

```javascript
trigger.output[[asset=base]]
trigger.output[[asset=base]].amount
trigger.output[[asset='j52n7Bfec9jW']]
trigger.output[[asset=$asset]]
trigger.output[[asset!=base]]
trigger.output[[asset!=base]].amount
if (trigger.output[[asset!=base]].asset == 'ambiguous'){
    ...
}
```

If there is no output that satisfies the search criteria, the returned `.amount` is 0 and the returned `.asset` is a string `none`. Your code should check for this string if necessary.

If there is more than one output that satisfies the search criteria (which is possible only for `!=`), the returned `.asset` is a string `ambiguous`. Your code should check for this string if necessary. Trying to access `.amount` of an ambiguous asset fails the script.

### trigger.outputs

```javascript
trigger.outputs[assetID]
```

An object that stores the outputs sent to the AA address in various assets.

`assetID` can be `'base'` for bytes or any expression that evaluates to asset ID.

Examples:

```javascript
$asset = 'base';
trigger.outputs['base']
trigger.outputs[$asset]
trigger.outputs.base
```

`trigger.outputs` is an associative array, you can iterate it with [`map`, `foreach`, etc](#iteration-methods-map-reduce-foreach-filter), [delete elements](#objects-and-arrays), [pass to functions](#remote-functions-getters), [post as data message](#messages), etc.

### trigger.data

Data sent with the trigger unit in its `data` message. `trigger.data` returns the entire data object, `trigger.data.field1.field2` or `trigger.data.field1[expr2]` tries to access a deeper nested field:

* if it is an object, object is returned;
* if it is a scalar (string, number, or boolean), scalar is returned;
* if it doesn't exist, `false` is returned.
* `exists` function can be used to check if param [exists](#check-trigger-data-existence).

For example, if the trigger unit had this data message

```javascript
{
    "app": "data",
    "payload": {
        "field1": {
            "field2": "value2",
            "abc": 88
        },
        "abc": "def"
    },
    "payload_hash": "..."
}
```

`trigger.data` would be equal to

```javascript
{
    "field1": {
        "field2": "value2",
        "abc": 88
    },
    "abc": "def"
}
```

`trigger.data.field1` would be equal to

```javascript
{
    "field2": "value2",
    "abc": 88
}
```

`trigger.data.field1.field2` would be equal to string `value2`,

`trigger.data.field1['a' || 'bc']` would be equal to number `88`,

`trigger.data.field1.nonexistent` would be equal to boolean `false`,

`trigger.data.nonexistent.anotherfield` would be equal to boolean `false`.

### mci

MCI of the trigger unit, which is the same as MCI of MC unit the response unit (if any) will be attached to.

### timestamp

Timestamp of the MC unit that recently became stable, this is the unit whose stabilization triggered the execution of this AA. This is the same unit the response unit (if any) will be attached to. It's number of seconds since Epoch - Jan 01 1970. (UTC).

### mc\_unit

Hash of the MC unit that includes (or is equal to) the trigger unit.

### storage\_size

The size of AA’s storage occupied before the current invocation

### number\_of\_responses

Built-in variable says how many responses were already generated in response to a primary trigger and might help to avoid exceeding the limit of 10 responses per primary trigger.

### previous\_aa\_responses

Built-in variable that holds an array of responses generated by previous AAs in the chain (empty array for the first AA in the chain). Each element of the array is an object with the following fields:

* `unit_obj`: response unit object (if any);
* `trigger_unit`: trigger unit for this response;
* `trigger_address`: trigger address for this response;
* `aa_address`: address of the AA that handled the trigger and generated the response.

### this\_address

The address of this AA.

### response\_unit

The hash of the unit that will be generated by the AA in response to the trigger. This variable is available only in state script. Any references to this variable in any other scripts will fire an error.

### definition

```javascript
definition[trigger.address]
```

It allows to inspect the definition of any address using `definition['ADDRESS']` syntax.

Examples:

```javascript
definition[trigger.address][0] == 'autonomous agent'
definition[trigger.address][1].base_aa == 'EXPECTED_BASE_AA'.
```

### asset

```javascript
asset[expr].field
asset[expr][field_expr]
```

Extracts information about an asset. This adds +1 to complexity. `expr` is `base` for bytes or an expression that evaluates to an asset ID.

`field` is one of the following, or `field_expr` should evaluate to one of the following:

* `exists`: boolean, returns `false` if asset ID is invalid;
* `cap`: number, total supply of the asset. For uncapped assets, 0 is returned;
* `is_private`: boolean, is the asset private?
* `is_transferrable`: boolean, is the asset transferrable?
* `auto_destroy`: boolean, does the asset gets autodestroyed when sent to definer address?
* `fixed_denominations`: boolean, is the asset issued in fixed denominations? Currently AAs can't send fixed denomination assets, but if `issued_by_definer_only` is `false` then somebody else can issue them.
* `issued_by_definer_only`: boolean, is the asset issued by definer only?
* `cosigned_by_definer`: boolean, should each transfer be cosigned by definer?
* `spender_attested`: boolean, should each holder be attested?
* `is_issued`: boolean, is any amount of the asset already issued?
* `definer_address`: string, returns wallet address of the definer.

Examples:

```javascript
asset[base].cap
asset['base'].cap
asset['abc'].exists
asset['n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY='].is_issued
asset['n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=']['is_' || 'issued']
asset['n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=']['is_' || 'private']
```

If the asset ID is valid, but does not exist then `false` is returned for any field.

### data\_feed

```javascript
data_feed[[oracles=listOfOracles, feed_name=nameOfDataFeed, ...]]
```

Finds data feed value by search criteria. This adds +1 to complexity.

There are multiple search criteria listed between the double brackets, their order is insignificant.

* `oracles`: string, list of oracle addresses delimited by `:` (usually only one oracle). `this_address` refers to the current AA;
* `feed_name`: string, the name of the data feed;
* `feed_value`: string or number, optional, search only for this specific value of the data feed;
* `min_mci`: number, optional, search only since the specified MCI;
* `ifseveral`: string, optional, `last` or `abort`, what to do if several values found that match all the search criteria, return the last one or abort the script with error, default is `last`
* `ifnone`: string or number or boolean, optional, the value to return if nothing is found. By default, this results in an error and aborts the script;
* `what`: string, optional, `value` or `unit`, what to return, the data feed value or the unit where it was posted, default is `value`;
* `type`: string, optional, `auto` or `string`, what type to return, default is `auto`. For `auto`, data feed values that look like valid IEEE754 numbers are returned as numbers, otherwise they are returned as strings. If `string`, the returned value is always a string. This setting affects only the values extracted from the database; if `ifnone` is used, the original type of `ifnone` value is always preserved.

Data feeds are searched before the MCI of the triggering unit (inclusively). If there are several AAs stemming from the same MCI, previous AA responses are also searched.

Examples:

```javascript
data_feed[[oracles='JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC', feed_name='BTC_USD']]
data_feed[[oracles=this_address, feed_name='score']]
data_feed[[oracles='JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC:I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT', feed_name='timestamp']]
```

### in\_data\_feed

```javascript
in_data_feed[[oracles=listOfOracles, feed_name=nameOfDataFeed, feed_value>feedValue, ...]]
```

Determines if a data feed can be found by search criteria. Returns `true` or `false`. This adds +1 to complexity.

There are multiple search criteria listed between the double brackets, their order is insignificant.

* `oracles`: string, list of oracle addresses delimited by `:` (usually only one oracle). `this_address` refers to the current AA;
* `feed_name`: string, the name of the data feed;
* `feed_value`: string or number, search only for values of the data feed that are `=`, `!=`, `>`, `>=`, `<`, or `<=` than the specified value;
* `min_mci`: number, optional, search only since the specified MCI.

Data feeds are searched before the MCI of the triggering unit (inclusively). If there are several AAs stemming from the same MCI, previous AA responses are also searched.

Examples:

```javascript
in_data_feed[[oracles='JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC', feed_name='BTC_USD', feed_value>12345.67]]
in_data_feed[[oracles=this_address, feed_name='score', feed_value=$score]]
in_data_feed[[oracles='JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC:I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT', feed_name='timestamp', feed_value>=1.5e9]]
```

### attestation

```javascript
attestation[[attestors=listOfAttestors, address=attestedAddress, ...]].field
attestation[[attestors=listOfAttestors, address=attestedAddress, ...]][field_expr]
```

Finds an attestation by search criteria. This adds +1 to complexity.

There are multiple search criteria listed between the double brackets, their order is insignificant.

* `attestors`: string, list of attestor addresses delimited by `:` (usually only one attestor). `this_address` refers to the current AA;
* `address`: string, the address that was attested;
* `ifseveral`: string, optional, `last` or `abort`, what to do if several matching attestations are found, return the last one or abort the script with error, default is `last`
* `ifnone`: string or number or boolean, optional, the value to return if nothing is found. By default, this results in an error and aborts the script;
* `type`: string, optional, `auto` or `string`, what type to return, default is `auto`. For `auto`, attested field values that look like valid IEEE754 numbers are returned as numbers, otherwise they are returned as strings. If `string`, the returned value is always a string. This setting affects only the values extracted from the database; if `ifnone` is used, the original type of `ifnone` value is always preserved.

`field` string or `field_expr` expression are optional and they indicate the attested field whose value should be returned. Without `field` or `field_expr`, `true` is returned if an attestation is found.

If no matching attestation is found, `ifnone` value is returned (independently of `field`). If there is no `ifnone`, `false` is returned.

If a matching attestation exists but the requested field does not, the result is as if the attestation did not exist.

Attestations are searched before the MCI of the triggering unit (inclusively). If there are several AAs stemming from the same MCI, previous AA responses are also searched.

Examples:

```javascript
attestation[[attestors='UOYYSPEE7UUW3KJAB5F4Y4AWMYMDDB4Y', address='BI2MNEVU4EFWL4WSBILFK7GGMVNS2Q3Q']].email
attestation[[attestors=this_address, address=trigger.address]]
attestation[[attestors='JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725', address='TSXOWBIK2HEBVWYTFE6AH3UEAVUR2FIF', ifnone='anonymous']].steem_username
attestation[[attestors='JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725', address='TSXOWBIK2HEBVWYTFE6AH3UEAVUR2FIF']].reputation
```

### balance

```javascript
balance[asset]
balance[aa_address][asset]
```

Returns the balance of an AA in the specified asset. If `aa_address` is omitted, the current AA is assumed. `asset` can be `base` for bytes, asset id for any other asset, or any expression that evaluates to an asset id or `base` string.

This adds +1 to complexity count.

The returned balance includes the outputs received from the current trigger.

Examples:

```javascript
balance[base]
balance['n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=']
balance['JVUJQ7OPBJ7ZLZ57TTNFJIC3EW7AE2RY'][base]
```

### input, output

```javascript
output[[asset=assetID, amount>minAmount, address=outputAddress]].field
input[[asset=assetID, amount=amountValue, address=inputAddress]].field
```

Tries to find an input or output in the current unit by search criteria.

These language constructs are available only in non-AA formulas in smart contracts (`["formula", ...]` clause).

There are multiple search criteria listed between the double brackets, their order is insignificant. All search criteria are optional but at least one must be present.

* `asset`: string, asset of input or output, can be `base` for bytes. Comparison operators can be only `=` or `!=`;
* `address`: string, the address receives an output or spends an input, can be `this_address`. Comparison operators can be only `=` or `!=` (other addresses);
* `amount`: number, the condition for the amount of an input or output. Allowed comparison operators are: `=`, `!=`, `>`, `>=`, `<`, `<=`.

`field` is one of `amount`, `address`, and `asset`. It indicates which information about the input or output we are interested in.

If no input/output is found by search criteria or there is more than one matching entry, the formula fails.

Examples:

```javascript
input[[asset=base]].amount
output[[asset = base, address=GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN]].amount
output[[asset = base, address='GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN']].amount
output[[asset = 'n9y3VomFeWFeZZ2PcSEcmyBb/bI7kzZduBJigNetnkY=', amount>=100]].address
```

### unit

```javascript
unit[unit_hash] // returns an object that represents the requested unit
unit[response_unit] // returns an object of response unit generated by the current AA invocation
```

**Searching and filtering**

Assuming $x is a variable that contains an object, arrays within this object can be searched and filtered like this:

```javascript
$x.messages[[.app = 'payment', .payload.asset != 'ff', .payload.outputs.0.amount > 10]].payload.asset
```

The above filters the ‘messages’ array by 3 filtering criteria. Like elsewhere in Oscript, double brackets indicate searching by listed criteria (similar to WHERE in SQL).

When the object is a 1-element array but the next key is a string, unwrap the array. This helps to avoid writing \[0]. For example, `$x.messages.payload.asset and $x.messages[0].payload.asset` are equivalent if ‘messages’ is a 1-element array.

Examples:

```javascript
unit['kGQZkIj3gRclCp2vw9LMg0jVnPKYCebXHxm8XYPxbQ4='].mci
unit['kGQZkIj3gRclCp2vw9LMg0jVnPKYCebXHxm8XYPxbQ4='].timestamp
unit['kGQZkIj3gRclCp2vw9LMg0jVnPKYCebXHxm8XYPxbQ4='].messages[[.app='payment']].payload.outputs[[.address='MYESSCFGDERS3YIEGNZDOG2BI5HKQHLU']].amount
```

## Limits

* strings cannot be longer than 4096 characters;
* state var value strings cannot be longer than 1024 characters;
* state var names cannot be longer than 128 characters;
* numbers must be in IEEE754 double range;
* all intermediary calculations are rounded to 15 significant digits;
* total complexity of all scripts cannot exceed 100;
* total number of operations of all scripts cannot exceed 2000.

Any attempt to exceed these limits will result in script's failure.

## Deployment

AA code can be deployed with [Oscript](https://oscript.org)[ (mainnet)](https://oscript.org)[ editor](https://oscript.org) and [Oscript](https://testnet.oscript.org/)[ (testnet)](https://testnet.oscript.org/)[ editor](https://testnet.oscript.org/), but AA code can also be deployed by sending a unit that includes a message with `app=definition`. This can be done with headless wallet or with AA itself, which has the definition of new AA in its payload.

```javascript
const headlessWallet = require('headless-obyte');
const eventBus = require('ocore/event_bus.js');
const objectHash = require('ocore/object_hash.js');

function postAA() {
    let definition = ["autonomous agent", {
        bounce_fees: { base: 10000 },
        messages: [
            ...
        ]
    }];
    let payload = {
        address: objectHash.getChash160(definition),
        definition: definition
    };
    let objMessage = {
        app: 'definition',
        payload_location: 'inline',
        payload_hash: objectHash.getBase64Hash(payload),
        payload: payload
    };
    let opts = {
        messages: [objMessage]
    };

    ​headlessWallet.issueChangeAddressAndSendMultiPayment(opts, (err, unit) => {
        if (err){
            /*
            something went wrong,
            maybe put this transaction on a retry queue
            */
            return;
        }
        // handle successful payment
    });
}

eventBus.on('headless_wallet_ready', postAA);
```

There is no error if the same definition is posted twice.

The user who deployed the AA doesn't have any privileges over the AA aside from those directly coded in the AA source code.

Once deployed, the AA definition can never be changed.

Any outputs sent to the AA address before its definition was revealed ("before" means before the MCI of the first unit where the definition was revealed) are treated like regular outputs, they just increase the address'es balance but do not trigger any action, even delayed action after the definition was revealed. This might be a convenient way to fill the AA with some coins before actually launching it.

It is possible for AA to deploy another AA, which is especially useful when creating [parameterized AAs](#base_aa) for previously deployed AA templates:

```javascript
["autonomous agent", {
    bounce_fees: { base: 10000 },
    messages: [
        {
            app: "definition",
            payload: {
                definition: ["autonomous agent", {
                    base_aa: "BASE_AA_TEMPLATE_ADDRESS",
                    params: {
                        name1: "{trigger.data.name1}",
                        name2: "{trigger.data.name2}",
                        ...
                    }
                }]
            }
        },
        ...
    ]
}]
```

In case you wish to enter expressions that doesn't get evaluated with the deployment of new AA, but as actual expressions for a new AA, instead of `"{expression}"` write an expression that outputs another expression `"{'{expression}'}"`.


# Issuing assets on Obyte

On Obyte, users can issue new assets and define rules that govern their transferability.

To start a user-defined asset on Obyte, you need to complete two steps

* Define your asset. Asset definition is a special type of message (distinct from payments) that you send to the Obyte DAG
* Issue the asset by sending the 1st transaction that spends it

## Asset ID

After an asset is defined, the hash of the unit where it was defined becomes the unique ID of the asset. The asset is referenced by this ID in future payments and definitions (smart contracts). There are no user-assignable names of assets in the protocol, but there are independent registries that link asset IDs to user-friendly names for a fee. One such registry is [Obyte Asset Registry](https://asset.obyte.app/), another decentralized registry is [tokens.ooo](https://tokens.ooo/)

If you are not a developer, but wish to issue an asset on Obyte then you can also use [Obyte Asset Registry](https://asset.obyte.app/) to do that without writing any code. If Obyte Asset Registry is too limited for your needs or you need to issue an asset on TESTNET then continue reading.

## Defining a new asset

See a sample of asset-defining transaction at <https://github.com/byteball/headless-obyte/blob/master/tools/create_asset.js>.

To define a new asset you need a headless wallet. In your dependencies:

```javascript
"dependencies": {
	"headless-obyte": "git+https://github.com/byteball/headless-obyte.git",
	"ocore": "git+https://github.com/byteball/ocore.git"
	// .....
}
```

Call this function to create a new asset definition and broadcast it:

```javascript
var headlessWallet = require('headless-obyte');
var network = require('ocore/network.js');
var composer = require('ocore/composer.js');

var my_address = ''; // set definer address.
var asset = {}; // defined asset here.
composer.composeAssetDefinitionJoint(my_address, asset, headlessWallet.signer,
    {
        ifError: console.error,
        ifNotEnoughFunds: console.error,
        ifOk: function(objJoint, assocPrivatePayloads, composer_unlock) {
            network.broadcastJoint(objJoint);
            console.error('==== Asset ID:'+ objJoint.unit.unit);
        }
    }
);
```

Here `my_address` is your address you use to post the asset-defining message. The address must be funded to pay at least the transaction fees (about 1000 bytes).

`asset` is a javascript object that describes the properties of your asset. Here is an example:

```javascript
var asset = {
	cap: 1000000,
	is_private: false,
	is_transferrable: true,
	auto_destroy: false,
	fixed_denominations: false,
	issued_by_definer_only: true,
	cosigned_by_definer: false,
	spender_attested: false
}
```

`cap` is the total number of coins that can be issued (money supply). If omitted, the number is unlimited.

`is_private`: indicates whether the asset is private (such as blackbytes) or publicly traceable (similar to bytes).

`is_transferrable`: indicates whether the asset can be freely transferred among arbitrary parties or all transfers should involve the definer address as either sender or recipient. The latter can be useful e.g. for loyalty points that cannot be resold.

`auto_destroy`: indicates whether the asset is destroyed when it is sent to the definer address.

`fixed_denominations`: indicates whether the asset exists as coins (banknotes) of a limited set of denominations, similar to blackbytes. If it is `true`, the definition must also include property `denominations`, which is an array of all denominations and the number of coins of that denomination:

```javascript
var asset = {
	// ....
	fixed_denominations: true,
	denominations: [
		{denomination: 1, count_coins: 1e10},
		{denomination: 2, count_coins: 2e10},
		{denomination: 5, count_coins: 1e10},
		{denomination: 10, count_coins: 1e10},
		{denomination: 20, count_coins: 2e10},
		{denomination: 50, count_coins: 1e10},
		{denomination: 100, count_coins: 1e10},
		{denomination: 200, count_coins: 2e10},
		{denomination: 500, count_coins: 1e10},
		{denomination: 1000, count_coins: 1e10},
		{denomination: 2000, count_coins: 2e10},
		{denomination: 5000, count_coins: 1e10},
		{denomination: 10000, count_coins: 1e10},
		{denomination: 20000, count_coins: 2e10},
		{denomination: 50000, count_coins: 1e10},
		{denomination: 100000, count_coins: 1e10}
	]
};
```

`issued_by_definer_only`: indicates whether the asset can be issued only by the definer address. If `false`, anyone can issue the asset, in this case `cap` must be unlimited and it would make sense that issuing is limited by `issue_condition`.

`cosigned_by_definer`: indicates whether each operation with the asset must be cosigned by the definer address. Useful for regulated assets where the issuer (bank) wants to perform various compliance checks (such as the funds are not arrested by a court order) prior to approving a transaction. This could also be used to allow fee-less asset transfers for users (paid by definer), but wallets don't support that yet.

`spender_attested`: indicates whether the spender of the asset must be attested by one of approved attestors. Also useful for regulated assets e.g. to limit the access to the asset only to KYC'ed users. If `true`, the definition must also include the list of approved attestor addresses:

```javascript
var asset = {
	// ....
	spender_attested: true,
	attestors: ["ADDRESS1", "ADDRESS2"]
};
```

The definition can also include two optional properties `issue_condition` and `transfer_condition` which specify the restrictions when the asset can be issued and transferred. They evaluate to a boolean and are coded in the same [smart contract language](/contracts/reference) as address definitions.

```javascript
var asset = {
	// ....
	issue_condition: ["and", [
		["has one", {what: "output", asset: "this asset"}],
		["has", {what: "output", asset: "base", address: "MO7ZZIU5VXHRZGGHVSZWLWL64IEND5K2"}],
		["has one equal", {
			equal_fields: ["amount"], 
			search_criteria: [{what: "output", asset: "base"}, {what: "output", asset: "this asset"}]
		}]
	]],
	transfer_condition: ["and", [
		["has one", {what: "output", asset: "this asset"}],
		["has one equal", {
			equal_fields: ["address", "amount"], 
			search_criteria: [{what: "output", asset: "base"}, {what: "output", asset: "this asset"}]
		}]
	]]
};
```

The above conditions stipulate that the newly defined asset can be issued if the issuer also sends equal amount of bytes to the address MO7ZZIU5VXHRZGGHVSZWLWL64IEND5K2, and it can be transferred if equal amount of bytes is transferred to the same address at the same time.

## Issuance of a new asset

The new asset can be issued after its definition is confirmed. To issue, you need just to spend the asset from an address that is allowed to issue and it will be issued to address you transferred it.

You cannot use `wallet.sendMultiPayment()`, `headlessWallet.issueChangeAddressAndSendPayment()`and similar functions because they can do only transfers and they don't know about addresses that can issue new coins. Instead, you have to use lower level functions:

* `composeAndSaveDivisibleAssetPaymentJoint` from `ocore/divisible_asset.js`
* `composeAndSaveIndivisibleAssetPaymentJoint` from `ocore/indivisible_asset.js`

See [create\_divisible\_asset\_payment.js](https://github.com/byteball/headless-obyte/blob/master/tools/create_divisible_asset_payment.js) (assets without fixed denominations) and [create\_indivisible\_asset\_payment.js](https://github.com/byteball/headless-obyte/blob/master/tools/create_indivisible_asset_payment.js) (assets with fixed denominations) for examples.

See an example of how an asset can be both defined and issued in a single script <https://github.com/byteball/ico-bot/blob/master/scripts/issue_tokens.js>

## Whitepaper

For more details see chapter 24 of the [whitepaper](https://byteball.org/Byteball.pdf).


# Attestation profiles / KYC

This guide explains how to request, validate, and use the attested data in your chat bot.

Users can have some of their data verified by a trusted third party (attestor). The attestor posts an attestation record to the Obyte DAG, this record serves as a proof for relying parties that a user was attested. The attested data itself can be either posted publicly by the attestor, or only a hash of this data is posted while the plain-text data is saved in the wallet of the attested user. In the latter case, the user can disclose the attested data to selected peers, for example to your bot.

This can be used to KYC your users prior to providing a service, see <https://medium.com/byteball/bringing-identity-to-crypto-b35964feee8e>. You may need it e.g. to comply with regulations or protect against fraud.

ICO bot <https://github.com/byteball/ico-bot> already uses the attested private profiles in order to allow only verified users to invest and to collect their personal data. You can use its code as reference.

## Requesting private profile

You should point the user to your privacy policy before requesting sensitive personal data.

To request a private profile, you need to send profile-request message to the user. The message includes the list of fields you require the user to disclose. The message will be displayed in the user's chat window as a clickable link, which allows them to select one of the profiles stored in his wallet and send it over to the peer (your chat bot).

### Real Name Attestation

This is a profile request message that asks the fields that all [Real Name Attestation](https://github.com/byteball/real-name-attestation) profiles have:

```
[...](profile-request:first_name,last_name,dob,country,id_type)
```

Here is the full list of available fields:

* `first_name`: first name
* `last_name`: last name
* `dob`: date of birth in YYYY-MM-DD format\_
* `country`: the country that issued the ID (2-letter ISO code)
* `us_state`: US state (only if country=US)
* `personal_code`: government issued personal code (not all countries)
* `id_number`: government issued document ID (not all documents)
* `id_type`: ID type
* `id_subtype`: ID sub-type (not all attestations)
* `id_expiry`: ID expires at (not all attestations)
* `id_issued_at`: ID issued at (not all attestations)

### Email Attestation

This is a profile request message that asks the email field that all [Email Attestation](https://github.com/byteball/email-attestation) profiles have:

```
[...](profile-request:email)
```

### Steem Attestation

This is a profile request message that asks the fields that all [Steem Attestation](https://github.com/byteball/steem-attestation) profiles have:

```
[...](profile-request:steem_username,reputation)
```

## Receiving private profile

When a user sends you his private profile (on profile request or by choosing "Insert private profile" from the menu), you receive it in a chat message that includes:

```
[...](profile:privateProfileJsonBase64)
```

where `privateProfileJsonBase64` is a base64-encoded JSON of the private profile object. You can easily find the profile in an incoming message using regular expression:

```javascript
let arrProfileMatches = text.match(/\(profile:(.+?)\)/);
```

Then, decode the profile using `private_profile.js` module in `ocore`:

```javascript
const privateProfile = require('ocore/private_profile.js');
let privateProfileJsonBase64 = arrProfileMatches[1];
let objPrivateProfile = privateProfile.getPrivateProfileFromJsonBase64(privateProfileJsonBase64);
```

`objPrivateProfile` object has 3 fields:

```javascript
objPrivateProfile {
    unit: "...", // attestation unit
    payload_hash: "...", // pointer to attestation payload in this unit
    src_profile: object // attested fields
}
```

Next, you need to validate this object and extract information about the attested and attestor addresses:

```javascript
privateProfile.parseAndValidatePrivateProfile(objPrivateProfile, (err, address, attestor) => {
    if (err) {
        device.sendMessageToDevice(from_address, 'text', err);
    }
    // validated
    // ...
});
```

This function verifies that the provided profile matches the hash stored on the DAG by the attestor. It also returns the user's address `address` (hence you don't need to ask the user about his address, the profile is enough) and the attestor address `attestor` (make sure it is on the list of attestors you trust for each type of attestations).

The `src_profile` field of `objPrivateProfile` contains an associative array of attested fields. But not all fields have to be disclosed by the user.

* If a field is disclosed, the value of `objPrivateProfile[field]` is an array of two elements: the plain-text value of the field and blinding. Blinding is a random string generated by the attestor when creating the profile, it serves to protect the private data from brute force attacks (the profile data is too predictable and can be easily checked against known hashes).
* If the field is not disclosed, the value of `objPrivateProfile[field]` is a hash of plain-text value and blinding.

To extract just the disclosed data and remove all the bindings, use

```javascript
let assocPrivateData = privateProfile.parseSrcProfile(objPrivateProfile.src_profile);
```

You should double check if the user sent all the required fields because users can send private profiles on profile request (required fields in locked state) or by choosing "Insert private profile" from the menu (none of the fields in locked state).

To save the received private profile of previously mentioned Real Name Attestation profile request, use code like this:

```javascript
let required_fields = ['first_name', 'last_name', 'dob', 'country', 'id_type'];
if (required_fields.every(key => key in assocPrivateData)) {
    privateProfile.savePrivateProfile(objPrivateProfile, address, attestor);
}
else {
    device.sendMessageToDevice(from_address, 'text',
            'Please share all the required fields.');
}
```

It will save the profile in the tables `private_profiles` and `private_profile_fields`, which you can later query to read the data.

## Sending private profile

If your bot is setting up [prosaic contracts](/contracts/prosaic-contracts) between 2 users then they need to get each others private profiles. All you need to do is first request the profiles from both users, then receive and save the profiles from both users and then send the first user and second user's profile and the second user a first user's profile.

```javascript
db.query("SELECT unit, payload_hash, src_profile \
		FROM private_profiles \
		WHERE address = ? AND attestor_address = ? \
		LIMIT 1;", [wallet_address_1, attestor], (rows) => {
	if (rows.length === 0) {
		return device.sendMessageToDevice(device_address_1, 'text',
				'Please provide your private email \
				[...](profile-request:first_name,last_name)');
	}
	let objPrivateProfile = {
		unit: rows[0].unit,
		payload_hash: rows[0].payload_hash,
		src_profile: JSON.parse(rows[0].src_profile)
	};
	let privateProfileJsonBase64 = Buffer.from(JSON.stringify(objPrivateProfile)).toString('base64');
	device.sendMessageToDevice(device_address_2, 'text',
			'Save the private profile of the other side of the contract. \
			[...](profile:'+ privateProfileJsonBase64 +')');
});
```

## Retrieving public attestation

[Real Name Attestation](https://github.com/byteball/real-name-attestation) profiles are all private, but [Email Attestation](https://github.com/byteball/email-attestation) and [Steem Attestation](https://github.com/byteball/steem-attestation) bots let user to choose whether they like to publish the data publicly or privately and [Username Attestation](https://github.com/byteball/username-attestation) bot publishes attestations only publicly. So, if you are asking attested email address from the user, you should let them do it with public attestation too.

```javascript
const device = require('ocore/device.js');
let challenge = 'This is my address.';
device.sendMessageToDevice(from_address, 'text', 'Please provide your private email [...](profile-request:email) \
        or insert the wallet address, which has publicly attested email address [...](sign-message-request:'+ challenge +'). \
        \nIf you haven\'t verified your email address yet then please do it with Email Attestation bot from Bot Store.');
```

For full nodes that is easy, you ask user to [sign some message](/verifying-address-with-signed-message), after which you get a wallet address that they own. Then you just query your full node database for that data:

```javascript
const email_attestor = 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG';
/*
convert base64 signed message into JSON object
like it is described in Wallet address verification documentation.
*/

validation.validateSignedMessage(objSignedMessage, err => {
    if (err)
        return device.sendMessageToDevice(from_address, 'text', err);
    if (objSignedMessage.signed_message !== challenge)
        return device.sendMessageToDevice(from_address, 'text',
                "You signed a wrong message: "+objSignedMessage.signed_message+", expected: "+challenge);

    db.query("SELECT unit, field, value FROM attested_fields \
            WHERE attestor_address = ? AND address = ?;",
            [email_attestor, objSignedMessage.authors[0].address], (rows) => {
        if (rows.length === 0) return;
        rows.forEach((row) => {
            if (row.field == 'email') {
                device.sendMessageToDevice(from_address, 'text',
                        'Found: '+ row.value);
            }
        });
    });
});
```

On the light node, it is also possible, but more complicated. You need to ask the Hub for all the attestation for user address and then you would need to request proofs for those attestation units:

```javascript
const email_attestor = 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG';
/*
convert base64 signed message into JSON object
like it is described in Wallet address verification documentation.
*/

validation.validateSignedMessage(objSignedMessage, err => {
    if (err)
        return device.sendMessageToDevice(from_address, 'text', err);
    if (objSignedMessage.signed_message !== challenge)
        return device.sendMessageToDevice(from_address, 'text',
                "You signed a wrong message: "+objSignedMessage.signed_message+", expected: "+challenge);

    const network = require('ocore/network.js');
    network.requestFromLightVendor('light/get_attestations', {
        address: objSignedMessage.authors[0].address
    },
    (ws, request, response) => {
        if (response.error){
            console.error('light/get_attestations failed: '+response.error);
            return;
        }
        let arrAttestations = response;
        if (!Array.isArray(arrAttestations)){
            console.error('light/get_attestations response is not an array: '+response);
            return;
        }
        if (arrAttestations.length === 0){
            return device.sendMessageToDevice(from_address, 'text',
                    "Not an attested address.");
        }
        console.log('attestations', arrAttestations);
        let arrUnits = arrAttestations.map(attestation => attestation.unit);
        network.requestProofsOfJointsIfNewOrUnstable(arrUnits, err => {
            if (err){
                console.log('requestProofsOfJointsIfNewOrUnstable failed: '+err);
                return;
            }
            arrAttestations.forEach( (attestation) => {
                if (attestation.attestor_address === email_attestor) {
                    device.sendMessageToDevice(from_address, 'text',
                            'Found: '+ attestation.profile.email);
                }
            });
        });
    });
});
```

## Creating attestation profiles

Above examples here show how to use different existing profiles from other attestation bots, but if you would like to create your own attestation bot, it is recommended to click on the links of these bots on this article and take a look how they have been done from the source code. There is also article ["How to create private/public attestation profile" on Sending data to DAG ](/payments/data#attestation-profile)page.


# Address signing/verification

If you need to verify that a user owns a particular address, you can do it by offering to sign a message.

You can also verify ownership of address by requesting a payment from their address and this method is more appropriate if you need to receive a payment anyway.

To request the user to sign a message, send this message in chat:

```
[...](sign-message-request:challenge)
```

where `challenge` is the message to be signed. This request will be displayed in the user's wallet as a link that the user can click and confirm signing. Once the user signs it, your chat bot receives a specially formatted message:

```
[...](signed-message:base64_encoded_text)
```

You can parse and validate it, here is an example how to verify user's account address:

```javascript
// verify posted addresss
const validationUtils = require('ocore/validation_utils');
const device = require('ocore/device.js');
var sessionData = [];

eventBus.on('text', (from_address, text) => {
	let arrSignedMessageMatches = text.match(/\(signed-message:(.+?)\)/);
	
	if (validationUtils.isValidAddress(text)) {
		sessionData[from_address] = text;
		let challenge = 'My address is '+text;
		return device.sendMessageToDevice(from_address, 'text',
				'[...](sign-message-request:'+ challenge  +')');
	}
	else if (arrSignedMessageMatches){
		let signedMessageBase64 = arrSignedMessageMatches[1];
		let validation = require('ocore/validation.js');
		let signedMessageJson = Buffer.from(signedMessageBase64, 'base64').toString('utf8');
		try{
			var objSignedMessage = JSON.parse(signedMessageJson);
		}
		catch(e){
			return null;
		}
		validation.validateSignedMessage(objSignedMessage, err => {
			let user_address = sessionData[from_address];
			let challenge = 'My address is '+user_address;
			if (err)
				return device.sendMessageToDevice(from_address, 'text', err);
			if (objSignedMessage.signed_message !== challenge)
				return device.sendMessageToDevice(from_address, 'text',
					"You signed a wrong message: "+objSignedMessage.signed_message+", expected: "+challenge);
			if (objSignedMessage.authors[0].address !== user_address)
				return device.sendMessageToDevice(from_address, 'text',
					"You signed the message with a wrong address: "+objSignedMessage.authors[0].address+", expected: "+user_address);
			
			// all is good, address proven, continue processing
		});
	}
});
```

The above code also checks that the user signed the correct message and with the correct address.

`objSignedMessage` received from the peer has the following fields:

* `signed_message`: (string) the signed message
* `authors`: array of objects, each object has the following structure (similar to the structure of `authors` in a unit):
  * `address`: (string) the signing address
  * `definition`: (array) definition of the address
  * `authentifiers`: (object) signatures for different signing paths

To validate the message, call `validation.validateSignedMessage` as in the example above.

Note that the challenge that you offer to sign must be both clear to the user and sufficiently unique. The latter is required to prevent reuse of a previously saved signed message.


# URI protocol

This URI protocol enables developers to open the wallet app in desired screen with pre-filled inputs.

If you want to open Obyte app for users then there is a `obyte:` protocol [URI ](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Examples)for that. If you are not aware what it is then it's like `mailto:` , `ftp:` , `tel:` or [intents on Android](https://developer.android.com/reference/android/content/Intent). When user visits a link with that protocol then it can open the wallet app in specific screen with pre-filled inputs, helping users to insert long account addresses or amounts without the need to copy-paste them.

## Opening Send screen

Following hyperlinks will open the wallet app on Send screen. These hyperlinks (without the HTML) also work when posted as chat messages.

### Requesting to send funds

We can [request payments with chat bot messages](/payments#requesting-payments) and we can use the same commands as links on the website. This is how it will look as a hyperlink:

```markup
<a href="obyte:ACCOUNT_ADDRESS?amount=123000&amp;asset=base">
    open Send screen with bytes
</a>
```

`ACCOUNT_ADDRESS` should be replaced with the wallet address where the funds should be sent, `amount` parameter should have `bigInt` type number in bytes (not KByte, not MByte, not GByte) and `asset` parameter is optional, by default it is `base` for bytes, but it can be issued [asset unit ID](/issuing-assets-on-byteball#asset-id) too.

One website that heavily relies on this feature is [Currency converter for Obyte](https://tarmo888.github.io/bb-convert/) ([source code](https://github.com/tarmo888/bb-convert)).

It is also possible to request that the payment to be done from specific address in user's wallet. Since wallet version 3.3.0, this also work from [chat messages](/payments#payments-from-single-address-wallet).

```markup
<a href="obyte:ACCOUNT_ADDRESS?amount=123000&amp;from_address=USER_ACCOUNT_ADDRESS">
    open Send screen with bytes
</a>
```

If you don't know user's account address, but still want them to user single-address account then you can use `single_address=1` parameter like this:

```markup
<a href="obyte:ACCOUNT_ADDRESS?amount=123000&amp;single_address=1">
    open Send screen with bytes
</a>
```

### Requesting to send data to AA

In order to open a Send screen with pre-filled payment and data, the data object needs to be converted into URI encoded Base64 (using `JSON.stringify`, `btoa` and`encodeURIComponent`) string. Many cases, when the Autonomous Agent stores data based on triggering address, we would also want the users to use single-address account, this can by adding the `single_address=1` parameter. Autonomous agents can also accept nested data.

```javascript
var base64 = global.btoa || require('btoa');
var data = {
    number: 1,
    foo: "bar",
    foobar: {
        foo: "bar",
    },
    "?<?>?": ["a",1,2,3],
};
var json_string = JSON.stringify(data);
var base64_string = base64(json_string);
var uri_encoded_base64data = encodeURIComponent(base64_string);
```

This will open Send screen, which will be pre-filled to post 10 000 bytes and data object.

```markup
<a href="obyte:AA_ADDRESS?amount=10000&amp;single_address=1&amp;base64data=eyJudW1iZXIiOjEsImZvbyI6ImJhciIsImZvb2JhciI6eyJmb28iOiJiYXIifSwiPzw%2FPj8iOlsiYSIsMSwyLDNdfQ%3D%3D">
    open Send screen with bytes and data
</a>
```

### Requesting to post data

This will open Send screen, which will be pre-filled to post unstructured key/value pairs as data (single-address account required). Keys need to be unique.

```markup
<a href="obyte:data?app=data&amp;anykey1=anyvalue&amp;anykey2=anyvalue">
    open Send screen with data
</a>
```

### Requesting to post temporary data

Like the above, this will open Send screen, which will be pre-filled to post unstructured key/value pairs as data (single-address account required) meant for temporary storage. Keys need to be unique.

```markup
<a href="obyte:data?app=temp_data&amp;anykey1=anyvalue&amp;anykey2=anyvalue">
    open Send screen with temp data
</a>
```

The data posted this way will be available on the Obyte DAG only for 1 day, after which it will be purged but the hashes of the data will stay on the DAG forever. Unlike permanent data, temporary data costs less in fees.

### Requesting to post data feed

This will open Send screen, which will be pre-filled to post indexable key/value pairs as data feed (single-address account required). Keys need to be unique.

```markup
<a href="obyte:data?app=data_feed&amp;anykey1=anyvalue&amp;anykey2=anyvalue">
    open Send screen with data feed
</a>
```

### Requesting to post a profile

This will open Send screen, which will be pre-filled to post key/value pairs as profile info (single-address account required). Keys need to be unique.

```markup
<a href="obyte:data?app=profile&amp;anykey1=anyvalue&amp;anykey2=anyvalue">
    open Send screen with profile
</a>
```

### Requesting to post attestation

This will open Send screen, which will be pre-filled to post key/value pairs as someone else attestation profile (single-address account required). Keys need to be unique.

```markup
<a href="obyte:data?app=attestation&amp;address=ACCOUNT_ADDRESS&amp;anykey1=anyvalue&amp;anykey2=anyvalue">
    open Send screen with attestation
</a>
```

### Requesting to post a poll

This will open Send screen, which will be pre-filled to post poll (single-address account required). Option keys can be named anything, but values need to be unique. Question parameter is also required.

```markup
<a href="obyte:data?app=poll&amp;question=How%20are%20you&amp;option1=fine&amp;option2=tres%20bien">
    open Send screen with poll
</a>
```

### Requesting to post a AA definition

This will open Send screen, which will be pre-filled to post Autonomous Agent definition (single-address account required). The `definition` parameter needs to be URL encoded.

```markup
<a href="obyte:data?app=definition&amp;definition=%7B%0A%09messages%3A%20%5B%0A%09%09%7B%0A%09%09%09app%3A%20'payment'%2C%0A%09%09%09payload%3A%20%7B%0A%09%09%09%09asset%3A%20'base'%2C%0A%09%09%09%09outputs%3A%20%5B%0A%09%09%09%09%09%7B%0A%09%09%09%09%09%09address%3A%20%22%7Btrigger.address%7D%22%0A%09%09%09%09%09%7D%0A%09%09%09%09%5D%0A%09%09%09%7D%0A%09%09%7D%0A%09%5D%0A%7D">
    open Send screen with AA definition
</a>
```

Because most browsers support only URLs up to 2048 characters length, it is also possible to post a AA definition by making it fetch the definition from some other other address like this:

```markup
<a href="obyte:data?app=definition&amp;definition=https%3A%2F%2Fexample.com%2Fdefinition.json">
    open Send screen with AA definition
</a>
```

### Requesting to post short text content

This will open Send screen, which will be pre-filled to post short text content (single-address account required). The `content` parameter needs to be URL encoded and can be maximum of 140 chars before encoding.

```markup
<a href="obyte:data?app=text&amp;content=Lorem%20ipsum%20dolor%20sit%20amet%2C%20consectetur%20adipiscing%20elit.%0AQuisque%20venenatis%20elementum%20dolor%20in%20malesuada.%20Cras%20ultrices%20ultrices%20fermentum.%20Nullam%20ac%20commodo%20ante.%20Pellentesque%20quis%20nibh%20laoreet%2C%20sagittis%20augue%20in%2C%20dapibus%20nunc.%20Etiam%20vel%20eleifend%20urna%2C%20in%20tincidunt%20turpis%20nullam.">
    open Send screen with text content
</a>
```

### Requesting to post a system vote

This will open Send screen, which will be pre-filled to post a vote for a system variable.&#x20;

```markup
<a href="obyte:data?app=system_vote&subject=base_tps_fee&value=11.5">
    open Send screen with the system vote
</a>
```

The `subject` parameter is one of `op_list`, `threshold_size`, `base_tps_fee`, `tps_interval`, `tps_fee_multiplier`, it is the name of the variable being voted for. The `value` parameter is the value of the variable that the voter supports. For `op_list`, it must be a list of 12 valid addresses of the proposed [order providers](https://obyte.org/technology/order-providers) (OPs) separated by `\n` (url-encoded, of course). All other variables have positive numeric (including fractional) values.

The votes are used to govern the network and change the values of the said system-wide variables (described in [OIP 3](https://github.com/byteball/OIPs/blob/master/oip-0003.md), [OIP 5](https://github.com/byteball/OIPs/blob/master/oip-0005.md), and [OIP 6](https://github.com/byteball/OIPs/blob/master/oip-0006.md)). The weight of each vote depends on the balance of the voting address(es) in Bytes.

### Requesting to count votes for a system variable

This will open Send screen, which will be pre-filled to post a vote-count request for a system variable.&#x20;

```markup
<a href="obyte:data?app=system_vote_count&subject=base_tps_fee">
    open Send screen with the system vote count request
</a>
```

The `subject` parameter is one of `op_list`, `threshold_size`, `base_tps_fee`, `tps_interval`, `tps_fee_multiplier`, it is the name of the variable whose vote count is requested.&#x20;

The vote-count requests are used to govern the network and commit changes to the values of the said system-wide variables (described in [OIP 3](https://github.com/byteball/OIPs/blob/master/oip-0003.md), [OIP 5](https://github.com/byteball/OIPs/blob/master/oip-0005.md), and [OIP 6](https://github.com/byteball/OIPs/blob/master/oip-0006.md)). All votes for the requested variable will be tallied, weighted by the voter's current balance in Bytes, and the value that received most votes will become active. For `op_list`, total votes for each proposed OP will be calculated, and the top 12 will become the new active OPs.

The user pays a 1 GB fee for this request.

## Receiving textcoins via link

Textcoins are funds that can be sent via text messages. These text messages contain 12 randomly picked words and by entering them into the wallet app in exact same order, user will get the funds that were added to them. If you have ever received any textcoins then you also know that you don't actually have to re-type or copy-paste those words, textcoin receivers are usually directed to [Obyte textcoin claiming page](https://byteball.org/#textcoin?test-test-test-test-test-test-test-test-test-test-test-test), which has green "Receive funds" button, which will launch the wallet app with exactly those textcoin words. Obyte textcoin claiming page tries to check first if user has wallet installed, but basically, underneath that button is a hyperlink similar to this:

```markup
<a href="obyte:textcoin?RANDOMLY-GENERATED-TWELVE-WORDS">
    Recieve funds
</a>
```

So, additionally to [sending textcoins with a bot](/payments/textcoins), you can also make clickable textcoins on your website (link either to textcoin claiming page or directly to `obyte:` protocol). Just make sure each user on your webiste has access to textcoins specifically generated for them. Otherwise, if all users see the same textcoins then it can become a rush to who claims the textcoins first.

## Interacting with chat bot

Bot Store on Obyte is like Apple App Store or Google Play Store, but instead of apps, Bot Store has chat bots that are written for Obyte platform. Each Obyte Hub can have each own bots that are shown for users of that app. Currently, most users are using the official wallet app and official Hub, but it makes sense that if somebody forks the wallet, they would use their own Hub for it too. This means that in the future, in order to get your chat bot exposed to maximum amount of users, it needs to get listed on all Hubs.

### Pairing with another device

Luckily, adding chat bots to your wallet app is much easier on Obyte than it is to side-load apps on iOS or Android. All you need to do is add the pairing code that bot outputs to your website - everyone who has Byteball app already installed and clicks on it, will get automatically paired with your chat bot. Hyperlink to pairing code would be something like this:

```markup
<a href="obyte:AnpzF9nVTV5JZXzlG2fSnA+8UmjFuBdbqU+rJchz3qcN@byteball.org/bb#0000">
    Add Sports Betting bot
</a>
```

One example, where all the official Hub bots are displayed on a website can be seen on [Bots section obyte.io](https://obyte.io/bots).

Pairing codes in hyperlinks are not limited to only chat bots, you could create a pairing link to any device, all you need to do is find you pairing invitation code (Chat > Add new device > Invite other device) and add the code after `obyte:` protocol inside the hyperlink.

### Sending commands to chat bots

Once you have paired with a chat bot already, you might wonder whether it is possible to get users from your website to some specific state in chat bot (for example, by [sending a predefined command](/#predefined-chat-commands)) with a click on any hyperlink. There are 2 options how to do that, first option would be to fill the `pairing_secrets` database table with all the possible commands, but if there could be indefinite number of valid commands then easiest would be to accept any pairing secret and use them as custom commands.

{% code title="conf.js" %}

```javascript
exports.permanent_pairing_secret = '*';
```

{% endcode %}

Websites that use this feature are [BB Odds](https://bb-odds.herokuapp.com/) and [Polls section on obyte.io](https://obyte.io/polls). How it can be done can be seen from Poll bot ([source code](https://github.com/byteball/poll-bot/blob/master/poll-bot.js)). For example, opening a poll app with results of specific poll can be done with hyperlink like this:

```markup
<a href="obyte:AhMVGrYMCoeOHUaR9v/CZzTC34kScUeA4OBkRCxnWQM+@byteball.org/bb#stats-HAXKXC1EBn8GtiAiW0xtYLAJiyV4V1jTt1rc2TDJ7p4=">
    see stats
</a>
```

Steem Attestation bot uses this method also as an alternative way how to refer other people, source code for that is more advanced that the poll bot code, but [it can be found on Github](https://github.com/byteball/steem-attestation/blob/66e72d4062f7c1f5a8a057366023c5eaa6863bf4/attestation.js#L90).

## Using protocol URI in a QR code

`obyte:` protocol is not only for websites, it could be used in physical world too with QR codes. This means that if users have the Obyte app installed and they scan any QR code that contains any of the above codes (just value of the href, without quotes and without the HTML around them) then the installed Obyte app will open the same way. The QR code is not just meant to be printed on paper, it can work on websites too, giving the users the ability to use your services cross-device (browse the website on a laptop, scan the QR code with a phone and complete the payment on the phone).

There are many online QR code generators to create those QR codes manually, but QR codes can be created in real-time too. Following is the example how to create a QR code with `obyte:` protocol link using jQuery.

```markup
<div class="container">
	<div id="qr_code"></div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
	integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
	crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"
	integrity="sha256-9MzwK2kJKBmsJFdccXoIDDtsbWFh8bjYK/C7UjB1Ay0="
	crossorigin="anonymous"></script>
<script type="text/javascript">
$(document).ready(function() {
	$('#qr_code').html('').qrcode({
		width: 512,
		height: 512,
		text: 'obyte:ACCOUNT_ADDRESS?amount=123000&asset=base'
	});
});
</script>
```

A website that creates QR codes this way is [Currency converter for Obyte](https://tarmo888.github.io/bb-convert/) ([source code](https://github.com/tarmo888/bb-convert)) and Steem Attestation bot ([source code](https://github.com/byteball/steem-attestation/blob/master/public/qr/index.html)) generates referral links this way. Alternatively, there is also code example [how to generate QR code like that on server side](/tutorials-for-newcomers/log-in-on-website-with-byteball).

## Using these with testnet wallets

If you are testing these functions with [TESTNET headless wallet](https://github.com/byteball/headless-obyte#testnet) and [TESTNET GUI wallet](https://obyte.org/testnet.html) then instead of `obyte:` protocol, use `obyte-tn:`. This can be easily controlled in your bot's code like this:

```javascript
const pairingProtocol = process.env.testnet ? 'obyte-tn:' : 'obyte:';
```


# Events list

Event bus provides a way to subscribe to events from any of the services running.

```javascript
const eventBus = require('ocore/event_bus.js');
```

### Wallet is ready (only headless wallet)

Headless wallet is needed for bots that hold private keys and can send transactions. This event is emitted when passphrase has been entered by bot admin and single wallet is loaded. Before that event, bot outputs device address, device pubkey and pairing key.

```javascript
eventBus.on('headless_wallet_ready', () => {

});
```

### Start database update

This event is emitted when bot executes series database queries to upgrade the database to new version.

```javascript
eventBus.on('started_db_upgrade', () => {

});
```

### End of database update

This event is emitted when bot finishes database upgrade.

```javascript
eventBus.on('finished_db_upgrade', () => {

});
```

### Connection to the hub via ws is established

```javascript
eventBus.on('connected', () => {

});
```

### Connection to the hub is established and an error is possible

The `url` parameter is protocol + domain + path (for example: `wss://obyte.org/bb`).

```javascript
eventBus.on('open-' + url, (error) => {

});
```

### Connected to ws

```javascript
eventBus.on('connected_to_source', (new_ws) => {

});
```

### Not a fatal error

```javascript
eventBus.on('nonfatal_error', (msg, Error) => {

});
```

### Unit validation status

```javascript
eventBus.on("validated-" + unit, (bValid) => {

});
```

### New joint

```javascript
eventBus.on('new_joint', (objJoint) => {

});
```

### Main chain index has become stable

```javascript
eventBus.on('mci_became_stable', (mci) => {

});
```

### New unstable transactions

```javascript
eventBus.on('new_my_transactions', (arrNewUnits) => {

});
```

### Stable transactions

```javascript
eventBus.on('my_transactions_became_stable', (arrUnits) => {

});
```

### Bad transactions

```javascript
eventBus.on('sequence_became_bad', (arrUniqueUnits) => {

});
```

### First history received

```javascript
eventBus.on('first_history_received', () => {

});
```

### Changes with addresses leading to possible new transactions

```javascript
eventBus.on('maybe_new_transactions', () => {

});
```

### New unstable unit

```javascript
eventBus.on("new_my_unit-" + unit, (objJoint) => {

});
```

### New private payment

```javascript
eventBus.on("received_payment", (payer_device_address, assocAmountsByAsset, asset, message_counter, bToSharedAddress) => {

});
```

### Stable unit

```javascript
eventBus.on('my_stable-' + unit , () => {

});
```

### Syncing is idle

```javascript
eventBus.on('sync_idle' , () => {

});
```

### Catching up done

```javascript
eventBus.on('catching_up_done' , () => {

});
```

### Catching up started

```javascript
eventBus.on('catching_up_started' , () => {

});
```

### Catchup next hash tree

```javascript
eventBus.on('catchup_next_hash_tree' , () => {

});
```

### New direct private chains

```javascript
eventBus.on('new_direct_private_chains' , (arrChains) => {

});
```

### Unhandled private payments left

```javascript
eventBus.on('unhandled_private_payments_left' , (rowsLength) => {

});
```

### Version of the connected user

```javascript
eventBus.on('peer_version', (ws, body) => {

});
```

### New wallet version available

This event is emitted when Hub sends message about new wallet version.

```javascript
eventBus.on('new_version', (ws, body) => {

});
```

### Received the project number for notifications on the phone

```javascript
eventBus.on('receivedPushProjectNumber', (ws, body) => {

});
```

### Client logged in

```javascript
eventBus.on('client_logged_in', (ws) => {

});
```

### Message from the hub

```javascript
eventBus.on("message_from_hub", (ws, subject, body) => {

});
```

### **Message for light client**

```javascript
eventBus.on("message_for_light", (ws, subject, body) => {

});
```

### Exchange rates are updated

This event is emitted when wallet updated rates that they got from Hub.

```javascript
const network = require('ocore/network.js');
eventBus.on("rates_updated", () => {
    console.log(JSON.stringify(network.exchangeRates, null, 2));
});
```

### Message received by hub

```javascript
eventBus.on('peer_sent_new_message', (ws, objDeviceMessage) => {

});
```

### Notifications are enabled

```javascript
eventBus.on("enableNotification", (device_address, params) => {

});
```

### Notifications are disabled

```javascript
eventBus.on("disableNotification", (device_address, params) => {

});
```

### Create new wallet

```javascript
eventBus.on("create_new_wallet", (walletId, wallet_definition_template, arrDeviceAddresses, wallet_name, other_cosigners, is_single_address) => {

});
```

### Wallet created and signed

```javascript
eventBus.on('wallet_completed', (walletId) => {

});
```

### Wallet was rejected by the other side

```javascript
eventBus.on('wallet_declined', (wallet, rejector_device_address) => {

});
```

### Wallet has been confirmed by the other party

```javascript
eventBus.on('wallet_approved', (wallet, device_address) => {

});
```

### Created new address

```javascript
eventBus.on('new_wallet_address', (address) => {

});
```

### Created new address

```javascript
eventBus.on("new_address-" + address, () => {

});
```

### Unit saved

```javascript
eventBus.on('saved_unit-' + unit, (objJoint) => {

});
```

### Attempt to pair us with another correspondent

This event is emitted when there is a pairing attempt, this enables bot to decide with the code if the pairing code is valid or not. If you would like to accept any pairing code then [there is easier solution](/configuration#accepting-incoming-connections).

```javascript
eventBus.on("pairing_attempt", (from_address, pairing_secret) => {
    if (pairing_secret == "SOME_SECRET") {
        eventBus.emit("paired", from_address, pairing_secret);
    }
});
```

### Pairing was successful

This event is emitted on successful pairing (also when user removed and re-added the bot).

```javascript
eventBus.on("paired", (from_address, pairing_secret) => {
    let device = require('ocore/device.js');
    // say hi to anyone who pair with bot
    device.sendMessageToDevice(from_address, 'text', 'Hi!');
});
```

### **P**airing was successful using pairing secret

```javascript
eventBus.on('paired_by_secret-' + body, (from_address) => {

});
```

### The paired device has been removed

```javascript
eventBus.on("removed_paired_device", (from_address) => {

});
```

### History update started

```javascript
eventBus.on('refresh_light_started', () => {

});
```

### History update finished

```javascript
eventBus.on('refresh_light_done', () => {

});
```

### A new message string type message has been received

This event is emitted when text message is received by bot.

```javascript
eventBus.on("text", (from_address, body, message_counter) => {
    let device = require('ocore/device.js');
    // echo back the same message
    device.sendMessageToDevice(from_address, 'text', 'ECHO: '+ body);
});
```

### A new message object type message has been received

This event is emitted when object message is received by bot.

```javascript
eventBus.on("object", (from_address, body, message_counter) => {
    let device = require('ocore/device.js');
    // echo back the same object back
    device.sendMessageToDevice(from_address, 'object', body);
});
```

### Change in permission to store message history

```javascript
eventBus.on("chat_recording_pref", (from_address, body, message_counter) => {

});
```

### Created a new shared address

```javascript
eventBus.on("create_new_shared_address", (address_definition_template, assocMemberDeviceAddressesBySigningPaths) => {

});
```

### Signing request

```javascript
eventBus.on("signing_request", (objAddress, address, objUnit, assocPrivatePayloads, from_address, signing_path) => {

});
```

### Signed event

```javascript
eventBus.on("signature-" + device_address + "-" + address + "-" + signing_path + "-" + buf_to_sign.toString("base64"), (sig) => {

});
```

### Refuse to sign

```javascript
eventBus.on('refused_to_sign', (device_address) => {

});
```

### Confirmed on another device

```javascript
eventBus.on('confirm_on_other_devices', () => {

});
```

### All private payments are processed

```javascript
eventBus.on('all_private_payments_handled', (from_address) => {

});
```

### All private payments are processed in a unit

```javascript
eventBus.on('all_private_payments_handled-' + first_chain_unit, () => {

});
```

### Event for custom Request

You can add your own communication protocol on top of the Obyte one. See Request example [there](/websocket-api/request#custom-request).

```javascript
const network = require('ocore/network.js');

eventBus.on('custom_request', function(ws, params, tag) {
    var response = 'put response here';
    return network.sendResponse(ws, tag, response);
}
```

### Event for custom JustSaying

You can add your own communication protocol on top of the Obyte one. See JustSaying example [there](/websocket-api/justsaying#custom-justsaying).

```javascript
eventBus.on('custom_justsaying', function(ws, content) {

};
```

### Database is read and ready to work (only Cordova)

```javascript
eventEmitter.once('ready', () => {
   console.log("db is now ready");
});
```

### Error sending message via ws

```javascript
ws.on('error', (error) => {

});
```


# Websocket API

WebSocket API is a technology that makes it possible to open a communication session between the nodes. Normally you would use the Core library (ocore) or Web library (obyte.js) to make these calls.


# Request

This is a message type, which gets a reply with a response type message.

Example:

```javascript
const network = require('ocore/network.js');
const ws = network.getInboundDeviceWebSocket(device_address);

// function parameters: websocket, command, params, bReroutable, callback
var tag = network.sendRequest(ws, 'get_witnesses', null, false, getParentsAndLastBallAndWitnessListUnit);

function getParentsAndLastBallAndWitnessListUnit(ws, req, witnesses) {
  var params = {
    witnesses: witnesses
  };
  network.sendRequest(ws, 'light/get_parents_and_last_ball_and_witness_list_unit', params, false,
    function(ws, req, response) {
      console.log(response);
    }
  );
}

//you can have your own timeout logic and delete a pending request like this
setTimeout(function() {
  var deleted = network.deletePendingRequest(ws, tag); // true if request was deleted
}, 30*1000);
```

Following is a list of `request` type JSON messages that are sent over the network:

### **Get node list**

This requests returns response with nodes that accept incoming connections.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_peers'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [
          "wss://relay.bytes.cash/bb",
          "wss://hub.obytechina.org/bb",
          "wss://hub.obyte.connectory.io/bb",
          "wss://odex.ooo/bb",
          ...
        ]
    }
}
```

{% endtab %}
{% endtabs %}

### **Get a list of witnesses**

This requests returns response with list of witnesses.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_witnesses'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [
          "4GDZSXHEFVFMHCUCSHZVXBVF5T2LJHMU",
          "BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3",
          "DJMMI5JYA5BWQYSXDPRZJVLW3UGL3GJS",
          ...
        ]
    }
}
```

{% endtab %}
{% endtabs %}

### **Get transaction data**

This requests returns response with unit data. Example shows a unit, which created a new asset.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_joint',
        params: '0xXOuaP5e3z38TF5ooNtDhmwNkh1i21rBWDvrrxKt0U='
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
          "joint": {
            "unit": {
              "unit": "0xXOuaP5e3z38TF5ooNtDhmwNkh1i21rBWDvrrxKt0U=",
              "version": "1.0",
              "alt": "1",
              "witness_list_unit": "oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=",
              "last_ball_unit": "AV4qvQ5JuI7J3EO5pFD6UmMu+j0crPbH17aJfigozrc=",
              "last_ball": "Ogq4+uR6LaDspK89MmyydxRchgdN/BYwXvWXwNCMubQ=",
              "headers_commission": 344,
              "payload_commission": 607,
              "main_chain_index": 2336026,
              "timestamp": 1524844417,
              "parent_units": [
                "IFiHjYbzuAUC9TwcTrmpvezjTKBl6nIXjgjoKuVyCz0="
              ],
              "authors": [
                {
                  "address": "AM6GTUKENBYA54FYDAKX2VLENFZIMXWG",
                  "authentifiers": {
                    "r": "MBWlL31OkibUXhoxmwIcWB/fAx1uWdNTE8PYTBNeN3w+tev4N1anOXjGtXiGW4whW3PfJeTO9fA5WxwyqK/m2w=="
                  }
                }
              ],
              "messages": [
                {
                  "app": "data",
                  "payload_hash": "MiuMtTSgP0brPQijsRc0igb+dxcrkLjXWRE253AE/S8=",
                  "payload_location": "inline",
                  "payload": {
                    "asset": "IYzTSjJg4I3hvUaRXrihRm9+mSEShenPK8l8uKUOD3o=",
                    "decimals": 0,
                    "name": "WCG Point by Byteball",
                    "shortName": "WCG Point",
                    "issuer": "Byteball",
                    "ticker": "WCG",
                    "description": "WCG Point is a honorific token, a recognition of contributing to World Community Grid projects. The token is not transferable, therefore, it cannot be sold and the balance reflects a lifetime contribution to WCG. Some services might choose to offer a privilege to users with large balance of this token."
                  }
                },
                {
                  "app": "payment",
                  "payload_hash": "FaVxPdeRKTgcO/LCDtu/YUZego8xyrnpUMF3V/sujr8=",
                  "payload_location": "inline",
                  "payload": {
                    "inputs": [
                      {
                        "unit": "1p85M8VSRDaAkNoCAdtMrv6cVGpPNNeVJpLzOkzWLk8=",
                        "message_index": 1,
                        "output_index": 0
                      }
                    ],
                    "outputs": [
                      {
                        "address": "AM6GTUKENBYA54FYDAKX2VLENFZIMXWG",
                        "amount": 17890
                      }
                    ]
                  }
                }
              ]
            },
            "ball": "Ef36OjK5m6lQMII4S9MN3iGtQcsvTzzQFLKQZ44UBCg="
          }
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Send transaction data**

This requests returns response whether composed unit was accepted or not. Unit object can be composed with `ocore/composer.js`.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'post_joint',
        params: {Object}
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'accepted'
    }
}
```

{% endtab %}
{% endtabs %}

### **Send heartbeat that you don't sleep**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'heartbeat'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: null
    }
}
```

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'sleep'
    }
}
```

{% endtab %}
{% endtabs %}

### **Subscribe to transaction data**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: "request",
    content: {
        tag: tag,
        command: "subscribe",
        params: {
            subscription_id: crypto.randomBytes(30).toString('base64'),
            last_mci: 0,
            library_version: "0.1"
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: "subscribed"
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light, cannot subscribe you to updates",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Synchronous transaction data**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'catchup',
        params: {
            witnesses: witnesses,
            last_stable_mci: last_stable_mci,
            last_known_mci: last_known_mci
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
            status: 'current'
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Get the hash tree**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_hash_tree',
        params: {
            from_ball: from_ball,
            to_ball: to_bal      
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
          "balls": [
            {
              "unit": "c2teVop7xa1BmH1LPvytvOKU8HHTrprGWQw+uHlWPHo=",
              "ball": "ht1QP48paWg5hpjx+Nbd/DSRFT8WlbQKk9+Uum0/tso=",
              "parent_balls": [
                "aEU1WiY9FQ9ihv9cKkX/EHWDxYYVaWYs2AL1yxyYZAQ="
              ]
            },
            {
              "unit": "tPbC6QLeweGuiGYRPsIhfd0TQWXWASYBJJUPGa9AOfw=",
              "ball": "ba5wFB+gewdRX6nSpxt6+Nt8PaRen4pLIYg3jC6EvIw=",
              "parent_balls": [
                "ht1QP48paWg5hpjx+Nbd/DSRFT8WlbQKk9+Uum0/tso="
              ]
            },
            {
              "unit": "J7quEBEZ5ksq+0vK4cku7NtWkZ4Kxb8aHCu66RkN2eU=",
              "ball": "4B+R+gW91BPmTqxF3G10oWmF4tg5LiHdpMQcL1ezqCo=",
              "parent_balls": [
                "ba5wFB+gewdRX6nSpxt6+Nt8PaRen4pLIYg3jC6EvIw="
              ]
            },
            ...
          ]
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Get the main chain index**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_last_mci'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 3795741
    }
}
```

{% endtab %}
{% endtabs %}

### Send message to client that is connected to hub

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/deliver',
        params: {
            to: device_address,
            pubkey: pubkey,
            signature: signature,
            encrypted_package: encrypted_message
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'accepted'
    }
}
```

{% endtab %}
{% endtabs %}

### **Get temporary public key**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/get_temp_pubkey',
        params: permanent_pubkey
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'TEMP_PUBKEY_PACKAGE'
    }
}
```

{% endtab %}
{% endtabs %}

### **Update temporary public key**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/temp_pubkey',
        params: {
            temp_pubkey: temp_pubkey,
            pubkey: permanent_pubkey,
            signature: signature
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'updated'
    }
}
```

{% endtab %}
{% endtabs %}

### **Enable notifications**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/enable_notification',
        params: registrationId
    }
}
```

{% endtab %}

{% tab title="request.json" %}

```
{
    type: 'response',
    content: {
        tag: tag,
        response: 'ok'
    }
}
```

{% endtab %}
{% endtabs %}

### **Disable notifications**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/disable_notification',
        params: registrationId
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'ok'
    }
}
```

{% endtab %}
{% endtabs %}

### **Get list of chat bots**

This requests returns response with chat bots of connected hub.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/get_bots'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
	type: 'response',
	content: {
		tag: tag,
		response: [
			{
				"id": 29,
				"name": "Buy Bytes with Visa or Mastercard",
				"pairing_code": "A1i/ij0Na4ibEoSyEnTLBUidixtpCUtXKjgn0lFDRQwK@byteball.org/bb#0000",
				"description": "This bot helps to buy Bytes with Visa or Mastercard.  The payments are processed by Indacoin.  Part of the fees paid is offset by the reward you receive from the undistributed funds."
			},
			{
				"id": 31,
				"name": "World Community Grid linking bot",
				"pairing_code": "A/JWTKvgJQ/gq9Ra+TCGbvff23zqJ9Ec3Bp0XHxyZOaJ@byteball.org/bb#0000",
				"description": "Donate your device’s spare computing power to help scientists solve the world’s biggest problems in health and sustainability, and earn some Bytes in the meantime.  This bot allows you to link your Byteball address and WCG account in order to receive daily rewards for your contribution to WCG computations.\n\nWCG is an IBM sponsored project, more info at https://www.worldcommunitygrid.org"
			},
			{
			"id": 36,
				"name": "Username registration bot",
				"pairing_code": "A52nAAlO05BLIfuoZk6ZrW5GjJYvB6XHlCxZBJjpax3c@byteball.org/bb#0000",
				"description": "Buy a username and receive money to your @username instead of a less user-friendly cryptocurrency address.\n\nProceeds from the sale of usernames go to Byteball community fund and help fund the development and promotion of the platform."
			},
			...
		]
	}
}
```

{% endtab %}
{% endtabs %}

### **Get asset metadata**

This requests returns response with asset metadata (unit and registry). Example gets WCG Point asset metadata.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'hub/get_asset_metadata',
        params: 'IYzTSjJg4I3hvUaRXrihRm9+mSEShenPK8l8uKUOD3o='
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
            "metadata_unit": "0xXOuaP5e3z38TF5ooNtDhmwNkh1i21rBWDvrrxKt0U=",
            "registry_address": "AM6GTUKENBYA54FYDAKX2VLENFZIMXWG",
            "suffix": null
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Get transaction history**

This requests returns response with transaction history of specified addresses.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_history',
        params: {
            witnesses: witnesses,
            requested_joints: joints,
            addresses: addresses
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {Object}
    }
}
```

{% endtab %}
{% endtabs %}

### **Get chain link proofs**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_link_proofs',
        params: units
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [Array]
    }
}
```

{% endtab %}
{% endtabs %}

### **Get the parent unit and the witness unit**

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_parents_and_last_ball_and_witness_list_unit',
        params: {
            witnesses: witnesses
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
          "parent_units": [
            "QEdpDamxpez8dlOE4nF8TWwHs+efokBXlxQHK27/y4g="
          ],
          "last_stable_mc_ball": "xF0K/NKO6CGMU6XeBGXzurEcCajomfZMOAU4XmAy+6o=",
          "last_stable_mc_ball_unit": "R/RosYwuXJ/mXw5TTfWLVLHdtnnzaKn5EgJkDfzagcs=",
          "last_stable_mc_ball_mci": 3795817,
          "witness_list_unit": "J8QFgTLI+3EkuAxX+eL6a0q114PJ4h4EOAiHAzxUp24="
        }
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### **Get specific attestation unit**

This requests returns response with attestation units for specified field and value.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_attestation',
        params: {
            attestor_address: 'FZP4ZJBMS57LYL76S3J75OJYXGTFAIBL',
            field: 'name',
            value: 'tarmo888'
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 'jeiBABcZI5fjyIPHkpb2PipLHzjUgafoPd0b6bdsGUI='
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Get all attestation data about address

This requests returns response with all the attestation data about specific address.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_attestations',
        params: {
            address: 'MNWLVYTQL5OF25DRRCR5DFNYXLSFY43K'
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [
          {
            "unit": "jeiBABcZI5fjyIPHkpb2PipLHzjUgafoPd0b6bdsGUI=",
            "attestor_address": "FZP4ZJBMS57LYL76S3J75OJYXGTFAIBL",
            "profile": {
              "name": "tarmo888"
            }
          }
        ]
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Pick divisible inputs for amount

This requests returns response with spendable inputs for specified asset, amount and addresses.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/pick_divisible_coins_for_amount',
        params: {
            asset: '',
            addresses: addresses,
            last_ball_mci: last_ball_mci,
            amount: amount,
            spend_unconfirmed: 'own'
        }
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {Object}
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Get address definition

This requests returns response with address definition (smart-contracts have address smart-contract definition only after somebody has spent from it).

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_definition',
        params: 'JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [
          "sig",
          {
            "pubkey": "Aiy5z+jM1ySTZl1Qz1YZJouF7tU6BU++SYc/xe0Rj5OZ"
          }
        ]
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Get balances of addresses

This request returns a response with balances of one or more addresses.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_balances',
        params: [
            'JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725',
            'UENJPVZ7HVHM6QGVGT6MWOJGGRTUTJXQ'
        ]
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: {
          "JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725": {
            "base": {
              "stable": 1454617324,
              "pending": 2417784
            }
          },
          "UENJPVZ7HVHM6QGVGT6MWOJGGRTUTJXQ": {
            "base": {
              "stable": 0,
              "pending": 6
            }
          }
        }
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Get profile unit IDs of addresses

It is possible for users to post a profile information about themselves, this request returns a response with all the profile data units.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'light/get_profile_units',
        params: [
            'MNWLVYTQL5OF25DRRCR5DFNYXLSFY43K'
        ]
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: [
          "gUrJfmdDeYhTKAHM5ywydHXpvcensbkv8TPQLuPG3b0="
        ]
    }
}
```

```javascript
{
    type: "response",
    content: {
        tag: tag,
        response: {
            error: "I'm light myself, can't serve you",
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Get the current state of votes for system vars

Get information about the current state of user votes for system variables such as `op_list`, `threshold_size`, `base_tps_fee`, `tps_interval`, and `tps_fee_multiplier`. Since later votes by the same user concerning the same variable overwrite their previous votes, only the latest votes are shown. The response also includes the balances of the voting addresses. They determine the weight of the votes.

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'get_system_var_votes'
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```json
{
    type: "response",
    content: {
        tag: tag,
        response: {
            votes: {
                op_list: [
                    {
                        address: "EJC4A7WQGHEZEKW6RLO7F26SAR4LAQBU",
                        unit: "LpxhHEfxbOyj0sPlp6UC6XrRABvRJiH4qKEsOcMd1Bc=",
                        timestamp: 1727794413,
                        value: [
                            "2FF7PSL7FYXVU5UIQHCVDTTPUOOG75GX",
                            ....
                        ],
                        is_stable: 1
                    },
                    ....
                ],
                threshold_size: [
                    {
                        address: "EJC4A7WQGHEZEKW6RLO7F26SAR4LAQBU",
                        unit: "LpxhHEfxbOyj0sPlp6UC6XrRABvRJiH4qKEsOcMd1Bc=",
                        timestamp: 1727794413,
                        value: 10000,
                        is_stable: 1
                    },
                    ....
                ],
                ....
            },
            balances: {
                "EJC4A7WQGHEZEKW6RLO7F26SAR4LAQBU": 188576687136,
                ....
            }
        }
    }
}
```

{% endtab %}
{% endtabs %}

### Custom Request

You can add your own communication protocol on top of the Obyte one. See event [there](/list-of-events#event-for-custom-request).

{% tabs %}
{% tab title="request.json" %}

```javascript
{
    type: 'request',
    content: {
        tag: tag,
        command: 'custom',
        params: params
    }
}
```

{% endtab %}

{% tab title="response.json" %}

```javascript
{
    type: 'response',
    content: {
        tag: tag,
        response: 0 || 'some response' || {Object} || [Array]
    }
}
```

{% endtab %}
{% endtabs %}


# JustSaying

This is a message type, which doesn't require response back.

Example:

```javascript
const network = require('ocore/network.js');
const eventBus = require('ocore/event_bus.js');
const ws = network.getInboundDeviceWebSocket(device_address);

// function parameters: websocket, subject, body
network.sendJustsaying(ws, 'custom', 'some data');

eventBus.on('custom_justsaying', function(ws, content) {
    console.log(content);
};
```

Following is a list of `justsaying` type JSON messages that are sent over the network:

### **Send version information**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'version', 
        body: {
            protocol_version: protocol_version, 
            alt: alt, 
            library: name, 
            library_version: version, 
            program: program, 
            program_version: program_version
        }
    }
}
```

### **Send free joints**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'free_joints_end', 
        body: null
    }
}
```

### **Send a private transaction**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'private_payment', 
        body: privateElement
    }
}
```

### **Share your node WebSocket URL to accept incoming connections**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'my_url', 
        body: my_url
    }
}
```

### **Ask to verify your WebSocket URL**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'want_echo', 
        body: random_echo_string
    }
}
```

### **Verify your WebSocket URL with echo message**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'your_echo', 
        body: echo_string
    }
}
```

### **Log in to Hub**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/login', 
        body: {
            challenge: challenge,
            pubkey: pubkey,
            signature: signature
        }
    }
}
```

### **Get new messages**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/refresh', 
        body: null
    }
}
```

### Remove handled message

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/delete', 
        body: message_hash
    }
}
```

### **Send pairing message**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/challenge', 
        body: challenge
    }
}
```

### **Send message to device**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/message', 
        body: {
            message_hash: message_hash,
            message: message
        }
    }
}
```

### Ask more messages

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/message_box_status', 
        body: 'has_more'
    }
}
```

### **Light wallet transaction update**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'light/have_updates', 
        body: null
    }
}
```

### **Light wallet sequence became bad**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'light/sequence_became_bad', 
        body: arrUniqueUnits
    }
}
```

### **Add light wallet to monitor address**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'light/new_address_to_watch', 
        body: address
    }
}
```

### **Send bug report**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'bugreport', 
        body: {
            message: message,
            exception: exception
        }
    }
}
```

### Push project number (only accepted from hub)

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'hub/push_project_number', 
        body: {
            projectNumber: projectNumber
        }
    }
}
```

### New version is available (only accepted from hub)

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'new_version', 
        body: {
            version: version
        }
    }
}
```

### **Exchange rates (only accepted from hub)**

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'exchange_rates', 
        body: exchangeRates
    }
}
```

### Ask to update (only accepted from hub)

```javascript
{
    type: 'justsaying',
    content: {
        subject: 'upgrade_required', 
        body: null
    }
}
```

### Watch system variables

```
{
    type: 'justsaying',
    content: {
        subject: 'watch_system_vars', 
        body: null
    }
}
```

This will subscribe you to updates of the currently active system variables and votes for them.

Immediately after this request, you'll get the current state of all system variables and their past values with the MCIs when they were voted in:

```
{
    type: 'justsaying',
    content: {
        subject: 'system_vars', 
        body: {
            op_list: [
                {
                    vote_count_mci: 123,
                    is_emergency: 0,
                    value: [
                        "2FF7PSL7FYXVU5UIQHCVDTTPUOOG75GX",
                        ....
                    ]
                },
                .....
            ],
            threshold_size: [
                {
                    vote_count_mci: 456,
                    is_emergency: 0,
                    value: 10000
                },
                .....
            ],
            .....    
        }
    }
}
```

Similar data will be pushed to you whenever any system variable changes as a result of vote count.

Also, user votes will be pushed to you as soon as they are sent by users (first, with `is_stable=0`, then with `is_stable=1` as soon as the voting transaction becomes final):

```
{
    type: "justsaying",
    content: {
        subject: "system_var_vote", 
        body: {
            subject: "op_list",
            value: [
                "2FF7PSL7FYXVU5UIQHCVDTTPUOOG75GX",
                ....
            ],
            author_addresses: ["EJC4A7WQGHEZEKW6RLO7F26SAR4LAQBU"],
            unit: "LpxhHEfxbOyj0sPlp6UC6XrRABvRJiH4qKEsOcMd1Bc=",
            is_stable: 1
        }
    }
}
```

### Custom JustSaying

You can add your own communication protocol on top of the Obyte one. See event [there](/list-of-events#event-for-custom-justsaying).

{% code title="" %}

```javascript
{
    type: 'justsaying',
    content: {
        tag: tag,
        subject: 'custom',
        body: body
    }
}
```

{% endcode %}


# Obyte for merchants

Obyte has a payment gateway, Woocommerce plugin and cashback program for merchants who would like to accept Bytes for goods or services.


# Payments gateway

Obyte can accept Byte payments for you and notify you when the Bytes have arrived to your account. There is also an easy-to-setup Wordpress/Woocommerce plugin.

## Requirements

* A Obyte light wallet to provide us with your merchant Obyte address (you do not need to run the heavy full wallet, we are running it for you). Download the wallet from <https://obyte.org>.
* If you want to use our Woocommerce plugin skip reading now and go to: <https://wordpress.org/plugins/woobytes-gateway/>
* Upon going live a *merchant\_id* and a *secret\_key*. Contact us on <https://obyte.org/discord> #merchants channel to get your `merchant_id` and you `secret_key`.

## Integration process

**Step 1:** Either in *test* mode or in *live* mode, customize the Obyte quick payment button script with your merchant parameters and insert it in your checkout web page. Obyte quick payment button init script has to be inserted in the header section of your checkout page and the button itself can be displayed anywhere on the page in a Div container. The *test* mode triggers the whole notification process except there is **no real payment**. Once you are done with your tests, switch to *live* mode by changing the "mode" parameter from "*test*" to "*live*" in the button init script.\
See example.html: <https://github.com/tarmo888/bbfm/tree/master/bbfm_www/example>

**Step 2:** We notify you (upon your choice), either by mail and/or by a GET or a POST to your server, when a payment for your sale has arrived, we simultaneously send you the payment to your merchant address, minus our fee. At this stage you receive a first notification with an *unconfirmed* "result" field. When the payment is confirmed by the network you receive a second notification with a *ok* "result" field. Such notification of a confirmed payment typically takes between 5 to 15 minutes from the customer click to pay (live mode) or 1 minute (in test mode). You then have to handle the notification on your end so that you actualy process your customer order. You can process the delivery as soon as you received the *ok* notification (processing on *unconfirmed* notification is at your own risk!). In any case always check on your end that ***received\_amount*** does match ***amount\_asked\_in\_B*** before processing the order or contact your customer for missing Bytes (the event of an incomplete payment is not an error case on our end but it must be one on your end).

## Parameters

### Step 1: Obyte payment button field list

* **order\_UID** (mandatory): Your merchant order ID *(should match /^\[a-zA-Z0-9-]{4,20}$/)*.
* **merchant\_return\_url** (optional): The full URL we will POST or GET to notify you a payment arrived.
* **mode\_notif** (optional, default is get): Shall we GET or POST the notification to your server? *(should match get | post)*.
* **currency** (optional, default B): Currency from which convert the amount into Bytes *(should be B (for Bytes), BTC, ETH, USD, EUR, PLN, KRW, GBP, CAD, JPY, RUB, TRY, NZD, AUD, CHF, UAH, HKD, SGD, NGN, PHP, MXN, BRL, THB, CLP, CNY, CZK, DKK, HUF, IDR, ILS, INR, MYR, NOK, PKR, SEK, TWD, ZAR, VND, BOB, COP, PEN, ARS, ISK)*. Conversion is done automaticaly in real time at rates from [CoinPaprika](https://api.coinpaprika.com/).
* **merchant\_email** (optional): Fill in your email address if you want to be notified by email when payment arrives OR to get an alert email if we were not able to GET or POST to notify you on your ***merchant\_return\_url***. Take care to whitelist emails from "<noreply@obyte-for-merchants.com>" (you can usually do that by adding this email to your contacts).
* **amount** (mandatory): The amount charged to your customer in ***currency** (should match /^\[0-9]+.?\[0-9]\*$/)*. Minimum amount is 1500 Bytes (or its equivalent in *currency*) Maximum amount is 1000 GBytes.
* **byteball\_merchant\_address** (mandatory): Your unique Obyte merchant address to receive your payment.
* **merchant\_id** (mandatory): In *test* mode ***merchant\_id*** is *test\_merchant*. Contact us on <https://obyte.org/discord> #merchants channel to get a merchant id when you first go live.
* **mode** (mandatory): live | test. Are you testing the implementation or are you running the Obyte payment button from a production server? *(should match live or test and will be returned **as is** on **merchant\_return\_url**)*.
* **attach** (optional): free text field (255 chars). Will be returned as is for your own convenience (must match /^\[a-zA-Z0-9\_.@,=?& -]{0,255}$/).
* **qrcode** (optional): you can here indicate your own qrcode url mask to use the qrcode api of your choice, using {text} as url placeholder. By default, the Google QRCode API is used, that is to say the value is: '<https://chart.googleapis.com/chart?chs=200x200&cht=qr&chl={text}&chld=H>' But you can change it and choose for instance the Chinese liantu API by setting the value: '<http://qr.liantu.com/api.php?text={text}&w=100>'

### Step 2: Returned field list on ***merchant\_return\_url***

* **mode**: live | test

  ***WARNING! WARNING! WARNING!*** Always check this field as in test mode the notification of payment received is always sent for integration and test purpose without any effective payment. Do not use the test mode on a production merchant server.
* **result**: nok | incoming | unconfirmed | ok

  *'nok'*: check **error\_msg** for text error.

  *'incoming'*: the payment has been sent to us by your customer but it is still waiting for network confirmation.

  *'unconfirmed'*: the payment has been sent to you but it is still waiting for network confirmation.

  *'ok'*: final step. The payment unit we sent to you has been confirmed by the network. Process the order on your end.
* **error\_msg** (occurence: 1 on *result=nok* or 0): human readable text field
* **order\_UID**: Your merchant order ID
* **currency**: B (for Bytes, see rest above).
* **amount\_asked\_in\_currency** (occurence: 0 on *currency=B* or 1): decimal

  ***WARNING! WARNING! WARNING!*** Always check ***amount\_asked\_in\_currency*** does match the amount of the order in your own database and in your expected currency.
* **currency\_B\_rate** (occurence: 0 on *currency=B* or 1): decimal
* **amount\_asked\_in\_B**: integer (in Bytes)
* **fee**: our fee (in Bytes)
* **received\_amount**: the amount we received (in Bytes).

  ***WARNING! WARNING! WARNING!*** check on your end that ***received\_amount*** does match ***amount\_asked\_in\_B*** before processing the order. Contact your customer if some Bytes are missing from what you expected (the event of an incomplete payment is not an error case on our end but it must be one on your end).
* **receive\_unit**: the DAG unit that shows the payment from your customer to our Obyte address.
* **amount\_sent**: the amount sent to your ***byteball\_merchant\_address*** (***received\_amount*** minus ***fee***)
* **unit**: the DAG unit that shows the payment from our Obyte address to your ***byteball\_merchant\_address***
* **sha256\_digest**: the digest of the notification is computed as sha256(secret\_key+order\_UID+merchant\_return\_url+merchant\_email) where '+' means concatenate.

  ***WARNING! WARNING! WARNING!*** You SHOULD re-calculate on your end the sha256 digest on each notification to check if it does match *sha256\_digest*. An attacker could POST or GET to your merchant server a false notification but he will never be able to compute a correct *sha256\_digest*. In *test* mode *secret\_key* is *134c8nfWK4XrrfkgN1UJ9ytqae76d7uDbs*.
* **attach**: free text field (255 chars) returned "as is" from step 1 for your own convenience.

Note: if you filled in the optional **merchant\_email** on step 1 you will receive the same information in an email plus possible alert email when - for any reason - if we were not able to notify you on **merchant\_return\_url** (for example a server time out on your end). We advise you to provide the **merchant\_email** in order to receive such alert emails. We strongly advise you to whitelist <noreply@obyte-for-merchants.com>


# Cashback API

This API is for merchants and payment processors who participate in the Obyte cashback program.

This is API documentation to integrate cashback to your point of sale device, but you could also [build your own cashback app](https://github.com/myactivities/byteball-cashback-app), where this API has already been implemented. The first thing you need [sign up to Cashback Program](https://medium.com/obyte/byteball-cashback-program-9c717b8d3173) in order to get partner name and partner key.

After you accepted payment from the customer, you use this API to request cashback for your customer. You send a POST request to:

`https://byte.money/new_purchase`

(for testnet use `https://byte.money/test/new_purchase`)

and pass the following parameters:

* `partner`: (string) your partner name you were assigned when you signed up for the program.
* `partner_key`: (string) partner key used to authenticate your requests.
* `customer`: (string) any id of the customer who made a purchase such as customer name or id in your database. This field must be the same when the same customer makes another purchase.
* `order_id`: (string) unique id of the order associated with the purchase. You should never request cashback for the same order id again.
* `description`: (string) description of the purchase.
* `merchant`: (string) this field is used by payment processors only to identify the individual merchant. When another purchase is made from the same merchant, this fiels should be the same.
* `address`: (string) Wallet address or email address of the customer. The cashback will be sent to this address. If it is email address, a [textcoin](https://medium.com/byteball/sending-cryptocurrency-to-email-5c9bce22b8a9) will be sent. If the textcoin is not claimed within 1 week, it will be taken back.
* `currency`: (string) currency of the purchase. Supported values: USD, EUR, RUR, GBYTE, BTC. If the purchase was paid in any other currency, you should convert its amount to any of the supported currencies except GBYTE.
* `currency_amount`: (number) amount of the purchase in `currency`.
* `partner_cashback_percentage`: (number) the percentage of the amount you want to pay to the customer out of your own funds in addition to the regular cashback. Obyte will add the same percentage out of the distribution fund (merchant match). Default it 0. You have to deposit the funds in advance in order to fund this option.
* `purchase_unit`: (string) unit (transaction id) of the customer's purchase if it was paid in GBYTE.

### Response format

The response is in JSON format. It always contains a `result` field, which is either 'ok' or 'error'.

If the cashback was successfully sent to the customer, the response has `"result": "ok"` and also indicates the cashback amount and the unit it was sent in:

```javascript
{
    "result": "ok",
    "cashback_amount": 101318,
    "unit": "kYbc5KGKB/KnjynYePEF4cpumKmOz22xVKSVWbmtZ0M="
}
```

In case of an error, the response has `"result": "error"` and error description in `error` field:

```javascript
{
    "result": "error",
    "error": "authentication failed"
}
```


# JSON-RPC

JSON-RPC is a remote procedure call protocol encoded in JSON. It allows multiple calls to be sent to the server which may be answered out of order.


# Exposing RPC interface

If you are developing a service on Obyte and your programming language is node.js, your best option is to just require() the ocore modules that you need.

For exchanges and other custody wallets, there is a specialized [JSON RPC service](/json-rpc/running-rpc-service). However it is limited and exposes only those functions that the exchanges need.

If you are developing a service on Obyte and your programming language is node.js, your best option is to just `require()` the ocore modules that you need (most likely you need [headless-obyte](https://github.com/byteball/headless-byteball) and various modules inside [ocore](https://github.com/byteball/byteballcore)). This way, you'll also be running a Obyte node in-process.

If you are programming in another language, or you'd like to run your Obyte node in a separate process, you can still access many of the functions of `headless-obyte` and `ocore`by creating a thin RPC wrapper around the required functions and then calling them via JSON-RPC.

## Get started

To get started, we can add RPCify to existing project or directly to headless-obyte with this command:

```bash
npm install https://github.com/byteball/rpcify.git
```

See the documentation about [RPCify](https://github.com/byteball/rpcify) for more details.

## Exposing functions and events

To expose the required functions via JSON-RPC, create a project that has `headless-obyte`, `ocore` (and any other ocore modules) and [RPCify](https://github.com/byteball/rpcify) as dependencies:

```javascript
var rpcify = require('rpcify');
var eventBus = require('ocore/event_bus.js');

// this is a module whose methods you want to expose via RPC
var headlessWallet = require('headless-obyte'); // when headless-obyte is dependency of your project
//var headlessWallet = require('../start.js'); // when this script is in headless-obyte tools folder
var balances = require('ocore/balances.js'); // another such module

// most of these functions become available only after the passphrase is entered
eventBus.once('headless_wallet_ready', function(){
	// start listening on RPC port
	rpcify.listen(6333, '127.0.0.1');

	// expose some functions via RPC
	rpcify.expose(headlessWallet.issueChangeAddressAndSendPayment);
	rpcify.expose(balances.readBalance, true);
	rpcify.expose(balances.readAllUnspentOutputs);
	rpcify.expose([
		headlessWallet.readFirstAddress,
		headlessWallet.readSingleWallet,
		headlessWallet.issueOrSelectAddressByIndex
	], true);

	// expose some events 
	rpcify.exposeEvent(eventBus, "my_transactions_became_stable");
	rpcify.exposeEvent(eventBus, "new_my_transactions");
});
```

## Calling with HTTP requests

From another Node.js app, calling the function would look something like this:

```javascript
var rpc    = require('json-rpc2');
var client = rpc.Client.$create(6333, '127.0.0.1');

client.call('issueChangeAddressAndSendPayment', [asset, amount, to_address, device_address], function(err, unit) {
    ...
});
```

## Listening via WebSockets

From another Node.js app, sending function calls and listening to events would look something like this:

```javascript
var WebSocket = require('ws');
var ws        = new WebSocket("ws://127.0.0.1:6333");

ws.on('open', function onWsOpen() {
	console.log("ws open");
	ws.send(JSON.stringify({
		"jsonrpc":"2.0",
		"id":1,
		"method":"readBalance",
		"params":["LUTKZPUKQJDQMUUZAH4ULED6FSCA2FLI"]
	})); // send a command
});

ws.on('error', function onWsError(e){
	console.log("websocket error"+e);
})

ws.on('message', function onWsMessage(message){ // JSON responses
	console.error(message);
	// {"jsonrpc":"2.0","result":{"base":{"stable":0,"pending":0}},"error":null,"id":1} // response to readBalance
  // {"event":"my_transactions_became_stable","data":[["1pLZa3aVicNLE6vcClG2IvBe+tO0V7kDsxuzQCGlGuQ="]]} // event my_transactions_became_stable
});
```


# Running RPC service

If you run an exchange, you will likely want to interact with your Obyte node via RPC interface.

By default, RPC service is not enabled for security reasons. To enable it, you should start your headless node differently: instead of `node start.js`, cd to `tools` folder and start RPC-enabled node:

```javascript
cd tools
node rpc_service.js
```

This headless node works as usual, plus it listens to port 6332 of loop-back interface (configured in [conf.js](https://github.com/byteball/headless-byteball/blob/master/conf.js) or conf.json) for JSON-RPC commands. Here are some of the commands that are usually needed by custody wallet solutions, like exchanges (these are similar to older Bitcoin node RPC methods): `getinfo`, `getnewaddress`, `validateaddress`, `getbalance`, `listtransactions`, `sendtoaddress`.

There are more methods available, which documentation can be read from [headless wallet documentation page](https://byteball.github.io/headless-obyte/rpc_service.html), which is generated from JSDoc code comments.

These are all simple HTTP request, but you can build your own [custom JSON-RPC API that can use WebSockets](/json-rpc/json-rpc-interface#listening-via-websockets) too and even make it to listen events.

## getinfo

The command returns information about the current state of the DAG.

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"getinfo", "params":{} }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": {
    "connections": 5,
    "last_mci": 253151,
    "last_stable_mci": 253120,
    "count_unhandled": 0
  },
  "id": 1
}
```

The command has no parameters and returns an object with 4 fields:

* `connections`: number of incoming and outgoing connections
* `last_mci`: the highest known main chain index (MCI)
* `last_stable_mci`: last stable MCI (stability point)
* `count_unhandled`: number of unhandled units in the queue. Large number indicates that sync is still in progress, 0 or small number means that the node is synced (it can occasionally go above 0 when new units are received out of order).

## getnewaddress

This command generates a new address in your wallet. You will likely want to use it to create a new deposit address and bind it to a user account.

Example usage:

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"getnewaddress", "params":{} }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": "QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3",
  "id": 1
}
```

The command has no parameters and the response is a newly generated wallet address (32-character string).

## validateaddress

This command validates a wallet address and returns `true` or `false`.

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"validateaddress", "params":["QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3"] }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": true,
  "id": 1
}
```

You will likely want to use it before saving a withdrawal address for a customer. There is `verifyaddress` alias for this method too.

## getbalance

Returns the balance of the specified address or the entire wallet.

Example usage for querying wallet balance:

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"getbalance", "params":{} }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": {
    "base": {
      "stable": 8000,
      "pending": 0
    }
  },
  "id": 1
}
```

Querying balance of an individual address:

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"getbalance", "params":["QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3"] }' http://127.0.0.1:6332 | json_pp
```

To query the balance of the entire wallet, parameters must be empty. To query the balance of an individual address, pass it as the only element of the params array.

The response is an object, keyed by asset ID ("base" for Bytes). For each asset, there is another nested object with keys `stable` and `pending` for stable and pending balances respectively. Balances are in the smallest units (bytes for the native currency), they are always integers.

If the queried address is invalid, you receive error "invalid address". If the address does not belong to your wallet, you receive error "address not found".

## listtransactions

Use it to get the list of transactions on the wallet or on a specific address.

Example request for transactions on the entire wallet (all addresses):

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"listtransactions", "params":{"since_mci": 1234} }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": [
    {
      "action": "received",
      "amount": 3000,
      "my_address": "YA3RYZ6FEUG3YEIDIJICGVPD6PPCTIZK",
      "arrPayerAddresses": [
        "EENED5HS2Y7IJ5HACSH4GHSCFRBLA6CN"
      ],
      "confirmations": 0,
      "unit": "sALugOU8fjVyUvtfKPP0pxlE74GlPqOJxMbwxA1B+eE=",
      "fee": 588,
      "time": "1490452729",
      "level": 253518
    },
    {
      "action": "received",
      "amount": 5000,
      "my_address": "QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3",
      "arrPayerAddresses": [
        "UOOHQW4ZKPTII4ZEE4ENAM5PC6LWAQHQ"
      ],
      "confirmations": 1,
      "unit": "vlt1vzMtLCIpb8K+IrvqdpNLA9DkkNAGABJ420NvOBs=",
      "fee": 541,
      "time": "1490452322",
      "level": 253483
    }
  ],
  "id": 1
}
```

On individual address:

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"listtransactions", "params":["QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3"] }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": [
    {
      "action": "received",
      "amount": 5000,
      "my_address": "QZEM3UWTG5MPKYZYRMUZLNLX5AL437O3",
      "arrPayerAddresses": [
        "UOOHQW4ZKPTII4ZEE4ENAM5PC6LWAQHQ"
      ],
      "confirmations": 0,
      "unit": "vlt1vzMtLCIpb8K+IrvqdpNLA9DkkNAGABJ420NvOBs=",
      "fee": 541,
      "time": "1490452322",
      "level": 253483
    }
  ],
  "id": 1
}
```

To query the transactions on an individual address, pass it as the only element of the `params` *array*. In this case, only transactions in *bytes* are returned. If the passed address is invalid, you receive error "invalid address".

Using `params` as an `object` gives more flexibility of parameter ordering, but if `address` is set in a object or first element of array, all other parameters are ignored.

To get the list of transactions in a particular asset, set an `asset` parameter in `params`. If `asset` is `null` or omitted, transactions in bytes will be returned.

To query the list of transactions since a particular main chain index (MCI), specify `since_mci`property in the `params` object, e.g. `"params": {"since_mci":254000}` or `"params": {"since_mci":254000; "asset": "f2TMkqij/E3qx3ALfVBA8q5ve5xAwimUm92UrEribIE="}`. The full list of matching transactions will be returned, however large it is.

To query an individual transaction, specify its unit in the `params` object: `"params": {"unit":"vlt1vzMtLCIpb8K+IrvqdpNLA9DkkNAGABJ420NvOBs="}`.

The response is an array of transactions in reverse chronological order.

Each transaction is described by an object with the following fields:

* `action`: string, one of `invalid`, `received`, `sent`, `moved`.
* `amount`: integer, amount of the transaction in the smallest units
* `my_address`: string, the address that belongs to your wallet and received funds (for `received`and `moved` actions only)
* `addressTo`: string, the address where the funds were moved (for `moved` and `sent` actions only)
* `arrPayerAddresses`: array of payer addresses (for `received` only)
* `confirmations`: integer 0 (pending) or 1 (final), shows confirmation status of the transaction
* `unit`: string, unit of the transaction (also known as transaction id)
* `fee`: integer, fee in bytes
* `time`: integer, seconds since the Epoch
* `level`: integer, level of the unit in the DAG
* `mci`: integer, MCI of the unit. It can change while the unit is still pending and becomes immutable after the unit gets final

### Waiting for deposits

To operate an exchange, you'll want to wait for new deposits using the following scenario:

* call `getinfo` and remember `last_stable_mci`, you'll use it in the following (not this one) iteration;
* call `listtransactions` with `since_mci` set to `last_stable_mci` remembered from the previous (not this one!) iteration;
* look for transactions with `action`s `received` and `moved` (you need `moved` in case one user withdraws to a deposit address of another user) and identify the user by `my_address`;
* wait;
* repeat the cycle.

In each cycle, save `last_stable_mci` in persistent storage and start from it after the wallet is restarted.

If you support several Obyte-issued assets, you'll need to call `listtransactions` with that asset parameter and store `last_stable_mci` from `getinfo` method for each asset individually.

## sendtoaddress

Use this command to withdraw bytes or another asset. Example usage:

```javascript
$ curl -s --data '{"jsonrpc":"2.0", "id":1, "method":"sendtoaddress", "params":["BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3", 1000] }' http://127.0.0.1:6332 | json_pp

{
  "jsonrpc": "2.0",
  "result": "vuudtbL5ASwr0LJZ9tuV4S0j/lIsotJCKifphvGATmU=",
  "id": 1
}
```

There are 3 parameters to this command:

* destination address (32-character string);
* amount in bytes or smallest indivisible units (integer);
* (optional) asset (44-character string or `null`). If missing or `null`, the asset is assumed to be bytes.

On success, the response is the unit of the spending transaction (string). If the command failed, an error message is returned. It is possible that the command returns error due to lack of confirmed funds, in this case you should retry the command in a few minutes. If the request timed out without returning an error, do not retry automatically, the funds might be already sent!

If the destination address is invalid, the command returns error "invalid address". To avoid this, it is recommended to validate user-entered withdrawal address using [`validateaddress`](#validateaddress) above or [C++ function](https://wiki.obyte.org/Dev#Obyte_address_validation_in_C.2B.2B) or [ocore library module](https://github.com/byteball/ocore/blob/master/validation_utils.js) in NodeJs:

```javascript
var validationUtils = require("ocore/validation_utils.js");
if (!validationUtils.isValidAddress(address)){
  // notify user that the entered wallet address is invalid
}
```

## Additional methods

More detailed documentation of all RPC service methods can be found there <https://byteball.github.io/headless-obyte/rpc_service.html>


# Libraries and Scripts

* [ocore](https://github.com/byteball/ocore) - official core networking and consensus library for node.js
* [headless-obyte](https://github.com/byteball/headless-obyte) - official wallet and messaging library for node.js
* [obyte-browser-chat](https://github.com/byteball/obyte-browser-chat) - official messaging library for node.js and browsers
* [obyte.js](https://obytejs.com) - Lightweight wallet library for working with Obyte from browser and node.js
* [kbyte.js](https://bonustrack.gitbook.io/kbyte/) - Lightweight networking-only JS library (predecessor of obyte.js)
* [owallet.js](https://github.com/olabs-org/owallet.js) - Lightweight wallet library JS library (based on obyte.js)
* [VS Code plugin for Oscript](https://marketplace.visualstudio.com/items?itemName=obyte.oscript-vscode-plugin)
* [aa-testkit](https://github.com/valyakin/aa-testkit) - Instant Obyte devnet network set up and testing
* [parser-aa-vars](https://github.com/olabs-org/parser-aa-vars) - Script for parsing variables from AA
* [aabot](https://github.com/byteball/aabot) - Node.js library for interacting with Autonomous Agents and tracking their state
* [aagent.js ](https://github.com/olabs-org/aagent.js)- Helper library for AA data and events
* [AA-channels-lib](https://github.com/byteball/aa-channels-lib) - a general purpose library for payment channels
* [Pay-Per-Call API Library](https://github.com/byteball/pay-per-call-API) - pay-as-you-go payment library for API use
* [byteduino](https://github.com/Papabyte/byteduino) - A very light C/C++ implementation of Obyte for Arduino ESP8266 and ESP32
* [ocore-wallet-service](https://github.com/guantau/ocore-wallet-service) - A Multisig HD Obyte Light Wallet API Service
* [ocore-wallet](https://github.com/guantau/ocore-wallet) - A Simple Command Line Interface Wallet for Obyte using OWS/OWC
* [Obyte Assets Ledger](https://github.com/byteball/obyte-assets-ledger) - API for headless wallet, which can be used as internal exchange ledger with its own tokens.
* [byteball-rpc-client](https://github.com/emre/byteball-rpc-client) - JSON-RPC client on Python


