A JavaScript client to the drand randomness beacon network.
In the browser or Deno you can grab and use the client from a CDN e.g. https://cdn.jsdelivr.net/npm/drand-client/index.js.
In Node.js or when using a bundler, install with:
npm install drand-client
Typescript types are included and don't need installed separately.
The drand-client
contains HTTP implementations, but other transports can be supported by implementing the DrandNode
, Chain
and ChainClient
interfaces where appropriate.
<script type='module'>
import {
fetchBeacon,
fetchBeaconByTime,
HttpChainClient,
watch,
HttpCachingChain,
FastestNodeClient,
MultiBeaconNode
} from 'https://cdn.jsdelivr.net/npm/drand-client'
const chainHash = '8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce' // (hex encoded)
const publicKey = '868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31' // (hex encoded)
async function main () {
const options = {
disableBeaconVerification: false, // `true` disables checking of signatures on beacons - faster but insecure!!!
noCache: false, // `true` disables caching when retrieving beacons for some providers
chainVerificationParams: { chainHash, publicKey } // these are optional, but recommended! They are compared for parity against the `/info` output of a given node
}
// if you want to connect to a single chain to grab the latest beacon you can simply do the following
// note: if you want to access e.g. quicknet you must use 'https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971'
// passing the chainHash in the `chainVerificationParams` will not fill in the path for you (unless using `MultiBeaconNode`)
const chain = new HttpCachingChain('https://api.drand.sh', options)
const client = new HttpChainClient(chain, options)
const theLatestBeacon = await fetchBeacon(client)
// alternatively you can also get the beacon for a given time
const theBeaconRightNow = await fetchBeaconByTime(client, Date.now())
// if you're happy to get randomness from many APIs and automatically use the fastest
// you can construct a `FastestNodeClient` with multiple URLs
// note: the randomness beacons are cryptographically verifiable, so as long as you fill
// in the `chainVerificationParams` in the options, you don't need to worry about malicious
// providers sending you fake randomness!
const urls = [
'https://api.drand.sh',
'https://drand.cloudflare.com'
// ...
]
const fastestNodeClient = new FastestNodeClient(urls, options)
// don't forget to start the client, or it won't periodically optimise for the fastest node!
fastestNodeClient.start()
const theLatestBeaconFromTheFastestClient = await fetchBeacon(fastestNodeClient)
// don't forget to stop the speed testing, or you may leak a `setInterval` call!
fastestNodeClient.stop()
// you can also use the `watch` async generator to watch the latest randomness automatically!
// use an abort controller to stop it
const abortController = new AbortController()
for await (const beacon of watch(client, abortController)) {
if (beacon.round === 10) {
abortController.abort('round 10 reached - listening stopped')
}
}
// finally you can interact with multibeacon nodes by using the `MultiBeaconNode` class
// prior to drand 1.4, each node could only follow and contribute to a single beacon chain
// - now nodes can contribute to many at once
// here you only need the base URL, and the chain hashes for each respective beacon chain
// will be filled in
const multiBeaconNode = new MultiBeaconNode('https://api.drand.sh', options)
// you can monitor its health
const health = await multiBeaconNode.health()
if (health.status === 200) {
console.log(`Multibeacon node is healthy and has processed ${health.current} of ${health.expected} rounds`)
}
// get the chains it follows
const chains = await multiBeaconNode.chains()
for (const c of chains) {
const info = await c.info()
console.log(`Chain with baseUrl ${c.baseUrl} has a genesis time of ${info.genesis_time}`)
}
// and even create clients straight from the chains it returns
const latestBeaconsFromAllChains = Promise.all(
chains.map(chain => new HttpChainClient(chain, options))
.map(client => fetchBeacon(client))
)
}
main()
</script>
Usage in Deno is the same as the browser, minus the HTML <script>
tag. Ensure you run your script with
the --allow-net
flag e.g. deno run --allow-net client.js
.
If you'd like to run it in Node.js, add a fetch polyfill such as node-fetch
and AbortController
as globals e.g.
import fetch from 'node-fetch'
import AbortController from 'abort-controller'
global.fetch = fetch
global.AbortController = AbortController
// Use as per browser example...
From common.js:
const fetch = require('node-fetch')
const AbortController = require('abort-controller')
global.fetch = fetch
global.AbortController = AbortController
// Use as per browser example...
This repo automatically publishes to npmjs.com as drand-client if changes hit the master branch with an updated version number.
Feel free to dive in! Open an issue or submit PRs.
This project is dual-licensed under Apache 2.0 and MIT terms:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
- relays exposing only the default endpoints and not the chain-hash-based ones are not supported
- this supports only 1.4 drand nodes+