import BigNumber from 'bignumber.js'; import UnichainClient from '../client'; import Addresses from '../constants/Addresses'; import ProgamBase64Codes from '../constants/ProgamBase64Codes'; import { AccountAddress } from '../wallet/Accounts'; import { UnichainVMStatusError } from './Errors'; export interface UnichainProgram { code: Uint8Array; arguments: UnichainProgramArgument[]; modules: Uint8Array[]; } interface UnichainProgramArgument { type: UnichainProgramArgumentType; value: Uint8Array; } export enum UnichainProgramArgumentType { U64 = 0, ADDRESS = 1, STRING = 2, BYTEARRAY = 3, } export interface UnichainGasConstraint { maxGasAmount: BigNumber; gasUnitPrice: BigNumber; } export class UnichainTransaction { public static createTransfer(recipientAddress: string, numAccount: BigNumber): UnichainTransaction { const amountBuffer = Buffer.alloc(8); amountBuffer.writeBigUInt64LE(BigInt(numAccount), 0); const programArguments: UnichainProgramArgument[] = [ { type: UnichainProgramArgumentType.ADDRESS, value: Uint8Array.from(Buffer.from(recipientAddress, 'hex')), }, { type: UnichainProgramArgumentType.U64, value: Uint8Array.from(amountBuffer), }, ]; const program: UnichainProgram = { arguments: programArguments, code: Uint8Array.from(Buffer.from(ProgamBase64Codes.peerToPeerTxn, 'base64')), modules: [], }; return new UnichainTransaction( program, { gasUnitPrice: new BigNumber(0), maxGasAmount: new BigNumber(1000000), }, `${Math.floor(new Date().getTime() / 1000) + 100}`, new Uint8Array(Addresses.AddressLength), '-1', ); } // NOTE: Ensure this raw bytes is always set used internally public program: UnichainProgram; public gasContraint: UnichainGasConstraint; public expirationTime: BigNumber; public sendersAddress: AccountAddress; public sequenceNumber: BigNumber; /** * Create a new Transaction * * @param program * @param gasConstraint * @param expirationTime * @param sendersAddress * @param sequenceNumber */ constructor( program: UnichainProgram, gasConstraint: UnichainGasConstraint, expirationTime: string | BigNumber, sendersAddress: Uint8Array, sequenceNumber: string | BigNumber, ) { this.program = program; this.gasContraint = gasConstraint; this.expirationTime = new BigNumber(expirationTime); this.sendersAddress = new AccountAddress(sendersAddress); this.sequenceNumber = new BigNumber(sequenceNumber); } } export class UnichainTransactionResponse { public readonly signedTransaction: UnichainSignedTransaction; public readonly validatorId: Uint8Array; public readonly acStatus?: UnichainAdmissionControlStatus; public readonly mempoolStatus?: UnichainMempoolTransactionStatus; public readonly vmStatus?: UnichainVMStatusError; constructor( signedTransaction: UnichainSignedTransaction, validatorId: Uint8Array, acStatus?: UnichainAdmissionControlStatus | number, mempoolStatus?: UnichainMempoolTransactionStatus | number, vmStatus?: UnichainVMStatusError, ) { this.signedTransaction = signedTransaction; this.validatorId = validatorId; this.acStatus = acStatus; this.mempoolStatus = mempoolStatus; this.vmStatus = vmStatus; } public async awaitConfirmation(client: UnichainClient): Promise { return client.waitForConfirmation( this.signedTransaction.transaction.sendersAddress, this.signedTransaction.transaction.sequenceNumber.plus(1), ); } } export enum UnichainAdmissionControlStatus { ACCEPTED = 0, BLACKLISTED = 1, REJECTED = 2, UNKNOWN = -1, } export enum UnichainMempoolTransactionStatus { VALID = 0, INSUFFICIENTBALANCE = 1, INVALIDSEQNUMBER = 2, MEMPOOLISFULL = 3, TOOMANYTRANSACTIONS = 4, INVALIDUPDATE = 5, UNKNOWN = -1, } export class UnichainSignedTransaction { public readonly transaction: UnichainTransaction; public readonly publicKey: Uint8Array; public readonly signature: Uint8Array; constructor(transaction: UnichainTransaction, publicKey: Uint8Array, signature: Uint8Array) { this.transaction = transaction; this.publicKey = publicKey; this.signature = signature; } } export class UnichainSignedTransactionWithProof { public readonly signedTransaction: UnichainSignedTransaction; public readonly proof?: UnichainSignedTransactionProof; public readonly events?: UnichainTransactionEvent[]; constructor(signedTransaction: UnichainSignedTransaction, proof?: object, events?: UnichainTransactionEvent[]) { this.signedTransaction = signedTransaction; this.proof = proof; this.events = events; } } // TODO: Implement abstraction over the pb classes for transaction proof class UnichainSignedTransactionProof {} export class UnichainTransactionEvent { public readonly data: Uint8Array; // eventData public readonly sequenceNumber: BigNumber; public readonly address?: AccountAddress; public readonly path?: Uint8Array; constructor(data: Uint8Array, sequenceNumber: BigNumber | string, address?: AccountAddress, path?: Uint8Array) { this.data = data; this.sequenceNumber = new BigNumber(sequenceNumber); this.address = address; this.path = path; } }