forked from bitshares/bitsharesjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
58 changed files
with
7,633 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"presets": [ | ||
"./tools/es2015Preset", | ||
"stage-1" | ||
], | ||
"env": { | ||
"cjs": { | ||
"plugins": ["add-module-exports"] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.npmrc | ||
npm-debug.log | ||
node_modules | ||
dist | ||
es |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
lib | ||
build | ||
test | ||
tools |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## v0.4.0 | ||
- Add AccountLogin class | ||
- Clean up imports | ||
- Use babel for tests | ||
## v0.3.0 | ||
- Extract websocket library to separate bitsharesjs-ws lib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# BitsharesJS (bitsharesjs) | ||
|
||
Pure JavaScript Bitshares library for node.js and browsers. Can be used to construct, sign and broadcast transactions in JavaScript, and to easily obtain data from the blockchain via public apis. | ||
|
||
Most of this code was written by [jcalfeee](https://github.com/jcalfee), my work was mostly just repackaging to a discrete npm package. | ||
|
||
[](https://www.npmjs.com/package/bitsharesjs) | ||
[](https://www.npmjs.com/package/bitsharesjs) | ||
|
||
|
||
## Setup | ||
|
||
This library can be obtained through npm: | ||
``` | ||
npm install bitsharesjs | ||
``` | ||
|
||
## Usage | ||
|
||
Three sub-libraries are included: `ECC`, `Chain` and `Serializer`. Generally only the `ECC` and `Chain` libraries need to be used directly. | ||
|
||
### Chain | ||
This library provides utility functions to handle blockchain state as well as a login class that can be used for simple login functionality using a specific key seed. | ||
|
||
#### Login | ||
The login class uses the following format for keys: | ||
|
||
``` | ||
keySeed = accountName + role + password | ||
``` | ||
|
||
Using this seed, private keys are generated for either the default roles `active, owner, memo`, or as specified. A minimum password length of 12 characters is enforced, but an even longer password is recommended. Three methods are provided: | ||
|
||
``` | ||
generateKeys(account, password, [roles]) | ||
checkKeys(account, password, auths) | ||
signTransaction(tr) | ||
``` | ||
|
||
The auths object should contain the auth arrays from the account object. An example is this: | ||
|
||
``` | ||
{ | ||
active: [ | ||
["GPH5Abm5dCdy3hJ1C5ckXkqUH2Me7dXqi9Y7yjn9ACaiSJ9h8r8mL", 1] | ||
] | ||
} | ||
``` | ||
|
||
If checkKeys is successful, you can use signTransaction to sign a TransactionBuilder transaction using the private keys for that account. | ||
|
||
#### State container | ||
The Chain library contains a complete state container called the ChainStore. The ChainStore will automatically configure the `set_subscribe_callback` and handle any incoming state changes appropriately. It uses Immutable.js for storing the state, so all objects are return as immutable objects. It has its own `subscribe` method that can be used to register a callback that will be called whenever a state change happens. | ||
|
||
The ChainStore has several useful methods to retrieve, among other things, objects, assets and accounts using either object ids or asset/account names. These methods are synchronous and will return `undefined` to indicate fetching in progress, and `null` to indicate that the object does not exist. | ||
|
||
``` | ||
import {Apis} from "bitsharesjs-ws"; | ||
var {ChainStore} = require("bitsharesjs"); | ||
Apis.instance("wss://bitshares.openledger.info/ws", true).init_promise.then((res) => { | ||
console.log("connected to:", res[0].network); | ||
ChainStore.init().then(() => { | ||
ChainStore.subscribe(updateState); | ||
}); | ||
}); | ||
let dynamicGlobal = null; | ||
function updateState(object) { | ||
dynamicGlobal = ChainStore.getObject("2.1.0"); | ||
console.log("ChainStore object update\n", dynamicGlobal ? dynamicGlobal.toJS() : dynamicGlobal); | ||
} | ||
``` | ||
|
||
### ECC | ||
The ECC library contains all the crypto functions for private and public keys as well as transaction creation/signing. | ||
|
||
#### Private keys | ||
As a quick example, here's how to generate a new private key from a seed (a brainkey for example): | ||
|
||
``` | ||
var {PrivateKey, key} = require("bitsharesjs"); | ||
let seed = "THIS IS A TERRIBLE BRAINKEY SEED WORD SEQUENCE"; | ||
let pkey = PrivateKey.fromSeed( key.normalize_brainKey(seed) ); | ||
console.log("\nPrivate key:", pkey.toWif()); | ||
console.log("Public key :", pkey.toPublicKey().toString(), "\n"); | ||
``` | ||
|
||
#### Transactions | ||
TODO transaction signing example | ||
|
||
## ESDoc (beta) | ||
```bash | ||
npm i -g esdoc esdoc-es7-plugin | ||
esdoc -c ./esdoc.json | ||
open out/esdoc/index.html | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"source": ".", | ||
"includes": ["\\.(js|es6)$"], | ||
"excludes": ["node_modules"], | ||
"destination": "./out/esdoc", | ||
"index": "./README.md", | ||
"package": "./package.json", | ||
"title": "BitsharesJS Docs" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {Apis} from "bitsharesjs-ws"; | ||
import {ChainStore} from "../lib"; | ||
|
||
Apis.instance("wss://bitshares.openledger.info/ws", true).init_promise.then((res) => { | ||
console.log("connected to:", res[0].network); | ||
ChainStore.init().then(() => { | ||
ChainStore.subscribe(updateState); | ||
}); | ||
}); | ||
|
||
let dynamicGlobal = null; | ||
function updateState(object) { | ||
dynamicGlobal = ChainStore.getObject("2.1.0"); | ||
|
||
console.log("ChainStore object update\n", dynamicGlobal ? dynamicGlobal.toJS() : dynamicGlobal); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
import {PrivateKey, key} from "../lib"; | ||
|
||
let seed = "THIS IS A TERRIBLE BRAINKEY SEED WORD SEQUENCE"; | ||
let pkey = PrivateKey.fromSeed( key.normalize_brainKey(seed) ); | ||
|
||
console.log("\nPrivate key:", pkey.toWif()); | ||
console.log("Public key :", pkey.toPublicKey().toString(), "\n"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import {Apis} from "bitsharesjs-ws"; | ||
import {ChainStore, FetchChain, PrivateKey, TransactionHelper, Aes, TransactionBuilder} from "../lib"; | ||
|
||
var privKey = "5KBuq5WmHvgePmB7w3onYsqLM8ESomM2Ae7SigYuuwg8MDHW7NN"; | ||
let pKey = PrivateKey.fromWif(privKey); | ||
|
||
Apis.instance("wss://testnet.bitshares.eu/ws", true) | ||
.init_promise.then((res) => { | ||
console.log("connected to:", res[0].network_name, "network"); | ||
|
||
ChainStore.init().then(() => { | ||
|
||
let fromAccount = "bitsharesjs"; | ||
let memoSender = fromAccount; | ||
let memo = "Testing transfer from node.js"; | ||
|
||
let toAccount = "faucet"; | ||
|
||
let sendAmount = { | ||
amount: 10000, | ||
asset: "TEST" | ||
} | ||
|
||
Promise.all([ | ||
FetchChain("getAccount", fromAccount), | ||
FetchChain("getAccount", toAccount), | ||
FetchChain("getAccount", memoSender), | ||
FetchChain("getAsset", sendAmount.asset), | ||
FetchChain("getAsset", sendAmount.asset) | ||
]).then((res)=> { | ||
// console.log("got data:", res); | ||
let [fromAccount, toAccount, memoSender, sendAsset, feeAsset] = res; | ||
|
||
// Memos are optional, but if you have one you need to encrypt it here | ||
let memoFromKey = memoSender.getIn(["options","memo_key"]); | ||
console.log("memo pub key:", memoFromKey); | ||
let memoToKey = toAccount.getIn(["options","memo_key"]); | ||
let nonce = TransactionHelper.unique_nonce_uint64(); | ||
|
||
let memo_object = { | ||
from: memoFromKey, | ||
to: memoToKey, | ||
nonce, | ||
message: Aes.encrypt_with_checksum( | ||
pKey, | ||
memoToKey, | ||
nonce, | ||
memo | ||
) | ||
} | ||
|
||
let tr = new TransactionBuilder() | ||
|
||
tr.add_type_operation( "transfer", { | ||
fee: { | ||
amount: 0, | ||
asset_id: feeAsset.get("id") | ||
}, | ||
from: fromAccount.get("id"), | ||
to: toAccount.get("id"), | ||
amount: { amount: sendAmount.amount, asset_id: sendAsset.get("id") }, | ||
memo: memo_object | ||
} ) | ||
|
||
tr.set_required_fees().then(() => { | ||
tr.add_signer(pKey, pKey.toPublicKey().toPublicKeyString()); | ||
console.log("serialized transaction:", tr.serialize()); | ||
tr.broadcast(); | ||
}) | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module.exports = { | ||
PrivateKey: require("./ecc/src/PrivateKey"), | ||
PublicKey: require("./ecc/src/PublicKey"), | ||
Signature: require("./ecc/src/signature"), | ||
key: require("./ecc/src/KeyUtils"), | ||
TransactionBuilder: require("./chain/src/TransactionBuilder"), | ||
Login: require("./chain/src/AccountLogin"), | ||
bitshares_ws: require("bitsharesjs-ws") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import ChainStore from "./src/ChainStore"; | ||
import TransactionBuilder from "./src/TransactionBuilder"; | ||
import ChainTypes from "./src/ChainTypes"; | ||
import ObjectId from "./src/ObjectId"; | ||
import NumberUtils from "./src/NumberUtils"; | ||
import TransactionHelper from "./src/TransactionHelper"; | ||
import ChainValidation from "./src/ChainValidation"; | ||
import EmitterInstance from "./src/EmitterInstance"; | ||
import Login from "./src/AccountLogin"; | ||
|
||
const {FetchChainObjects, FetchChain} = ChainStore; | ||
|
||
export {ChainStore, TransactionBuilder, FetchChainObjects, ChainTypes, | ||
ObjectId, NumberUtils, TransactionHelper, ChainValidation, FetchChain, Login } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import PrivateKey from "../../ecc/src/PrivateKey"; | ||
import key from "../../ecc/src/KeyUtils"; | ||
|
||
import {get, set} from "./state"; | ||
|
||
var _keyCachePriv = {}; | ||
var _keyCachePub = {}; | ||
|
||
class AccountLogin { | ||
|
||
constructor() { | ||
let state = {loggedIn: false, roles: ["active", "owner", "memo"]}; | ||
this.get = get(state); | ||
this.set = set(state); | ||
|
||
this.subs = {}; | ||
} | ||
|
||
addSubscription(cb) { | ||
this.subs[cb] = cb; | ||
} | ||
|
||
setRoles(roles) { | ||
this.set("roles", roles); | ||
} | ||
|
||
generateKeys(accountName, password, roles, prefix) { | ||
var start = new Date().getTime(); | ||
if (!accountName || !password) { | ||
throw new Error("Account name or password required"); | ||
} | ||
if (password.length < 12) { | ||
throw new Error("Password must have at least 12 characters"); | ||
} | ||
|
||
let privKeys = {}; | ||
let pubKeys = {}; | ||
|
||
(roles || this.get("roles")).forEach(role => { | ||
let seed = accountName + role + password; | ||
let pkey = _keyCachePriv[seed] ? _keyCachePriv[seed] : PrivateKey.fromSeed( key.normalize_brainKey(seed) ); | ||
_keyCachePriv[seed] = pkey; | ||
|
||
privKeys[role] = pkey; | ||
pubKeys[role] = _keyCachePub[seed] ? _keyCachePub[seed] : pkey.toPublicKey().toString(prefix); | ||
|
||
_keyCachePub[seed] = pubKeys[role]; | ||
}); | ||
|
||
return {privKeys, pubKeys}; | ||
} | ||
|
||
checkKeys({accountName, password, auths}) { | ||
if (!accountName || !password || !auths) { | ||
throw new Error("checkKeys: Missing inputs"); | ||
} | ||
let hasKey = false; | ||
|
||
for (let role in auths) { | ||
let {privKeys, pubKeys} = this.generateKeys(accountName, password, [role]); | ||
auths[role].forEach(key => { | ||
if (key[0] === pubKeys[role]) { | ||
hasKey = true; | ||
this.set(role, {priv: privKeys[role], pub: pubKeys[role]}); | ||
} | ||
}); | ||
}; | ||
|
||
if (hasKey) { | ||
this.set("name", accountName); | ||
} | ||
|
||
this.set("loggedIn", hasKey); | ||
|
||
return hasKey; | ||
} | ||
|
||
signTransaction(tr) { | ||
let myKeys = {}; | ||
let hasKey = false; | ||
|
||
this.get("roles").forEach(role => { | ||
let myKey = this.get(role); | ||
if (myKey) { | ||
hasKey = true; | ||
console.log("adding signer:", myKey.pub); | ||
tr.add_signer(myKey.priv, myKey.pub); | ||
} | ||
}); | ||
|
||
if (!hasKey) { | ||
throw new Error("You do not have any private keys to sign this transaction"); | ||
} | ||
} | ||
} | ||
|
||
let accountLogin = new AccountLogin(); | ||
|
||
export default accountLogin; |
Oops, something went wrong.