@sentinel-official/sentinel-js-sdk
v2.1.0
Published
sentinel javascript sdk
Readme
sentinel-js-sdk
The Sentinel JS SDK relays on CosmJS and it was developed following the official tutorial, it take also inspiration from other open source Cosmos SDK.
The SDK exstends the followings:
- @cosmjs/stargate/StargateClient as
SentinelClient - @cosmjs/stargate/SigningStargateClient
SigningSentinelClient - @cosmjs/stargate/QueryClient as
client.sentinelQuery
Full documentation: https://sentinel-official.github.io/sentinel-js-sdk/
VPN protocols
The SDK supports every service type advertised by sentinel-dvpnx v9:
| Protocol | SDK class | Client mode | Runtime executable |
| --- | --- | --- | --- |
| WireGuard | Wireguard | Full tunnel | wg-quick |
| V2Ray | V2Ray | Local SOCKS5 proxy | v2ray |
| OpenVPN | OpenVPN | Full tunnel | openvpn |
| Xray | Xray | Local SOCKS5 proxy | xray |
| AmneziaWG | AmneziaWG | Full tunnel | awg-quick |
| Hysteria2 | Hysteria2 | Full tunnel | hysteria2 |
The SDK creates protocol credentials, parses the authenticated node handshake,
writes private configuration files (0600 on Unix), and starts/stops the
corresponding client. Native executables are not bundled in the npm package.
Full-tunnel clients require root/administrator network privileges.
The connection flow is the same for all protocols:
- Query an active node and inspect
nodeInfo(remoteAddr).service_type. - Start an on-chain session and obtain its session ID from
NodeEventCreateSession. - Create the matching client class and send its peer request through
handshake. - Base64-decode and parse
result.data, then callparseConfig. - Call
connect; later calldisconnectandcleanup.
import {
AmneziaWG,
Hysteria2,
NodeVPNType,
OpenVPN,
V2Ray,
Wireguard,
Xray,
handshake,
} from "@sentinel-official/sentinel-js-sdk";
const clients = {
[NodeVPNType.WIREGUARD]: () => new Wireguard(),
[NodeVPNType.V2RAY]: () => new V2Ray(),
[NodeVPNType.OPENVPN]: () => new OpenVPN(),
[NodeVPNType.XRAY]: () => new Xray(),
[NodeVPNType.AMNEZIAWG]: () => new AmneziaWG(),
[NodeVPNType.HYSTERIA2]: () => new Hysteria2(),
};
const serviceType = nodeStatus.service_type;
const vpn = clients[serviceType]();
const result = await handshake(
sessionId,
vpn.getPeerRequest(),
cosmosPrivateKey,
node.remoteAddrs[0],
);
const data = JSON.parse(Buffer.from(result.data, "base64").toString("utf8"));
await vpn.parseConfig(data, result.addrs);
await vpn.connect();V2Ray and Xray expose the selected local proxy port as vpn.socksPort.
Their traffic must be routed through socks5://127.0.0.1:<socksPort>; they do
not alter the system default route.
clients
import { SentinelClient } from "@sentinel-official/sentinel-js-sdk";
const rpc = "https://rpc.sentinel.co:443"
const client = await SentinelClient.connect(rpc)If you need to sign and broadcast a tx you need to instantiate a SigningClient.
import { SigningSentinelClient } from "@sentinel-official/sentinel-js-sdk";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"
import { GasPrice } from "@cosmjs/stargate"
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "sent" });
const [account] = await wallet.getAccounts();
const rpc = "https://rpc.sentinel.co:443"
// With a default GasPrice:
const customDenom = "udvpn"
const gasPrice = GasPrice.fromString(`0.2${customDenom}`);
const client = await SigningSentinelClient.connectWithSigner(rpc, wallet, {
gasPrice: gasPrice
})
// Without a default GasPrice:
const client = await SigningSentinelClient.connectWithSigner(rpc, wallet)You can also set other default parameters: https://cosmos.github.io/cosmjs/latest/stargate/interfaces/SigningStargateClientOptions.html.
In order to subscribe to chain events you need a websocket client
import { SentinelWsClient } from "@sentinel-official/sentinel-js-sdk";
const client = new SentinelWsClient("wss://rpc.sentinel.quokkastake.io");
const stream = client.subscribe("tm.event='NewBlock'")
stream.addListener({
next: data => console.log(data),
error: err => console.error(err),
complete: () => console.log('completed'),
});query
import { Status, PageRequest } from "@sentinel-official/sentinel-js-sdk";
const nodes = await client.sentinelQuery?.node.nodes(
Status.STATUS_ACTIVE,
PageRequest.fromPartial({
limit: 5,
countTotal: true
})
)For pagination please follow:
- https://docs.cosmos.network/v0.45/core/proto-docs.html#cosmos-base-query-v1beta1-pagination-proto
- https://github.com/cosmos/cosmos-sdk/blob/main/types/query/pagination.pb.go#L32-L53
- https://github.com/confio/cosmjs-types/blob/main/src/cosmos/base/query/v1beta1/pagination.ts
transaction
After you have initialize a SigningClient you can prepare and broadcast a tx in multiple ways.
- Create a MsgEcodeObject and call
signAndBroadcastfrom your client.
import { TxNodeStartSession, nodeStartSession } from "@sentinel-official/sentinel-js-sdk";
import Long from "long";
const udvpn = p2pNode.node.gigabytePrices.filter(x => x.denom === "udvpn")[0] as Price
const args: TxNodeStartSession = {
from: account.address,
nodeAddress: p2pNode.node.address,
gigabytes: Long.fromString(gygabytes, true),
maxPrice: udvpn
}
const msg = nodeStartSession(args)
const tx = client.signAndBroadcast(account.address, [msg], "auto", "memo")- Call directly
nodeStartSessionfrom your client or from submodule (this will automatically signAndBroadcast the tx)
import { TxNodeStartSession } from "@sentinel-official/sentinel-js-sdk";
import Long from "long";
const args: TxNodeStartSession = {
from: account.address,
nodeAddress: sentnode,
gigabytes: Long.fromNumber(gygabyte, true),
fee: "auto",
memo: "hello from js-sdk"
maxPrice: ....
}
// call directly
const tx1 = client.nodeStartSession(args)
// use submodule
const tx2 = client.node.startSession(args)It is up to you if you want to await the tx or use a callback
const tx1 = await client.nodeStartSession(args)
client.nodeStartSession(args).then(tx => { do stuff... })events parsing
client.signAndBroadcast or implicit call trought, for example, client.nodeStartSession or client.node.subscribe return a DeliverTxResponse. You can search for a determinate event using the method searchEvent. For example if you are looking for sentinel.node.v3.EventCreateSession, you can do the following:
import { searchEvent } from "@sentinel-official/sentinel-js-sdk";
const eventCreateSubscription = searchEvent(sentinel.node.v3.EventCreateSession, tx.events);or better
import { searchEvent } from "@sentinel-official/sentinel-js-sdk";
import { NodeEventCreateSession } from "@sentinel-official/sentinel-js-sdk";
const eventCreateSubscription = searchEvent(NodeEventCreateSession.type, tx.events);The single event can also be parsed via the appropriate interface, following the example:
import { searchEvent } from "@sentinel-official/sentinel-js-sdk";
import { NodeEventCreateSession, isNodeEventCreateSession } from "@sentinel-official/sentinel-js-sdk";
const eventCreateSubscription = searchEvent(NodeEventCreateSession.type, tx.events);
if(eventCreateSubscription && isNodeEventCreateSession(eventCreateSubscription)) {
const eventParsed = NodeEventCreateSession.parse(eventCreateSubscription)
console.log(`Your subscription id is: ${eventParsed.value.sessionId}`)
} else console.log("eventCreateSubscription, not found")protobuf
All the .proto files are compiled using protoc and ts-proto as plugin. The compiled .ts proto files are under src/protobuf. If you want to compile again you can use scripts/generate-proto.sh. The script requires git and protoc, it will automatically download all the .proto definitions from sentinel-hub and relative third parties.
examples
The official cosmjs examples can be used as well.
Just remember to replace StargateClient with SentinelClient and SigningStargateClient with SigningSentinelClient.
The repository provide currently a nodejs script example and a keplr one (based on: https://tutorials.cosmos.network/tutorials/7-cosmjs/4-with-keplr.html).
The opt-in mainnet VPN smoke test discovers nodes dynamically and verifies session creation, handshake, configuration, connectivity, cleanup, and cancellation. It is not run in CI: it spends wallet funds and some protocols require root network privileges.
If you want to use a local version of sdk (for testing purpose) you have to compile the src folder into dist and then link the package with npm.
npm run build
npm link
cd examples/<choose-an-example>
npm link @sentinel-official/sentinel-js-sdkrun keplr example
cd examples/keplr
npm i
npm run devNavigate to: http://127.0.0.1:3000/.
run nodejs example
cd examples/node
npm i
ts-node main.ts