Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/horizenofficial/zencashjs
Dead simple and easy to use JavaScript library for Horizen
https://github.com/horizenofficial/zencashjs
javascript zencash
Last synced: about 1 month ago
JSON representation
Dead simple and easy to use JavaScript library for Horizen
- Host: GitHub
- URL: https://github.com/horizenofficial/zencashjs
- Owner: HorizenOfficial
- License: mit
- Created: 2017-08-29T09:59:24.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-02-02T15:49:06.000Z (11 months ago)
- Last Synced: 2024-11-11T21:34:06.459Z (about 2 months ago)
- Topics: javascript, zencash
- Language: JavaScript
- Homepage:
- Size: 1.28 MB
- Stars: 43
- Watchers: 19
- Forks: 27
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# zencashjs ![build status](https://api.travis-ci.org/HorizenOfficial/zencashjs.svg?branch=master)
A javascript library for Node.js. Used in the development of Sphere and other wallets. Implements all non-computationally intensive operations.#### address.js
- Create private keys, public keys, and addresses
- Transform addresses / keys into different formats (WIF)#### transaction.js
- Create and sign (non-shielded) transactions (1 input & multiple inputs)
- Transaction serialization / deserialization#### message.js
- Sign and verify messages#### address.js
- Create secret key and transform to a spending key, paying key, or transmission key
- Viewing key is not yet supportedAddress / keys prefixes for both mainnet and testnet in config.js.
Inspired by [pybitcointools](https://github.com/vbuterin/pybitcointools)
### Installation
`npm install zencashjs`### Usage
See examples below## Migrating from 1.x to 2.x
Version 2 brings sidechain support and compatibility with Zendoo. Most functionality and example usage remains identical to Version 1, with the exception of the changes listed below:### `zencashjs.transaction.deserializeTx`
This function now takes a third parameter `envPubKeyHash: string`
```javascript
function deserializeTx (
hexStr: string,
withPrevScriptPubKey: boolean = false,
envPubKeyHash: string = zconfig.mainnet.pubKeyHash
): TXOBJ {}
```
This parameter `envPubKeyHash` is a constant hashed value representing the environment (mainnet/testnet). These constants are stored on the `zencashjs.config` object.For example,
```javascript
// Testnet
const testnetTxHex = 'fcff...';zencashjs.transaction.deserializeTx(
testnetTxHex,
false,
zencashjs.config.testnet.pubKeyHash
);// Mainnet
const mainnetTxHex = 'fcff...';zencashjs.transaction.deserializeTx(
mainnetTxHex,
false,
zencashjs.config.mainnet.pubKeyHash // Could be omitted, as it defaults to mainnet
);
```### `zencashjs.transaction.createRawTx`
This function now takes a fifth optional parameter `vft` to be used for a forward transfer transaction
```javascript
function createRawTx (
history: HISTORY[],
recipients: RECIPIENTS[],
blockHeight: number,
blockHash: string,
vft: TXOBJ.vft_ccout
): TXOBJ {}
```### Example forward transfer transaction
```javascript// Sending 10 ZEN from address 'ztphoWCQmyJVuNq2L3SLnRgy2Lw5i5a7hxL' to address '8d8137d57eee250bdd0302fcad05243276ba059556165517c3d919331cd5bdc8' on sidechain with sidechain id '1a4d5813b260d0cb456c649b005840e1a1eb6eb2e0f98f3af7d201ea1e95d0b8'
var blockHeight = 937649
var blockHash = '0002d980065e2bb502a302905ed81229aa467a9502b527a491d7978b970b1ae5'var txobj = zencashjs.transaction.createRawTx(
[{
txid: '087faec93611add81dcf0ec31df934248e63c4abde21ee81d65584c7396feb2b', vout: 0,
scriptPubKey: ''
}],
[{address: 'ztphoWCQmyJVuNq2L3SLnRgy2Lw5i5a7hxL', satoshis: 297799952794}],
blockHeight,
blockHash,
[{
scid: "1a4d5813b260d0cb456c649b005840e1a1eb6eb2e0f98f3af7d201ea1e95d0b8",
n: 0,
value: 1000000000,
address: "8d8137d57eee250bdd0302fcad05243276ba059556165517c3d919331cd5bdc8",
mcReturnAddress: "ztphoWCQmyJVuNq2L3SLnRgy2Lw5i5a7hxL"
}]
)
// { locktime: 0,
// version: -4,
// ins:
// [ { output: { hash: '087faec93611add81dcf0ec31df934248e63c4abde21ee81d65584c7396feb2b', vout: 0 },
// script: '',
// prevScriptPubKey: '',
// sequence: 'ffffffff' } ],
// outs:
// [ { script:
// '76a914ec6039c0505e74b8f74fb1e22b77da64d30ce6b388ac20e51a0b978b97d791a427b502957a46aa2912d85e9002a302b52b5e0680d9020003b14e0eb4',
// satoshis: 297799952794 } ],
// vft_ccout:
// [ { scid:
// '1a4d5813b260d0cb456c649b005840e1a1eb6eb2e0f98f3af7d201ea1e95d0b8',
// n: 0,
// value: 1000000000,
// address:
// '8d8137d57eee250bdd0302fcad05243276ba059556165517c3d919331cd5bdc8',
// mcReturnAddress: 'ztphoWCQmyJVuNq2L3SLnRgy2Lw5i5a7hxL' } ],
// vsc_ccout: [],
// vcsw_ccin: [],
// vmbtr_out: [] }zencashjs.transaction.serializeTx(txobj)
// fcffffff012beb6f39c78455d681ee21deabc4638e2434f91dc30ecf1dd8ad1136c9ae7f080000000000ffffffff019aa94256450000003f76a914ec6039c0505e74b8f74fb1e22b77da64d30ce6b388ac20e51a0b978b97d791a427b502957a46aa2912d85e9002a302b52b5e0680d9020003b14e0eb400000100ca9a3b00000000c8bdd51c3319d9c3175516569505ba76322405adfc0203dd0b25ee7ed537818db8d0951eea01d2f73a8ff9e0b26eeba1e14058009b646c45cbd060b213584d1aec6039c0505e74b8f74fb1e22b77da64d30ce6b30000000000
```### New Transaction Types
Zendoo introduces new transaction types related to sidechains. Therefore, `deserializeTx` will return extra fields if applicable. See the [Zendoo Upgrade Guide](https://downloads.horizen.io/file/web-assets/Zend_to_Zend_oo_Exchanges_v1.4.pdf) for more details on these transaction types.
See also the updated [TX_OBJ](src/types.js) type declaration.
> Note: `serializeTx` and `createRawTx` do not yet support all the new types (only forward transfers are supported), but will in future releases.
## Version 1
### Example usage (Transparent address)
```javascript
var zencashjs = require('zencashjs')var priv = zencashjs.address.mkPrivKey('chris p. bacon, defender of the guardians')
// 2c3a48576fe6e8a466e78cd2957c9dc62128135540bbea0685d7c4a23ea35a6cvar privWIF = zencashjs.address.privKeyToWIF(priv)
// 5J9mKPd531Tk4A73kKp4iowoi6EvhEp8QSMAVzrZhuzZkdpYbK8var pubKey = zencashjs.address.privKeyToPubKey(priv, true) // generate compressed pubKey
// 038a789e0910b6aa314f63d2cc666bd44fa4b71d7397cb5466902dc594c1a0a0d2var zAddr = zencashjs.address.pubKeyToAddr(pubKey)
// znnjppzJG7ajT7f6Vp1AD6SjgcXBVPA2E6c// It is imperative that the block used for bip115BlockHeight and bip115BlockHash has a sufficient number of
// confirmations (recommded values: 150 to 600 blocks older than current BLOCKHEIGHT). If the block used for
// the replay protection should get orphaned the transaction will be unspendable for at least 52596 blocks.
// For details on the replay protection please see: https://github.com/bitcoin/bips/blob/master/bip-0115.mediawiki// To create and sign a raw transaction at BLOCKHEIGHT with BIP115BLOCKHEIGHT and BIP115BLOCKHASH
const blockHeight = 450150 // Example of current BLOCKHEIGHT
const bip115BlockHeight = blockHeight - 150 // Chaintip - 150 blocks, the block used for the replay protection needs a sufficient number of confirmations
const bip115BlockHash = '0000000007844e62d471b966cc5926bd92e56a27d2c6a6ac8f90d34e11d3028d' // Blockhash of block 450000// If it is unfeasable to get the current BLOCKHEIGHT or transactions are to be signed completely offline
// use hard coded values for BIP115BLOCKHEIGHT and BIP115BLOCKHASH that are at least 52596 blocks older than the
// current BLOCKHEIGHT. For example:
const bip115BlockHeight = 142091
const bip115BlockHash = '00000001cf4e27ce1dd8028408ed0a48edd445ba388170c9468ba0d42fff3052'var txobj = zencashjs.transaction.createRawTx(
[{
txid: '196173ec34d22a52cc689a21d01dd33b633671cbe1141e7e66240c7f3b4ccf7b', vout: 0,
scriptPubKey: '76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac20ebd78933082d25d56a47d471ee5d57793454cf3d2787f77c21f9964b02000000034f2902b4'
}],
[{address: 'znkz4JE6Y4m8xWoo4ryTnpxwBT5F7vFDgNf', satoshis: 100000}],
bip115BlockHeight,
bip115BlockHash
)// To do a NULL_DATA transaction
// var txobj = zencashjs.transaction.createRawTx(
// [{
// txid: '196173ec34d22a52cc689a21d01dd33b633671cbe1141e7e66240c7f3b4ccf7b', vout: 0,
// scriptPubKey: '76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac20ebd78933082d25d56a47d471ee5d57793454cf3d2787f77c21f9964b02000000034f2902b4'
// }],
// [{address: 'znkz4JE6Y4m8xWoo4ryTnpxwBT5F7vFDgNf', satoshis: 99000},
// {address: undefined, data: 'hello world', satoshis: 900}],
// bip115BlockHeight,
// bip115BlockHash
// )// zencashjs.transaction.serializeTx(txobj)
// 01000000019dd5ae887ce5e354c4cabe75230a439b03e494f36c5e7726cb7385f892a304270000000000ffffffff01a0860100000000003f76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac205230ff2fd4a08b46c9708138ba45d4ed480aed088402d81dce274ecf01000000030b2b02b400000000var tx0 = zencashjs.transaction.signTx(txobj, 0, '2c3a48576fe6e8a466e78cd2957c9dc62128135540bbea0685d7c4a23ea35a6c', true) // The final argument sets the `compressPubKey` boolean. It is `false` by default.
// zencashjs.transaction.serializeTx(tx0)
// 01000000017bcf4c3b7f0c24667e1e14e1cb7136633bd31dd0219a68cc522ad234ec736119000000008b483045022100b69baff0eb5570fd8ddda7b180463035d47eb3b1c07a808a68085fd58e9e22b102202eb3983a2137af4f8c3967b3c6c16c024ad952a712ab92b8911a8797f1864d3d0141048a789e0910b6aa314f63d2cc666bd44fa4b71d7397cb5466902dc594c1a0a0d2e4d234528ff87b83f971ab2b12cd2939ff33c7846716827a5b0e8233049d8aadffffffff01a0860100000000003f76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac205230ff2fd4a08b46c9708138ba45d4ed480aed088402d81dce274ecf01000000030b2b02b400000000// You can now do zen-cli sendrawtransaction `SERIALIZED_TRANSACTION`
// To serialize and deserialize an unsigned raw transaction for signing on a separate machine, 'prevScriptPubKey' can be
// encoded in the raw transaction by passing 'true' as a second optional parameter to serializeTx/deserializeTx.
// Take note that the final signed transaction has to be serialized with serializeTx(tx, false).// Default serializeTx/deserializeTx setting 'prevScriptPubKey' to '':
zencashjs.transaction.deserializeTx(zencashjs.transaction.serializeTx(txobj))
// {
// version: 1,
// locktime: 0,
// ins: [
// {
// output: [Object],
// script: '',
// sequence: 'ffffffff',
// prevScriptPubKey: ''
// }
// ],
// outs: [
// {
// satoshis: 100000,
// script: '76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac200206260143838b5ff52dc2eb7b4b8099d4e4c99dc3ef19794289a2cd4c10070000b4'
// }
// ]
// }// serializeTx/deserializeTx with 2nd argument 'true' keeping 'prevScriptPubKey':
zencashjs.transaction.deserializeTx(zencashjs.transaction.serializeTx(txobj, true), true)
// {
// version: 1,
// locktime: 0,
// ins: [
// {
// output: [Object],
// script: '',
// sequence: 'ffffffff',
// prevScriptPubKey: '76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac20ebd78933082d25d56a47d471ee5d57793454cf3d2787f77c21f9964b02000000034f2902b4'
// }
// ],
// outs: [
// {
// satoshis: 100000,
// script: '76a914da46f44467949ac9321b16402c32bbeede5e3e5f88ac200206260143838b5ff52dc2eb7b4b8099d4e4c99dc3ef19794289a2cd4c10070000b4'
// }
// ]
// }
```### Example Usage (Multi-sig)
```javascript
var zencashjs = require('zencashjs')// Private keys in wallet import format
var privKeysWIF = ['L2sjwCsdZQmckKkTKGDqhKcWtbe3EU2FL4N1YHpD2SC1GhHRhqxF', 'L5bpskJWAGGWR1GA9SJkCQ2ndHkezqm8GuoWaBesrrwnsa1roSN6',
'KxvE58rxEwckkCjemDVdMDp7wzgosnyX1oyjzWmrcAVpV7EaZdSP']// Converts Private keys in WIF to its original form
var privKeys = privKeysWIF.map((x) => zencashjs.address.WIFToPrivKey(x))
// [ 'a8c04b7209d16606532bbbd158420bd7dcde415db5ff3ec269f9c3cb327661d6', 'fa137ed90f4876b7154884caf2d889de9ea9a838e1c938380c2de25d4de613f7', '32ae14a84a5f4e0ec804daef223cc7f48412abde76f78a2d2df463bb065d6617' ]// Get public keys (NOT address)
var pubKeys = privKeys.map((x) => zencashjs.address.privKeyToPubKey(x, true))
// [ '03519842d08ea56a635bfa8dd617b8e33f0426530d8e201107dd9a6af9493bd487', '02d3ac8c0cb7b99a26cd66269a312afe4e0a621579dfe8b33e29c597a32a616544', '02696187262f522cf1fa2c30c5cd6853c4a6c51ad5ba418abb4e3898dbc5a93d2e' ]// Make a 2-of-3 multisig address
// NOTE: The redeemScript determines the order of your signatures for multisign
// E.g. I made an address with pk1, pk3, pk2 for a 2-of-3 multisig
// Valid Sigs: [pk1, pk2] OR [pk3, pk2] OR [pk1, pk3] ...
// Invalid Sigs: [pk3, pk1], [pk2, pk1]
var redeemScript = zencashjs.address.mkMultiSigRedeemScript(pubKeys, 2, 3)
// 522103519842d08ea56a635bfa8dd617b8e33f0426530d8e201107dd9a6af9493bd4872102d3ac8c0cb7b99a26cd66269a312afe4e0a621579dfe8b33e29c597a32a6165442102696187262f522cf1fa2c30c5cd6853c4a6c51ad5ba418abb4e3898dbc5a93d2e53aevar multiSigAddress = zencashjs.address.multiSigRSToAddress(redeemScript)
// zsmSCni8GXoCdTGqUfn26QJVGh6rpaFs17T// It is imperative that the block used for bip115BlockHeight and bip115BlockHash has a sufficient number of
// confirmations (recommded values: 150 to 600 blocks older than current BLOCKHEIGHT). If the block used for
// the replay protection should get orphaned the transaction will be unspendable for at least 52596 blocks.
// For details on the replay protection please see: https://github.com/bitcoin/bips/blob/master/bip-0115.mediawiki// To create and sign a raw transaction at BLOCKHEIGHT with BIP115BLOCKHEIGHT and BIP115BLOCKHASH
const blockHeight = 450150 // Example of current BLOCKHEIGHT
const bip115BlockHeight = blockHeight - 150 // Chaintip - 150 blocks, the block used for the replay protection needs a sufficient number of confirmations
const bip115BlockHash = '0000000007844e62d471b966cc5926bd92e56a27d2c6a6ac8f90d34e11d3028d' // Blockhash of block 450000// If it is unfeasable to get the current BLOCKHEIGHT or transactions are to be signed completely offline
// use hard coded values for BIP115BLOCKHEIGHT and BIP115BLOCKHASH that are at least 52596 blocks older than the
// current BLOCKHEIGHT. For example:
const bip115BlockHeight = 142091
const bip115BlockHash = '00000001cf4e27ce1dd8028408ed0a48edd445ba388170c9468ba0d42fff3052'var txobj = zencashjs.transaction.createRawTx(
[{
txid: 'f5f324064de9caab9353674c59f1c3987ca997bf5882a41a722686883e089581', vout: 0,
scriptPubKey: '' // Don't need script pub key since we'll be using redeemScript to sign
}],
[{address: 'zneng6nRqTrqTKfjYAqXT86HWtk96ftPjtX', satoshis: 10000}],
bip115BlockHeight,
bip115BlockHash
)// Prepare our signatures for mutli-sig
var sig1 = zencashjs.transaction.multiSign(txobj, 0, privKeys[0], redeemScript)
// 3045022100c65ec438dc13028b1328a0f8426e1970ef202cba168772fe9d91d141e3020413022021b038c2098c29014aa7feef1624c3d9e4035ca960791f3bbe256df9f008038d01var sig2 = zencashjs.transaction.multiSign(txobj, 0, privKeys[1], redeemScript)
// 3045022100db1f423fe11bf06c9c97692e8086f5743653cad289e3a1c085ae656847ffb9d10220063c103d8c7c54597b055106ab70a45a2254c63435b64375a966c002f85d141901// NOTE: If you wanna send the tx to someone to get their signature, you can serialize the txObj and send it over in bytes, they can also deserialize it: e.g.
// var txBytes = zencashjs.transaction.serializeTx(txobj)
// var txObj = zencashjs.transaction.deserializeTx(txBytes)// Apply the signatures to the transaction object
var tx0 = zencashjs.transaction.applyMultiSignatures(txobj, 0, [sig1, sig2], redeemScript)// Serialize the transaction
var serializedTx = zencashjs.transaction.serializeTx(tx0)// You can now send the serializedTx using the RPC command sendrawtransaction or through an API like insight
```### Example usage (Private address)
```javascript
var zencashjs = require('zencashjs')var z_secretKey = zencashjs.zaddress.mkZSecretKey('Z pigs likes to snooze. ZZZZ')
// 0c10a61a669bc4a51000c4c74ff58c151912889891089f7bae5e4994a73af7a8// Spending key (this is what you import into your wallet)
var spendingKey = zencashjs.zaddress.zSecretKeyToSpendingKey(z_secretKey)
// SKxtHJsneoLByrwME9Nh4cd4AvYLNK9jJkAnB3AHNW794udD1qpx// Paying key
var a_pk = zencashjs.zaddress.zSecretKeyToPayingKey(z_secretKey)
// 927a3819627247c0dd39102ec5449fc6fc952e242aad08615df9f26718912e27// Transmission key
var pk_enc = zencashjs.zaddress.zSecretKeyToTransmissionKey(z_secretKey)
// 22d666c34ababacf6a9a4a752cc7870b505b64e85638aa45d23ac32992397960var Zaddress = zencashjs.zaddress.mkZAddress(a_pk, pk_enc)
// zcTPZR8Hqz2ZcStwMJju9L4VBHW7YWmNyL6tDAT4eVmzmxLaG7h4QmqUXfmrjz8twizH4piDGiRYJRZ1bhHhT5gFL6TKsQZ
```### Example usage (Sign/Verify message)
```javascript
var zencashjs = require('zencashjs')var priv = zencashjs.address.mkPrivKey('chris p. bacon, defender of the guardians')
// 2c3a48576fe6e8a466e78cd2957c9dc62128135540bbea0685d7c4a23ea35a6cvar privWIF = zencashjs.address.privKeyToWIF(priv)
// 5J9mKPd531Tk4A73kKp4iowoi6EvhEp8QSMAVzrZhuzZkdpYbK8var pubKey = zencashjs.address.privKeyToPubKey(priv, true) // generate compressed pubKey
// 038a789e0910b6aa314f63d2cc666bd44fa4b71d7397cb5466902dc594c1a0a0d2var zAddr = zencashjs.address.pubKeyToAddr(pubKey)
// znnjppzJG7ajT7f6Vp1AD6SjgcXBVPA2E6cvar message = 'ciao'
/**
* Will sign a message with a given zen private key.
*
* @param {string} message - The message to be signed
* @param {string} privateKey - A private key
* @param {Boolean} compressed
* @returns {Buffer} The signature
*/
var signature = zencashjs.message.sign(message, priv, true)
// signature.toString('base64')
// IC7SPUlfyjKjG7hrrPWc6WTsm79ksjHAYXSFmjlGwAL9SSvAIvpYmOm3U5CzG2k0QBxDYuzpltw+UAET3J8e7Gg=/**
* Validate a signature against a given zend address.
*
* @param {String} message - the message to verify
* @param {String} zenAddress - A zen address
* @param {String|Buffer} signature - A base64 encoded compact signature
* @returns {Boolean} true if the signature is valid
*/
var verification = zencashjs.message.verify(message, zAddr, signature)
// true
```# Development guide (more to come..)
```bash
# src is where the source code resides.
# lib is where the transpiled code resides in.
# edit src if you wanna make a PR
git clone https://github.com/HorizenOfficial/zencashjs.git
cd zencashjs
npm install
npm run [dev | build | test]
```