import { TX_VERSION } from "../../consts" ; import logger from "../../logging" ; import { Fixed8 , hash256 , num2hexstring , reverseHex , str2hexstring , } from "../../u" ; import { Account , Balance , sign } from "../../wallet" ; import { calculateInputs } from "../calculate" ; import { TransactionAttribute , TransactionAttributeLike , TransactionInput , TransactionInputLike , TransactionOutput , TransactionOutputLike , Witness , WitnessLike , } from "../components" ; import { calculationStrategyFunction } from "../strategy" ; import TxAttrUsage from "../txAttrUsage" ; import { serializeArrayOf } from "./main" ; import TransactionType from "./TransactionType" ; const log = logger ( "tx" ) ; export interface TransactionLike { type : number ; version : number ; attributes : TransactionAttributeLike [ ] ; inputs : TransactionInputLike [ ] ; outputs : TransactionOutputLike [ ] ; scripts : WitnessLike [ ] ; } export abstract class BaseTransaction { public readonly type : TransactionType = 0x00 ; public version : number ; public attributes : TransactionAttribute [ ] ; public inputs : TransactionInput [ ] ; public outputs : TransactionOutput [ ] ; public scripts : Witness [ ] ; public constructor ( tx = { } ) { this . version = tx . version || TX_VERSION . CONTRACT ; this . attributes = Array . isArray ( tx . attributes ) ? tx . attributes . map ( ( a ) => new TransactionAttribute ( a ) ) : [ ] ; this . inputs = Array . isArray ( tx . inputs ) ? tx . inputs . map ( ( a ) => new TransactionInput ( a ) ) : [ ] ; this . outputs = Array . isArray ( tx . outputs ) ? tx . outputs . map ( ( a ) => new TransactionOutput ( a ) ) : [ ] ; this . scripts = Array . isArray ( tx . scripts ) ? tx . scripts . map ( ( a ) => new Witness ( a ) ) : [ ] ; } public get [ Symbol . toStringTag ] ( ) : string { return "Transaction" ; } /**
     * Transaction hash.
     */ public get hash ( ) : string { return reverseHex ( hash256 ( this . serialize ( false ) ) ) ; } abstract get fees ( ) : number ; abstract get exclusiveData ( ) : { [ key ] : any ; } ; public abstract serializeExclusive ( ) ; public addOutput ( txOut ) { this . outputs . push ( new TransactionOutput ( txOut ) ) ; return this ; } param symbol param value param address public addIntent ( symbol , value , address ) { this . outputs . push ( TransactionOutput . fromIntent ( symbol , value , address ) ) ; return this ; } param usage param data public addAttribute ( usage , data ) { if ( typeof data !== "string" ) { throw new TypeError ( "data should be formatted as string!" ) ; } this . attributes . push ( new TransactionAttribute ( { usage , data } ) ) ; return this ; } param remark public addRemark ( remark ) { const hexRemark = str2hexstring ( remark ) ; return this . addAttribute ( TxAttrUsage . Remark , hexRemark ) ; } param witness public addWitness ( witness ) { if ( witness . scriptHash === "" ) { throw new Error ( "Please define the scriptHash for this Witness!" ) ; } this . scripts . push ( witness ) ; this . scripts = this . scripts . sort ( ( w1 , w2 ) => parseInt ( w1 . scriptHash , 16 ) - parseInt ( w2 . scriptHash , 16 ) ) ; return this ; } param balance param strategy param fees public calculate ( balance , strategy ? , fees = 0 ) { const { inputs , change } = calculateInputs ( balance , this . outputs , new Fixed8 ( this . fees ) . add ( fees ) , strategy ) ; this . inputs = inputs ; this . outputs = this . outputs . concat ( change ) ; log . info ( `Calculated the inputs required for Transaction with Balance: ${ balance . address }` ) ; return this ; } param { boolean } signed return { string } public serialize ( signed = true ) { let out = "" ; out += num2hexstring ( this . type ) ; out += num2hexstring ( this . version ) ; out += this . serializeExclusive ( ) ; out += serializeArrayOf ( this . attributes ) ; out += serializeArrayOf ( this . inputs ) ; out += serializeArrayOf ( this . outputs ) ; if ( signed ) { out += serializeArrayOf ( this . scripts ) ; } return out ; } param { Account | string } signer return { Transaction } public sign ( signer ) { if ( typeof signer === "string" ) { signer = new Account ( signer ) ; } const signature = sign ( this . serialize ( false ) , signer . privateKey ) ; log . info ( `Signed Transaction with Account: ${ signer . label }` ) ; this . addWitness ( Witness . fromSignature ( signature , signer . publicKey ) ) ; return this ; } public export ( ) { return { type : this . type , version : this . version , attributes : this . attributes . map ( ( a ) => a . export ( ) ) , inputs : this . inputs . map ( ( a ) => a . export ( ) ) , outputs : this . outputs . map ( ( a ) => a . export ( ) ) , scripts : this . scripts . map ( ( a ) => a . export ( ) ) , } ; } } export default BaseTransaction ;