// Copyright (C) 2018 Zilliqa // // This file is part of zilliqa-js // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . import { ReqMiddlewareFn, RPCMethod } from "@zilliqa-js/core"; import { bytes, validation, Long } from "@zilliqa-js/util"; import * as proto from "@zilliqa-js/proto"; const ZilliqaMessage = proto.ZilliqaMessage; import { TxReceipt, TxParams } from "./types"; import { Buffer } from "buffer"; /* tslint:disable:no-unused-variable */ export const encodeTransactionProto = (tx: TxParams): Buffer => { const msg = { version: tx.version, nonce: new Long(tx.nonce || 0, 0), // core protocol Schnorr expects lowercase, non-prefixed address. toaddr: bytes.hexToByteArray(tx.toAddr.replace("0x", "").toLowerCase()), senderpubkey: ZilliqaMessage.ByteArray.create({ data: bytes.hexToByteArray(tx.pubKey || "00"), }), amount: ZilliqaMessage.ByteArray.create({ data: Uint8Array.from(tx.amount.toArrayLike(Buffer, undefined, 16)), }), gasprice: ZilliqaMessage.ByteArray.create({ data: Uint8Array.from(tx.gasPrice.toArrayLike(Buffer, undefined, 16)), }), gaslimit: tx.gasLimit, code: tx.code && tx.code.length ? Uint8Array.from([...tx.code].map((c) => c.charCodeAt(0))) : null, data: tx.data && tx.data.length ? Uint8Array.from([...tx.data].map((c) => c.charCodeAt(0))) : null, }; const serialised = ZilliqaMessage.ProtoTransactionCoreInfo.create(msg); return Buffer.from( ZilliqaMessage.ProtoTransactionCoreInfo.encode(serialised).finish() ); }; export const isTxReceipt = (x: unknown): x is TxReceipt => { return validation.isPlainObject(x) && validation.matchesObject(x, {}); }; export const isTxParams = (obj: unknown): obj is TxParams => { const validator = { version: [validation.required(validation.isNumber)], toAddr: [validation.required(validation.isAddress)], amount: [validation.required(validation.isBN)], gasPrice: [validation.required(validation.isBN)], gasLimit: [validation.required(validation.isLong)], code: [validation.isString], data: [validation.isString], receipt: [isTxReceipt], nonce: [validation.required(validation.isNumber)], signature: [validation.required(validation.isSignature)], }; return validation.matchesObject(obj, validator); }; export const formatOutgoingTx: ReqMiddlewareFn<[TxParams]> = (req) => { // if batch create transaction, payload is array if ( Array.isArray(req.payload) && req.payload[0].method === RPCMethod.CreateTransaction && isTxParams(req.payload[0].params[0]) ) { // loop thru batch payloads and format the params const payloads = []; for (const txPayload of req.payload) { const txConfig = txPayload.params[0]; payloads.push({ ...txPayload, params: [ { ...txConfig, amount: txConfig.amount.toString(), gasLimit: txConfig.gasLimit.toString(), gasPrice: txConfig.gasPrice.toString(), }, ], }); } const ret = { ...req, payload: payloads, }; return ret; } // non-batch create transactions if ( !Array.isArray(req.payload) && req.payload.method === RPCMethod.CreateTransaction && isTxParams(req.payload.params[0]) ) { const txConfig = req.payload.params[0]; const ret = { ...req, payload: { ...req.payload, params: [ { ...txConfig, amount: txConfig.amount.toString(), gasLimit: txConfig.gasLimit.toString(), gasPrice: txConfig.gasPrice.toString(), }, ], }, }; return ret; } return req; }; export async function sleep(ms: number) { return new Promise((resolve) => { setTimeout(() => resolve(undefined), ms); }); }