thor_devkit_dart 1.0.0 copy "thor_devkit_dart: ^1.0.0" to clipboard
thor_devkit_dart: ^1.0.0 copied to clipboard

outdated

Dart package to assist smooth development on VeChain for developers and hobbyists.

VeChain Thor Devkit (SDK) in Dart #

Dart package to assist smooth development on VeChain for developers and hobbyists.

Content
Public key, private key, address conversion.
Mnemonic Wallets.
HD Wallet.
Keystore.
Various Hashing functions.
Signing messages.
Verify signature of messages.
Bloom filter.
Transaction Assembling (Multi-task Transaction, MTT).
Fee Delegation Transaction (VIP-191).
Self-signed Certificate (VIP-192).
ABI decoding of "functions" and "events" in logs.

... and will always be updated with the newest features on VeChain.

Usage #

Private/Public Keys #

import 'package:thor_devkit_dart/crypto/address.dart';
import 'package:thor_devkit_dart/crypto/secp256k1.dart';
import 'package:thor_devkit_dart/utils.dart';

//generate a new private key
BigInt priv = generatePrivateKey();
//derive public key from given private key
Uint8List pub = derivePublicKey(priv, false); // byte[65].
//derive address from given public key
Uint8List addr = Address.publicKeyToAddressBytes(pub);
//turn address into a hex string and prepend 0x to get a valid address String
String address = "0x" + bytesToHex(addr);
print(address);
// address should look like this: 0x63ad8a6d015ae579ad128e0c63040bb860cc5d34

String checksumAddress = Address.toChecksumAddress(address);
print(checksumAddress);
// checksumAddress should look like this: 0x63ad8A6D015aE579ad128e0c63040bB860Cc5D34

Sign & Verify Signatures #

import 'package:thor_devkit_dart/crypto/keccak.dart';
import 'package:thor_devkit_dart/crypto/secp256k1.dart';
import 'package:thor_devkit_dart/crypto/thor_signature.dart';
import 'package:thor_devkit_dart/utils.dart';
Uint8List priv = hexToBytes(
    "7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a"
); // byte[32].

Uint8List msgHash = keccak256(
    [asciiToBytes("hello world")]
); // byte[32].

// Sign the message hash.
ThorSignature sig = sign(msgHash, priv);

//you can turn a ThorSignature object into bytes
Uint8List sigBytes = sig.serialize();
print(bytesToHex(sigBytes));
//f8fe82c74f9e1f5bf443f8a7f8eb968140f554968fdcab0a6ffe904e451c8b9244be44bccb1feb34dd20d9d8943f8c131227e55861736907b02d32c06b934d7200

// Recover public key from given message hash and signature.
Uint8List pub = recover( msgHash, sig); // byte[65].


// Verify if the public key matches.
expect(pub, derivePublicKey(bytesToInt(priv), false));// true.

Mnemonic Wallet #

import 'package:thor_devkit_dart/crypto/mnemonic.dart';

    List<String> words = Mnemonic.generate(entropyLength: 128);
    print(words);
// [carry, slow, attack, december, number, film, scale, faith, can, old, cage, expose]

    bool flag = Mnemonic.validate(words);
    print(flag); // true.

// Quickly get a Bip32 master seed for HD wallets.
// How to use the seed? See "HD wallet" below.
    Uint8List seed = Mnemonic.deriveSeed(words);

// Quickly get a private key at index 0.
// Need to generate more? See "HD wallet" below.
    Uint8List priv = Mnemonic.derivePrivateKey(words);

HD Wallet #

Hierarchical Deterministic Wallets. See bip-32 and bip-44.

import 'package:thor_devkit_dart/crypto/address.dart';
import 'package:thor_devkit_dart/crypto/hd_node.dart';
import 'package:thor_devkit_dart/utils.dart';

    List<String> words = [
      "ignore",
      "empty",
      "bird",
      "silly",
      "journey",
      "junior",
      "ripple",
      "have",
      "guard",
      "waste",
      "between",
      "tenant"
    ];

// Construct an HD node from words. (Recommended)
    HDNode topMostNode = HDNode.fromMnemonic(words);

// Or, construct from seed. (Advanced)
    String seed_hex =
        "28bc19620b4fbb1f8892b9607f6e406fcd8226a0d6dc167ff677d122a1a64ef936101a644e6b447fd495677f68215d8522c893100d9010668614a68b3c7bb49f";

    HDNode topMostNode2 = HDNode.fromSeed(hexToBytes(seed_hex));

// Access the HD node's properties.
    Uint8List priv = topMostNode.privateKey!; //private key can be null
    Uint8List pub = topMostNode.publicKey;
    Uint8List cc = topMostNode.chainCode;

// Or, construct from a private key. (Advanced)
    HDNode topMostNode3 = HDNode.fromPrivateKey(priv, cc);

// Or, construct from a public key. (Advanced)
// Notice: This HD node CANNOT derive child HD node contains "private key".
    HDNode topMostNode4 = HDNode.fromPublicKey(pub, cc);

// Let it derive further child HD nodes.
    for (int i = 0; i < 3; i++) {
      HDNode child = topMostNode.derive(i);
      print("addr: " + Address.publicKeyToAddressString(child.publicKey));
      print("priv: " + bytesToHex(child.privateKey!));
    }
// addr: 0x339fb3c438606519e2c75bbf531fb43a0f449a70
// priv: 27196338e7d0b5e7bf1be1c0327c53a244a18ef0b102976980e341500f492425
// addr: 0x5677099d06bc72f9da1113afa5e022feec424c8e
// priv: cf44074ec3bf912d2a46b7c84fa6eb745652c9c74e674c3760dc7af07fc98b62
// addr: 0x86231b5cdcbfe751b9ddcd4bd981fc0a48afe921
// priv: 2ca054a50b53299ea3949f5362ee1d1cfe6252fbe30bea3651774790983e9348

Keystore #

import 'package:thor_devkit_dart/crypto/keystore.dart';

    String ks = """
{
    "version": 3,
    "id": "f437ebb1-5b0d-4780-ae9e-8640178ffd77",
    "address": "dc6fa3ec1f3fde763f4d59230ed303f854968d26",
    "crypto":
    {
        "kdf": "scrypt",
        "kdfparams": {
            "dklen": 32,
            "salt": "b57682e5468934be81217ad5b14ca74dab2b42c2476864592c9f3b370c09460a",
            "n": 262144,
            "r": 8,
            "p": 1
        },
        "cipher": "aes-128-ctr",
        "ciphertext": "88cb876f9c0355a89cad88ee7a17a2179700bc4306eaf78fa67320efbb4c7e31",
        "cipherparams": {
            "iv": "de5c0c09c882b3f679876b22b6c5af21"
        },
        "mac": "8426e8a1e151b28f694849cb31f64cbc9ae3e278d02716cf5b61d7ddd3f6e728"
    }
}
""";

// Must be UTF_8 string.
    String password = "123456";
// Decrypt from keystore to a private key.
    Uint8List priv = Keystore.decrypt(ks, password);
// Encrypt from a private key to a keystore.
    String ks2 = Keystore.encrypt(priv, password);
    print(ks2);

Hash #

import 'package:thor_devkit_dart/utils.dart';
import 'package:thor_devkit_dart/crypto/keccak.dart';

    String input = "hello world";
    List<String> inputs = ["hello", " ", "world"];

    Uint8List output1 = keccak256([asciiToBytes(input)]);
    Uint8List output2 = keccak256([
      asciiToBytes(inputs[0]),
      asciiToBytes(inputs[1]),
      asciiToBytes(inputs[2])
    ]); // output1 == outpu2
    print(bytesToHex(output1));
    print(bytesToHex(output2));
    //47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad

    Uint8List output3 = blake2b256([asciiToBytes(input)]);
    Uint8List output4 = blake2b256([
      asciiToBytes(inputs[0]),
      asciiToBytes(inputs[1]),
      asciiToBytes(inputs[2])
    ]); // output3 == outpu4
    print(bytesToHex(output3));
    print(bytesToHex(output4));
    //256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610
  });

Bloom Filter #

import 'package:thor_devkit_dart/function.dart';
import 'package:thor_devkit_dart/utils.dart';
import 'package:thor_devkit_dart/bloom.dart';

// Create a bloom filter that stores 100 items.
    int k = Bloom.estimateK(100);
    Bloom b = Bloom(k);

// Add to it.
    b.add(Uint8List.fromList(utf8.encode("hello world")));

// Test if exists.
    bool contain =
        b.mightContain(Uint8List.fromList(utf8.encode("hello world"))); // true.
    bool contain2 = b.mightContain(
        Uint8List.fromList(utf8.encode("bye bye blue bird"))); // false.
    print(contain);
    print(contain2);

ABI: Enode Function Calls. #


    String f1 = """
{
    "constant": false,
    "inputs": [
        {
            "name": "a1",
            "type": "uint256"
        },
        {
            "name": "a2",
            "type": "string"
        }
    ],
    "name": "f1",
    "outputs": [
        {
            "name": "r1",
            "type": "address"
        },
        {
            "name": "r2",
            "type": "bytes"
        }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
}
"""; // Function definition.

    ThorFunction f = ThorFunction(f1);

// Calculate the selector of the function.
    expect(bytesToHex(f.selector()), "27fcbb2f");

// Encode a function call with params (1, "foo").
    expect(
        f.encode([BigInt.from(1), "foo"]),
        hexToBytes(
            '0x27fcbb2f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000'));
  });

ABI: Decode Function Return #


String f1 = """
{
    "constant": false,
    "inputs": [
        {
            "name": "a1",
            "type": "uint256"
        },
        {
            "name": "a2",
            "type": "string"
        }
    ],
    "name": "f1",
    "outputs": [
        {
            "name": "r1",
            "type": "address"
        },
        {
            "name": "r2",
            "type": "bytes"
        }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
}
"""; // Function definition.

ThorFunction f = ThorFunction(f1);

// The function call return value.
String data = "000000000000000000000000abc000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000";



// f.decodeReturnV1() returns  V1ParamWrapper objects
List<V1ParamWrapper> result = f.decodeReturnV1(data);
result[0].name;  // "r1"
result[0].canonicalType; //"address"
result[0].value; // "0xabc0000000000000000000000000000000000001"
result[1].name;  // "r2"
result[1].canonicalType; // "bytes"
result[1].value; // "0x666f6f"

Transaction #

// Transaction Structure:
// See: https://docs.vechain.org/thor/learn/transaction-model.html#model
import 'package:thor_devkit_dart/crypto/blake2b.dart';
import 'package:thor_devkit_dart/crypto/secp256k1.dart';
import 'package:thor_devkit_dart/crypto/thor_signature.dart';
import 'package:thor_devkit_dart/transaction.dart';
import 'package:thor_devkit_dart/types/clause.dart';
import 'package:thor_devkit_dart/utils.dart';

// Set up clauses.
    List<Clause> clauses = [
      Clause(
          "0x7567d83b7b8d80addcb281a71d54fc7b3364ffed", // to
          "10000", // value
          "0x000000606060" // data
          ),
      Clause("0x7567d83b7b8d80addcb281a71d54fc7b3364ffed", "20000",
          "0x000000606060")
    ];

// Create a tx.
    Transaction tx = Transaction(
        39, // chainTag
        "0x00000000aabbccdd", // blockRef
        "32", // expiration
        clauses, // clauses
        "128", // gasPriceCoef
        "21000", // gas
        null, // dependsOn
        "12345678", // nonce
        null // reserved
        );

// Sign the tx.
    Uint8List privateKey = hexToBytes(
        "7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a");
    Uint8List h = blake2b256([tx.encode()] // unsigned tx encoded.
        );
    ThorSignature sig = sign(h, privateKey);

// Set signature on tx.
    tx.signature = sig.serialize();

// Properties.
    tx.getId();
    tx.signature;
    tx.getIntrinsicGas(); // 37432
    tx.getOriginAsAddressBytes();
    tx.getOriginAsAddressString();

// Signed tx encoded.
    Uint8List encodedTx = tx.encode();
// Then you can HTTP POST to send the encodedTx to VeChain...
// See the REST API details:
// testnet: https://sync-testnet.vechain.org/doc/swagger-ui/
// mainnet: https://sync-mainnet.vechain.org/doc/swagger-ui/

Sign & Verify Certificate (VIP-192) #

https://github.com/vechain/VIPs/blob/master/vips/VIP-192.md

import 'package:thor_devkit_dart/crypto/blake2b.dart';
import 'package:thor_devkit_dart/crypto/secp256k1.dart';
import 'package:thor_devkit_dart/utils.dart';
import 'package:thor_devkit_dart/certificate.dart';
import 'package:thor_devkit_dart/crypto/address.dart';

/* For a Certificate looks like this:
{
  "purpose": "identification",
  "payload": {
    "type": "text",
    "content": "fyi"
  },
  "domain": "localhost",
  "timestamp": 1545035330,
  "signer": "0xd989829d88b0ed1b06edf5c50174ecfa64f14a64"
}
*/

Uint8List priv = hexToBytes("7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a");
Uint8List addr = Address.publicKeyToAddressBytes(derivePublicKey(bytesToInt(priv), false));

// Create a Certificate.
Map<String, String> payload = {
    "type": "text",
    "content": "fyi"
  };

Certificate c = Certificate(
    "identification",               // purpose
    payload,                        // payload
    "localhost",                    // domian
    1545035330,                     // timestamp
    "0x" + bytesToHex(addr),        // signer
    signature: null                 //optional parameter signature, default null
);

// Or create from some external json string.
// Certificate c2 = Certificate.fromJsonString(...);

// Or create from some external Map<String, Object>.
// Certificate c3 = Certificate.fromMap(...);

// Sign the cert.
// 1) Calculate signature.
String j = c.toJsonString();
Uint8List signingHash = blake2b256([Uint8List.fromList(utf8.encode(j))]);
Uint8List sig = sign(signingHash, priv).serialize();
// 2) Set signature on cert.
c.signature = "0x" + bytesToHex(sig);
// 3) Verify. If signature matches this cert.
c.verify();



Knowledge #

Name Bytes Description
private key 32 random number
public key 65 uncompressed, starts with "04"
address 20 derived from public key
keccak256 32 hash
blake2b256 32 hash
message hash 32 hash of a message
signature 65 signing result, last bit as recovery parameter
seed 64 used to derive bip32 master key
12
likes
0
points
120
downloads

Publisher

verified publishersaynode.ch

Weekly Downloads

Dart package to assist smooth development on VeChain for developers and hobbyists.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

base_x, bip32, bip39, convert, flutter, pointycastle, r_crypto, rlp, web3dart

More

Packages that depend on thor_devkit_dart