# Obyte.js

A pure and powerful JavaScript Obyte library.

{% content-ref url="/pages/-LJ4TbBVSWsrKdpWEsUz" %}
[Quick start](/getting-started/quick-start)
{% endcontent-ref %}

{% content-ref url="/pages/-LJU1DogFsLlfL3PS6\_L" %}
[Generate a random address](/utils/generate-wallet)
{% endcontent-ref %}


# Quick start

To install and run Obyte.js, follow this quick start guide.

### Install

Obyte.js was designed to work both in the browser and in Node.js.

#### Node.js

To install Obyte.js on Node.js, open your terminal and run:

```
npm i obyte --save
```

#### Browser

You can create an index.html file and include Obyte.js with:

```markup
<script src="https://cdn.jsdelivr.net/npm/obyte"></script>
```

### Usage

Ways to initiate WebSocket client:

```javascript
const obyte = require('obyte');

// Connect to mainnet official node 'wss://obyte.org/bb'
const client = new obyte.Client();

// Connect to a custom node
const client = new obyte.Client('wss://relay.bytes.cash/bb');

// Connect to testnet
const options = { testnet: true };
const client = new obyte.Client('wss://obyte.org/bb-test', options);
```

Available client options:

| Option         | Default | Description                                                                 |
| -------------- | ------- | --------------------------------------------------------------------------- |
| `testnet`      | `false` | connect to testnet                                                          |
| `reconnect`    | `false` | automatically reconnect (one attempt per second) after the connection drops |
| `closeIfError` | `false` | close on the first connection error instead of reconnecting                 |

#### Connection lifecycle <a href="#connection-lifecycle" id="connection-lifecycle"></a>

`onConnect` fires on every successful connection — including every reconnection when `reconnect: true` is set. Notification subscriptions live for a single connection *by design*, so register them inside `onConnect` to have them set up again after every reconnect:

```js
const client = new obyte.Client('wss://obyte.org/bb', { reconnect: true });

client.onConnect(function() {
  // per-connection setup goes here: it runs again after every reconnect

  // hub-side subscriptions are per-connection too: the hub forgets which AAs
  // this connection watched when it drops, so re-register the watches here
  client.justsaying('light/new_aa_to_watch', {
    aa: 'AA_ADDRESS_TO_WATCH',
  });

  client.subscribe(function(err, result) {
    console.log('notification:', result);
  });
});

// error subscribers persist across reconnections, register them once
client.onError(function(err) {
  console.error('connection error:', err);
});

// the hub drops idle connections, send a heartbeat to keep it alive
setInterval(function() {
  client.api.heartbeat();
}, 10 * 1000);
```

Unlike `subscribe`, the heartbeat timer belongs *outside* `onConnect`: one timer per client, not per connection. Heartbeats are skipped automatically while the connection is down (and while there is recent traffic), whereas a timer registered on every reconnection would pile up duplicates. Call `clearInterval` once you are done with the client.

Close the client:

```javascript
client.close();
```

With `reconnect: true` the client treats a closed socket as a dropped connection and reconnects even after an intentional `close()`. To close such a client permanently, disable reconnection first:

```js
client.client.reconnect = false;
client.close();
```

All API methods follow this pattern:

```javascript
// If the last argument is a function it is treated as a callback
client.api.getJoint('oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=', function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});

// If a callback is not provided, a Promise is returned
client.api.getJoint('oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=')
  .then(function(result) {
    console.log(result);
  })
  .catch(function(err) {
    console.error(err);    
  });
```

### Transaction

To compose and post unit you need first to create a Obyte wallet and fund it with the native currency ‘bytes’. The generated WIF will be used on Obyte.js. Click on the link below to learn more:

{% content-ref url="/pages/-LJU1DogFsLlfL3PS6\_L" %}
[Generate a random address](/utils/generate-wallet)
{% endcontent-ref %}

Sending a payment:

```javascript
const wif = '5JBFvTeSY5...'; // WIF string generated (private key)

const params = {
  outputs: [
    {
      address: 'NX2BTV43XN6BOTCYZUUFU6TK7DVOC4LU', // The Obyte address of the recipient
      amount: 1000 // The amount he receives
    }
  ]
};

client.post.payment(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result); // The unit hash is returned
});
```

### Migration to 0.2.0 <a href="#migration-to-020" id="migration-to-020"></a>

`0.2.0` modernizes the internals (updated dependencies, pure-JS crypto, a much smaller browser bundle) and is **backward compatible for normal use** — addresses, signatures and WIF keys are byte-for-byte identical, and messages signed by older versions still validate (and vice-versa). There is **one** breaking change to watch for.

#### `utils.fromWif().privateKey` is now a `Uint8Array` (was a `Buffer`) <a href="#utilsfromwifprivatekey-is-now-a-uint8array-was-a-buffer" id="utilsfromwifprivatekey-is-now-a-uint8array-was-a-buffer"></a>

The bytes are exactly the same — only the type changed, so `Buffer`-specific methods behave differently:

```js
const { privateKey } = obyte.utils.fromWif(wif, false);

privateKey.toString('hex'); // ❌ 0.1.x: "42...42"  |  0.2.0: "66,66,...,66"
privateKey.equals(other);   // ❌ Uint8Array has no .equals()
```

If your code consumed the private key as a `Buffer`, wrap it once:

```js
const privateKey = Buffer.from(obyte.utils.fromWif(wif, false).privateKey);
// now .toString('hex'), .equals(), etc. work as before
```

Everything else is unchanged. `utils.toWif()` and `utils.signMessage({ privateKey })` still accept **both** `Buffer` and `Uint8Array`, so passing a `Buffer` keeps working.


# Testnet

Getting started with Byteball testnet.

### Get ready

1. [Click this link](https://bonuschain.github.io/byteball-paperwallet/) and select "Testnet" to generate a new testnet wallet
2. [Download Obyte testnet wallet](https://obyte.org/testnet.html)
3. Install Obyte testnet wallet and [click this link](byteball-tn:AxBxXDnPOzE/AxLHmidAjwLPFtQ6dK3k70zM0yKVeDzC@byteball.org/bb-test#0000) to receive free testnet bytes
4. Send testnet bytes to the address you created on first step

### Usage

Here is how to initiate client for Obyte testnet:

```javascript
const obyte = require('obyte');

const options = { testnet: true };
const client = new obyte.Client('wss://obyte.org/bb-test', options);
```

### Links

{% embed url="<https://obyte.org/testnet.html>" %}

{% embed url="<https://testnetexplorer.obyte.org/>" %}


# Get witnesses

Get the list of current witnesses.

### **Example**

```javascript
client.api.getWitnesses(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/ohae4Lv5/).

### **Returns**

```javascript
[
  'BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3',
  'DJMMI5JYA5BWQYSXDPRZJVLW3UGL3GJS',
  'FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH',
  'GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN',
  'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
  'I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT',
  'JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725',
  'JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC',
  'OYW2XTDKSNKGSEZ27LMGNOPJSYIXHBHC',
  'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
  'TKT4UESIKTTRALRRLWS4SENSTJX6ODCW',
  'UENJPVZ7HVHM6QGVGT6MWOJGGRTUTJXQ'
]
```

### **Learn more**

* "6. Witnesses" (page 6) <https://obyte.org/Byteball.pdf>
* Obyte Wiki: <https://wiki.obyte.org/Witness>


# Get peers

Get the list of the current peers.

### Example

```javascript
client.api.getPeers(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/2azq1ruL/).

### Returns

```javascript
[
  'wss://byteball.fr/bb',
  'wss://byteball.me/bb',
  'wss://blackbytes.me/bb',
  'wss://hub.byteball.ee',
  'wss://byteball-hub.com/bb',  
  'wss://relay.papabyte.com/bb'
]
```


# Get joint

Request data of a specific unit.

### **Example**

```javascript
const unit = 'k37Xlns198EHCtubX5X0kqbrnC9XYVTa0aFpR78gidM=';

client.api.getJoint(unit, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/rqzsdL36/).

### **Returns**&#x20;

```javascript
{
  joint: {
    unit: {
      unit: 'k37Xlns198EHCtubX5X0kqbrnC9XYVTa0aFpR78gidM=',
      version: '1.0',
      alt: '1',
      witness_list_unit: 'oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=',
      last_ball_unit: '9tIFlniHyoVJEp0i+WHMTZqnnR1UqgAhrIWFRkgE8m0=',
      last_ball: 'qxl8Rq1IjVUICgbm9A1+d+ZC3pG75HoDEFTchdL6scg=',
      headers_commission: 344,
      payload_commission: 123,
      main_chain_index: 2870558,
      timestamp: 1529756195,
      parent_units: [
        '0V3X7wyTl/17YX83YbjFgyJ2LRNxbgT5jXQOdLvZR2A=',
        'HJoe07dHWj5fH5s7PMgwbtryM/o14YERshGVz4cP1BQ='
      ],
      authors: [
        {
          address: 'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
          authentifiers: {
            r: 'nNx6QBfwIQkZydLEDXs/di0U5wqFaw4L15OCGICFGkwDgDh3KK+ks5hxFoUhSLxiZZIeNt1gIjmpKFv+bIiDtQ=='
          }
        }
      ],
      messages: [
        {
          app: 'payment',
          payload_hash: 'g0eNA+42F6Zxx650BLNxUKAwx3R3HJ/pC1tjxXVg8Lg=',
          payload_location: 'inline',
          payload: {
            inputs: [
              {
                type: 'witnessing',
                from_main_chain_index: 580671,
                to_main_chain_index: 580684
              }
            ],
            outputs: [
              {
                address: 'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
                amount: 79
              }
            ]
          }
        }
      ]
    },
    ball: 'XRz6FcvpNLjrzXkCeQGIM/ekqQTrmB/kBEpn1grsrI0='
  }
}
```

### **Learn more**

* "12. Unit structure" (page 15) <https://obyte.org/Byteball.pdf>


# Get last MCI

Get the last main chain index of the node you logged to.

### Example

```javascript
client.api.getLastMci(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/kzjy6s97/).

### Returns

```
2870575
```

### **Learn more**

* "5. The main chain" (page 8) <https://obyte.org/Byteball.pdf>


# Get history

Get the history of one or multiple addresses.

### Example - address

```javascript
const params = {
  witnesses: await client.getCachedWitnesses(),
  addresses: [
    'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
  ]
};
client.api.getHistory(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Example - requested joints

```javascript
const params = {
  witnesses: await client.getCachedWitnesses(),
  requested_joints: [
    'QjJsukONZ57VBVtLk/0ak1jMYNW0vw7q0So95KBJH2k=',
    'H1RSMS/7sBM77rYNiN1rWtbVJthg5BTRIf6ode9vaiE='
  ]
};
client.api.getHistory(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
{
  unstable_mc_joints: [
    {
      unit: {Object}
    },
    {
      unit: {Object}
    }, 
    ...
  ],
  witness_change_and_definition_joints: [
    {
      unit: {Object},
      ball: 'CxK1luSnAk5+MaGyaE9wl26JdwAkSPFDqWJdYs9gRng='
    }
  ],
  joints: [
    {
      unit: {Object},
      ball: 'HCEsVPYN9g7tGOVWlixTlA7Cg4fXsd1VDQSgUzHZljI='
    },
    {
      unit: {Object},
      ball: '7Zk9IQja19XZyJY0MPZZxAhIjV5Uydr+zUvoQXvGBKs='
    },
    ...
  ],
  proofchain_balls: [
    {
      unit: 'rVuepU0c43PKbqM2BgnpOLaBCGdaxG0w6WBpSjaCHgA=',
      ball: 'zTN1OJcGfibm2hxitGnQRx0HSzhfhycFIXsaL7gnUNY=',
      parent_balls: [Array]
    },
    {
      unit: 'Mn8nOpIQvhQvPjlnDBbtYwUbRolrt40Igr8txWch0s0=',
      ball: 'Ocgs5zd0mWeqWNm/+gT0wqpfnd9+mj5BaaABndamw0E=',
      parent_balls: [Array]
    },
   ...
  ],
  aa_responses: [
    {
      mci: 5570689,
      trigger_address: "ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q",
      aa_address: "NINAQ4KWRURQDX3O7G3KE6IFJKIA4Q25",
      trigger_unit: "QjJsukONZ57VBVtLk/0ak1jMYNW0vw7q0So95KBJH2k=",
      bounced: 0,
      response_unit: "H1RSMS/7sBM77rYNiN1rWtbVJthg5BTRIf6ode9vaiE=",
      response: "{\"responseVars\":{\"type\":\"swap\",\"asset1_amount\":6149564711}}",
      timestamp: 1595783576,
      creation_date: "2020-07-26 17:23:08"
    }
  ]
}
```


# Get attestation

Get attestation unit id from a specific attested value.

### Example

```javascript
const params = {
  attestor_address: 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
  field: 'email',
  value: 'fabien@bonustrack.co'
};

client.api.getAttestation(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```
7SEJqVRpog8Ezn5A3PSDX+h3iIYMfJaUsozoUlrsm+o=
```

### **Learn more**

* "23. Attestations" (page 32) <https://obyte.org/Byteball.pdf>


# Get attestations

Get all attestations of a specific address.

### Example

```javascript
const params = {
  address: 'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
};

client.api.getAttestations(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
[
  {
    unit: 'ekUq+0FW1uf1Bm1Dos7epi6AdWy2+m8CTOzU5/04y84=',
    attestor_address: 'I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT',
    profile: {
      profile_hash: 'cyZ7L8pPE4Df7pqH4jKtpuaB2SLEy2HR/K2rBGLRzYM=',
      user_id: 'd4wISqCAUd1yDv2FGyjQD/+Xe+l7GGGtuxzxlpKayfk='
    }
  },
  {
    unit: '0miOAkbyv40DGVyJToxWroyoiJ+xhOnDb1aTbF6YXR8=',
    attestor_address: 'C4O37BFHR46UP6JJ4A5PA5RIZH5IFPZF',
    profile: {
      nonus: 1
    }
  },
  {
    unit: '7SEJqVRpog8Ezn5A3PSDX+h3iIYMfJaUsozoUlrsm+o=',
    attestor_address: 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
    profile: {
      email: 'fabien@bonustrack.co',
      user_id: 'uyeABSHzEgArC14L504vKgza+BmpgXlemnkDpyFC0mA='
    }
  }
]
```

### **Learn more**

* "23. Attestations" (page 32) <https://obyte.org/Byteball.pdf>


# Get bots

Get the list of current chatbots.

### Example

```javascript
client.api.getBots(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/xanrbcgz/).

### **Returns**

```javascript
[
  {
    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'
  },
  ...
]
```

### **Learn more**

* Obyte Wiki: <https://wiki.obyte.org/Chatbot>


# Get asset metadata

Get metadata of a specific asset.

### Example - Asset Registry & Token Registry

```javascript
const asset = 'IYzTSjJg4I3hvUaRXrihRm9+mSEShenPK8l8uKUOD3o=';

client.api.getAssetMetadata(asset, function(err, registry_unit) {
  if (err) return console.error(err);
  client.api.getJoint(registry_unit.metadata_unit, function(err, result) {
    if (err) return console.error(err);
    const metadata = result.joint.unit.messages.find(item => item.app == 'data');
    console.log(registry_unit, metadata ? metadata.payload : null);
  });
});
```

### **Returns**

```javascript
{
  metadata_unit: "0xXOuaP5e3z38TF5ooNtDhmwNkh1i21rBWDvrrxKt0U=",
  registry_address: "AM6GTUKENBYA54FYDAKX2VLENFZIMXWG",
  suffix: null
}
{
  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."
}
```

### Example - Token Registry only

```javascript
const symbol = 'TONY';
const asset = 'fAmGezsOuWr6TEkUmKA6zYDZUUzeE0j95pvPgIcgTkM=';
const registry = client.api.getOfficialTokenRegistryAddress();
client.api.getAssetBySymbol(registry, symbol).then(console.log);
client.api.getSymbolByAsset(registry, asset).then(console.log);
client.api.getDecimalsBySymbolOrAsset(registry, symbol).then(console.log);
client.api.getDecimalsBySymbolOrAsset(registry, asset).then(console.log);
```

### **Returns**

```javascript
fAmGezsOuWr6TEkUmKA6zYDZUUzeE0j95pvPgIcgTkM=
TONY
9
9
```

### **Learn more**

* Obyte Wiki: <https://wiki.obyte.org/Asset>
* Asset Registry: <https://obyte.app>
* Token Registry: <https://tokens.ooo/>


# Get definition

Get an address definition.

### Example 1

```javascript
const address = 'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH';

client.api.getDefinition(address, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  'sig',
  {
    pubkey: 'AsD2GQ3+CSHfFO9CfX8+gBxmxSm9TGweKjWVie0rt/0p'
  }
]
```

### Example 2

```javascript
const params = {
  address; 'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH'
};

client.api.getDefinitionForAddress(address, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
{
    definition_chash: "TMWNLXR42CKIP4A774BQGNVBZAPHY7GH",
    definition: [
        "sig",
        {
            pubkey: "AsD2GQ3+CSHfFO9CfX8+gBxmxSm9TGweKjWVie0rt/0p"
        }
    ],
    is_stable: true
}
```

### **Learn more** <a href="#learn-more" id="learn-more"></a>

* "21. Addresses" (page 23) <https://obyte.org/Byteball.pdf>


# Get balances

Get balances from one or multiple addresses (max 100).

### Example

```javascript
const addresses = [
  'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH',
  'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
];

client.api.getBalances(addresses, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
{
  TMWNLXR42CKIP4A774BQGNVBZAPHY7GH: {
    base: {
      stable: 838,
      pending: 0
    },
    's+bzDkwx0TVMtdyf9YU4wEA23oInOUzulO+r5WxBUZs=': {
      stable: 98,
      pending: 0
    },
    'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=': {
      stable: 5000,
      pending: 0
    }
  },
  ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q: {
    base: {
      stable: 942956698,
      pending: 0
    },
    'f2TMkqij/E3qx3ALfVBA8q5ve5xAwimUm92UrEribIE=': {
      stable: 918528,
      pending: 0
    },
    'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=': {
      stable: 970979,
      pending: 0
    }
  }
}
```


# Get profile units

Get profile unit ids from one or multiple addresses (max 100).

### Example

```javascript
const addresses = [
  'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH',
  'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
];

client.api.getProfileUnits(addresses, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  '46fTf+Wf5EAq5KQmEttKmKUlrFzzCkXYO1f3JLP7uyE=',
  'itguFXI8RtuLmmXK5/yXu+Rma2F3xmlvuipnYSeuwQI=',
  'U2y+yti2vSJpm4Le2/o+JBfBgbP0F5GDm7ffHHd3+AQ=',
  'DVwBupJaKPnEMQBT2sd3DDAumEYTVcPCxs7nyDS8CkA=',
  'Ii/IEEYuyJh+7r/Bkp6T8+Neu+DlZSNw+pupdq0U43U=',
  'pJWt6QqtDQLxmY/7h+rbKO+It6gLk8wfLnXNmnuguVs=',
  'zPEqWmZIiGdlDQw9q9/K5cVAQUkR1LlgUpnhwk5hCwQ=',
  'xrVwToW5Yy1xJqCm0DUuriZjbWDVyAk0CBj2DtK9uoI=',
  'wp8wScoEuznmVivWi5fYO6KL8z2U9KcqhtcQZza8LS4=',
  'GMqQeyPs+//n2YJg8tlc4EkR0GhemU+Jq0Fx76KQjIs=',
  'gYd2UTq5mBT298NaS7qcAHlBzB4RyCPw+k7PQSfjino=',
  'K1s64SAgA9EsknN6HP/KiBvNCs5mttkshyt/A5yo3q0=',
  'dJizRyUSQDqSg4vV4ExDRbwg8Wi3yK3MQvv+zzQEZxI=',
  'CvTEcsP+yIGEhU33Nt4XLs8otlh87gcGez86Wecam0M='
]
```

### **Learn more**

* "22. Profiles" (page 32) <https://obyte.org/Byteball.pdf>


# Get data feed

### Example

```javascript
const params = {
    oracles: [
        'I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT',
        'BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3'
    ],
    feed_name: 'timestamp',
	// feed_value: string | number | boolean;
	// min_mci: number;
	// ifseveral: 'abort' | 'last';
	// what: 'unit' | 'value';
	// type: 'string' | 'auto';
	// ifnone: string | number | boolean;
};
client.api.getDataFeed(params, function(err, result) {
    if (err) return console.error(err);
    console.log(result);
});
```

### Returns

```javascript
1618629895590
```

### **Learn more**

* "21.1.7. Data feeds" (page 45) <https://obyte.org/Byteball.pdf>


# Get last stable unit props

### Example

```javascript
const result = await client.api.getLastStableUnitProps();
```

### Returns&#x20;

```javascript
{
  unit: 'SaLC9xO2c+6d2sQGH0Iij8MkftUFOIS68kU6ltIkhkU=',
  main_chain_index: 12000000,
  timestamp: 1700000000
}
```


# Autonomous Agents


# Dry run AA

Calculates the predicted outcome of an Autonomous Agent with a sample transaction.

### Example

```javascript
const params = {
  trigger: {
    address: 'K237YYRMBYWCJBLSZGLJTXLZVVEXLI2Y', // sent from address
    outputs: {
      'base': 10000 // default AA bounce fee in bytes
    },
    data: {
      'vest': true
    }
  },
  address: 'TSDLQPZTSVDNC63G7YROC26CYCCZC4GO' // sent to AA address
};

client.api.dryRunAa(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  {
    mci: 1023895,
    trigger_address: 'K237YYRMBYWCJBLSZGLJTXLZVVEXLI2Y',
    trigger_initial_address: 'K237YYRMBYWCJBLSZGLJTXLZVVEXLI2Y',
    trigger_unit: 'RpENIf8NoLY/OFpJ1n2i8E38lZDH7ZsqF6Xa2Pkca5w=',
    aa_address: 'TSDLQPZTSVDNC63G7YROC26CYCCZC4GO',
    bounced: false,
    response_unit: null,
    objResponseUnit: null,
    response: {
      responseVars: {
        message: 'Vested 10000 bytes',
        amount: 10000
      },
      error: 'no messages after filtering'
    },
    updatedStateVars: {
      TSDLQPZTSVDNC63G7YROC26CYCCZC4GO: {
        vested_total: {
          value: 60000,
          old_value: 50000,
          delta: 10000
        },
        vested_K237YYRMBYWCJBLSZGLJTXLZVVEXLI2Y: {
          value: 50000,
          old_value: 40000,
          delta: 10000
        }
      }
    }
  }
]
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Get AA state vars

Get state variables of an Autonomous Agent.

### Example

```javascript
const params = {
  address: 'TSDLQPZTSVDNC63G7YROC26CYCCZC4GO',
  var_prefix: 'proposal_1'
};

client.api.getAaStateVars(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
{
  proposal_1: '1',
  proposal_1_amount: '25000',
  proposal_1_author: 'CWUD2ZRELMGI7CQIXRRGENRMSV2NFZOT',
  proposal_1_expiration: '1567288484',
  proposal_1_url: 'https://bit.ly/2Ka8HGo',
  proposal_1_vest: '40000',
  proposal_1_vote_K237YYRMBYWCJBLSZGLJTXLZVVEXLI2Y: '1'
}
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Get AAs by base AAs

Get Autonomous Agents that are based on some Autonomous Agent.

### Example

```javascript
const params = {
  base_aa: 'QFM5ECICVHZKRVTW3EMVTUSYJ6P2WLDY'
};

const params_multi = {
  base_aas: ['QFM5ECICVHZKRVTW3EMVTUSYJ6P2WLDY']
};

client.api.getAasByBaseAas(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  {
    address: 'VUSZEABYYJDLCQ2SLWERIV2WXUNPMF3I',
    definition: [
      'autonomous agent',
      {
        base_aa: 'QFM5ECICVHZKRVTW3EMVTUSYJ6P2WLDY',
        params": {
          asset: 'vTSkFkoxAtS7mnq03rd8MjNV4EC6RIIfvxPbnER9O4w='
        }
      }
    ]
  },
  {
    address: 'LMDG6R64KCLDVMEJPJEG3FOJ2TJGFEHM',
    definition: [
      'autonomous agent',
      {
        base_aa: 'QFM5ECICVHZKRVTW3EMVTUSYJ6P2WLDY',
        params: {
          asset: 'w91kcLlYaAHC+1lK19y+cvF0AUCKmU3+DWz+9cEKto4='
        }
      }
    ]
  }
]
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Get AA responses

Get latest Autonomous Agent responses.

### Example

```javascript
const params = {
  aa: 'PVMCXUZBEHCFWOLXUDQVNCQZ476LNEW4'
};

const params_multi = {
  aas: ['PVMCXUZBEHCFWOLXUDQVNCQZ476LNEW4']
};

client.api.getAaResponses(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  {
    mci: 5216435,
    trigger_address: "FZP4ZJBMS57LYL76S3J75OJYXGTFAIBL",
    aa_address: "PVMCXUZBEHCFWOLXUDQVNCQZ476LNEW4",
    trigger_unit: "NKqqm7ZxuT9WAYlUDWRSNiDmIZz9waTiOpnDGw54a38=",
    bounced: 0,
    response_unit: "TEHRTOxReqcYiKbpVi7lPO0fZiJB0tMY8SCOzdPtHjs=",
    response: {},
    timestamp: 1583167472,
    objResponseUnit: {Object}
  },
  ...
]
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Get AA response chain

### Example

```javascript
const params = {
  trigger_unit: 'QjJsukONZ57VBVtLk/0ak1jMYNW0vw7q0So95KBJH2k='
};

client.api.getAaResponseChain(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
[
  {
    mci: 5570689,
    trigger_address: "ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q",
    aa_address: "NINAQ4KWRURQDX3O7G3KE6IFJKIA4Q25",
    trigger_unit: "QjJsukONZ57VBVtLk/0ak1jMYNW0vw7q0So95KBJH2k=",
    bounced: 0,
    response_unit: "H1RSMS/7sBM77rYNiN1rWtbVJthg5BTRIf6ode9vaiE=",
    response: {
      responseVars: {
        type: "swap",
        asset1_amount: 6149564711
      }
    },
    timestamp: 1595783576,
    objResponseUnit: {Object}
  }
]
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Get AA balances

Returns balances held by an Autonomous Agent.

### Example

```javascript
const result = await client.api.getAaBalances({
  address: 'AA_ADDRESS',
});

console.log(result);
```

### Returns

```javascript
{
    "balances": {
        "1Rw5RpmwPystzAn7nSuZyAnjr1skwCIRFcQmTAe5ZQc=": 113151237,
        "3WweeKWzl/RmG5wkZ8XQ4XKg8BbGKI756JMJKKfbO2A=": 129984206,
        "3xfBzmukw+JfU1CA0ulXBnIojDG38q4tnA+hOA1ighg=": 442718714,
        "4xntUEnN9EXQRKRAX7IIp7Av6RXFe1RzTgwytbCzR6U=": 224897776,
        "AuPo15GIXxi9WxNDnYc+RIx0rrBSDaHCNdAOIXPiJeM=": 3522441935,
        "HRvZ927EJn+o94+cVoBFdk5+xjZcdLAJzzhSfOF0SAk=": 24576608,
        "KxyAj3Yk9OFy+cweRFl8yjwYEmeg6scHoRXJsExun98=": 911938651282,
        "UWkb/dR5Ssezzui9CoIblCVpJ4+9j7x054zpE9fH67o=": 68283931926,
        "Vy8qi2hcTscFdO9KBIEUK6X7DO9qohfavk64DRI7VCI=": 11626226848,
        "base": 11830046620931,
        "fEp6xijf6poHYonQG2cPoBgtqoYwCRlNBec2qK/4HXU=": 0,
        "hPmuKsfVWnWjUIDjeQE8ATDBT7nYbgfyy+Tz2hHDawo=": 150296496564,
        "hPutBNl409Sy91myOt1wWmayimKmoFAES/9568vuAuc=": 11116247,
        "oBk8tCOZhY9Y1Rq/JchUpLG1bH1ljB9T+naiFFkfzVc=": 8160630,
        "ojgx2jTzE7UyW8n+ZkfRBeb87PUYq5a9HTCc/4yb5qQ=": 2955337,
        "rkLRiM+QHI73J4LxvOWj3Qu4Sqpqsg1WDNqaparKfAA=": 307063258,
        "sBfPv/5CQEhJCHpihhcMa8OZ/OKnGTjVJCUQ8cqI82g=": 2213593492492,
        "tfqJ1Z0oIG1gdQMmwk565dsr44CfaJJxn1t+GDXQ1Jg=": 870315644
    }
}
```


# Execute AA getter

Execute AA getter function

### Example

```javascript
const iusd_amount = 100;
const params = {
  address: 'VLKI3XMMX5YULOBA6ZXBXDPI6TXF6V3D',
  getter: 'get_exchange_result',
  args: [0, iusd_amount]
};

client.api.executeGetter(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Returns**

```javascript
{
  reserve_needed: 362169,
  reserve_delta: 362346,
  fee: 0,
  regular_fee: false,
  reward: 177,
  initial_p2: 0.036234510530851,
  p2: 0.0362345130263091,
  target_p2: 0.0367399935327185,
  new_distance: 0.0139502497533879,
  turnover: 362346,
  fee_percent: 0,
  slow_capacity_share: 0.5
}
```

### **Learn more**

* Autonomous agents documentation <https://developer.obyte.org/autonomous-agents>
* Oscript editor [https://oscript.org](https://oscript.org/)


# Token registry

Token registry helper methods resolve symbols, assets, and decimals through a token registry AA.

{% content-ref url="/pages/MdxPVUZCAep8p4NRIztj" %}
[Get asset by symbol](/api/token-registry/get-asset-by-symbol)
{% endcontent-ref %}

{% content-ref url="/pages/ZvfOrLX7RzhWaPxoM1OH" %}
[Get decimals by symbol or asset](/api/token-registry/get-decimals-by-symbol-or-asset)
{% endcontent-ref %}

{% content-ref url="/pages/h078eDwwHp81yP5F2D10" %}
[Get symbol by asset](/api/token-registry/get-symbol-by-asset)
{% endcontent-ref %}

{% content-ref url="/pages/zGLFPd1ZX2QDpaWsSAM0" %}
[Get official token registry address](/api/token-registry/get-official-token-registry-address)
{% endcontent-ref %}

{% embed url="<https://tokens.ooo/>" %}


# Get official token registry address

### Example

```js
const registry = client.api.getOfficialTokenRegistryAddress();
console.log(registry);
```

### Returns

```js
'O6H6ZIFI57X3PLTYHOCVYPP5A553CYFQ'
```

{% embed url="<https://tokens.ooo/>" %}


# Get symbol by asset

### Example

```js
const symbol = await client.api.getSymbolByAsset(
  'AHVV8Um6AwHY9/nsX/YMZkWSBptWdn4g9aYVhNLcUWs='
);

console.log(symbol);
```

### Returns

```js
'BNB'
```

Special case:

```js
await client.api.getSymbolByAsset('base');
// 'GBYTE'
```

{% embed url="<https://tokens.ooo/>" %}


# Get asset by symbol

### Example

```js
const asset = await client.api.getAssetBySymbol('BNB');
console.log(asset);
```

### Returns

```js
'AHVV8Um6AwHY9/nsX/YMZkWSBptWdn4g9aYVhNLcUWs='
```

Special case:

```js
await client.api.getAssetBySymbol('GBYTE');
// 'base'
```

{% embed url="<https://tokens.ooo/>" %}


# Get decimals by symbol or asset

### Example

```js
const decimalsBySymbol = await client.api.getDecimalsBySymbolOrAsset('BNB');
const decimalsByAsset = await client.api.getDecimalsBySymbolOrAsset('AHVV8Um6AwHY9/nsX/YMZkWSBptWdn4g9aYVhNLcUWs=');

console.log(decimalsBySymbol);
```

### Returns

```js
8
```

{% embed url="<https://tokens.ooo/>" %}


# Explicit registry

All helper methods still accept an explicit registry address.

```js
await client.api.getSymbolByAsset('TOKEN_REGISTRY_ADDRESS', 'assetHashBase64=');
await client.api.getAssetBySymbol(null, 'GBYTE'); // null uses the official registry
```

{% embed url="<https://tokens.ooo/>" %}


# Core


# Catchup

Get balls units between 2 main chain ids.

### Example

```javascript
const params = {
  witnesses: witnesses,
  last_stable_mci: 2871302,
  last_known_mci: 2871312
};

client.api.catchup(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
{
  status: 'current'
}
```


# Get hash tree

Get units between balls.

### Example

```javascript
const params = {
  from_ball: 'aEU1WiY9FQ9ihv9cKkX/EHWDxYYVaWYs2AL1yxyYZAQ=',
  to_ball: 'nOqDBwCVHy+bkBSRIgNlzcKR+EXlTC79aA62qT+Lcj0='
};

client.api.getHashTree(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
{
  balls: [
    {
      unit: 'c2teVop7xa1BmH1LPvytvOKU8HHTrprGWQw+uHlWPHo=',
      ball: 'ht1QP48paWg5hpjx+Nbd/DSRFT8WlbQKk9+Uum0/tso=',
      parent_balls: [Array]
    },
    {
      unit: 'tPbC6QLeweGuiGYRPsIhfd0TQWXWASYBJJUPGa9AOfw=',
      ball: 'ba5wFB+gewdRX6nSpxt6+Nt8PaRen4pLIYg3jC6EvIw=',
      parent_balls: [Array]
    },
    ...
  ]
}
```


# Get light props

Get light client properties.

### Example

```javascript
const params = {
  witnesses: await client.getCachedWitnesses()
};
client.api.getParentsAndLastBallAndWitnessListUnit(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
{
    timestamp: 1618626721,
    parent_units: [
        "dtH1LbuYJuScVEa8m1c7Hc4Ua4DrPrFJK1zmB8sKD8A="
    ],
    last_stable_mc_ball: "/A35gMoMgKv5awkWH4iMr61Pk+/N47ffOFIKAlkRomU=",
    last_stable_mc_ball_unit: "zgClV7gSONFqFk9sRyCNpIXGIlmRj9tLSgqjjAHCHxM=",
    last_stable_mc_ball_mci: 7268841,
    witness_list_unit: "p1sRwcMeO9js90ztqin+cK21AL7L7SLYKXtehrGkwwQ="
}
```


# Post joint

Post an unit on Byteball network.

### Example

```javascript
const params = {
  unit: {Object}
};

client.api.postJoint(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

The unit object can be generated with the method "compose".

### Returns

```javascript
accepted
```


# Pick divisible coins for amount

Get spendable inputs from a specific amount and asset.

### Example

```javascript
const params = {
  asset: 'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=',
  addresses: ['ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'],
  last_ball_mci: 1000000000,
  amount: 10000,
  spend_unconfirmed: 'own',
};

client.api.pickDivisibleCoinsForAmount(params, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
{
  inputs_with_proofs: [
    {
      input: {
        unit: "06ni8/eDzmcxwtWeQyuSXhqGsqmVN3I1fsR+5NAj4Sw=",
        message_index: 1,
        output_index: 1
      }
    }
  ],
  total_amount: 985000
}
```


# Heartbeat

Send heartbeat to notify the node you are awake.

### Example

```javascript
client.api.heartbeat(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### Returns

```javascript
null
```


# Address definition change

Users can update definitions of their addresses while keeping the old address.

### **Arguments**

* **definition\_chash** `string` *required*\
  Indicates the checksummed hash of the new address definition.
* **address** `string` *optional*\
  When multi-authored, must indicate address.

### Returns

Returns the unit hash.

Example

```javascript
const params = {
  definition_chash: 'I4Z7KFNIYTPHPJ5CA5OFC273JQFSZPOX',
};

client.post.addressDefinitionChange(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* 21\. Addresses (page 23) <https://obyte.org/Byteball.pdf>


# Attestation

Attestations confirm that the user who issued the attestation (the attestor) verified some data about the attested user (the subject).

### **Arguments**

* **address** `string` *required*\
  Address of the attested user (the subject).
* **profile** `object` *required*\
  Verified data about the attested user.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  address: 'IX77DDUQ56TVQVC3E77KIC5QLPQHD4PV',
  profile: {
    email: 'robertjsmc@gmail.com',
    user_id: 'mT+Qwu2e2OH+QJ5mwCijrkQ6Bz2IW/Ad9IIHHHffbwo='
  }
};

client.post.attestation(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
  // -> J12wi3v0tSco6JJKagqJ265/jEt8Evl4Rk03YIErlpQ=
});
```

### **Learn more**

* "23. Attestations" (page 32) <https://obyte.org/Byteball.pdf>


# Asset

Assets in Byteball can be issued, transferred, and exchanged, and.they behave similarly to the native currency ‘bytes’.

### **Arguments**

* **cap** `integrer` *optional*\
  Is the total number of coins that can be issued (money supply). If omitted, the number is unlimited.
* **is\_private** `boolean` *required*\
  Indicates whether the asset is private (such as blackbytes) or publicly traceable (similar to bytes).
* **is\_transferrable** `boolean` *required*\
  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** `boolean` *required*

  Indicates whether the asset is destroyed when it is sent to the definer address.
* **fixed\_denominations** `boolean` *required*

  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.
* **denominations** `array` *optional*\
  Array of all denominations and the number of coins of that denomination.
* **issued\_by\_definer\_only** `boolean` *required*\
  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.
* **cosigned\_by\_definer** `boolean` *required*\
  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.
* **spender\_attested** `boolean` *required*\
  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.
* **attestors** `array` *optional*\
  List of approved attestor addresses
* **issue\_condition** `array` *optional*\
  Specify the restrictions when the asset can be issued. It evaluate to a boolean and are coded in the same [smart contract language](https://github.com/byteball/byteballcore/wiki/Smart-contracts) as address definitions.
* **transfer\_condition** `array` *optional*\
  Specify the restrictions when the asset can be transferred. It evaluate to a boolean and are coded in the same [smart contract language](https://github.com/byteball/byteballcore/wiki/Smart-contracts) as address definitions.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  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
}; 

client.post.asset(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
  // -> xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=
});
```

### **Learn more**

* "24. Assets" (page 33) <https://obyte.org/Byteball.pdf>
* Issuing assets on Obyte: <https://github.com/byteball/ocore/wiki/Issuing-assets-on-Byteball>
* Smart contracts: <https://github.com/byteball/ocore/wiki/Smart-contracts>
* Obyte Wiki: <https://wiki.obyte.org/Asset>
* Obyte Asset Registry: <https://obyte.app>


# Asset attestors

The list of an asset attestors can be amended by the definer by sending an ‘asset\_attestors’ message that replaces the list of attestors.

### **Arguments**

* **asset** `string` *required*\
  Asset unit id.
* **attestors** `array` *required*\
  List of approved attestor addresses

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  asset: 'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=',
  attestors: [
    'X5ZHWBYBF4TUYS35HU3ROVDQJC772ZMG',
    'GZSEKMEQVOW2ZAHDZBABRTECDSDFBWVH',
    '2QLYLKHMUG237QG36Z6AWLVH4KQ4MEY6'
  ].sort()
};

client.post.assetAttestors(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "24. Assets" (page 33) <https://obyte.org/Byteball.pdf>


# Data

One can store arbitrary structured data using ‘data’ message type.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  key: "value",
  another_key: {
    subkey: "other value",
    another_subkey: 232
  }
};

client.post.data(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "28. Arbitrary structured data" (page 45) <https://obyte.org/Byteball.pdf>


# Data feed

Data fields can be used to design definitions that involve oracles.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  time: new Date().toString(), 
  timestamp: Date.now()
};

client.post.dataFeed(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "21.1.7. Data feeds" (page 45) <https://obyte.org/Byteball.pdf>


# Definition

Post a definition to create an autonomous agent.

### **Arguments**

* **address** `string` *required*\
  Address of the definition
* **definition** `array` *required*\
  Definition of the autonomous agent

### Returns

Returns the unit hash.

### Example

```javascript
const { Client, utils } = require('obyte');

const client = new Client('wss://obyte.org/bb-test', { testnet: true });

const definition = [
  'autonomous agent',
  {
    bounce_fees: {
      base: 10000
    },
    messages: [
      {
        app: 'payment',
        payload: {
          asset: 'base',
          outputs: [
            {
              address: "{trigger.address}",
              amount: "{trigger.output[[asset=base]] - 1000}"
            }
          ]
        }
      }
    ]
  }
];

const params = {
  address: utils.getChash160(definition),
  definition
}

client.post.definition(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

The above example of an AA just sends the received money less 1000 bytes back to the sender.&#x20;

### **Learn more**

* "Getting started guide": <https://developer.obyte.org/autonomous-agents/getting-started-guide>
* "Oscript language reference": <https://developer.obyte.org/autonomous-agents/oscript-language-reference>


# Definition template

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.

### Returns

Returns the unit hash.

### Example

This template depends on two variables: `$address` and `$ts`.

```javascript
const params = ['and', [
  ['address', '$address'], 
  ['in data feed', [['MO7ZZIU5VXHRZGGHVSZWLWL64IEND5K2'], 'timestamp', '>=', '$ts']]
]];

client.post.definitionTemplate(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "21.1.4. Definition templates" (page 27) <https://obyte.org/Byteball.pdf>


# Payment

### **Arguments**

* **asset** `string` *optional*\
  Hash of unit where the asset was defined.
* **outputs** `array` *required*\
  Outputs is an array of outputs that say who receives the money.
  * **address** `string` *required* \
    The Byteball address of the recipient.
  * **amount** `integrer` *required* \
    The amount he receives.

### Returns

Returns the unit hash.

### Examples

#### Spend bytes

```javascript
const params = {
  outputs: [
    { address: 'NX2BTV43XN6BOTCYZUUFU6TK7DVOC4LU', amount: 1000 }
  ]
};

client.post.payment(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

#### Send bytes to multiple recipients

```javascript
const params = {
  outputs: [
    { address: 'NX2BTV43XN6BOTCYZUUFU6TK7DVOC4LU', amount: 1000 },
    { address: 'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q', amount: 2000 }
  ]
};

client.post.payment(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

#### Spend asset

```javascript
const params = {
  asset: 'Hh22Wmd+xAYhgjCBACAxKXWErh/zJuwGc2w2DCB9H24=',
  outputs: [
    { address: 'NX2BTV43XN6BOTCYZUUFU6TK7DVOC4LU', amount: 500 }
  ]
};

client.post.payment(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "12. Unit structure" (page 15) <https://obyte.org/Byteball.pdf>


# Poll

Anyone can set up a poll by sending a message with app=’poll’.

### **Arguments**

* **question** `string` *required*\
  Question of the poll.
* **choices** `array` *required*\
  Allowed set of choices.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  question: 'Should I stay or should I go?',
  choices: ['stay', 'go']
};

client.post.poll(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more** <a href="#learn-more" id="learn-more"></a>

* "29. Voting" (page 46) <https://obyte.org/Byteball.pdf>


# Vote

To cast votes, users send ‘vote’ messages

### **Arguments**

* **unit** `string` *required*\
  Hash of unit where the poll was defined.
* **choice** `string` *required*\
  Indicate what the user want to vote for. The choice must be defined in the poll message.

### Returns

Returns the unit hash.

### **Example** <a href="#learn-more" id="learn-more"></a>

```javascript
const params = {
  unit: 'E0qMVlyvKUQ/H7QQjB1pEevprTUnl44cY/DPWyn3cF4=',
  choice: 'stay'
};

client.post.vote(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more** <a href="#learn-more" id="learn-more"></a>

* "29. Voting" (page 46) <https://obyte.org/Byteball.pdf>&#x20;


# Profile

Users can store their profiles on Obyte if they want.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  name: 'Joe Average',
  emails: ['joe@example.com', 'joe@domain.com'],
  twitter: 'joe'
};

client.post.profile(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "22. Profiles" (page 32) <https://obyte.org/Byteball.pdf>&#x20;


# Text

One can store arbitrary texts using ‘text’ message type.

### Returns

Returns the unit hash.

### Example

```javascript
client.post.text('Hello world', wif, function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

### **Learn more**

* "27. Texts" (page 45) <https://obyte.org/Byteball.pdf>


# Multi

Broadcast multiple messages in a single unit.

### Returns

Returns the unit hash.

### Example

```javascript
const params = [
    {
        app: "payment",
        payload: {
            outputs: [
                { address: "AA_ADDRESS", amount: 10000 }
            ]
        }
    },
    {
        app: "payment",
        payload: {
            asset: "CUSTOM_ASSET_ID",
            outputs: [
                { address: "AA_ADDRESS", amount: 1 }
            ]
        }
    },
    {
        app: "data",
        payload: {
            key: "value",
            another_key: {
                subkey: "other value",
                another_subkey: 232
            }
        }
    }
];

client.post.multi(params, wif, function(err, result) {
  if (err) return console.error(err);
  console.log(err, result);
});
```

###


# Get system vars

Returns governance variables and their vote-count history.

### Example

```javascript
const vars = await client.api.getSystemVars();
```

### Returns

```javascript
{
    "op_list": [
        {
            "vote_count_mci": 11240469,
            "value": [
                "2TO6NYBGX3NF5QS24MQLFR7KXYAMCIE5",
                "4GDZSXHEFVFMHCUCSHZVXBVF5T2LJHMU",
                "APABTE2IBKOIHLS2UNK6SAR4T5WRGH2J",
                "DXYWHSZ72ZDNDZ7WYZXKWBBH425C6WZN",
                "FAB6TH7IRAVHDLK2AAWY5YBE6CEBUACF",
                "FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH",
                "GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN",
                "I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT",
                "JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC",
                "TKT4UESIKTTRALRRLWS4SENSTJX6ODCW",
                "UE25S4GRWZOLNXZKY4VWFHNJZWUSYCQC",
                "XY6JXVBITD4EKY3DFT27XS65D2M3FJ5V"
            ],
            "is_emergency": 0
        },
        {
            "vote_count_mci": -1,
            "value": [
                "2TO6NYBGX3NF5QS24MQLFR7KXYAMCIE5",
                "4GDZSXHEFVFMHCUCSHZVXBVF5T2LJHMU",
                "APABTE2IBKOIHLS2UNK6SAR4T5WRGH2J",
                "DXYWHSZ72ZDNDZ7WYZXKWBBH425C6WZN",
                "FAB6TH7IRAVHDLK2AAWY5YBE6CEBUACF",
                "FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH",
                "GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN",
                "I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT",
                "JMFXY26FN76GWJJG7N36UI2LNONOGZJV",
                "JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC",
                "TKT4UESIKTTRALRRLWS4SENSTJX6ODCW",
                "UE25S4GRWZOLNXZKY4VWFHNJZWUSYCQC"
            ],
            "is_emergency": 0
        }
    ],
    "threshold_size": [
        {
            "vote_count_mci": -1,
            "value": 10000,
            "is_emergency": 0
        }
    ],
    "base_tps_fee": [
        {
            "vote_count_mci": -1,
            "value": 10,
            "is_emergency": 0
        }
    ],
    "tps_interval": [
        {
            "vote_count_mci": -1,
            "value": 1,
            "is_emergency": 0
        }
    ],
    "tps_fee_multiplier": [
        {
            "vote_count_mci": -1,
            "value": 10,
            "is_emergency": 0
        }
    ]
}
```

{% embed url="<https://governance.obyte.org>" %}


# Get system var votes

Returns votes for system variables and balances of voting addresses.

### Example

```javascript
const votes = await client.api.getSystemVarVotes();
```

### Returns

```javascript
{
    "votes": {
        "op_list": [
            {
                "address": "3Y24IXW57546PQAPQ2SXYEPEDNX4KC6Y",
                "unit": "hqf3YRWAy7VQqN3M09sMu25HhC77j6Yk4qlNbKz1Ujc=",
                "timestamp": 1741253572,
                "value": [
                    "2TO6NYBGX3NF5QS24MQLFR7KXYAMCIE5",
                    "4GDZSXHEFVFMHCUCSHZVXBVF5T2LJHMU",
                    "APABTE2IBKOIHLS2UNK6SAR4T5WRGH2J",
                    "DXYWHSZ72ZDNDZ7WYZXKWBBH425C6WZN",
                    "FAB6TH7IRAVHDLK2AAWY5YBE6CEBUACF",
                    "FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH",
                    "GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN",
                    "I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT",
                    "JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC",
                    "TKT4UESIKTTRALRRLWS4SENSTJX6ODCW",
                    "UE25S4GRWZOLNXZKY4VWFHNJZWUSYCQC",
                    "XY6JXVBITD4EKY3DFT27XS65D2M3FJ5V"
                ],
                "is_stable": 1
            },
            {
                "address": "ZCJD5VY24AJOCHAVKHGOFZHFP5EKE6YW",
                "unit": "abBOAxLk9B6x6d8c5BBWxbn5ai002ipCqxitJtq61iQ=",
                "timestamp": 1740935827,
                "value": [
                    "2TO6NYBGX3NF5QS24MQLFR7KXYAMCIE5",
                    "4GDZSXHEFVFMHCUCSHZVXBVF5T2LJHMU",
                    "APABTE2IBKOIHLS2UNK6SAR4T5WRGH2J",
                    "DXYWHSZ72ZDNDZ7WYZXKWBBH425C6WZN",
                    "FAB6TH7IRAVHDLK2AAWY5YBE6CEBUACF",
                    "FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH",
                    "GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN",
                    "I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT",
                    "JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC",
                    "TKT4UESIKTTRALRRLWS4SENSTJX6ODCW",
                    "UE25S4GRWZOLNXZKY4VWFHNJZWUSYCQC",
                    "XY6JXVBITD4EKY3DFT27XS65D2M3FJ5V"
                ],
                "is_stable": 1
            }
        ],
        "threshold_size": [
            {
                "address": "3Y24IXW57546PQAPQ2SXYEPEDNX4KC6Y",
                "unit": "",
                "timestamp": 1724716800,
                "value": 10000,
                "is_stable": 1
            },
            {
                "address": "G4E66WLVL4YMNFLBKWPRCVNBTPB64NOE",
                "unit": "",
                "timestamp": 1724716800,
                "value": 10000,
                "is_stable": 1
            },
            {
                "address": "BVISWXMUXG5S6SN6X2HHXPEBIAG6R6SH",
                "unit": "eX3o1MK4C5EsbO6NIPbe9sqGmNmTxS1gy8+oXZAXxvo=",
                "timestamp": 1740913230,
                "value": 11111,
                "is_stable": 1
            }
        ],
        "base_tps_fee": [
            {
                "address": "G4E66WLVL4YMNFLBKWPRCVNBTPB64NOE",
                "unit": "",
                "timestamp": 1724716800,
                "value": 10,
                "is_stable": 1
            },
            {
                "address": "RBWJEVUGFDFWXWQ4RSOFDJRHRXP3T2J2",
                "unit": "PgwAw1lSeUKr+5SH7OuArdgt/0ONt8HOdEL2Ie/wkVw=",
                "timestamp": 1734033891,
                "value": 10,
                "is_stable": 1
            },
            {
                "address": "BVISWXMUXG5S6SN6X2HHXPEBIAG6R6SH",
                "unit": "dcLTXt9DHwKDJRyaiqSoX3s1q8HxlD6xasbO7snBBPk=",
                "timestamp": 1740913310,
                "value": 12,
                "is_stable": 1
            }
        ],
        "tps_interval": [
            {
                "address": "3Y24IXW57546PQAPQ2SXYEPEDNX4KC6Y",
                "unit": "",
                "timestamp": 1724716800,
                "value": 1,
                "is_stable": 1
            },
            {
                "address": "RBWJEVUGFDFWXWQ4RSOFDJRHRXP3T2J2",
                "unit": "RGKwvNCwEQL6xSRaXbCdqL282SxyxmTIud+UKashLws=",
                "timestamp": 1734033912,
                "value": 1.1,
                "is_stable": 1
            }
        ],
        "tps_fee_multiplier": [
            {
                "address": "3Y24IXW57546PQAPQ2SXYEPEDNX4KC6Y",
                "unit": "",
                "timestamp": 1724716800,
                "value": 10,
                "is_stable": 1
            },
            {
                "address": "G4E66WLVL4YMNFLBKWPRCVNBTPB64NOE",
                "unit": "",
                "timestamp": 1724716800,
                "value": 10,
                "is_stable": 1
            },
            {
                "address": "BVISWXMUXG5S6SN6X2HHXPEBIAG6R6SH",
                "unit": "hwGuRJGSluIbFJUwUBQlXDsmIfEFybFm3pCTBDJAcv8=",
                "timestamp": 1740913416,
                "value": 22,
                "is_stable": 1
            }
        ]
    },
    "balances": {
        "3Y24IXW57546PQAPQ2SXYEPEDNX4KC6Y": 2007509338238,
        "4DEF75MAHKSEV7NRGLJNZUC2T7B6SOZR": 3852543,
        "4OFKGOOM6W6SZJVMNJCAPZVYRLIGXOK5": 7713961,
        "6ONO2OLXJGZBARCSMBPN3LIRPBVPANHU": 12848627,
        "A3JUXRM6K2F7326WD5IJP2MJGIZEAKJG": 1198975186,
        "AIPFLEFQO74TRHKU6PEXZGJ2U2HH4LVQ": 7691187,
        "ASO3PWI5KHAP3RFMD7DLBRY25DHCQC7P": 2679050085,
        "B74PLANYUJTAJS22KES5OZDTCY7ASU6P": 177779153125,
        "BQCVIU7Y7LHARKJVZKWL7SL3PEH7UHVM": 8453004354968,
        "BVISWXMUXG5S6SN6X2HHXPEBIAG6R6SH": 29037127314,
        "CLLUPP76C26EBN3Z6CZUUJVQE42PC5IO": 83354118240,
        "D6IR4XXKEIFQVMEVMCLIQJPTW265POFP": 229666908070,
        "G4E66WLVL4YMNFLBKWPRCVNBTPB64NOE": 2000000354395,
        "M2LGZ6M46QRM3LIX3YQXZZ3XPIEO26JR": 553142933734,
        "N7H54GU4LASVFW6XGKZXBLBX4D4SRPPO": 10226297714,
        "NSNOK3DXDHZ6PTUJZGSEGDBYVVVKJGMH": 3815153946,
        "NVZ34OINE775TAGC7KE3X36KE7RLVZJZ": 50660161075,
        "OVZ36GLFXKTAFFALJGBGRXP7FTMVUHSY": 24288843177,
        "ZCJD5VY24AJOCHAVKHGOFZHFP5EKE6YW": 114156750746
        // ...
    }
}
```

{% embed url="<https://governance.obyte.org/>" %}


# Post system vote

### Example

```javascript
const unitHash = await client.post.systemVote(
  { subject: 'base_tps_fee', value: 10 },
  { wif }
);
```

### Returns&#x20;

```javascript
'unitHashBase64='
```

{% embed url="<https://governance.obyte.org/>" %}


# Subscribe

Subscribe to WebSocket notifications.

### Example

```javascript
client.subscribe(function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Here is an example of a notification that you may receive:

```javascript
[
  'justsaying',
  {
    subject: 'exchange_rates',
    body: {
      GBYTE_USD: 117.17363175179999,
      GBB_USD: 5.7415079558382
    } 
  }
]
```


# Just saying

Send a message to a node that does not require response.

### Example

```javascript
client.justsaying('light/new_address_to_watch', 'BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3');
```

You need to subscribe to WebSocket notifications [see here](/client/subscribe) to see messages sent to you. Here is an example of a notification:

```javascript
[
  'justsaying',
  {
    subject: 'info',
    body: 'now watching BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3'
  }
]
```


# Requests

Send a message to a node that requires a response.

Obyte.js library has API helper functions for most requests that the [WebSocket API](https://developer.obyte.org/websocket-api/request) supports (even some that are not documented: api.getTempPubkey, api.tempPubkey, api.deliver), but if there is anything missing, it's possible to extend it with existing internal functions. Here is quick start example written without the helper function.

### Example

```javascript
// API helper function
client.api.getJoint('oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=', function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});

// internal function
client.client.request('get_joint', 'oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=', function(err, result) {
  if (err) return console.error(err);
  console.log(result);
});
```

Here is an example of a response that you may receive:

```javascript
{
  "joint": {
    "unit": {Object}
  }
}
```


# Subscribe to errors

Subscribe to low-level WebSocket errors with client.onError.

### Example

```javascript
const client = new obyte.Client('wss://obyte.org/bb', {
  reconnect: true,
  closeIfError: true,
});

client.onError(function(err) {
  console.error('WebSocket error:', err.message);
});
```

### Returns

```javascript
WebSocket error: boom
```

When `closeIfError: true` is set, the client disables reconnect and closes the socket on the first WebSocket error.

```js
client.client.reconnect;
// false after the error
```


# Connection lifecycle

`onConnect` fires on every successful WebSocket connection, including every reconnection when `reconnect: true` is enabled.

Hub-side subscriptions live only for the current connection, so register them inside `onConnect` when you use reconnecting clients.

### Example

```js
const client = new obyte.Client('wss://obyte.org/bb', {
  reconnect: true,
});

client.onConnect(function() {
  client.justsaying('light/new_aa_to_watch', {
    aa: 'AA_ADDRESS_TO_WATCH',
  });

  client.subscribe(function(err, result) {
    if (err) return console.error(err);
    console.log('notification:', result);
  });
});

client.onError(function(err) {
  console.error('connection error:', err);
});

const heartbeat = setInterval(function() {
  client.api.heartbeat();
}, 10 * 1000);
```

### Close permanently

When `reconnect: true` is enabled, a closed socket is treated as a dropped connection and the client reconnects. Disable reconnection before closing if you want to shut down permanently.

```js
client.client.reconnect = false;
client.close();
clearInterval(heartbeat);
```

### Returns

`subscribe` receives hub notifications.

```js
['justsaying', { subject: 'light/have_updates', body: { ... } }]
```


# Sign a message

Sign a message with specific address

### Example

`signMessage` function takes 2 parameters: first parameter as message to be signed and second parameter as WIF of specific wallet address. Second parameter can also be object that contains binary  `privateKey` or `wif` string and boolean testnet switch.

Documentation how to generate WIF can be found [o](/utils/generate-wallet)n [Generate a random address](/utils/generate-wallet) page.

```javascript
const { signMessage } = require('obyte/lib/utils');
const privateKey = window.atob('base64 of private key'); // convert to binary
const address_wif = 'wif string';
//const address_key = { privateKey, testnet: false }; // optional way
//const address_key = { wif: address_wif, testnet: false }; // optional way
const address_key = wallet_wif;
const message = 'Hello world';

const objSignedMessage = signMessage(message, address_key);
const signedMessageBase64 = window.btoa(JSON.stringify(objSignedMessage));

console.log(objSignedMessage, signedMessageBase64);
```

### **Returns**

```javascript
{
  authors: [
    {
      address: 'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH',
      definition: [
        'sig',
        {
          pubkey: 'AsD2GQ3+CSHfFO9CfX8+gBxmxSm9TGweKjWVie0rt/0p'
        }
      ],
      authentifiers: {
        r: 'Xfw43Kiu+q+L/1b+z+daKe784V3KcvxWXedwcyC/Yvp+ziR1Jomo7Og7ZoPUPUwQeM4UPpIVU/cTtgurH0LzvA=='
      }
    }
  ],
  signed_message: 'Hello world',
  version: '3.0'
}

"eyJ2ZXJzaW9uIjoiMy4wIiwic2lnbmVkX21lc3NhZ2UiOiJIZWxsbyB3b3JsZCIsImF1dGhvcnMiOlt7ImFkZHJlc3MiOiJUTVdOTFhSNDJDS0lQNEE3NzRCUUdOVkJaQVBIWTdHSCIsImRlZmluaXRpb24iOlsic2lnIix7InB1YmtleSI6IkFzRDJHUTMrQ1NIZkZPOUNmWDgrZ0J4bXhTbTlUR3dlS2pXVmllMHJ0LzBwIn1dLCJhdXRoZW50aWZpZXJzIjp7InIiOiJYZnc0M0tpdStxK0wvMWIreitkYUtlNzg0VjNLY3Z4V1hlZHdjeUMvWXZwK3ppUjFKb21vN09nN1pvUFVQVXdRZU00VVBwSVZVL2NUdGd1ckgwTHp2QT09In19XX0="
```


# Validate signed message

### Example

`validateSignedMessage` function can take multiple input parameters, first parameter is JSON object, which is required, second parameter is wallet address (optional) used for signing and third parameter is signed message (optional).

```javascript
const { signMessage, validateSignedMessage } = require('obyte/lib/utils');
const address_wif = '';
const wallet_address = 'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH';
const message = 'Hello world';

const objSignedMessage = signMessage(message, address_wif);

console.log(validateSignedMessage(objSignedMessage, wallet_address, message));
console.log(validateSignedMessage(objSignedMessage, null, message));
console.log(validateSignedMessage(objSignedMessage));
```

### Returns

Returns boolean `true` if signed message is valid, otherwise boolean `false`.


# Generate a random address

### Paper wallet

To generate a new random address you can use Obyte paper wallet offline here: <https://bonustrack.github.io/obyte-paperwallet/>

### Node.js

Open your terminal and run:

```
npm i byteball bitcore-mnemonic --save
```

Then run this script to generate a new wallet:

```javascript
const { toWif, getChash160 } = require('byteball/lib/utils');
const Mnemonic = require('bitcore-mnemonic');

const testnet = false; // Change to "true" to generate testnet wallet
const passphrase = ''; // Add a passphrase for encryption

const path = "m/44'/0'/0'/0/0";
let mnemonic = new Mnemonic();
while (!Mnemonic.isValid(mnemonic.toString())) {
  mnemonic = new Mnemonic();
}
const xPrivKey = mnemonic.toHDPrivateKey(passphrase);
const { privateKey } = xPrivKey.derive(path);
const privKeyBuf = privateKey.bn.toBuffer({ size: 32 });
const wif = toWif(privKeyBuf, testnet);
const pubkey = privateKey.publicKey.toBuffer().toString('base64');
const definition = ['sig', { pubkey }];

const { privateKey: devicePrivateKey } = xPrivKey.derive('m/1');
const devicePubKey = devicePrivateKey.publicKey.toBuffer().toString('base64');

console.log(
  'Root private key:', xPrivKey.toString(),
  '\nSeed words:', mnemonic.phrase,
  '\nPath:', path,
  '\nWIF:', wif,
  '\nWallet public key:', pubkey,
  '\nWallet address:', getChash160(definition),
  '\nDevice address:', `0${getChash160(devicePubKey)}`
);
```


# Get definition address

Generate address from a definition (or smart contract).

### Example

```javascript
const { getChash160 } = require('obyte/lib/utils');

const definition = ['and', [
    ["address", "TMWNLXR42CKIP4A774BQGNVBZAPHY7GH"],
    ["in data feed", [["BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3"], "timestamp", ">", 1525593731872]]
]];

const address = getChash160(definition);
console.log(address);
```

### **Returns**

```
ETARZZW2G3R3KT4UZKMQUXMWKRZMY7RQ
```

### **Learn more** <a href="#learn-more" id="learn-more"></a>

* "21. Addresses" (page 23) <https://obyte.org/Byteball.pdf>
* "Smart contracts" <https://github.com/byteball/ocore/wiki/Smart-contracts>&#x20;


# Is valid address

Check if an address is valid.

### Example

```javascript
const { isValidAddress } = require('obyte/lib/utils');

const isValid = isValidAddress('ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q');
console.log(isValid);
```

### **Returns**

```
true
```


# Keep connection alive

### Reconnect

You can enable auto reconnection with the option "reconnect".

```javascript
const options = { reconnect: true };
const client = new obyte.Client('wss://obyte.org/bb', options);
```

### Notify

Another way to keep the connection with the WebSocket node alive is to notify the node that your peer is awake every 10 sec.&#x20;

```javascript
setInterval(function() {
  client.api.heartbeat()
}, 10 * 1000);
```


# About

### What is Obyte.js?

Obyte.js is an open source library for building Obyte applications using JavaScript.

### Want to get involved? <a href="#want-to-get-involved" id="want-to-get-involved"></a>

Obyte.js is an open source project and contributions are very much encouraged. Check out the [project’s contributing guide](https://github.com/obytescript/obyte.js/blob/master/docs/CONTRIBUTING.md) and **join us on the** [**Obyte Discord**](https://discord.gg/Qn6JWfT).


# Links

{% embed url="<https://obyte.org/>" %}
Obyte official website
{% endembed %}

{% embed url="<https://explorer.obyte.org>" %}
Obyte official explorer
{% endembed %}

{% embed url="<https://obyte.io>" %}
Obyte.io is a non-financial data explorer for Byteball
{% endembed %}

{% embed url="<https://wiki.obyte.org>" %}
Obyte wiki
{% endembed %}


# Tutorials

A curated list of tutorials using Byteball.js.

{% embed url="<https://busy.org/@genievot/byteball-js-tutorials-1-understanding-basics-1535603550862>" %}

{% embed url="<https://busy.org/@genievot/byteball-js-tutorials-2-create-a-web-page-that-sends-bytes-to-any-byteball-account-1535960188987>" %}


# Byteball.js

A pure and powerful JavaScript Byteball library.

{% content-ref url="/pages/-LJ4TbBVSWsrKdpWEsUz" %}
[Quick start](/0.1.2/getting-started/quick-start)
{% endcontent-ref %}

{% content-ref url="/pages/-LJU1DogFsLlfL3PS6\_L" %}
[Generate a random address](/0.1.2/utils/generate-wallet)
{% endcontent-ref %}


# Quick start

To install and run Byteball.js, follow this quick start guide.

### Install

Byteball.js was designed to work both in the browser and in Node.js.

#### Node.js

To install Byteball.js on Node.js, open your terminal and run:

```
npm i byteball --save
```

#### Browser

You can create an index.html file and include Byteball.js with:

```markup
<script src="https://cdn.jsdelivr.net/npm/byteball"></script>
```

### Usage

Ways to initiate WebSocket client:

```javascript
const byteball = require('byteball');

// Connect to mainnet official node 'wss://byteball.org/bb'
const client = new byteball.Client();

// Connect to a custom node
const client = new byteball.Client('wss://byteball.org/bb');

// Connect to testnet
const options = { testnet: true };
const client = new byteball.Client('wss://byteball.org/bb-test', options);
```

Close the client:

```javascript
client.close();
```

All API methods follow this pattern:

```javascript
// If the last argument is a function it is treated as a callback
client.api.getJoint('oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=', function(err, result) {
  console.log(err, result);
});

// If a callback is not provided, a Promise is returned
client.api.getJoint('oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=').then(function(result) {
  console.log(result);
});
```

### Transaction

To compose and post unit you need first to create a Byteball wallet and fund it with the native currency ‘bytes’. The generated WIF will be used on Byteball.js. Click on the link below to learn more:

{% content-ref url="/pages/-LJU1DogFsLlfL3PS6\_L" %}
[Generate a random address](/0.1.2/utils/generate-wallet)
{% endcontent-ref %}

Sending a payment:

```javascript
const wif = '5JBFvTeSY5...'; // WIF string generated (private key)

const params = {
  outputs: [
    {
      address: 'NX2BTV43XN6BOTCYZUUFU6TK7DVOC4LU', // The Byteball address of the recipient
      amount: 1000 // The amount he receives
    }
  ]
};

client.post.payment(params, wif, function(err, result) {
  console.log(result); // The unit hash is returned
});
```


# Testnet

Getting started with Byteball testnet.

### Get ready

1. [Click this link](https://bonuschain.github.io/byteball-paperwallet/) and select "Testnet" to generate a new testnet wallet
2. [Download Byteball testnet wallet](https://byteball.org/testnet.html)
3. Install Byteball testnet wallet and [click this link](byteball-tn:AxBxXDnPOzE/AxLHmidAjwLPFtQ6dK3k70zM0yKVeDzC@byteball.org/bb-test#0000) to receive free testnet bytes
4. Send testnet bytes to the address you created on first step

### Usage

Here is how to initiate client for Byteball testnet:

```javascript
const byteball = require('byteball');

const options = { testnet: true };
const client = new byteball.Client('wss://byteball.org/bb-test', options);
```

### Links

{% embed url="<https://byteball.org/testnet.html>" %}

{% embed url="<https://testnetexplorer.byteball.org/>" %}
Byteball testnet explorer
{% endembed %}


# Subscribe

Subscribe to WebSocket notifications.

### Example

```javascript
client.subscribe(function(err, result) {
  console.log(result);
});
```

Here is an example of a notification that you may receive:

```javascript
[
  'justsaying',
  {
    subject: 'exchange_rates',
    body: {
      GBYTE_USD: 117.17363175179999,
      GBB_USD: 5.7415079558382
    } 
  }
]
```


# Just saying

Send a message to a node that does not require response.

### Example

```javascript
client.justsaying('light/new_address_to_watch', 'BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3');
```

You need to subscribe to WebSocket notifications [see here](/0.1.2/client/subscribe) to see messages sent to you. Here is an example of a notification:

```javascript
[
  'justsaying',
  {
    subject: 'info',
    body: 'now watching BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3'
  }
]
```


# Get witnesses

Get the list of current witnesses.

### **Example**

```javascript
client.api.getWitnesses(function(err, result) {
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/ohae4Lv5/).

### **Returns**

```javascript
[
  'BVVJ2K7ENPZZ3VYZFWQWK7ISPCATFIW3',
  'DJMMI5JYA5BWQYSXDPRZJVLW3UGL3GJS',
  'FOPUBEUPBC6YLIQDLKL6EW775BMV7YOH',
  'GFK3RDAPQLLNCMQEVGGD2KCPZTLSG3HN',
  'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
  'I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT',
  'JEDZYC2HMGDBIDQKG3XSTXUSHMCBK725',
  'JPQKPRI5FMTQRJF4ZZMYZYDQVRD55OTC',
  'OYW2XTDKSNKGSEZ27LMGNOPJSYIXHBHC',
  'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
  'TKT4UESIKTTRALRRLWS4SENSTJX6ODCW',
  'UENJPVZ7HVHM6QGVGT6MWOJGGRTUTJXQ'
]
```

### **Learn more**

* "6. Witnesses" (page 6) <https://byteball.org/Byteball.pdf>
* Byteball Wiki: <https://wiki.byteball.org/Witness>


# Get peers

Get the list of the current peers.

### Example

```javascript
client.api.getPeers(function(err, result) {
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/2azq1ruL/).

### Returns

```javascript
[
  'wss://byteball.fr/bb',
  'wss://byteball.me/bb',
  'wss://blackbytes.me/bb',
  'wss://hub.byteball.ee',
  'wss://byteball-hub.com/bb',  
  'wss://relay.papabyte.com/bb'
]
```


# Get joint

Request data of a specific unit.

### **Example**

```javascript
const unit = 'k37Xlns198EHCtubX5X0kqbrnC9XYVTa0aFpR78gidM=';

client.api.getJoint(unit, function(err, result) {
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/rqzsdL36/).

### **Returns**&#x20;

```javascript
{
  joint: {
    unit: {
      unit: 'k37Xlns198EHCtubX5X0kqbrnC9XYVTa0aFpR78gidM=',
      version: '1.0',
      alt: '1',
      witness_list_unit: 'oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=',
      last_ball_unit: '9tIFlniHyoVJEp0i+WHMTZqnnR1UqgAhrIWFRkgE8m0=',
      last_ball: 'qxl8Rq1IjVUICgbm9A1+d+ZC3pG75HoDEFTchdL6scg=',
      headers_commission: 344,
      payload_commission: 123,
      main_chain_index: 2870558,
      timestamp: 1529756195,
      parent_units: [
        '0V3X7wyTl/17YX83YbjFgyJ2LRNxbgT5jXQOdLvZR2A=',
        'HJoe07dHWj5fH5s7PMgwbtryM/o14YERshGVz4cP1BQ='
      ],
      authors: [
        {
          address: 'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
          authentifiers: {
            r: 'nNx6QBfwIQkZydLEDXs/di0U5wqFaw4L15OCGICFGkwDgDh3KK+ks5hxFoUhSLxiZZIeNt1gIjmpKFv+bIiDtQ=='
          }
        }
      ],
      messages: [
        {
          app: 'payment',
          payload_hash: 'g0eNA+42F6Zxx650BLNxUKAwx3R3HJ/pC1tjxXVg8Lg=',
          payload_location: 'inline',
          payload: {
            inputs: [
              {
                type: 'witnessing',
                from_main_chain_index: 580671,
                to_main_chain_index: 580684
              }
            ],
            outputs: [
              {
                address: 'S7N5FE42F6ONPNDQLCF64E2MGFYKQR2I',
                amount: 79
              }
            ]
          }
        }
      ]
    },
    ball: 'XRz6FcvpNLjrzXkCeQGIM/ekqQTrmB/kBEpn1grsrI0='
  }
}
```

### **Learn more**

* "12. Unit structure" (page 15) <https://byteball.org/Byteball.pdf>


# Get last MCI

Get the last main chain index of the node you logged to.

### Example

```javascript
client.api.getLastMci(function(err, result) {
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/kzjy6s97/).

### Returns

```
2870575
```

### **Learn more**

* "5. The main chain" (page 8) <https://byteball.org/Byteball.pdf>


# Get history

Get the history of one or multiple addresses.

### Example

```javascript
const params = {
  witnesses: witnesses,
  addresses: ['ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q']
};

client.api.getHistory(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
{
  unstable_mc_joints: [
    {
      unit: [Object]
    },
    {
      unit: [Object]
    }, 
    ...
  ],
  witness_change_and_definition_joints: [
    {
      unit: [Object],
      ball: 'CxK1luSnAk5+MaGyaE9wl26JdwAkSPFDqWJdYs9gRng='
    }
  ],
  joints: [
    {
      unit: [Object],
      ball: 'HCEsVPYN9g7tGOVWlixTlA7Cg4fXsd1VDQSgUzHZljI='
    },
    {
      unit: [Object],
      ball: '7Zk9IQja19XZyJY0MPZZxAhIjV5Uydr+zUvoQXvGBKs='
    },
    ...
  ],
  proofchain_balls: [
    {
      unit: 'rVuepU0c43PKbqM2BgnpOLaBCGdaxG0w6WBpSjaCHgA=',
      ball: 'zTN1OJcGfibm2hxitGnQRx0HSzhfhycFIXsaL7gnUNY=',
      parent_balls: [Array]
    },
    {
      unit: 'Mn8nOpIQvhQvPjlnDBbtYwUbRolrt40Igr8txWch0s0=',
      ball: 'Ocgs5zd0mWeqWNm/+gT0wqpfnd9+mj5BaaABndamw0E=',
      parent_balls: [Array]
    },
   ...
  ]
}
```


# Get attestation

Get attestation unit id from a specific attested value.

### Example

```javascript
const params = {
  attestor_address: 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
  field: 'email',
  value: 'fabien@bonustrack.co'
};

client.api.getAttestation(params, function(err, result) {
  console.log(result);
});
```

### Returns

```
7SEJqVRpog8Ezn5A3PSDX+h3iIYMfJaUsozoUlrsm+o=
```

### **Learn more**

* "23. Attestations" (page 32) <https://byteball.org/Byteball.pdf>


# Get attestations

Get all attestations of a specific address.

### Example

```javascript
const params = {
  address: 'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
};

client.api.getAttestations(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
[
  {
    unit: 'ekUq+0FW1uf1Bm1Dos7epi6AdWy2+m8CTOzU5/04y84=',
    attestor_address: 'I2ADHGP4HL6J37NQAD73J7E5SKFIXJOT',
    profile: {
      profile_hash: 'cyZ7L8pPE4Df7pqH4jKtpuaB2SLEy2HR/K2rBGLRzYM=',
      user_id: 'd4wISqCAUd1yDv2FGyjQD/+Xe+l7GGGtuxzxlpKayfk='
    }
  },
  {
    unit: '0miOAkbyv40DGVyJToxWroyoiJ+xhOnDb1aTbF6YXR8=',
    attestor_address: 'C4O37BFHR46UP6JJ4A5PA5RIZH5IFPZF',
    profile: {
      nonus: 1
    }
  },
  {
    unit: '7SEJqVRpog8Ezn5A3PSDX+h3iIYMfJaUsozoUlrsm+o=',
    attestor_address: 'H5EZTQE7ABFH27AUDTQFMZIALANK6RBG',
    profile: {
      email: 'fabien@bonustrack.co',
      user_id: 'uyeABSHzEgArC14L504vKgza+BmpgXlemnkDpyFC0mA='
    }
  }
]
```

### **Learn more**

* "23. Attestations" (page 32) <https://byteball.org/Byteball.pdf>


# Get bots

Get the list of current chatbots.

### Example

```javascript
client.api.getBots(function(err, result) {
  console.log(result);
});
```

Try on [JSFiddle](https://jsfiddle.net/xanrbcgz/).

### **Returns**

```javascript
[
  {
    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'
  },
  ...
]
```

### **Learn more**

* Byteball Wiki: <https://wiki.byteball.org/Chatbot>


# Get asset metadata

Get metadata of a specific asset.

### Example

```javascript
const asset = '1OLPCz72F1rJ7IGtmEMuV1LvfLawT9WGOFuHugW2b7c=';

client.api.getAssetMetadata(asset, function(err, result) {
  console.log(result);
});
```

### **Returns**

```javascript
{
  metadata_unit: '3H0caQSbAjVOkgvOZLPJ8UTWKVdlRq56moVkqdE0noY=',
  registry_address: 'AM6GTUKENBYA54FYDAKX2VLENFZIMXWG',
  suffix: null
}
```

### **Learn more**

* Byteball Wiki: <https://wiki.byteball.org/Asset>
* Byteball Market: <https://byteball.market>


# Get definition

Get an address definition.

### Example

```javascript
const address = 'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH';

client.api.getDefinition(address, function(err, result) {
  console.log(result);
});
```

### **Returns**

```javascript
[
  'sig',
  {
    pubkey: 'AsD2GQ3+CSHfFO9CfX8+gBxmxSm9TGweKjWVie0rt/0p'
  }
]
```

### **Learn more** <a href="#learn-more" id="learn-more"></a>

* "21. Addresses" (page 23) <https://byteball.org/Byteball.pdf>​


# Get balances

Get balances from one or multiple addresses (max 100).

### Example

```javascript
const addresses = [
  'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH',
  'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
];

client.api.getBalances(addresses, function(err, result) {
  console.log(result);
});
```

### **Returns**

```javascript
{
  TMWNLXR42CKIP4A774BQGNVBZAPHY7GH: {
    base: {
      stable: 838,
      pending: 0
    },
    's+bzDkwx0TVMtdyf9YU4wEA23oInOUzulO+r5WxBUZs=': {
      stable: 98,
      pending: 0
    },
    'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=': {
      stable: 5000,
      pending: 0
    }
  },
  ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q: {
    base: {
      stable: 942956698,
      pending: 0
    },
    'f2TMkqij/E3qx3ALfVBA8q5ve5xAwimUm92UrEribIE=': {
      stable: 918528,
      pending: 0
    },
    'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=': {
      stable: 970979,
      pending: 0
    }
  }
}
```


# Get profile units

Get profile unit ids from one or multiple addresses (max 100).

### Example

```javascript
const addresses = [
  'TMWNLXR42CKIP4A774BQGNVBZAPHY7GH',
  'ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'
];

client.api.getProfileUnits(addresses, function(err, result) {
  console.log(result);
});
```

### **Returns**

```javascript
[
  '46fTf+Wf5EAq5KQmEttKmKUlrFzzCkXYO1f3JLP7uyE=',
  'itguFXI8RtuLmmXK5/yXu+Rma2F3xmlvuipnYSeuwQI=',
  'U2y+yti2vSJpm4Le2/o+JBfBgbP0F5GDm7ffHHd3+AQ=',
  'DVwBupJaKPnEMQBT2sd3DDAumEYTVcPCxs7nyDS8CkA=',
  'Ii/IEEYuyJh+7r/Bkp6T8+Neu+DlZSNw+pupdq0U43U=',
  'pJWt6QqtDQLxmY/7h+rbKO+It6gLk8wfLnXNmnuguVs=',
  'zPEqWmZIiGdlDQw9q9/K5cVAQUkR1LlgUpnhwk5hCwQ=',
  'xrVwToW5Yy1xJqCm0DUuriZjbWDVyAk0CBj2DtK9uoI=',
  'wp8wScoEuznmVivWi5fYO6KL8z2U9KcqhtcQZza8LS4=',
  'GMqQeyPs+//n2YJg8tlc4EkR0GhemU+Jq0Fx76KQjIs=',
  'gYd2UTq5mBT298NaS7qcAHlBzB4RyCPw+k7PQSfjino=',
  'K1s64SAgA9EsknN6HP/KiBvNCs5mttkshyt/A5yo3q0=',
  'dJizRyUSQDqSg4vV4ExDRbwg8Wi3yK3MQvv+zzQEZxI=',
  'CvTEcsP+yIGEhU33Nt4XLs8otlh87gcGez86Wecam0M='
]
```

### **Learn more**

* "22. Profiles" (page 32) <https://byteball.org/Byteball.pdf>


# Core


# Catchup

Get balls units between 2 main chain ids.

### Example

```javascript
const params = {
  witnesses: witnesses,
  last_stable_mci: 2871302,
  last_known_mci: 2871312
};

client.api.catchup(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
{
  status: 'current'
}
```


# Get hash tree

Get units between balls.

### Example

```javascript
const params = {
  from_ball: 'aEU1WiY9FQ9ihv9cKkX/EHWDxYYVaWYs2AL1yxyYZAQ=',
  to_ball: 'nOqDBwCVHy+bkBSRIgNlzcKR+EXlTC79aA62qT+Lcj0='
};

client.api.getHashTree(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
{
  balls: [
    {
      unit: 'c2teVop7xa1BmH1LPvytvOKU8HHTrprGWQw+uHlWPHo=',
      ball: 'ht1QP48paWg5hpjx+Nbd/DSRFT8WlbQKk9+Uum0/tso=',
      parent_balls: [Array]
    },
    {
      unit: 'tPbC6QLeweGuiGYRPsIhfd0TQWXWASYBJJUPGa9AOfw=',
      ball: 'ba5wFB+gewdRX6nSpxt6+Nt8PaRen4pLIYg3jC6EvIw=',
      parent_balls: [Array]
    },
    ...
  ]
}
```


# Get light props

Get light client properties.

### Example

```javascript
const params = {
  witnesses: witnesses
};

client.api.getParentsAndLastBallAndWitnessListUnit(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
{
  parent_units: [
    'OLlkgxuJhX0Ls/G6ElIWF/VhUXOUiHr2xaS0K/pdQmc='
  ],
  last_stable_mc_ball: '6vMXOW9f0dYP5/ZZRV/oevXfCyYvqeDkEIUQr32nNqQ=',
  last_stable_mc_ball_unit: 'aTOhoJOU8i326uEb7WJ0NOUuTkP5GMnpf8E0L7qzRIY=',
  last_stable_mc_ball_mci: 2871211,
  witness_list_unit: 'oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E='
}
```


# Post joint

Post an unit on Byteball network.

### Example

```javascript
const params = {
  unit: [Object]
};

client.api.postJoint(params, function(err, result) {
  console.log(result);
});
```

The unit object can be generated with the method "compose".

### Returns

```javascript
accepted
```


# Pick divisible coins for amount

Get spendable inputs from a specific amount and asset.

### Example

```javascript
const params = {
  asset: 'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=',
  addresses: ['ULQA63NGEZACP4N7ZMBUBISH6ZTCUS2Q'],
  last_ball_mci: 1000000000,
  amount: 10000,
  spend_unconfirmed: 'own',
};

client.api.pickDivisibleCoinsForAmount(params, function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
{
  inputs_with_proofs: [
    {
      input: {
        unit: "06ni8/eDzmcxwtWeQyuSXhqGsqmVN3I1fsR+5NAj4Sw=",
        message_index: 1,
        output_index: 1
      }
    }
  ],
  total_amount: 985000
}
```


# Heartbeat

Send heartbeat to notify the node you are awake.

### Example

```javascript
client.api.heartbeat(function(err, result) {
  console.log(result);
});
```

### Returns

```javascript
null
```


# Address definition change

Users can update definitions of their addresses while keeping the old address.

### **Arguments**

* **definition\_chash** `string` *required*\
  Indicates the checksummed hash of the new address definition.
* **address** `string` *optional*\
  When multi-authored, must indicate address.

### Returns

Returns the unit hash.

Example

```javascript
const params = {
  definition_chash: 'I4Z7KFNIYTPHPJ5CA5OFC273JQFSZPOX',
};

client.post.addressDefinitionChange(params, wif, function(err, result) {
  console.log(result);
});
```

### **Learn more**

* 21\. Addresses (page 23) <https://byteball.org/Byteball.pdf>


# Attestation

Attestations confirm that the user who issued the attestation (the attestor) verified some data about the attested user (the subject).

### **Arguments**

* **address** `string` *required*\
  Address of the attested user (the subject).
* **profile** `object` *required*\
  Verified data about the attested user.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  address: 'IX77DDUQ56TVQVC3E77KIC5QLPQHD4PV',
  profile: {
    email: 'robertjsmc@gmail.com',
    user_id: 'mT+Qwu2e2OH+QJ5mwCijrkQ6Bz2IW/Ad9IIHHHffbwo='
  }
};

client.post.attestation(params, wif, function(err, result) {
  console.log(result);
  // -> J12wi3v0tSco6JJKagqJ265/jEt8Evl4Rk03YIErlpQ=
});
```

### **Learn more**

* "23. Attestations" (page 32) <https://byteball.org/Byteball.pdf>


# Asset

Assets in Byteball can be issued, transferred, and exchanged, and.they behave similarly to the native currency ‘bytes’.

### **Arguments**

* **cap** `integrer` *optional*\
  Is the total number of coins that can be issued (money supply). If omitted, the number is unlimited.
* **is\_private** `boolean` *required*\
  Indicates whether the asset is private (such as blackbytes) or publicly traceable (similar to bytes).
* **is\_transferrable** `boolean` *required*\
  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** `boolean` *required*

  Indicates whether the asset is destroyed when it is sent to the definer address.
* **fixed\_denominations** `boolean` *required*

  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.
* **denominations** `array` *optional*\
  Array of all denominations and the number of coins of that denomination.
* **issued\_by\_definer\_only** `boolean` *required*\
  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.
* **cosigned\_by\_definer** `boolean` *required*\
  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.
* **spender\_attested** `boolean` *required*\
  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.
* **attestors** `array` *optional*\
  List of approved attestor addresses
* **issue\_condition** `array` *optional*\
  Specify the restrictions when the asset can be issued. It evaluate to a boolean and are coded in the same [smart contract language](https://github.com/byteball/byteballcore/wiki/Smart-contracts) as address definitions.
* **transfer\_condition** `array` *optional*\
  Specify the restrictions when the asset can be transferred. It evaluate to a boolean and are coded in the same [smart contract language](https://github.com/byteball/byteballcore/wiki/Smart-contracts) as address definitions.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  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
}; 

client.post.asset(params, wif, function(err, result) { 
  console.log(result);
  // -> xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=
});
```

### **Learn more**

* "24. Assets" (page 33) <https://byteball.org/Byteball.pdf>
* Issuing assets on Byteball: <https://github.com/byteball/byteballcore/wiki/Issuing-assets-on-Byteball>
* Smart contracts: <https://github.com/byteball/byteballcore/wiki/Smart-contracts>
* Byteball Wiki: <https://wiki.byteball.org/Asset>
* Byteball Market: <https://byteball.market>


# Asset attestors

The list of an asset attestors can be amended by the definer by sending an ‘asset\_attestors’ message that replaces the list of attestors.

### **Arguments**

* **asset** `string` *required*\
  Asset unit id.
* **attestors** `array` *required*\
  List of approved attestor addresses

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  asset: 'xamdfH5Uk+alv3le0pEA01qSsfZjycyMsqaqHtycJ1M=',
  attestors: [
    'X5ZHWBYBF4TUYS35HU3ROVDQJC772ZMG',
    'GZSEKMEQVOW2ZAHDZBABRTECDSDFBWVH',
    '2QLYLKHMUG237QG36Z6AWLVH4KQ4MEY6'
  ].sort()
};

client.post.assetAttestors(params, wif, function(err, result) {
  console.log(result);
});
```

### **Learn more**

* "24. Assets" (page 33) <https://byteball.org/Byteball.pdf>


# Data

One can store arbitrary structured data using ‘data’ message type.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  key: "value",
  another_key: {
    subkey: 'other value',
    another_subkey: 232
  }
};

client.post.data(params, wif, function(err, result) {
  console.log(result);
});
```

### **Learn more**

* "28. Arbitrary structured data" (page 45) <https://byteball.org/Byteball.pdf>


# Data feed

Data fields can be used to design definitions that involve oracles.

### Returns

Returns the unit hash.

### Example

```javascript
const params = {
  time: new Date().toString(), 
  timestamp: Date.now()
};

client.post.dataFeed(params, wif, function(err, result) {
  console.log(result);
});
```

### **Learn more**

* "21.1.7. Data feeds" (page 45) <https://byteball.org/Byteball.pdf>


# Definition template

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.

### Returns

Returns the unit hash.

### Example

This template depends on two variables: `$address` and `$ts`.

```javascript
const params = ['and', [
  ['address', '$address'], 
  ['in data feed', [['MO7ZZIU5VXHRZGGHVSZWLWL64IEND5K2'], 'timestamp', '>=', '$ts']]
]];

client.post.definitionTemplate(params, wif, function(err, result) {
  console.log(result);
});
```

### **Learn more**

* "21.1.4. Definition templates" (page 27) <https://byteball.org/Byteball.pdf>




---

[Next Page](/llms-full.txt/1)

