npm package: @inae/inae-js
Description: A JavasSript Open Source Library for iNAE blockchain.
Author: Hessegg based on Cosmostation
Latest version: 0.1.0

<h1 align="center">
    INAE-JS - JavaScript Library for iNAE blockchain
</h1>

*Originally based on JS library for [Cosmostation](https://www.cosmostation.io/)*

*Heavily modified by [Hessegg](http://www.hessegg.com/)*

- [Installation](#installation)
    - [NPM](#npm)
    - [Yarn](#yarn)
    - [Local](#local)
  - [Generate Protobuf](#generate-protobuf)
  - [Import](#import)
- [Examples](#examples)
- [Usage](#usage)
  - [Query information](#query-information)
    - [Predefined queries](#predefined-queries)
  - [Transactions](#transactions)
    - [Example](#example)

This is a preview of Javascript API for iNAE blockchain.
This delivery is tailored for INAE blockchain.

At the moment this package contains samples on how to build transactions for the
blockchain and how to make queries. The examples expect that:
- the blockchain has Chain ID `HostNet`,
- the address prefix is `inae`,
- the platform coin is called `INAE` with normalized denom `uinae`
- the blockchain node runs on the local host and provides REST API
  at port `localhost:31012`

# Installation

*To be written*

### NPM

*The package is not published yet*
```bash
npm install @inae/inae-js
```

### Yarn

*The package is not published yet*
```bash
yarn add @inae/inae-js
```

### Local

add to package.json

```json
{
  "name" : "...",
  ...
  "dependencies" : {
    ...
    "@inae/inae-js": "file:../inae-js",
  }
}
```

```bash 
# yarn env
$ yarn

# npm env
$ npm install 
```

## Generate Protobuf

**DON'T DO IT** unless you know what are you doing.
The generated files require manual tuning.
```bash
$ ./protocgen.sh
```

## Import 

```js
import { Blockchain, Query } from "@inae/inae-js";
```

# Examples

The package comes with two examples. 

`example/hostnet.query.js` demonstrates how to make queries. Execute it with
yarn:
```
yarn example.query
```

`example/hostnet.send.js` demonstrates how to issue a transaction that transfers
funds between two accounts. Execute it with yarn:
```
yarn example.send
```

# Usage

## Query information
```js
import { Blockchain, Query } from "@inae/inae-js";
const chainId = "HostNet";
// The rest server URL MUST NOT end with slash
const bc = new Blockchain("http://localhost:31012", chainId); 
const Q = new Query(bc)
```

The `Q` object provides method `query(path: string) : Promize<any>` that
performs query specified by the path and returns the result as object.

You can find the query paths in the protobuf files named `query.proto` in `./proto` and `./third_party/proto` directories.

For example, `./proto/inae/convert/v1/query.proto` defines the following
query service:
```protobuf
service Query {
  rpc RatePair(QueryRatePairRequest) returns (QueryRatePairResponse) {
    option (google.api.http).get = "/inae/convert/v1/rate/pair/{from}/{to}";
  }
  rpc RateFrom(QueryRateFromRequest) returns (QueryRatesResponse) {
    option (google.api.http).get = "/inae/convert/v1/rate/from/{from}";
  }
  rpc RateTo(QueryRateToRequest) returns (QueryRatesResponse) {
    option (google.api.http).get = "/inae/convert/v1/rate/to/{to}";
  }
  rpc RateAll(QueryRateAllRequest) returns (QueryRatesResponse) {
    option (google.api.http).get = "/inae/convert/v1/rate/all";
  }
}
```

The query `RatePair` returns conversion rate from one token to another. The query
path is defined by the option `google.api.http`: `"/inae/convert/v1/rate/pair/{from}/{to}"`.

It is a template. For the actual query the placeholders should be substituted by
the actual token symbols. E.g. the query path for the conversion rate from TEST
token to INAE coin is `"/inae/convert/v1/rate/pair/inae/test"`.

This query returns the value of the type `QueryRatePairResponse`:
```protobuf
message QueryRatePairResponse {
  ConvertPair pair = 1;
}

message ConvertPair{
    string from = 1;
    string to = 2;
    string rate = 3 [(gogoproto.customtype) = "Dec", (gogoproto.nullable) = false];
}
```

In JSON the response structure closly resembles the protobuf message.
```javascript
const result = await Q.query("/inae/convert/v1/rate/pair/inae/test");
console.log(result)
```
```javascript
 { pair: { from: 'test', to: 'inae', rate: '0.010000000000000000' } }
 ```

 ### Predefined queries

 `Query` class provides a number of predefined queries. See the source code
 `src/query.js` for more details.

## Transactions

Transactions consist of *messages*, *authentication information* and *signatures*.

Messages convoy the business logic of the transaction, the action that blockchain
nodes should execute upon receiving the transaction. 

Authentication information provides data about who authorized the transaction
by digitally signing it.

Signatures are the actual digital signatures of the transaction authorizers.

The messages could be found in the protobuf files named `tx.proto` in `./proto` and `./third_party/proto` directories. 

One of the most important transaction message is `MsgTransfer` that tells the blockchain to
transfer funds between accounts. It is defined in `proto/inae/bankz/v1/tx.proto`

```protobuf
package inae.bankz.v1;

// ...

// Msg defines the bank Msg service.
service Msg {
  rpc Transfer(MsgTransfer) returns (MsgTransferResponse) {
    option (google.api.http).post = "/inae/bankz/v1/transfer";
  };
  // ...
}

// MsgTransfer represents a message to send coins from one account to another.
message MsgTransfer {
  // ...
  string from_address = 1;
  string to_address = 3;
  cosmos.base.v1beta1.Coin coin = 4;
}
// MsgTransferResponse defines the Msg/Send response type.
message MsgTransferResponse {}
```

The package `inae-js` provides a library of Javascript types generated from Protobuf
files:
```javascript
import { message } from "@inae/inae-js/";
```

### Example

`Blockchain` class implements basic blockhain-related operations, including keys derivation,
transaction signing and broadcasting transactions to the blockchain.

`messages` provide classes generated from the protobuf files.
```javascript
import { Blockchain, Query } from "@inae/inae-js";
import { message } from "@inae/inae-js";
```

Setting up the blockchain and account. The keys and the address are derived from
the account mnemonics. In this example we use the mnemonic phrase for the account `supply`
defined for the localhost demonet.
```javascript
// [WARNING] This mnemonic is just for the demo purpose. DO NOT USE THIS MNEMONIC for your own wallet.
// Supply account on the Hostnet
const mnemonic = "also decide pole hello ready month distance favorite blush lawn theory flee hundred move outdoor fiscal online labor patch roof toast case cement hidden";
```
Setting up the blockchain adapter: chain ID, REST API URL, address prefix and key derivation
path. Change in any of the parameters will break compatibility with the localhost demonet.

```javascript
const chainId = "HostNet";
// The rest server URL MUST NOT end with slash
const bc = new Blockchain("http://localhost:31012", chainId); 
bc.setBech32MainPrefix("inae");
bc.setPath("m/44'/118'/0'/0/0");
const Q = new Query(bc);
```

Derive keys and address:
```javascript
// Generate address, private and public keys
const address = bc.getAddress(mnemonic);
const privKey = bc.getECPairPriv(mnemonic);
// getPubKeyAny returns the public key wrapped into `any` protobuf type
const pubKeyAny = bc.getPubKeyAny(privKey);
```

Query the blockchain for the account information. It will be used for the 
digital signature.
```javascript
// Load the account information from the blockchain
const account = await bc.getAccounts(address).then(obj => obj.account)

```

Create the transaction. The first step is to make the message of the type `MsgTransfer`.

```javascript
// Destination for the transaction
const toAddress = "inae1ty659nurtr5cstcxuqmlrkukfw924mkx9dlwdc";

console.log("Sending 1 iNAE from ", address, " to ", toAddress)

// Load the account information from the blockchain
const account = await bc.getAccounts(address).then(obj => obj.account)

// Prepare the transaction for signing
// signDoc = (1)txBody + (2)authInfo

// ---------------------------------- (1)txBody ----------------------------------

// The action of the transaction is presented by the `MsgTransfer` message.
// The path `message.inae.bankz.v1` is derived from protobuf package name.
// See `./proto/inae/bankz/v1/tx.proto`:
// `package inae.banks.v1`;
const msgTransfer = new message.inae.bankz.v1.MsgTransfer({
	from_address: address,
	// account01 in the HostNet
	to_address: toAddress,
	coin: { denom: "uinae", amount: String(1000000) }		// 6 zeroes: 1000000 uinae = 1 INAE
});

// Wrap the message into `any`.
const msgSendAny = new message.google.protobuf.Any({
	type_url: "/inae.bankz.v1.MsgTransfer",
	value: message.inae.bankz.v1.MsgTransfer.encode(msgTransfer).finish()
});

const txBody = new message.cosmos.tx.v1beta1.TxBody({ messages: [msgSendAny], memo: "" });
```

The object `txBody` keeps the list of messages and optional memo note to be included
in the transaction.

The procedure of making the signature doesn't require any knowledge about the messages. 
All transactions are signed in the same way.
```javascript
// --------------------------------- (2)authInfo ---------------------------------

// Signer information hold the public key of the transaction sender
// Sequence it used to prevent replay attacks.
const signerInfo = new message.cosmos.tx.v1beta1.SignerInfo({
	public_key: pubKeyAny,
	mode_info: { single: { mode: message.cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_DIRECT } },
	sequence: account.sequence
});

// Reserved for future use. At the moment set zero (empty) fees
const feeValue = new message.cosmos.tx.v1beta1.Fee({
	amount: [{ denom: "uinae", amount: String(10000) }],
	// amount: [],
	gas_limit: 200000,
	payer: "",
	granter: ""
});

const authInfo = new message.cosmos.tx.v1beta1.AuthInfo({ signer_infos: [signerInfo], fee: feeValue });

// -------------------------------- sign --------------------------------

// The signature includes the account number to prevent signature collisions
const signedTxBytes = bc.sign(txBody, authInfo, account.account_number, privKey);
```

The method `Blockchain.broadcast` delivers the signed transaction to the blockchain.

The mode `BROADCAST_MODE_BLOCK` means *wait until the transaction is included into a block*. 
The transaction hash is accessible as `response.tx_response.txhash`.
```javascript
// ----------------------- send to the blockchain ------------------------
const response = await bc.broadcast(signedTxBytes, "BROADCAST_MODE_BLOCK").then(response => response.json())
console.log(response)
```

This section of the example queries the blockchain about the transaction status.
If the field `txstatus.tx_response.code` is zero, the transaction is handled and
committed to the blockchain state. If processing the transaction resulted in an error
this field is non-zero.
```javascript
// --- Check the transaction status ---
const txid = response.tx_response.txhash;

if (response.tx_response.code != 0) {
	console.error("Transaction failed: reason:", response.tx_response.raw_log);
	if (response.tx_response.height == 0) {
		console.error("Transaction failed: invalid transaction, rejected");
	}
} else {

	// query the transaction
	const txstatus = await Q.tx(txid)

	if (txstatus.tx_response.code == 0) {
		console.log(`${txid}: success`);
	} else {
		const errorCode = txstatus.tx_response.code
		const errorCodeSpace = txstatus.tx_response.errorCodeSpace
		const errorInfo = txstatus.tx_response.info || "N/A"
		console.log(`${txid}: error: codespace ${errorCodeSpace}, error ${errorCode}: ${errorInfo}`);
	}
}
```