npm i @liquid-democracy/delegato-js
Or if you're using Yarn:
yarn add @liquid-democracy/delegato-js
Blockchain API client can be configured by address
and chainId
properties of Api class instance.
Name | Type | Description |
---|---|---|
address |
string | Websocket address and port of Delegato blockchain node. The address should contain protocol (ws or wss ). |
chainId |
string | Identifier of Delegato blockchain. This identifier makes difference between two different networks of Delegato blockchain. For example production and test networks. |
The following example illustrates how to connect to test blockhain network using JavaScript promises.
import { Api } from "@liquid-democracy/delegato-js";
let api = new Api();
api.address = "wss://delegato.stage.deeplace.md/blockchain";
api.chainId =
"74b66242d0ac8c5c447d04ae10460002fb5ee9c5013dd0d46a7296e259ae95a8";
api
.connect()
.then(() => {
// We have been connected. Now we can interact with blockchain API.
})
.catch((error) => {
// An error occurred on establishing connection with blockchain node.
// Here we can handle error and take some action.
// For example try to connect again.
});
Or you can use await operator.
import { Api } from "@liquid-democracy/delegato-js";
let api = new Api();
api.address = "wss://delegato.stage.deeplace.md/blockchain";
api.chainId =
"74b66242d0ac8c5c447d04ae10460002fb5ee9c5013dd0d46a7296e259ae95a8";
(async () => {
try {
await api.connect();
// We have been connected. Now we can interact with blockchain API.
} catch (error) {
// An error occurred on establishing connection with blockchain node.
// Here we can handle error and take some action.
// For example try to connect again.
}
})();
Error | Description | Data |
---|---|---|
ConnectionError | Web socket connection error. | No additional data. |
MethodError | Occurres after method call processing on server side. | The data returned by server in data property. |
ProtocolError | Occurres if not described by JSON-RPC 2.0 protocol action appears. | No additional data. |
InternalError | Unexpected error. Internal logic error of JsonRpcWebSocket class. | No additional data. |
ValidationError | Error on parse JS literal to blockchain data. | No additional data. |
LogicError | Occures on component state error. | No additional data. |
An example of error catching:
import {
Api,
ConnectionError,
MethodError,
ProtocolError,
InternalError,
} from "@liquid-democracy/delegato-js";
let api = new Api();
(async () => {
try {
await api.connect();
console.log(await api.database.getBlock(1));
} catch (error) {
switch (error.constructor) {
case ConnectionError:
console.error(error.message);
break;
case MethodError:
console.log(error);
break;
case ProtocolError:
case InternalError:
console.log(`Unexpected error: ${error.message}`);
break;
}
}
})();
The library supports event system according observer pattern. Here an example of handling disconnection event:
import { Api } from "@liquid-democracy/delegato-js";
let api = new Api();
api.onDisconnect.attach(() => {
console.log("Connection closed.");
});
api.connect().then(() => api.disconnect());
To use all functionality of Delegato blockchain, you need have an account registred in blockchain system.
Firstly, you need to generate keys using a pair of email and password. The same pair of email and password will generate the same pair of keys.
const email = "email@example.com";
const password = "1234567890123";
const owner = PrivateKey.create(email, password, PrivateKeyType.owner);
const active = PrivateKey.create(email, password, PrivateKeyType.active);
You do not need to generate keys every time you need them, better to store keys in memory and do not even save email/password pair, because generating of keys is resource-intensive task, but storing email/password pair in memory or persistent storage is dangerous.
To perform any other transaction you should perform AccountCreate one. AccountCreate transaction stores active and owner public keys and should be signed by both corresponding active and owner private one. DO NOT send your private keys in AccountCreate transaction, it leads for security issues of your account. By default API client uses MemoryStorage to save you keys, but you can use LocalStorage (which saves keys in browser localStorage) or create your own one implementing Storage interface.
After AccountCreate operation is applied, your active and owner public keys will be stored in blockchain database. These keys will be used to identify your transactions signed by your private keys.
The following example illustrates how to register new account in blockchain system using keys generated before.
import {
LocalStorage,
PrivateKey,
PrivateKeyType,
Api,
operations,
} from "@liquid-democracy/delegato-js";
(async () => {
// Be careful, this example cannot be compiled in NodeJS. Browser only.
const api = new Api(new LocalStorage());
const email = "email@example.com";
const password = "1234567890123";
const owner = PrivateKey.create(email, password, PrivateKeyType.owner);
const active = PrivateKey.create(email, password, PrivateKeyType.active);
const secret = "Dark Helmet";
try {
await api.connect();
console.log(
await (
await api.transaction([
new operations.AccountCreate({
firstName: "John",
lastName: "Doe",
birth: 2004,
idnp: 1234567890123,
email: "email@example.com",
locality: "1.20.1",
secretQuestion: "Who is your father’s brother’s nephew’s cousin’s former roommate?",
secretAnswer: sha256(
secret
.trim()
.toLocaleLowerCase()
.replace(/[^a-zа-я0-9]/, "")
),
owner: owner.publicKey,
active: active.publicKey,
}),
])
)
.sign([owner, active])
.broadcast()
);
api.disconnect();
}
catch (error) {
console.log(error);
}
})();
Some API methods need authorization, so you should be authenticated to perform them.
Now we can authenticate to your account (if you don't know how to create one, look Registration section) using email and password pair. You can use authenticate
method of Api class to log in your account created before.
Here is an example. You don't need to generate keys manualy. In this example the client automaticaly generates keys and stores them in MemoryStorage.
import {
MemoryStorage,
Api,
} from "@liquid-democracy/delegato-js";
(async () => {
const api = new Api(new MemoryStorage());
const email = "email@example.com";
const password = "1234567890123";
try {
await api.connect();
api.authenticate(email, password);
console.log(api.isAuthenticated);
api.disconnect();
}
catch (error) {
console.log(error);
}
})();
After account registration you can perform any other transaction using Api.transaction
method. The transaction
method returns Transaction object. Any transaction should be signed by corresponding private key(s) according operations which transaction contains. Use sign
method of Transaction class to sign the transaction and use operation documentation to determine which keys (active and/or owner) it requires. One transaction can contain multiple operations, but you should not sign one transaction with same key multiple times.
Signed transaction can be broadcasted to blockchain using broadcast
method of Transaction class. Also you can use Api.network.broadcastTransactionSynchronous
method to do this.
The following example shows how to vote in poll.
import {
Api,
PrivateKey,
PrivateKeyType,
operations,
} from "@liquid-democracy/delegato-js";
(async () => {
const api = new Api();
const email = "email@example.com";
const password = "1234567890123";
const active = PrivateKey.create(email, password, PrivateKeyType.active);
try {
await api.connect();
console.log(
await (
await api.transaction([
new operations.PollVote({
account: "1.2.7",
variant: "1.23.1",
}),
])
)
.sign([active])
.broadcast()
);
api.disconnect();
}
catch (error) {
console.log(error);
}
})();
Or if you have been authenticated before, use key from storage.
import {
Api,
PrivateKey,
PrivateKeyType,
operations,
} from "@liquid-democracy/delegato-js";
(async () => {
const api = new Api();
const email = "email@example.com";
const password = "1234567890123";
try {
await api.connect();
await api.authenticate(email, password);
console.log(
await (
await api.transaction([
new operations.PollVote({
account: "1.2.7",
variant: "1.23.1",
}),
])
)
.sign([api.storage.activePrivateKey])
.broadcast()
);
api.disconnect();
}
catch (error) {
console.log(error);
}
})();
While we need transactions to modify data in blockchain database, API methods are needed to get one. There are three types of API methods.
- Public API methods which don't need any authorization and can be performed by any user, even unauthenticated. That's why public methods don't contain any personal data.
- The second type is API methods which return data depending on user authentication. If user is authenticated API methods of this type can contain personal information. But these methods still can be used whithout authentication.
- The last one contains API methods which can be performed by authorized users only. Data returned by methods of this group contains personal information and differs for each authenticated user.
All API methods are separated to logical groups named "namespaces". There are 4 namespaces in delegato-js library.
Name | Name in blockchain | Description |
---|---|---|
login |
login |
Contains basic API methods to manage session. |
database |
database |
Contains information about chain, blocks and transactions. |
network |
network_broadcast |
This namespace contains information about blockchain network. Also blocks and transactions can be broadcasted by this API. |
poll |
poll |
This namespace serves all requests related to public polls and vote delegation in public polls. |
Any API method can be called using the following path: api.<namespace>.<method>
. For example getVoteDelegationAvailability
from poll
name space can be called using the following path: api.poll.getVoteDelegationAvailability
.
This example shows how to call getVoteDelegationAvailability
method. getVoteDelegationAvailability
method need user to be authorized.
import {
Api,
} from '@liquid-democracy/delegato-js';
(async () => {
const api = new Api();
const email = "email@example.com";
const password = "1234567890123";
try {
await api.connect();
await api.authenticate(email, password);
console.log(api.poll.getVoteDelegationAvailability(startDate, endDate, ['1.12.0']));
api.disconnect();
}
catch (error) {
console.log(error);
}
})();