UNPKG

apla-blockchain-tools

Version:

Module contains a number of tools to work with Apla Blockchain

160 lines (140 loc) 5.35 kB
"use strict"; // MIT License // // Copyright (c) 2016-2018 AplaProject // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /* * Package: apla-blockchain-tools * Author: Anton Zuev * mail: a.zuev@apla.io * Company: apla.io */ let msgpack = require('msgpack-lite'); let { Int64BE } = require('int64-buffer'); let keyring = require("../keyring"); let {getFieldInstanceByType} = require("./fields"); let convert = require('../lib/convert'); let {RequiredParamNotPassedError, RedundantParamPassedError} = require("./errors"); class Contract { /** * * @param contractSchema {object} - schema of the contract received from /api/v2/contract/{contractName} * @param params {object} - key - name of the parameter, value - its value * @param options {object} * @param options.keyId {string} - keyId of the user who executes contract * @param options.ecosystemId {number} - ecosystemId of the ecosystem that contract belongs to * @param options.networkId {number} - networkId * @param options.payOver {number} * @param options.maxSum */ constructor(contractSchema, params, options) { this._time = Math.floor((new Date()).getTime() / 1000); this.params = params; this.schema = contractSchema; let {keyId, ecosystemId, networkId} = options; if(!keyId){ throw new Error("keyId was not passed") } if(!networkId){ throw new Error("networkId was not passed") } if(!ecosystemId){ throw new Error("ecosystemId was not passed") } this.prepareParamsForTX(); this._keyID = keyId; this.id = contractSchema.id; this._ecosystemId = ecosystemId; this._networkId = networkId; } sign(privateKey) { const publicKey = keyring.generatePublicKey(privateKey, true); this._publicKey = convert.toArrayBuffer(publicKey); const data = this.serialize(); const txHash = keyring.hashData(data).digest(); const resultHash = keyring.hashData(txHash).digest("hex"); const hexHash = resultHash.toString(); const signature = convert.toArrayBuffer(keyring.signHex(hexHash, privateKey)); return { hash: hexHash, data: convert.concatBuffer( new Uint8Array([0x80]), convert.concatBuffer( convert.encodeLengthPlusData(data), convert.encodeLengthPlusData(signature) ) ) }; } serialize() { let codec = msgpack.createCodec({ binarraybuffer: true, preset: true }); let txBody = { Header: { ID: this.id, Time: this._time, EcosystemID: this._ecosystemId, KeyID: new Int64BE(this._keyID), NetworkID: this._networkId, PublicKey: this._publicKey }, Params: this.params, }; return msgpack.encode( txBody, { codec: codec } ); } prepareParamsForTX(){ let fields = {}; let obligatory = {}; this.schema.fields.forEach((field) => { fields[field.name] = field; if(!field.optional){ obligatory[field.name] = false; } }); let preparedParams = {}; Object.keys(this.params).forEach((paramName) => { let value = this.params[paramName]; if(!fields[paramName]){ throw new RedundantParamPassedError(paramName, this.schema.name) } let FieldForParam = getFieldInstanceByType(fields[paramName].type); preparedParams[paramName] = (new FieldForParam(value)).get(); obligatory[paramName] = true; }); let paramsNotPassed = []; Object.keys(obligatory).forEach((paramName) => { if(!obligatory[paramName]){ paramsNotPassed.push(paramName); } }); if(paramsNotPassed.length > 0){ throw new RequiredParamNotPassedError(paramsNotPassed); } this.params = preparedParams; } } module.exports = Contract;