@omisego/omg-js-childchain
Advanced tools
Comparing version 0.1.6 to 0.1.7
{ | ||
"name": "@omisego/omg-js-childchain", | ||
"version": "0.1.6", | ||
"version": "0.1.7", | ||
"description": "Module to interact with OMG ChildChain", | ||
@@ -25,3 +25,3 @@ "keywords": [ | ||
"dependencies": { | ||
"@omisego/omg-js-util": "^0.1.5", | ||
"@omisego/omg-js-util": "^0.1.7", | ||
"base-x": "^3.0.4", | ||
@@ -42,3 +42,3 @@ "buffer": "^5.2.0", | ||
}, | ||
"gitHead": "8cf1ff94f280a6acd2761b6adf9d0c0436ece6fe" | ||
"gitHead": "96445b5c2197d63dabf93da9484934c26d8fd689" | ||
} |
164
src/index.js
@@ -1,7 +0,22 @@ | ||
const newTransaction = require('./transaction/newTx') | ||
const { singleSign, signedEncode } = require('./transaction/signature') | ||
const { base16Encode } = require('./transaction/base16') | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
const watcherApi = require('./watcherApi') | ||
const sign = require('./transaction/signature') | ||
const submitTx = require('./transaction/submitRPC') | ||
const watcherApi = require('./watcherApi') | ||
const { hexToByteArr, byteArrToBuffer, InvalidArgumentError } = require('@omisego/omg-js-util') | ||
const transaction = require('./transaction/transaction') | ||
const rlp = require('rlp') | ||
const { InvalidArgumentError } = require('@omisego/omg-js-util') | ||
global.Buffer = global.Buffer || require('buffer').Buffer | ||
@@ -24,38 +39,2 @@ const Web3Utils = require('web3-utils') | ||
/** | ||
* generate, sign, encode and submit transaction to childchain (refer to examples/node-sendTx.js for example inputs) | ||
* | ||
* @method sendTransaction | ||
* @param {array} inputs | ||
* @param {array} currency | ||
* @param {array} outputs | ||
* @param {string} privateKey private key for signer (in hex with '0x' prefix) | ||
* @return {object} success/error message with `tx_index`, `tx_hash` and `blknum` params | ||
*/ | ||
async sendTransaction (inputs, currency, outputs, privKey) { | ||
// Validate arguments | ||
validateInputs(inputs) | ||
validateCurrency(currency) | ||
validateOutputs(outputs) | ||
validatePrivateKey(privKey) | ||
// turns 2 hex addresses input to 2 arrays | ||
outputs[0].newowner1 = Array.from(hexToByteArr(outputs[0].newowner1)) | ||
outputs[1].newowner2 = Array.from(hexToByteArr(outputs[1].newowner2)) | ||
// turn privkey string to addr | ||
privKey = byteArrToBuffer(hexToByteArr(privKey)) | ||
// creates new transaction object | ||
let transactionBody = newTransaction(inputs, currency, outputs) | ||
// sign transaction | ||
let signedTx = singleSign(transactionBody, privKey) | ||
// encode transaction with RLP | ||
let obj = signedTx.raw_tx | ||
let rlpEncodedTransaction = signedEncode(obj, signedTx.sig1, signedTx.sig2) | ||
// encode transaction with base16 | ||
let base16 = base16Encode(rlpEncodedTransaction) | ||
// submit via JSON RPC | ||
return submitTx(base16, this.childChainUrl) | ||
} | ||
/** | ||
* Obtain UTXOs of an address | ||
@@ -67,3 +46,2 @@ * | ||
*/ | ||
async getUtxos (address) { | ||
@@ -81,7 +59,6 @@ validateAddress(address) | ||
*/ | ||
async getBalance (address) { | ||
// return watcherApi.get(`${this.watcherUrl}/account/${address}/balance`) | ||
// TODO Temporarily use getUtxos to calculate balance because watcher/account/${address}/balance api is not deployed yet. | ||
// TODO Temporarily use getUtxos to calculate balance because watcher/account/${address}/balance api is not deployed yet. | ||
validateAddress(address) | ||
@@ -102,26 +79,89 @@ const utxos = await this.getUtxos(address) | ||
} | ||
} | ||
function validateInputs (arg) { | ||
// TODO | ||
const valid = true | ||
if (!valid) { | ||
throw new InvalidArgumentError() | ||
async getExitData (utxo) { | ||
// Calculate the utxoPos | ||
const utxoPos = transaction.encodeUtxoPos(utxo) | ||
return watcherApi.get(`${this.watcherUrl}/utxo/${utxoPos}/exit_data`) | ||
} | ||
} | ||
function validateOutputs (arg) { | ||
// TODO | ||
const valid = true | ||
if (!valid) { | ||
throw new InvalidArgumentError() | ||
/** | ||
* Create an unsigned transaction | ||
* | ||
* @method createTransaction | ||
* @param {object} transactionBody | ||
* @return {object} | ||
*/ | ||
createTransaction (transactionBody) { | ||
transaction.validate(transactionBody) | ||
const txArray = transaction.toArray(transactionBody) | ||
return rlp.encode(txArray).toString('hex') | ||
} | ||
} | ||
function validateCurrency (arg) { | ||
// TODO | ||
const valid = true | ||
if (!valid) { | ||
throw new InvalidArgumentError() | ||
/** | ||
* Sign a transaction | ||
* | ||
* @method signTransaction | ||
* @param {string} unsignedTx | ||
* @param {array} privateKeys | ||
* @return {array} signatures | ||
*/ | ||
signTransaction (unsignedTx, privateKeys) { | ||
privateKeys.forEach(key => validatePrivateKey) | ||
return sign(Buffer.from(unsignedTx, 'hex'), privateKeys) | ||
} | ||
/** | ||
* Build a signed transaction into the format expected by submitTransaction | ||
* | ||
* @method buildSignedTransaction | ||
* @param {string} unsignedTx | ||
* @param {array} signatures | ||
* @return {object} | ||
*/ | ||
buildSignedTransaction (unsignedTx, signatures) { | ||
// rlp-decode the tx bytes | ||
const decodedTx = rlp.decode(Buffer.from(unsignedTx, 'hex')) | ||
// Append the signatures | ||
const signedTx = [...decodedTx, ...signatures] | ||
// rlp-encode the transaction + signatures | ||
return rlp.encode(signedTx).toString('hex') | ||
} | ||
/** | ||
* Submit a signed transaction to the childchain | ||
* | ||
* @method submitTransaction | ||
* @param {string} transaction | ||
* @return {object} | ||
*/ | ||
async submitTransaction (transaction) { | ||
// validateTxBody(transactionBody) | ||
return submitTx(transaction, this.childChainUrl) | ||
} | ||
/** | ||
* create, sign, build and submit a transaction to the childchain using raw privatekey | ||
* | ||
* @method sendTransaction | ||
* @param {array} fromUtxos - array of utxos gathered from the watcher | ||
* @param {array} fromPrivateKeys - array of hex string private key | ||
* @param {string} toAddress - address | ||
* @param {number} toAmount - amount to transact | ||
* @return {object} | ||
*/ | ||
async sendTransaction (fromUtxos, fromPrivateKeys, toAddress, toAmount) { | ||
validateAddress(toAddress) | ||
validatePrivateKey(fromPrivateKeys) | ||
// transform fromUtxo to txbody | ||
const txBody = transaction.createTransactionBody(fromUtxos, toAddress, toAmount) | ||
// create transaction | ||
const unsignedTx = this.createTransaction(txBody) | ||
// sign a transaction | ||
const signatures = this.signTransaction(unsignedTx, fromPrivateKeys) | ||
// build a transaction | ||
const signedTx = this.buildSignedTransaction(unsignedTx, signatures) | ||
// submit via JSON rpc | ||
const result = await this.submitTransaction(signedTx) | ||
return result | ||
} | ||
} | ||
@@ -128,0 +168,0 @@ |
@@ -0,1 +1,16 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
// Get_block on JSON RPC | ||
@@ -2,0 +17,0 @@ |
@@ -0,87 +1,51 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
// generates signature | ||
global.Buffer = global.Buffer || require('buffer').Buffer | ||
const keccak256 = require('js-sha3').keccak256 | ||
const signatureDigest = require('./sigDigest') | ||
const { rlpEncodeArr } = require('./rlp') | ||
const debug = require('debug')('omg.childchain.signatureDigest') | ||
const ethUtil = require('ethereumjs-util') | ||
const sigUtil = require('eth-sig-util') | ||
function hash (message) { | ||
let hexValue = keccak256(message) | ||
let bufferValue = Buffer.from(hexValue, 'hex') | ||
let uint8Value = new Uint8Array(bufferValue) | ||
return uint8Value | ||
} | ||
const NULL_SIG = '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | ||
function signature (encodedTx, privateKey) { | ||
// TODO: Add logic to add 0 to function without message inputs | ||
let hashedMsg = hash(encodedTx) | ||
let signed = signatureDigest(hashedMsg, privateKey) | ||
let signedToArr = Array.from(signed) | ||
return signedToArr | ||
function ecSign (tosign, privateKey) { | ||
const hashed = keccak256(tosign) | ||
const signed = ethUtil.ecsign( | ||
Buffer.from(hashed, 'hex'), | ||
Buffer.from(privateKey.replace('0x', ''), 'hex') | ||
) | ||
return sigUtil.concatSig(signed.v, signed.r, signed.s) | ||
} | ||
// for when there is encodedTx but, no privateKey available | ||
function zeroSignature () { | ||
let zeroBytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | ||
return zeroBytes | ||
} | ||
function sign (tx, privateKeys) { | ||
// Currently transaction always have 2 inputs. | ||
// If no private key is given for an input, then we sign with a 'null' signature | ||
const REQUIRED_SIGNATURES = 2 | ||
const signatures = [] | ||
// sign an encoded signature | ||
function signedEncode (tx, sig1, sig2) { | ||
let transactionBody = [ | ||
tx.blknum1, | ||
tx.txindex1, | ||
tx.oindex1, | ||
tx.blknum2, | ||
tx.txindex2, | ||
tx.oindex2, | ||
tx.cur12, | ||
tx.newowner1, | ||
tx.amount1, | ||
tx.newowner2, | ||
tx.amount2, | ||
sig1, | ||
sig2 | ||
] | ||
for (let i = 0; i < REQUIRED_SIGNATURES; i++) { | ||
if (privateKeys.length > i) { | ||
signatures.push(ecSign(tx, privateKeys[i])) | ||
} else { | ||
// Use null sig for the second signature | ||
signatures.push(NULL_SIG) | ||
} | ||
} | ||
let rlpEncoded = rlpEncodeArr(transactionBody) | ||
return rlpEncoded | ||
return signatures | ||
} | ||
function singleSign (tx, priv1) { | ||
// transform tx into array format | ||
let txArray = | ||
[ | ||
tx.blknum1, | ||
tx.txindex1, | ||
tx.oindex1, | ||
tx.blknum2, | ||
tx.txindex2, | ||
tx.oindex2, | ||
tx.cur12, | ||
tx.newowner1, | ||
tx.amount1, | ||
tx.newowner2, | ||
tx.amount2 | ||
] | ||
// encode tx array | ||
let encodedTx = rlpEncodeArr(txArray) | ||
// generate first signature (signature function) | ||
let sig1 = signature(encodedTx, priv1) | ||
// generate second signature (zero signature function) | ||
let sig2 = zeroSignature() | ||
// generate signedTxBytes (with another Signed.encode function) | ||
let signedTxBytes = signedEncode(tx, sig1, sig2) | ||
// putting it all together and return the object | ||
let signedTransaction = { | ||
raw_tx: tx, | ||
sig1, | ||
sig2, | ||
signedTxBytes | ||
} | ||
debug(`signed transaction object is: ${JSON.stringify(signedTransaction)}`) | ||
return signedTransaction | ||
} | ||
module.exports = { signature, hash, signedEncode, zeroSignature, singleSign } | ||
module.exports = sign |
@@ -0,1 +1,16 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
// submit tx on JSON | ||
@@ -22,5 +37,8 @@ const fetch = require('node-fetch') | ||
debug(`rpc response is ${JSON.stringify(response)}`) | ||
return response | ||
if (response.error) { | ||
throw new Error(JSON.stringify(response.error)) | ||
} | ||
return response.result | ||
} | ||
module.exports = submitTx |
@@ -0,1 +1,16 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
const fetch = require('node-fetch') | ||
@@ -13,2 +28,15 @@ const JSONBigNumber = require('json-bigint') | ||
const resp = await fetch(url) | ||
return rpcResponse(resp) | ||
} | ||
async function post (url, body) { | ||
const resp = await fetch(url, { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify(body) | ||
}) | ||
return rpcResponse(resp) | ||
} | ||
async function rpcResponse (resp) { | ||
const body = await resp.text() | ||
@@ -28,2 +56,5 @@ let json | ||
module.exports = { get } | ||
module.exports = { | ||
get, | ||
post | ||
} |
@@ -0,1 +1,16 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
const chai = require('chai') | ||
@@ -77,3 +92,2 @@ const chaiAsPromised = require('chai-as-promised') | ||
}) | ||
}) |
@@ -0,1 +1,16 @@ | ||
/* | ||
Copyright 2018 OmiseGO Pte Ltd | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
const mocha = require('mocha') | ||
@@ -2,0 +17,0 @@ const describe = mocha.describe |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36274
12
688
5
Updated@omisego/omg-js-util@^0.1.7