UNPKG

caver-js

Version:

caver-js is a JavaScript API library that allows developers to interact with a Kaia node

391 lines (346 loc) 16.7 kB
/* Copyright 2020 The caver-js Authors This file is part of the caver-js library. The caver-js library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The caver-js library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the caver-js. If not, see <http://www.gnu.org/licenses/>. */ const _ = require('lodash') const utils = require('../../../caver-utils/src') const SignatureData = require('../../../caver-wallet/src/keyring/signatureData') /** * The transaction type strings. * * @example * caver.transaction.type.TxTypeLegacyTransaction * caver.transaction.type.TxTypeValueTransfer * caver.transaction.type.TxTypeFeeDelegatedValueTransfer * caver.transaction.type.TxTypeFeeDelegatedValueTransferWithRatio * caver.transaction.type.TxTypeValueTransferMemo * caver.transaction.type.TxTypeFeeDelegatedValueTransferMemo * caver.transaction.type.TxTypeFeeDelegatedValueTransferMemoWithRatio * caver.transaction.type.TxTypeAccountUpdate * caver.transaction.type.TxTypeFeeDelegatedAccountUpdate * caver.transaction.type.TxTypeFeeDelegatedAccountUpdateWithRatio * caver.transaction.type.TxTypeSmartContractDeploy * caver.transaction.type.TxTypeFeeDelegatedSmartContractDeploy * caver.transaction.type.TxTypeFeeDelegatedSmartContractDeployWithRatio * caver.transaction.type.TxTypeSmartContractExecution * caver.transaction.type.TxTypeFeeDelegatedSmartContractExecution * caver.transaction.type.TxTypeFeeDelegatedSmartContractExecutionWithRatio * caver.transaction.type.TxTypeCancel * caver.transaction.type.TxTypeFeeDelegatedCancel * caver.transaction.type.TxTypeFeeDelegatedCancelWithRatio * caver.transaction.type.TxTypeChainDataAnchoring * caver.transaction.type.TxTypeFeeDelegatedChainDataAnchoring * caver.transaction.type.TxTypeFeeDelegatedChainDataAnchoringWithRatio * * @alias module:Transaction.type * @type {Map<string:string>} */ const TX_TYPE_STRING = { TxTypeLegacyTransaction: 'TxTypeLegacyTransaction', TxTypeValueTransfer: 'TxTypeValueTransfer', TxTypeFeeDelegatedValueTransfer: 'TxTypeFeeDelegatedValueTransfer', TxTypeFeeDelegatedValueTransferWithRatio: 'TxTypeFeeDelegatedValueTransferWithRatio', TxTypeValueTransferMemo: 'TxTypeValueTransferMemo', TxTypeFeeDelegatedValueTransferMemo: 'TxTypeFeeDelegatedValueTransferMemo', TxTypeFeeDelegatedValueTransferMemoWithRatio: 'TxTypeFeeDelegatedValueTransferMemoWithRatio', TxTypeAccountUpdate: 'TxTypeAccountUpdate', TxTypeFeeDelegatedAccountUpdate: 'TxTypeFeeDelegatedAccountUpdate', TxTypeFeeDelegatedAccountUpdateWithRatio: 'TxTypeFeeDelegatedAccountUpdateWithRatio', TxTypeSmartContractDeploy: 'TxTypeSmartContractDeploy', TxTypeFeeDelegatedSmartContractDeploy: 'TxTypeFeeDelegatedSmartContractDeploy', TxTypeFeeDelegatedSmartContractDeployWithRatio: 'TxTypeFeeDelegatedSmartContractDeployWithRatio', TxTypeSmartContractExecution: 'TxTypeSmartContractExecution', TxTypeFeeDelegatedSmartContractExecution: 'TxTypeFeeDelegatedSmartContractExecution', TxTypeFeeDelegatedSmartContractExecutionWithRatio: 'TxTypeFeeDelegatedSmartContractExecutionWithRatio', TxTypeCancel: 'TxTypeCancel', TxTypeFeeDelegatedCancel: 'TxTypeFeeDelegatedCancel', TxTypeFeeDelegatedCancelWithRatio: 'TxTypeFeeDelegatedCancelWithRatio', TxTypeChainDataAnchoring: 'TxTypeChainDataAnchoring', TxTypeFeeDelegatedChainDataAnchoring: 'TxTypeFeeDelegatedChainDataAnchoring', TxTypeFeeDelegatedChainDataAnchoringWithRatio: 'TxTypeFeeDelegatedChainDataAnchoringWithRatio', TxTypeEthereumAccessList: 'TxTypeEthereumAccessList', TxTypeEthereumDynamicFee: 'TxTypeEthereumDynamicFee', } /** * The transaction tag hex strings. * This is because the transaction type tag string and the transaction type string are mapped, so the transaction type tag can be used as a key value. * * @example * caver.transaction.tag.TxTypeLegacyTransaction // caver.transaction.tag[''] * caver.transaction.tag.TxTypeValueTransfer // caver.transaction.tag['0x08'] * caver.transaction.tag.TxTypeFeeDelegatedValueTransfer // caver.transaction.tag['0x09'] * caver.transaction.tag.TxTypeFeeDelegatedValueTransferWithRatio // caver.transaction.tag['0x0a'] * caver.transaction.tag.TxTypeValueTransferMemo // caver.transaction.tag['0x10'] * caver.transaction.tag.TxTypeFeeDelegatedValueTransferMemo // caver.transaction.tag['0x11'] * caver.transaction.tag.TxTypeFeeDelegatedValueTransferMemoWithRatio // caver.transaction.tag['0x12'] * caver.transaction.tag.TxTypeAccountUpdate // caver.transaction.tag['0x20'] * caver.transaction.tag.TxTypeFeeDelegatedAccountUpdate // caver.transaction.tag['0x21'] * caver.transaction.tag.TxTypeFeeDelegatedAccountUpdateWithRatio // caver.transaction.tag['0x22'] * caver.transaction.tag.TxTypeSmartContractDeploy // caver.transaction.tag['0x28'] * caver.transaction.tag.TxTypeFeeDelegatedSmartContractDeploy // caver.transaction.tag['0x29'] * caver.transaction.tag.TxTypeFeeDelegatedSmartContractDeployWithRatio // caver.transaction.tag['0x2a'] * caver.transaction.tag.TxTypeSmartContractExecution // caver.transaction.tag['0x30'] * caver.transaction.tag.TxTypeFeeDelegatedSmartContractExecution // caver.transaction.tag['0x31'] * caver.transaction.tag.TxTypeFeeDelegatedSmartContractExecutionWithRatio // caver.transaction.tag['0x32'] * caver.transaction.tag.TxTypeCancel // caver.transaction.tag['0x38'] * caver.transaction.tag.TxTypeFeeDelegatedCancel // caver.transaction.tag['0x39'] * caver.transaction.tag.TxTypeFeeDelegatedCancelWithRatio // caver.transaction.tag['0x3a'] * caver.transaction.tag.TxTypeChainDataAnchoring // caver.transaction.tag['0x48'] * caver.transaction.tag.TxTypeFeeDelegatedChainDataAnchoring // caver.transaction.tag['0x49'] * caver.transaction.tag.TxTypeFeeDelegatedChainDataAnchoringWithRatio // caver.transaction.tag['0x4a'] * * @alias module:Transaction.type * @type {Map<string:string>} */ const TX_TYPE_TAG = { TxTypeLegacyTransaction: '', '': TX_TYPE_STRING.TxTypeLegacyTransaction, TxTypeValueTransfer: '0x08', '0x08': TX_TYPE_STRING.TxTypeValueTransfer, TxTypeFeeDelegatedValueTransfer: '0x09', '0x09': TX_TYPE_STRING.TxTypeFeeDelegatedValueTransfer, TxTypeFeeDelegatedValueTransferWithRatio: '0x0a', '0x0a': TX_TYPE_STRING.TxTypeFeeDelegatedValueTransferWithRatio, TxTypeValueTransferMemo: '0x10', '0x10': TX_TYPE_STRING.TxTypeValueTransferMemo, TxTypeFeeDelegatedValueTransferMemo: '0x11', '0x11': TX_TYPE_STRING.TxTypeFeeDelegatedValueTransferMemo, TxTypeFeeDelegatedValueTransferMemoWithRatio: '0x12', '0x12': TX_TYPE_STRING.TxTypeFeeDelegatedValueTransferMemoWithRatio, TxTypeAccountUpdate: '0x20', '0x20': TX_TYPE_STRING.TxTypeAccountUpdate, TxTypeFeeDelegatedAccountUpdate: '0x21', '0x21': TX_TYPE_STRING.TxTypeFeeDelegatedAccountUpdate, TxTypeFeeDelegatedAccountUpdateWithRatio: '0x22', '0x22': TX_TYPE_STRING.TxTypeFeeDelegatedAccountUpdateWithRatio, TxTypeSmartContractDeploy: '0x28', '0x28': TX_TYPE_STRING.TxTypeSmartContractDeploy, TxTypeFeeDelegatedSmartContractDeploy: '0x29', '0x29': TX_TYPE_STRING.TxTypeFeeDelegatedSmartContractDeploy, TxTypeFeeDelegatedSmartContractDeployWithRatio: '0x2a', '0x2a': TX_TYPE_STRING.TxTypeFeeDelegatedSmartContractDeployWithRatio, TxTypeSmartContractExecution: '0x30', '0x30': TX_TYPE_STRING.TxTypeSmartContractExecution, TxTypeFeeDelegatedSmartContractExecution: '0x31', '0x31': TX_TYPE_STRING.TxTypeFeeDelegatedSmartContractExecution, TxTypeFeeDelegatedSmartContractExecutionWithRatio: '0x32', '0x32': TX_TYPE_STRING.TxTypeFeeDelegatedSmartContractExecutionWithRatio, TxTypeCancel: '0x38', '0x38': TX_TYPE_STRING.TxTypeCancel, TxTypeFeeDelegatedCancel: '0x39', '0x39': TX_TYPE_STRING.TxTypeFeeDelegatedCancel, TxTypeFeeDelegatedCancelWithRatio: '0x3a', '0x3a': TX_TYPE_STRING.TxTypeFeeDelegatedCancelWithRatio, TxTypeChainDataAnchoring: '0x48', '0x48': TX_TYPE_STRING.TxTypeChainDataAnchoring, TxTypeFeeDelegatedChainDataAnchoring: '0x49', '0x49': TX_TYPE_STRING.TxTypeFeeDelegatedChainDataAnchoring, TxTypeFeeDelegatedChainDataAnchoringWithRatio: '0x4a', '0x4a': TX_TYPE_STRING.TxTypeFeeDelegatedChainDataAnchoringWithRatio, TxTypeEthereumAccessList: '0x7801', '0x7801': TX_TYPE_STRING.TxTypeEthereumAccessList, TxTypeEthereumDynamicFee: '0x7802', '0x7802': TX_TYPE_STRING.TxTypeEthereumDynamicFee, } const TX_TYPE_TAG_LEGACY_TX_TYPES = { ACCOUNT_UPDATE: TX_TYPE_TAG.TxTypeAccountUpdate, FEE_DELEGATED_ACCOUNT_UPDATE: TX_TYPE_TAG.TxTypeFeeDelegatedAccountUpdate, FEE_DELEGATED_ACCOUNT_UPDATE_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedAccountUpdateWithRatio, VALUE_TRANFSER: TX_TYPE_TAG.TxTypeValueTransfer, FEE_DELEGATED_VALUE_TRANSFER: TX_TYPE_TAG.TxTypeFeeDelegatedValueTransfer, FEE_DELEGATED_VALUE_TRANSFER_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedValueTransferWithRatio, VALUE_TRANSFER_MEMO: TX_TYPE_TAG.TxTypeValueTransferMemo, FEE_DELEGATED_VALUE_TRANSFER_MEMO: TX_TYPE_TAG.TxTypeFeeDelegatedValueTransferMemo, FEE_DELEGATED_VALUE_TRANSFER_MEMO_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedValueTransferMemoWithRatio, SMART_CONTRACT_DEPLOY: TX_TYPE_TAG.TxTypeSmartContractDeploy, FEE_DELEGATED_SMART_CONTRACT_DEPLOY: TX_TYPE_TAG.TxTypeFeeDelegatedSmartContractDeploy, FEE_DELEGATED_SMART_CONTRACT_DEPLOY_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedSmartContractDeployWithRatio, SMART_CONTRACT_EXECUTION: TX_TYPE_TAG.TxTypeSmartContractExecution, FEE_DELEGATED_SMART_CONTRACT_EXECUTION: TX_TYPE_TAG.TxTypeFeeDelegatedSmartContractExecution, FEE_DELEGATED_SMART_CONTRACT_EXECUTION_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedSmartContractExecutionWithRatio, CANCEL: TX_TYPE_TAG.TxTypeCancel, FEE_DELEGATED_CANCEL: TX_TYPE_TAG.TxTypeFeeDelegatedCancel, FEE_DELEGATED_CANCEL_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedCancelWithRatio, CHAIN_DATA_ANCHORING: TX_TYPE_TAG.TxTypeChainDataAnchoring, FEE_DELEGATED_CHAIN_DATA_ANCHORING: TX_TYPE_TAG.TxTypeFeeDelegatedChainDataAnchoring, FEE_DELEGATED_CHAIN_DATA_ANCHORING_WITH_RATIO: TX_TYPE_TAG.TxTypeFeeDelegatedChainDataAnchoringWithRatio, } const CODE_FORMAT = { EVM: '0x0', } /** * Returns transaction type number. * * @param {string} type - A transaction type string. * @return {number} */ const getTypeInt = type => { let typeInt = TX_TYPE_TAG[type] // If type int cannot be found from TX_TYPE_TAG, means old type string. if (typeInt === undefined) { typeInt = TX_TYPE_TAG_LEGACY_TX_TYPES[type] } return utils.hexToNumber(typeInt) } /** * Returns an EthereumTxTypeEnvelopeTag string. * This will be used to RLP encode ethereum typed transactions as a type prefix. * * @return {string} */ const getEthereumTxTypeEnvelopeTag = () => { return '0x78' } /** * Returns an ethereum type tag without EthereumTxTypeEnvelopeTag('0x78'). * This will be used to get RLP encoding to sign the ethereum typed transactions. * * @param {string} type - A transaction type string or tag. * @return {string} */ const getTypeTagWithoutEthereumTxTypeEnvelopeTag = type => { if (!isEthereumTypedTxType(type)) throw new Error(`Not EthereumTxTypeEnvelope tx type: ${type}`) let tag = type if (type.startsWith('TxType')) tag = TX_TYPE_TAG[type] return `0x${tag.replace(getEthereumTxTypeEnvelopeTag(), '')}` } /** * Returns whether the transaction type is ethereum tx or not. * * @param {string} type - A transaction type string or tag. * @return {boolean} */ const isEthereumTxType = txType => { // The transaction types in `caver.transaction` should have tx type string as a member variable. // So here we don't assume, user can define undefined for tx type. if (txType === undefined) return false return isLegacyTxType(txType) || isEthereumTypedTxType(txType) } /** * Returns whether the transaction type is legacy tx or not. * * @param {string} type - A transaction type string or tag. * @return {boolean} */ const isLegacyTxType = txType => { // The transaction types in `caver.transaction` should have tx type string as a member variable. // So here we don't assume, user can define undefined for tx type. if (txType === undefined) return false return txType === TX_TYPE_STRING.TxTypeLegacyTransaction || txType === TX_TYPE_TAG.TxTypeLegacyTransaction } /** * Returns the transaction type is ethereum typed tx or not. * * @param {string} type - A transaction type string or tag. * @return {boolean} */ const isEthereumTypedTxType = txType => { // The transaction types in `caver.transaction` should have tx type string as a member variable. // So here we don't assume, user can define undefined for tx type. if (txType === undefined) return false return ( txType.startsWith(getEthereumTxTypeEnvelopeTag()) || txType === TX_TYPE_STRING.TxTypeEthereumAccessList || txType === TX_TYPE_STRING.TxTypeEthereumDynamicFee ) } /** * Refines the array containing signatures. * - Removes duplicate signatures. * - Removes the default empty signature(['0x01', '0x', '0x']) included with other signatures. * - For an empty signature array, return an array containing the default empty signature(['0x01', '0x', '0x']). * * @param {Array.<string>|Array.<Array.<string>>|SignatureData|Array.<SignatureData>} sigArray - A signature or an array of signatures. * @param {string} [txType] - The transaction type string. This can be null if signature is not for transaction(for example message signed). * @return {SignatureData|Array.<SignatureData>} */ const refineSignatures = (sigArray, txType) => { const set = new Set() let result = [] const isSingleSignature = txType !== undefined ? isEthereumTxType(txType) : false let arrayOfSignatures = sigArray if (!_.isArray(sigArray) && sigArray instanceof SignatureData) { arrayOfSignatures = [sigArray] } else if (_.isArray(sigArray) && _.isString(sigArray[0])) { arrayOfSignatures = [sigArray] } for (const sig of arrayOfSignatures) { const signatureData = new SignatureData(sig) if (!signatureData.isEmpty()) { const sigString = sig.toString() if (!set.has(sigString)) { set.add(sigString, true) result.push(signatureData) } } } if (result.length === 0) result = [SignatureData.emtpySig] if (isSingleSignature && txType != undefined && result.length > 1) throw new Error(`${txType}} cannot have multiple sigantures.`) return !isSingleSignature ? result : result[0] } /** * Returns transaction type string. * * @param {string} rlpEncoded - An RLP-encoded transaction string. * @return {string} */ const typeDetectionFromRLPEncoding = rlpEncoded => { rlpEncoded = utils.addHexPrefix(rlpEncoded) let typeTag if (rlpEncoded.startsWith(getEthereumTxTypeEnvelopeTag())) { typeTag = rlpEncoded.slice(0, 6) } else { typeTag = rlpEncoded.slice(0, 4) } return TX_TYPE_TAG[typeTag] ? TX_TYPE_TAG[typeTag] : TX_TYPE_STRING.TxTypeLegacyTransaction } /** * Returns code format tag string. * * @param {string|number} cf - The code format. * @return {string} */ const getCodeFormatTag = cf => { if (cf === undefined) return CODE_FORMAT.EVM switch (cf) { case 0: case '0x': case '0x0': case 'EVM': return CODE_FORMAT.EVM } throw new Error(`Unsupported code format : ${cf}`) } /** * Returns `true` value is undefined or null. * * @param {*} value - The value to check. * @return {string} */ const isNot = function(value) { return _.isUndefined(value) || _.isNull(value) } module.exports = { TX_TYPE_STRING, TX_TYPE_TAG, CODE_FORMAT, isNot, refineSignatures, typeDetectionFromRLPEncoding, getCodeFormatTag, getTypeInt, isEthereumTxType, isEthereumTypedTxType, getEthereumTxTypeEnvelopeTag, getTypeTagWithoutEthereumTxTypeEnvelopeTag, }