Skip to content

Commit

Permalink
Merge pull request #6 from Adamant-im/dev
Browse files Browse the repository at this point in the history
v1.0.0
  • Loading branch information
adamant-al authored May 28, 2021
2 parents 8561902 + 930c90e commit 6d8f2e2
Show file tree
Hide file tree
Showing 22 changed files with 965 additions and 2,465 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ logs/
.vscode/
test.js
package-lock.json

47 changes: 39 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# ADAMANT JavaScript API library

ADAMANT JavaScript API is a library intended to interact with ADAMANT blockchain for Node.js developers. Also [ADAMANT Console](https://github.com/Adamant-im/adamant-console/wiki) and [ADAMANT node Direct API](https://github.com/Adamant-im/adamant/wiki/) are available.
ADAMANT JavaScript API is a library intended to interact with ADAMANT blockchain for JavaScript developers. Also [ADAMANT Console](https://github.com/Adamant-im/adamant-console/wiki) and [ADAMANT node Direct API](https://github.com/Adamant-im/adamant/wiki/) are available.

Abilities:
Features:

* Internal Health Check for ADAMANT nodes. Health Check system pings all nodes in the list using [`/status`](https://github.com/Adamant-im/adamant/wiki/API-Specification#get-blockchain-and-network-status) endpoint, and connect to a node with actual height.
* High reliability
* GET-requests to the blockchain
* Sending tokens
* Sending messages
* Caching public keys
* Encrypting and decrypting of messages
* Forming and signing transactions
* Working with ADM key pairs
Expand All @@ -13,14 +17,19 @@ Abilities:
* Support for WebSocket connections
* Logging warnings, errors, info

# Usage
## Reliability

Add current version of ADAMANT JavaScript API library in project's `package.json` in `dependencies` section like this:
JS API shows decentralization in action—if a network node cannot fulfill your request, the library will redirect it to another node, and so on several times. You will get the result and you do not need to think about processing the request.

Health Check system pings all nodes in the list using [`/status`](https://github.com/Adamant-im/adamant/wiki/API-Specification#get-blockchain-and-network-status) endpoint, and connects to a node with actual height. When the library unable to process request with current node, it forces to re-initialize Health Check.

## Usage

Add current version of ADAMANT JavaScript API library in project's `package.json` in `dependencies` section:

``` json
"dependencies": {
"adamant-api": "^0.5.3",
...
"adamant-api": "^1.0.0-beta.2",
```

Or install library from npm:
Expand All @@ -29,6 +38,28 @@ Or install library from npm:
npm i adamant-api
```

# Documentation
Initialize the library:

``` JS
const nodesList = [
"http://localhost:36666",
"https://endless.adamant.im",
"https://clown.adamant.im",
"http://23.226.231.225:36666",
"http://88.198.156.44:36666",
"https://lake.adamant.im"
];
const api = require('adamant-api')({ node: nodesList, logLevel: 'info' });
```

Request example:

``` JS
api.get('blocks').then(response => {
console.log(response.data)
})
```

## Documentation

See [Wiki](https://github.com/Adamant-im/adamant-api-jsclient/wiki) for documentation and usage.
7 changes: 6 additions & 1 deletion groups/decodeMsg.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const nacl = require('tweetnacl/nacl-fast');
const keys = require('../helpers/keys');

module.exports = (msg, senderPublicKey, passPhrase, nonce) => {

const keypair = keys.createKeypairFromPassPhrase(passPhrase);
let privateKey = keypair.privateKey;
if (typeof msg === 'string') {
Expand All @@ -23,20 +24,23 @@ module.exports = (msg, senderPublicKey, passPhrase, nonce) => {
const DHSecretKey = ed2curve.convertSecretKey(privateKey);
const decrypted = nacl.box.open(msg, nonce, DHPublicKey, DHSecretKey);
return decrypted ? Utf8ArrayToStr(decrypted) : ''
}

}

function hexToBytes(hexString = '') {

const bytes = []

for (let c = 0; c < hexString.length; c += 2) {
bytes.push(parseInt(hexString.substr(c, 2), 16))
}

return Uint8Array.from(bytes);

}

function Utf8ArrayToStr(array) {

var out, i, len, c;
var char2, char3;

Expand Down Expand Up @@ -75,4 +79,5 @@ function Utf8ArrayToStr(array) {
}

return out;

}
6 changes: 2 additions & 4 deletions groups/eth.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// https://web3js.readthedocs.io/en/1.0/web3-eth.html#eth-getbalance
const Web3 = require('web3');
var Mnemonic = require('bitcore-mnemonic');
const hdkey = require('hdkey');
const HD_KEY_PATH = "m/44'/60'/3'/1/0";
const {bufferToHex, privateToAddress } = require('ethereumjs-util');
const {eth} = new Web3('https://ethnode1.adamant.im');
const { bufferToHex, privateToAddress } = require('ethereumjs-util');
const eth = { }

/**
* Generates a ETH account from the passphrase specified.
Expand Down
108 changes: 40 additions & 68 deletions groups/get.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,46 @@
const request = require('sync-request');
const axios = require('axios');
const logger = require('../helpers/logger');
const validator = require('../helpers/validator');

module.exports = (syncReq) => {
return async (type, params) => {
let endpoint;
let returned_field = false;
switch (type) {
case 'account':
endpoint = '/api/accounts?address=' + params;
break;
case 'delegate_forged':
endpoint = '/api/delegates/forging/getForgedByAccount?generatorPublicKey=' + params;
break;
case 'account_delegates':
endpoint = '/api/accounts/delegates?address=' + params;
returned_field = 'delegates';
break;
case 'block':
endpoint = '/api/blocks/get?id=' + params;
break;
case 'states':
endpoint = '/api/states/get';
if (params) {
endpoint = endpoint + '?' + params;
}
break;
case 'delegate':
endpoint = '/api/delegates/get?username=' + params;
returned_field = 'delegate';
break;
case 'delegate_voters':
endpoint = '/api/delegates/voters?publicKey=' + params;
returned_field = 'accounts';
break;
case 'blocks':
endpoint = '/api/blocks';
if (params) {
endpoint = endpoint + '?' + params;
}
returned_field = 'blocks';
break;
case 'transaction':
endpoint = '/api/transactions/get?id=' + params;
break;
case 'transactions':
endpoint = '/api/transactions?' + params.split(' ').join('').split(',').join('&');
break;
case 'uri':
endpoint = '/api/' + params;
break;
default:
logger.error(`ADAMANT endpoint ${type} not implemented yet. Use 'uri' to use not implemented endpoints.`);
return false;
}
const DEFAULT_GET_REQUEST_RETRIES = 3; // How much re-tries for get-requests by default. Total 3+1 tries

try {
const res = await syncReq(endpoint);
if (res && res.success) {
if (returned_field) {
return res[returned_field];
}
return res;
}
module.exports = (nodeManager) => {
return (endpoint, params, maxRetries = DEFAULT_GET_REQUEST_RETRIES, retryNo = 0) => {

logger.warn(`Get request to ADAMANT node was not successful. Type: ${type}, URL: ${endpoint}, Result: ${res && res.error}`);
return false;
let url = trimAny(endpoint, "/ ").replace(/^api\//, '');
if (!url || !validator.validateEndpoint(endpoint))
return validator.badParameter('endpoint')

} catch (e) {
logger.error(`Failed to process Get request of type ${type} to ADAMANT node. Error: ${e}.`);
return false;
}
};
url = nodeManager.node() + '/api/' + url;
return axios.get(url, { params })
.then(function (response) {
return validator.formatRequestResults(response, true)
})
.catch(function (error) {
let logMessage = `[ADAMANT js-api] Get-request: Request to ${url} failed with ${error.response ? error.response.status : undefined} status code, ${error.toString()}${error.response && error.response.data ? '. Message: ' + error.response.data.toString().trim() : ''}. Try ${retryNo+1} of ${maxRetries+1}.`;
if (retryNo < maxRetries) {
logger.log(`${logMessage} Retrying…`);
return nodeManager.changeNodes()
.then(function () {
return module.exports(nodeManager)(endpoint, params, maxRetries, ++retryNo)
})
}
logger.warn(`${logMessage} No more attempts, returning error.`);
return validator.formatRequestResults(error, false)
})

}
};

function trimAny(str, chars) {
if (!str || typeof str !== 'string')
return ''
let start = 0,
end = str.length;
while(start < end && chars.indexOf(str[start]) >= 0)
++start;
while(end > start && chars.indexOf(str[end - 1]) >= 0)
--end;
return (start > 0 || end < str.length) ? str.substring(start, end) : str;
}

21 changes: 21 additions & 0 deletions groups/getPublicKey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const get = require('./get');
const logger = require('../helpers/logger');
const publicKeysCache = { };

module.exports = (nodeManager) => {

return async (address) => {
if (publicKeysCache[address])
return publicKeysCache[address]

const publicKey = await get(nodeManager)('/accounts/getPublicKey', { address });
if (publicKey.success) {
publicKeysCache[address] = publicKey.data.publicKey;
return publicKey.data.publicKey
} else {
logger.warn(`[ADAMANT js-api] Failed to get public key for ${address}. ${publicKey.errorMessage}.`);
return false
}
}

};
88 changes: 0 additions & 88 deletions groups/send.js

This file was deleted.

Loading

0 comments on commit 6d8f2e2

Please sign in to comment.