diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e8c013f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "restructuredtext.confPath": "/home/michiel/projects/bigchaindb-driver/js-bigchaindb-driver" +} \ No newline at end of file diff --git a/examples/.babelrc b/examples/.babelrc new file mode 100644 index 0000000..d2903f1 --- /dev/null +++ b/examples/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015", "stage-3"], + "plugins": ["syntax-async-functions", "transform-runtime", "transform-regenerator", "transform-async-to-generator"] +} \ No newline at end of file diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..efa3767 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,26 @@ +# Quick Notes +`dotenv` is listed as a dependencies in `package.json`. +If you want to use this, add a `.env` file to the root of this project (same level as this `README.md` file) +and replace the variables to fit your specific config. + +``` +BIGCHAINDB_API_PATH=http://localhost:9984/api/v1/ +BIGCHAINDB_APP_ID= +BIGCHAINDB_APP_KEY= +``` + +# Usage +`npm install` -> Installs all required dependencies to run these examples. + +## Different Examples +**Basic Usage**: Create asset and transfer it to new owner. +-> `npm start` + +**Async/Await Basic Usage**: Basic usage example rewritten with async/await. +-> `npm run basic-async` + +**Querying for Assets**: Query for assetdata or metadata. +-> `npm run query-assets` + +**Seed/Keypair Functionality**: Create keypair with bip39 library. +-> `npm run seed-func` diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..5a31f94 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,36 @@ +{ + "name": "js-driver-bigchaindb-examples", + "version": "1.0.0", + "main": "src/basic-usage.js", + "scripts": { + "build": "npm run clean && babel src -d dist", + "serve": "node dist/basic-usage.js", + "clean": "rimraf ./dist", + "start": "nodemon src/basic-usage.js --exec babel-node", + "query-assets": "nodemon src/query-assets.js --exec babel-node", + "seed-func": "nodemon src/seed-func.js --exec babel-node", + "basic-async": "nodemon src/basic-usage-async-await.js --exec babel-node" + }, + "author": "BigchainDB", + "license": "MIT", + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-core": "^6.13.2", + "babel-loader": "^6.2.4", + "babel-plugin-syntax-async-functions": "^6.13.0", + "babel-plugin-transform-async-to-generator": "^6.8.0", + "babel-plugin-transform-regenerator": "^6.11.4", + "babel-plugin-transform-runtime": "^6.12.0", + "babel-preset-es2015": "^6.13.2", + "babel-preset-stage-3": "^6.11.0", + "nodemon": "^1.14.8", + "rimraf": "^2.6.2" + }, + "repository": "/", + "private": true, + "dependencies": { + "bigchaindb-driver": "^3.2.0", + "bip39": "^2.5.0", + "dotenv": "^4.0.0" + } +} diff --git a/examples/src/basic-usage-async-await.js b/examples/src/basic-usage-async-await.js new file mode 100644 index 0000000..3d8e640 --- /dev/null +++ b/examples/src/basic-usage-async-await.js @@ -0,0 +1,62 @@ +const driver = require('bigchaindb-driver') // eslint-disable-line import/no-unresolved +require('dotenv').config() + + +// ======== Preparation ======== // +const conn = new driver.Connection('https://test.bigchaindb.com/api/v1/', { + app_id: process.env.BIGCHAINDB_APP_ID, + app_key: process.env.BIGCHAINDB_APP_KEY +}) + +const alice = new driver.Ed25519Keypair() +const bob = new driver.Ed25519Keypair() + +const assetdata = { + 'bicycle': { + 'serial_number': 'abcd1234', + 'manufacturer': 'Bicycle Inc.', + } +} + +const metadata = { 'planet': 'earth' } + + +// Call async basic usage function +basicUsage() + + +async function basicUsage() { + // ======== Create Transaction Bicycle ======== // + const txCreateAliceSimple = driver.Transaction.makeCreateTransaction( + assetdata, + metadata, + [ + driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) + ], + alice.publicKey + ) + + const txCreateAliceSimpleSigned = + driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey) + + + // ======== Post Transaction and Fetch Result ======== // + await conn.postTransaction(txCreateAliceSimpleSigned) + await conn.pollStatusAndFetchTransaction(txCreateAliceSimpleSigned.id) + + const txTransferBob = driver.Transaction.makeTransferTransaction( + [{ tx: txCreateAliceSimpleSigned, output_index: 0 }], + [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))], + { price: '100 euro' } + ) + + const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey) + + await conn.postTransaction(txTransferBobSigned) + await conn.pollStatusAndFetchTransaction(txTransferBobSigned.id) + + + // ======== Querying Assets ======== // + const assets = await conn.searchAssets('Bicycle Inc.') + console.log(assets) // eslint-disable-line no-console +} diff --git a/examples/src/basic-usage.js b/examples/src/basic-usage.js new file mode 100644 index 0000000..77cd25e --- /dev/null +++ b/examples/src/basic-usage.js @@ -0,0 +1,66 @@ +const driver = require('bigchaindb-driver') // eslint-disable-line import/no-unresolved +require('dotenv').config() + + +// ======== Preparation ======== // +const conn = new driver.Connection('https://test.bigchaindb.com/api/v1/', { + app_id: process.env.BIGCHAINDB_APP_ID, + app_key: process.env.BIGCHAINDB_APP_KEY +}) + +const alice = new driver.Ed25519Keypair() +const bob = new driver.Ed25519Keypair() + +const assetdata = { + 'bicycle': { + 'serial_number': 'abcd1234', + 'manufacturer': 'Bicycle Inc.', + } +} + +const metadata = { 'planet': 'earth' } + + +// ======== Create Transaction Bicycle ======== // +const txCreateAliceSimple = driver.Transaction.makeCreateTransaction( + assetdata, + metadata, + [ + driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) + ], + alice.publicKey +) + +const txCreateAliceSimpleSigned = + driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey) + + +// ======== Post Transaction and Fetch Result ======== // +conn.postTransaction(txCreateAliceSimpleSigned) + // Check status of transaction every 0.5 seconds until fulfilled + .then(() => conn.pollStatusAndFetchTransaction(txCreateAliceSimpleSigned.id)) + + +// ======== Transfer Bicycle to Bob ======== // + .then(() => { + const txTransferBob = driver.Transaction.makeTransferTransaction( + [{ tx: txCreateAliceSimpleSigned, output_index: 0 }], + [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))], + { price: '100 euro' } + ) + + // Sign transfer transaction with Alice's private key + const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey) + + return conn.postTransaction(txTransferBobSigned) + }) + .then(res => conn.pollStatusAndFetchTransaction(res.id)) + .then(tx => { + console.log('Is Bob the owner?', tx.outputs[0].public_keys[0] === bob.publicKey) // eslint-disable-line no-console + console.log('Was Alice the previous owner?', tx.inputs[0].owners_before[0] === alice.publicKey) // eslint-disable-line no-console + }) + + +// ======== Search Asset by Serial Number ======== // + .then(() => conn.searchAssets('Bicycle Inc.')) + .then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets)) // eslint-disable-line no-console diff --git a/examples/src/query-assets.js b/examples/src/query-assets.js new file mode 100644 index 0000000..cad31dd --- /dev/null +++ b/examples/src/query-assets.js @@ -0,0 +1,51 @@ +const driver = require('bigchaindb-driver') // eslint-disable-line import/no-unresolved +require('dotenv').config() + + +// ======== Preparation ======== // +const conn = new driver.Connection('https://test.bigchaindb.com/api/v1/', { + app_id: process.env.BIGCHAINDB_APP_ID, + app_key: process.env.BIGCHAINDB_APP_KEY +}) + +const alice = new driver.Ed25519Keypair() + + +// ======== Asset Array ======== // +const assetArray = [] +assetArray.push({ 'bicycle': { 'serial_number': 'abc', 'manufacturer': 'BicyclesInc' } }) +assetArray.push({ 'bicycle': { 'serial_number': 'cde', 'manufacturer': 'BicyclesInc' } }) +assetArray.push({ 'bicycle': { 'serial_number': 'fgh', 'manufacturer': 'BicyclesInc' } }) + +const metadata = { 'planet': 'Pluto' } + + +// ======== Create Transactions for bicycles ======== // +function createTx(assetdata) { + const txCreate = driver.Transaction.makeCreateTransaction( + assetdata, + metadata, + [ + driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) + ], + alice.publicKey + ) + + const txCreateSigned = driver.Transaction.signTransaction(txCreate, alice.privateKey) + return conn.postTransaction(txCreateSigned) + .then(() => conn.pollStatusAndFetchTransaction(txCreateSigned.id)) +} + + +// ======== Execute all promises in order to post transactions and fetch them ======== // +Promise.all(assetArray.map(createTx)) + + +// ======== Querying Assets for Assetdata ======== // + .then(() => conn.searchAssets('BicyclesInc')) + .then(assets => console.log('Found assets with serial number "BicyclesInc":', assets)) // eslint-disable-line no-console + + +// ======== Querying Assets for Metadata ======== // + .then(() => conn.searchMetadata('Pluto')) + .then(assets => console.log('Found assets with metadata "Pluto":', assets)) // eslint-disable-line no-console diff --git a/examples/src/seed-func.js b/examples/src/seed-func.js new file mode 100644 index 0000000..7d85cd5 --- /dev/null +++ b/examples/src/seed-func.js @@ -0,0 +1,34 @@ +import bip39 from 'bip39' // eslint-disable-line import/no-unresolved + +const driver = require('bigchaindb-driver') // eslint-disable-line import/no-unresolved + +// ======== Create Keypair ======== // +/** + * Use a passphrase to derive a keypair + * If you use the same seed -> you will derive the same keypair + * + * mnemnoicToSeed() transforms the passphrase you gave as an input + * to a byteArray + * + * BigchainDB however only accepts an input length of 32 characters + * so we have to slice this to give it as input for driver.Ed25519Keypair() + * + * Is it safe to slice? Yes, a seed of length 32 is very safe according + * to related papers discussing this. + */ +const passphrase = 'This is a random passphrase' +const seed = bip39.mnemonicToSeed(passphrase).slice(0, 32) + +const keypair = new driver.Ed25519Keypair(seed) + +console.log(`Public Key: ${keypair.publicKey} - Private Key: ${keypair.privateKey}`) // eslint-disable-line no-console + +// ======== Other Bip39 Functionality not related to BigchainDB ======== // + +/* Create Random passphrase */ +const mnemonic = bip39.generateMnemonic() +console.log('Random passphrase: ', mnemonic) // eslint-disable-line no-console + +/* Validate mnemnoic */ +console.log(bip39.validateMnemonic(mnemonic)) // eslint-disable-line no-console +console.log(bip39.validateMnemonic('some random strings together but to short')) // eslint-disable-line no-console