Skip to main content


A Dart library that supports the Topl blockchain.


A dart library that connects via gRPC to interact with the Thunder protocol. It connects to a Bifrost node to send transactions, interact with addresses and much more!


  • Connect to an Thunder node with the rpc-api, call common methods
  • Send signed transactions
  • Generate private keys, setup new blockchain addresses


Running the code generator

Run dart run build_runner build in the package directory to generate the missing .g.dartgenerated dart files

Credentials and Wallets

In order to send transactions on the Thunder network, some credentials are required. The library supports raw private keys and v1 encrypted key-files. In addition, it also supports the generation of keys via a HD wallet.

import 'package:brambldart/brambldart.dart';

// You can create credentials from private keys
Credentials credentials = ToplSigningKey.fromString("base58EncodedPrivateKeyHere");

// Or generate a new key randomly
var networkId = 0x40;
var propositionType = PropositionType.ed25519();
Credentials random = ToplSigningKey.createRandom(networkId, propositionType);

// In either way, the library can derive the public key and the address
// from a private key:

var address = await credentials.extractAddress();

Another way to obtain Credentials which the library uses to sign transactions is the usage of an encrypted keyfile. Wallets store a private key securely and require a password to unlock. The library has experimental support for version 1 keyfiles which are generated by this client and support Extended ED25519 Signing Keys:

import 'dart:io';
import 'package:brambldart/brambldart.dart';

String content = new File("wallet.json").readAsStringSync();
KeyStore keystore = KeyStore.fromV1Json(content, "testPassword");

Credentials unlocked = ToplSigningKey.fromString(keystore.privateKey);
// You can now use these credentials to sign transactions

You can also create Keystore files with this library. To do so, you first need the private key you want to encrypt and a desired password. Then, create your wallet with

Keystore keystore = KeyStore.createNew(credentials, 'password', random);

You can also write keystore.toJson() to file which you can later open with BramblSC and potentially other Topl API libraries in the future.

Custom credentials

If you want to integrate brambldart with other wallet providers, you can implement Credentials and override the appropriate methods.

Connecting to an RPC server

The library won't send signed transactions to forgers itself. Instead, it relies on an RPC client to do that. You can use a public RPC API like baas, or, if you just want to test things out, use a private testnet with bifrost. All of these options will give you an RPC endpoint to which the library can connect.

import 'package:dio/dio.dart'; //You can also import the browser version
import 'package:brambldart/brambldart.dart';

var networkId = 0x40;
var propositionType = PropositionType.ed25519();
var privateKey = 'base58EncodedPrivateKey';

var apiUrl = "http://localhost:9085"; //Replace with your API
var httpClient = Dio(BaseOptions(
baseUrl: basePathOverride ?? basePath,
contentType: 'application/json',
connectTimeout: 5000,
receiveTimeout: 3000)
var bramblClient = BramblClient(httpClient: httpClient, basePathOverride: apiUrl);
var credentials = bramblClient.credentialsFromPrivateKey(privateKey, networkId, propositionType);

// You can now call rpc methods. This one will query the amount of Topl tokens you own
Balance balance = bramblClient.getBalance(credentials.address);

Sending transactions

Of course, this library supports creating, signing and sending Topl transactions:

import 'package:brambldart/brambldart.dart';

/// [...], you need to specify the url and your client, see example above
var bramblClient = BramblClient(basePathOverride: apiUrl, httpClient: httpClient);

var credentials = bramblClient.credentialsFromPrivateKey("0x...");

const value = 1;

final assetCode =
AssetCode.initialize(1, senderAddress, 'testy', 'valhalla');

final securityRoot = SecurityRoot.fromBase58(

final assetValue = AssetValue(
value.toString(), assetCode, securityRoot, 'metadata', 'Asset');

final recipient = AssetRecipient(senderAddress, assetValue);

final data = Latin1Data.validated('data');

final assetTransaction = AssetTransaction(
recipients: [recipient],
sender: [senderAddress],
changeAddress: senderAddress,
consolidationAddress: senderAddress,
propositionType: PropositionType.ed25519().propositionName,
minting: true,
assetCode: assetCode,
data: data);

final rawTransaction =
await client.sendRawAssetTransfer(assetTransaction: assetTransaction);

expect(rawTransaction['rawTx'], isA<TransactionReceipt>());


final txId = await client.sendTransaction(
rawTransaction['rawTx'] as TransactionReceipt,
rawTransaction['messageToSign'] as Uint8List);

Missing data, like the fee, the sender or a change/consolidation address will be inferred by the BramblClient when not explicitly specified. If you only need the signed transaction but don't intend to send it, you can use client.signTransaction.

Feature requests and bugs

Please file feature requests and bugs at the issue tracker. If you want to contribute to this library, please submit a Pull Request.


View the documentation at


Open a PR here!

Additional Examples

View an example here!