UNPKG

@bsv/sdk

Version:

BSV Blockchain Software Development Kit

959 lines 94.9 kB
import * as Utils from '../../primitives/utils.js'; import calls from './WalletWireCalls.js'; import Certificate from '../../auth/certificates/Certificate.js'; /** * Processes incoming wallet calls received over a wallet wire, with a given wallet. */ export default class WalletWireProcessor { wallet; constructor(wallet) { this.wallet = wallet; } decodeOutpoint(reader) { const txidBytes = reader.read(32); const txid = Utils.toHex(txidBytes); const index = reader.readVarIntNum(); return `${txid}.${index}`; } encodeOutpoint(outpoint) { const writer = new Utils.Writer(); const [txid, index] = outpoint.split('.'); writer.write(Utils.toArray(txid, 'hex')); writer.writeVarIntNum(Number(index)); return writer.toArray(); } async transmitToWallet(message) { const messageReader = new Utils.Reader(message); try { // Read call code const callCode = messageReader.readUInt8(); // Map call code to call name const callName = calls[callCode]; // calls is enum if (callName === undefined || callName === '') { // Invalid call code throw new Error(`Invalid call code: ${callCode}`); } // Read originator length const originatorLength = messageReader.readUInt8(); const originatorBytes = messageReader.read(originatorLength); const originator = Utils.toUTF8(originatorBytes); // Read parameters const paramsReader = messageReader; // Remaining bytes switch (callName) { case 'createAction': { // Deserialize parameters from paramsReader const args = {}; // Read description const descriptionLength = paramsReader.readVarIntNum(); const descriptionBytes = paramsReader.read(descriptionLength); args.description = Utils.toUTF8(descriptionBytes); // tx const inputBeefLength = paramsReader.readVarIntNum(); if (inputBeefLength >= 0) { args.inputBEEF = paramsReader.read(inputBeefLength); // BEEF (Byte[]) } else { args.inputBEEF = undefined; } // Read inputs const inputsLength = paramsReader.readVarIntNum(); if (inputsLength >= 0) { args.inputs = []; for (let i = 0; i < inputsLength; i++) { const input = {}; // outpoint input.outpoint = this.decodeOutpoint(paramsReader); // unlockingScript / unlockingScriptLength const unlockingScriptLength = paramsReader.readVarIntNum(); if (unlockingScriptLength >= 0) { const unlockingScriptBytes = paramsReader.read(unlockingScriptLength); input.unlockingScript = Utils.toHex(unlockingScriptBytes); } else { input.unlockingScript = undefined; const unlockingScriptLengthValue = paramsReader.readVarIntNum(); input.unlockingScriptLength = unlockingScriptLengthValue; } // inputDescription const inputDescriptionLength = paramsReader.readVarIntNum(); const inputDescriptionBytes = paramsReader.read(inputDescriptionLength); input.inputDescription = Utils.toUTF8(inputDescriptionBytes); // sequenceNumber const sequenceNumber = paramsReader.readVarIntNum(); if (sequenceNumber >= 0) { input.sequenceNumber = sequenceNumber; } else { input.sequenceNumber = undefined; } args.inputs.push(input); } } else { args.inputs = undefined; } // Read outputs const outputsLength = paramsReader.readVarIntNum(); if (outputsLength >= 0) { args.outputs = []; for (let i = 0; i < outputsLength; i++) { const output = {}; // lockingScript const lockingScriptLength = paramsReader.readVarIntNum(); const lockingScriptBytes = paramsReader.read(lockingScriptLength); output.lockingScript = Utils.toHex(lockingScriptBytes); // satoshis output.satoshis = paramsReader.readVarIntNum(); // outputDescription const outputDescriptionLength = paramsReader.readVarIntNum(); const outputDescriptionBytes = paramsReader.read(outputDescriptionLength); output.outputDescription = Utils.toUTF8(outputDescriptionBytes); // basket const basketLength = paramsReader.readVarIntNum(); if (basketLength >= 0) { const basketBytes = paramsReader.read(basketLength); output.basket = Utils.toUTF8(basketBytes); } else { output.basket = undefined; } // customInstructions const customInstructionsLength = paramsReader.readVarIntNum(); if (customInstructionsLength >= 0) { const customInstructionsBytes = paramsReader.read(customInstructionsLength); output.customInstructions = Utils.toUTF8(customInstructionsBytes); } else { output.customInstructions = undefined; } // tags const tagsLength = paramsReader.readVarIntNum(); if (tagsLength >= 0) { output.tags = []; for (let j = 0; j < tagsLength; j++) { const tagLength = paramsReader.readVarIntNum(); const tagBytes = paramsReader.read(tagLength); const tag = Utils.toUTF8(tagBytes); output.tags.push(tag); } } else { output.tags = undefined; } args.outputs.push(output); } } else { args.outputs = undefined; } // lockTime const lockTime = paramsReader.readVarIntNum(); if (lockTime >= 0) { args.lockTime = lockTime; } else { args.lockTime = undefined; } // version const version = paramsReader.readVarIntNum(); if (version >= 0) { args.version = version; } else { args.version = undefined; } // labels const labelsLength = paramsReader.readVarIntNum(); if (labelsLength >= 0) { args.labels = []; for (let i = 0; i < labelsLength; i++) { const labelLength = paramsReader.readVarIntNum(); const labelBytes = paramsReader.read(labelLength); const label = Utils.toUTF8(labelBytes); args.labels.push(label); } } else { args.labels = undefined; } // options const optionsPresent = paramsReader.readInt8(); if (optionsPresent === 1) { args.options = {}; // signAndProcess const signAndProcessFlag = paramsReader.readInt8(); if (signAndProcessFlag === -1) { args.options.signAndProcess = undefined; } else { args.options.signAndProcess = signAndProcessFlag === 1; } // acceptDelayedBroadcast const acceptDelayedBroadcastFlag = paramsReader.readInt8(); if (acceptDelayedBroadcastFlag === -1) { args.options.acceptDelayedBroadcast = undefined; } else { args.options.acceptDelayedBroadcast = acceptDelayedBroadcastFlag === 1; } // trustSelf const trustSelfFlag = paramsReader.readInt8(); if (trustSelfFlag === -1) { args.options.trustSelf = undefined; } else if (trustSelfFlag === 1) { args.options.trustSelf = 'known'; } // knownTxids const knownTxidsLength = paramsReader.readVarIntNum(); if (knownTxidsLength >= 0) { args.options.knownTxids = []; for (let i = 0; i < knownTxidsLength; i++) { const txidBytes = paramsReader.read(32); const txid = Utils.toHex(txidBytes); args.options.knownTxids.push(txid); } } else { args.options.knownTxids = undefined; } // returnTXIDOnly const returnTXIDOnlyFlag = paramsReader.readInt8(); if (returnTXIDOnlyFlag === -1) { args.options.returnTXIDOnly = undefined; } else { args.options.returnTXIDOnly = returnTXIDOnlyFlag === 1; } // noSend const noSendFlag = paramsReader.readInt8(); if (noSendFlag === -1) { args.options.noSend = undefined; } else { args.options.noSend = noSendFlag === 1; } // noSendChange const noSendChangeLength = paramsReader.readVarIntNum(); if (noSendChangeLength >= 0) { args.options.noSendChange = []; for (let i = 0; i < noSendChangeLength; i++) { const outpoint = this.decodeOutpoint(paramsReader); args.options.noSendChange.push(outpoint); } } else { args.options.noSendChange = undefined; } // sendWith const sendWithLength = paramsReader.readVarIntNum(); if (sendWithLength >= 0) { args.options.sendWith = []; for (let i = 0; i < sendWithLength; i++) { const txidBytes = paramsReader.read(32); const txid = Utils.toHex(txidBytes); args.options.sendWith.push(txid); } } else { args.options.sendWith = undefined; } // randomizeOutputs const randomizeOutputsFlag = paramsReader.readInt8(); if (randomizeOutputsFlag === -1) { args.options.randomizeOutputs = undefined; } else { args.options.randomizeOutputs = randomizeOutputsFlag === 1; } } else { args.options = undefined; } // Call the method const createActionResult = await this.wallet.createAction(args, originator); // Serialize the result const resultWriter = new Utils.Writer(); // txid if (createActionResult.txid != null && createActionResult.txid !== '') { resultWriter.writeInt8(1); resultWriter.write(Utils.toArray(createActionResult.txid, 'hex')); } else { resultWriter.writeInt8(0); } // tx if (createActionResult.tx != null) { resultWriter.writeInt8(1); resultWriter.writeVarIntNum(createActionResult.tx.length); resultWriter.write(createActionResult.tx); } else { resultWriter.writeInt8(0); } // noSendChange if (createActionResult.noSendChange != null) { resultWriter.writeVarIntNum(createActionResult.noSendChange.length); for (const outpoint of createActionResult.noSendChange) { resultWriter.write(this.encodeOutpoint(outpoint)); } } else { resultWriter.writeVarIntNum(-1); } // sendWithResults if (createActionResult.sendWithResults != null) { resultWriter.writeVarIntNum(createActionResult.sendWithResults.length); for (const result of createActionResult.sendWithResults) { resultWriter.write(Utils.toArray(result.txid, 'hex')); let statusCode; if (result.status === 'unproven') statusCode = 1; else if (result.status === 'sending') statusCode = 2; else if (result.status === 'failed') statusCode = 3; resultWriter.writeInt8(statusCode); } } else { resultWriter.writeVarIntNum(-1); } // signableTransaction if (createActionResult.signableTransaction != null) { resultWriter.writeInt8(1); resultWriter.writeVarIntNum(createActionResult.signableTransaction.tx.length); resultWriter.write(createActionResult.signableTransaction.tx); const referenceBytes = Utils.toArray(createActionResult.signableTransaction.reference, 'base64'); resultWriter.writeVarIntNum(referenceBytes.length); resultWriter.write(referenceBytes); } else { resultWriter.writeInt8(0); } // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 responseWriter.write(resultWriter.toArray()); return responseWriter.toArray(); } case 'signAction': { const args = {}; // Deserialize spends const spendCount = paramsReader.readVarIntNum(); args.spends = {}; for (let i = 0; i < spendCount; i++) { const inputIndex = paramsReader.readVarIntNum(); const spend = {}; // unlockingScript const unlockingScriptLength = paramsReader.readVarIntNum(); const unlockingScriptBytes = paramsReader.read(unlockingScriptLength); spend.unlockingScript = Utils.toHex(unlockingScriptBytes); // sequenceNumber const sequenceNumber = paramsReader.readVarIntNum(); if (sequenceNumber >= 0) { spend.sequenceNumber = sequenceNumber; } else { spend.sequenceNumber = undefined; } args.spends[inputIndex] = spend; } // Deserialize reference const referenceLength = paramsReader.readVarIntNum(); const referenceBytes = paramsReader.read(referenceLength); args.reference = Utils.toBase64(referenceBytes); // Deserialize options const optionsPresent = paramsReader.readInt8(); if (optionsPresent === 1) { args.options = {}; // acceptDelayedBroadcast const acceptDelayedBroadcastFlag = paramsReader.readInt8(); if (acceptDelayedBroadcastFlag === -1) { args.options.acceptDelayedBroadcast = undefined; } else { args.options.acceptDelayedBroadcast = acceptDelayedBroadcastFlag === 1; } // returnTXIDOnly const returnTXIDOnlyFlag = paramsReader.readInt8(); if (returnTXIDOnlyFlag === -1) { args.options.returnTXIDOnly = undefined; } else { args.options.returnTXIDOnly = returnTXIDOnlyFlag === 1; } // noSend const noSendFlag = paramsReader.readInt8(); if (noSendFlag === -1) { args.options.noSend = undefined; } else { args.options.noSend = noSendFlag === 1; } // sendWith const sendWithLength = paramsReader.readVarIntNum(); if (sendWithLength >= 0) { args.options.sendWith = []; for (let i = 0; i < sendWithLength; i++) { const txidBytes = paramsReader.read(32); const txid = Utils.toHex(txidBytes); args.options.sendWith.push(txid); } } else { args.options.sendWith = undefined; } } else { args.options = undefined; } // Call the method const signActionResult = await this.wallet.signAction(args, originator); // Serialize the result const resultWriter = new Utils.Writer(); // txid if (signActionResult.txid != null && signActionResult.txid !== '') { resultWriter.writeInt8(1); resultWriter.write(Utils.toArray(signActionResult.txid, 'hex')); } else { resultWriter.writeInt8(0); } // tx if (signActionResult.tx != null) { resultWriter.writeInt8(1); resultWriter.writeVarIntNum(signActionResult.tx.length); resultWriter.write(signActionResult.tx); } else { resultWriter.writeInt8(0); } // sendWithResults if (signActionResult.sendWithResults != null) { resultWriter.writeVarIntNum(signActionResult.sendWithResults.length); for (const result of signActionResult.sendWithResults) { resultWriter.write(Utils.toArray(result.txid, 'hex')); let statusCode; if (result.status === 'unproven') statusCode = 1; else if (result.status === 'sending') statusCode = 2; else if (result.status === 'failed') statusCode = 3; resultWriter.writeInt8(statusCode); } } else { resultWriter.writeVarIntNum(-1); } // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 responseWriter.write(resultWriter.toArray()); return responseWriter.toArray(); } case 'abortAction': { // Deserialize reference const referenceBytes = paramsReader.read(); const reference = Utils.toBase64(referenceBytes); // Call the method await this.wallet.abortAction({ reference }, originator); // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 return responseWriter.toArray(); } case 'listActions': { const args = {}; // Deserialize labels const labelsLength = paramsReader.readVarIntNum(); args.labels = []; for (let i = 0; i < labelsLength; i++) { const labelLength = paramsReader.readVarIntNum(); const labelBytes = paramsReader.read(labelLength); args.labels.push(Utils.toUTF8(labelBytes)); } // Deserialize labelQueryMode const labelQueryModeFlag = paramsReader.readInt8(); if (labelQueryModeFlag === -1) { args.labelQueryMode = undefined; } else if (labelQueryModeFlag === 1) { args.labelQueryMode = 'any'; } else if (labelQueryModeFlag === 2) { args.labelQueryMode = 'all'; } // Deserialize include options const includeOptionsNames = [ 'includeLabels', 'includeInputs', 'includeInputSourceLockingScripts', 'includeInputUnlockingScripts', 'includeOutputs', 'includeOutputLockingScripts' ]; for (const optionName of includeOptionsNames) { const optionFlag = paramsReader.readInt8(); if (optionFlag === -1) { args[optionName] = undefined; } else { args[optionName] = optionFlag === 1; } } // Deserialize limit const limit = paramsReader.readVarIntNum(); if (limit >= 0) { args.limit = limit; } else { args.limit = undefined; } // Deserialize offset const offset = paramsReader.readVarIntNum(); if (offset >= 0) { args.offset = offset; } else { args.offset = undefined; } // Deserialize seekPermission const seekPermission = paramsReader.readInt8(); if (seekPermission >= 0) { args.seekPermission = seekPermission === 1; } else { args.seekPermission = undefined; } // Call the method const listActionsResult = await this.wallet.listActions(args, originator); // Serialize the result const resultWriter = new Utils.Writer(); // totalActions resultWriter.writeVarIntNum(listActionsResult.totalActions); // actions for (const action of listActionsResult.actions) { // txid resultWriter.write(Utils.toArray(action.txid, 'hex')); // satoshis resultWriter.writeVarIntNum(action.satoshis); // status let statusCode; switch (action.status) { case 'completed': statusCode = 1; break; case 'unprocessed': statusCode = 2; break; case 'sending': statusCode = 3; break; case 'unproven': statusCode = 4; break; case 'unsigned': statusCode = 5; break; case 'nosend': statusCode = 6; break; case 'nonfinal': statusCode = 7; break; case 'failed': statusCode = 8; break; default: statusCode = -1; break; } resultWriter.writeInt8(statusCode); // isOutgoing resultWriter.writeInt8(action.isOutgoing ? 1 : 0); // description const descriptionBytes = Utils.toArray(action.description, 'utf8'); resultWriter.writeVarIntNum(descriptionBytes.length); resultWriter.write(descriptionBytes); // labels if (action.labels !== undefined) { resultWriter.writeVarIntNum(action.labels.length); for (const label of action.labels) { const labelBytes = Utils.toArray(label, 'utf8'); resultWriter.writeVarIntNum(labelBytes.length); resultWriter.write(labelBytes); } } else { resultWriter.writeVarIntNum(-1); } // version resultWriter.writeVarIntNum(action.version); // lockTime resultWriter.writeVarIntNum(action.lockTime); // inputs if (action.inputs !== undefined) { resultWriter.writeVarIntNum(action.inputs.length); for (const input of action.inputs) { // sourceOutpoint resultWriter.write(this.encodeOutpoint(input.sourceOutpoint)); // sourceSatoshis resultWriter.writeVarIntNum(input.sourceSatoshis); // sourceLockingScript if (input.sourceLockingScript !== undefined) { const sourceLockingScriptBytes = Utils.toArray(input.sourceLockingScript, 'hex'); resultWriter.writeVarIntNum(sourceLockingScriptBytes.length); resultWriter.write(sourceLockingScriptBytes); } else { resultWriter.writeVarIntNum(-1); } // unlockingScript if (input.unlockingScript !== undefined) { const unlockingScriptBytes = Utils.toArray(input.unlockingScript, 'hex'); resultWriter.writeVarIntNum(unlockingScriptBytes.length); resultWriter.write(unlockingScriptBytes); } else { resultWriter.writeVarIntNum(-1); } // inputDescription const inputDescriptionBytes = Utils.toArray(input.inputDescription, 'utf8'); resultWriter.writeVarIntNum(inputDescriptionBytes.length); resultWriter.write(inputDescriptionBytes); // sequenceNumber resultWriter.writeVarIntNum(input.sequenceNumber); } } else { resultWriter.writeVarIntNum(-1); } // outputs if (action.outputs !== undefined) { resultWriter.writeVarIntNum(action.outputs.length); for (const output of action.outputs) { // outputIndex resultWriter.writeVarIntNum(output.outputIndex); // satoshis resultWriter.writeVarIntNum(output.satoshis); // lockingScript if (output.lockingScript !== undefined) { const lockingScriptBytes = Utils.toArray(output.lockingScript, 'hex'); resultWriter.writeVarIntNum(lockingScriptBytes.length); resultWriter.write(lockingScriptBytes); } else { resultWriter.writeVarIntNum(-1); } // spendable resultWriter.writeInt8(output.spendable ? 1 : 0); // outputDescription const outputDescriptionBytes = Utils.toArray(output.outputDescription, 'utf8'); resultWriter.writeVarIntNum(outputDescriptionBytes.length); resultWriter.write(outputDescriptionBytes); // basket if (output.basket !== undefined) { const basketBytes = Utils.toArray(output.basket, 'utf8'); resultWriter.writeVarIntNum(basketBytes.length); resultWriter.write(basketBytes); } else { resultWriter.writeVarIntNum(-1); } // tags if (output.tags !== undefined) { resultWriter.writeVarIntNum(output.tags.length); for (const tag of output.tags) { const tagBytes = Utils.toArray(tag, 'utf8'); resultWriter.writeVarIntNum(tagBytes.length); resultWriter.write(tagBytes); } } else { resultWriter.writeVarIntNum(-1); } // customInstructions if (output.customInstructions !== undefined) { const customInstructionsBytes = Utils.toArray(output.customInstructions, 'utf8'); resultWriter.writeVarIntNum(customInstructionsBytes.length); resultWriter.write(customInstructionsBytes); } else { resultWriter.writeVarIntNum(-1); } } } else { resultWriter.writeVarIntNum(-1); } } const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 responseWriter.write(resultWriter.toArray()); return responseWriter.toArray(); } case 'internalizeAction': { const args = {}; // Read tx const txLength = paramsReader.readVarIntNum(); args.tx = paramsReader.read(txLength); // Read outputs const outputsLength = paramsReader.readVarIntNum(); args.outputs = []; for (let i = 0; i < outputsLength; i++) { const output = {}; // outputIndex output.outputIndex = paramsReader.readVarIntNum(); // protocol const protocolFlag = paramsReader.readUInt8(); if (protocolFlag === 1) { output.protocol = 'wallet payment'; output.paymentRemittance = {}; // senderIdentityKey const senderIdentityKeyBytes = paramsReader.read(33); output.paymentRemittance.senderIdentityKey = Utils.toHex(senderIdentityKeyBytes); // derivationPrefix const derivationPrefixLength = paramsReader.readVarIntNum(); const derivationPrefixBytes = paramsReader.read(derivationPrefixLength); output.paymentRemittance.derivationPrefix = Utils.toBase64(derivationPrefixBytes); // derivationSuffix const derivationSuffixLength = paramsReader.readVarIntNum(); const derivationSuffixBytes = paramsReader.read(derivationSuffixLength); output.paymentRemittance.derivationSuffix = Utils.toBase64(derivationSuffixBytes); } else if (protocolFlag === 2) { output.protocol = 'basket insertion'; output.insertionRemittance = {}; // basket const basketLength = paramsReader.readVarIntNum(); const basketBytes = paramsReader.read(basketLength); output.insertionRemittance.basket = Utils.toUTF8(basketBytes); // customInstructions const customInstructionsLength = paramsReader.readVarIntNum(); if (customInstructionsLength >= 0) { const customInstructionsBytes = paramsReader.read(customInstructionsLength); output.insertionRemittance.customInstructions = Utils.toUTF8(customInstructionsBytes); } // tags const tagsLength = paramsReader.readVarIntNum(); if (tagsLength > 0) { output.insertionRemittance.tags = []; for (let j = 0; j < tagsLength; j++) { const tagLength = paramsReader.readVarIntNum(); const tagBytes = paramsReader.read(tagLength); output.insertionRemittance.tags.push(Utils.toUTF8(tagBytes)); } } else { output.insertionRemittance.tags = []; } } args.outputs.push(output); } const numberOfLabels = paramsReader.readVarIntNum(); if (numberOfLabels >= 0) { args.labels = []; for (let i = 0; i < numberOfLabels; i++) { const labelLength = paramsReader.readVarIntNum(); args.labels.push(Utils.toUTF8(paramsReader.read(labelLength))); } } const descriptionLength = paramsReader.readVarIntNum(); args.description = Utils.toUTF8(paramsReader.read(descriptionLength)); // Deserialize seekPermission const seekPermission = paramsReader.readInt8(); if (seekPermission >= 0) { args.seekPermission = seekPermission === 1; } else { args.seekPermission = undefined; } // Call the method await this.wallet.internalizeAction(args, originator); // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 return responseWriter.toArray(); } case 'listOutputs': { const args = {}; // Deserialize basket const basketLength = paramsReader.readVarIntNum(); const basketBytes = paramsReader.read(basketLength); args.basket = Utils.toUTF8(basketBytes); // Deserialize tags const tagsLength = paramsReader.readVarIntNum(); if (tagsLength > 0) { args.tags = []; for (let i = 0; i < tagsLength; i++) { const tagLength = paramsReader.readVarIntNum(); const tagBytes = paramsReader.read(tagLength); args.tags.push(Utils.toUTF8(tagBytes)); } } else { args.tags = undefined; } // Deserialize tagQueryMode const tagQueryModeFlag = paramsReader.readInt8(); if (tagQueryModeFlag === 1) { args.tagQueryMode = 'all'; } else if (tagQueryModeFlag === 2) { args.tagQueryMode = 'any'; } else { args.tagQueryMode = undefined; } // Deserialize include const includeFlag = paramsReader.readInt8(); if (includeFlag === 1) { args.include = 'locking scripts'; } else if (includeFlag === 2) { args.include = 'entire transactions'; } else { args.include = undefined; } // Deserialize includeCustomInstructions const includeCustomInstructionsFlag = paramsReader.readInt8(); if (includeCustomInstructionsFlag === -1) { args.includeCustomInstructions = undefined; } else { args.includeCustomInstructions = includeCustomInstructionsFlag === 1; } // Deserialize includeTags const includeTagsFlag = paramsReader.readInt8(); if (includeTagsFlag === -1) { args.includeTags = undefined; } else { args.includeTags = includeTagsFlag === 1; } // Deserialize includeLabels const includeLabelsFlag = paramsReader.readInt8(); if (includeLabelsFlag === -1) { args.includeLabels = undefined; } else { args.includeLabels = includeLabelsFlag === 1; } // Deserialize limit const limit = paramsReader.readVarIntNum(); if (limit >= 0) { args.limit = limit; } else { args.limit = undefined; } // Deserialize offset const offset = paramsReader.readVarIntNum(); if (offset >= 0) { args.offset = offset; } else { args.offset = undefined; } // Deserialize seekPermission const seekPermission = paramsReader.readInt8(); if (seekPermission >= 0) { args.seekPermission = seekPermission === 1; } else { args.seekPermission = undefined; } // Call the method const listOutputsResult = await this.wallet.listOutputs(args, originator); // Serialize the result const resultWriter = new Utils.Writer(); // totalOutputs resultWriter.writeVarIntNum(listOutputsResult.totalOutputs); // BEEF length and BEEF or -1 if (listOutputsResult.BEEF != null) { resultWriter.writeVarIntNum(listOutputsResult.BEEF.length); resultWriter.write(listOutputsResult.BEEF); } else { resultWriter.writeVarIntNum(-1); } // outputs for (const output of listOutputsResult.outputs) { // outpoint resultWriter.write(this.encodeOutpoint(output.outpoint)); // satoshis resultWriter.writeVarIntNum(output.satoshis); // lockingScript if (output.lockingScript !== undefined) { const lockingScriptBytes = Utils.toArray(output.lockingScript, 'hex'); resultWriter.writeVarIntNum(lockingScriptBytes.length); resultWriter.write(lockingScriptBytes); } else { resultWriter.writeVarIntNum(-1); } // customInstructions if (output.customInstructions !== undefined) { const customInstructionsBytes = Utils.toArray(output.customInstructions, 'utf8'); resultWriter.writeVarIntNum(customInstructionsBytes.length); resultWriter.write(customInstructionsBytes); } else { resultWriter.writeVarIntNum(-1); } // tags if (output.tags !== undefined) { resultWriter.writeVarIntNum(output.tags.length); for (const tag of output.tags) { const tagBytes = Utils.toArray(tag, 'utf8'); resultWriter.writeVarIntNum(tagBytes.length); resultWriter.write(tagBytes); } } else { resultWriter.writeVarIntNum(-1); } // labels if (output.labels !== undefined) { resultWriter.writeVarIntNum(output.labels.length); for (const label of output.labels) { const labelBytes = Utils.toArray(label, 'utf8'); resultWriter.writeVarIntNum(labelBytes.length); resultWriter.write(labelBytes); } } else { resultWriter.writeVarIntNum(-1); } } // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 responseWriter.write(resultWriter.toArray()); return responseWriter.toArray(); } case 'relinquishOutput': { const args = {}; // Deserialize basket const basketLength = paramsReader.readVarIntNum(); const basketBytes = paramsReader.read(basketLength); args.basket = Utils.toUTF8(basketBytes); // Deserialize outpoint args.output = this.decodeOutpoint(paramsReader); // Call the method await this.wallet.relinquishOutput(args, originator); // Return success code and result const responseWriter = new Utils.Writer(); responseWriter.writeUInt8(0); // errorByte = 0 return responseWriter.toArray(); } case 'getPublicKey': { const args = {}; // Deserialize identityKey flag const ide