PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-avaxp/src/lib
Просмотр файла: utxoEngine.ts
import { DecodedUtxoObj, SECP256K1_Transfer_Output } from './iface';
import { BN, Buffer as BufferAvax } from 'avalanche';
import { Signature } from 'avalanche/dist/common';
import utils from './utils';
import { BuildTransactionError } from '@bitgo/sdk-core';
import { StandardAmountInput, StandardTransferableInput } from 'avalanche/dist/common/input';
import { avaxSerial } from '@bitgo-forks/avalanchejs';
export interface InputData {
amount: BN;
txidBuf: BufferAvax;
outputIdx: BufferAvax;
signaturesIdx: number[];
signatures: Signature[];
}
/**
* Inputs can be controlled but outputs get reordered in transactions
* In order to make sure that the mapping is always correct we create an addressIndex which matches to the appropriate
* signatureIdx
* @param {StandardTransferableInput[]} utxos as transaction ins.
* @returns the list of UTXOs
*/
export function deprecatedRecoverUtxos(utxos: StandardTransferableInput[]): DecodedUtxoObj[] {
return utxos.map((utxo) => {
const secpInput = utxo.getInput() as StandardAmountInput;
// use the same addressesIndex as existing ones in the inputs
const addressesIndex: number[] = secpInput.getSigIdxs().map((s) => s.toBuffer().readUInt32BE(0));
return {
outputID: SECP256K1_Transfer_Output,
outputidx: utils.outputidxBufferToNumber(utxo.getOutputIdx()),
txid: utils.cb58Encode(utxo.getTxID()),
amount: secpInput.getAmount().toString(),
threshold: addressesIndex.length,
addresses: [], // this is empty since the inputs from deserialized transaction don't contain addresses
addressesIndex,
};
});
}
/**
* Inputs can be controlled but outputs get reordered in transactions
* In order to make sure that the mapping is always correct we create an addressIndex which matches to the appropriate
* signatureIdx
* @param {avaxSerial.TransferableInput[]} utxos as transaction ins.
* @returns the list of UTXOs
*/
export function recoverUtxos(utxos: avaxSerial.TransferableInput[]): DecodedUtxoObj[] {
return utxos.map((utxo) => {
const input = utxo.input;
// use the same addressesIndex as existing ones in the inputs
const addressesIndex: number[] = utxo.sigIndicies();
return {
outputID: SECP256K1_Transfer_Output,
outputidx: utxo.utxoID.outputIdx.value().toString(),
txid: utxo.utxoID.txID.value(),
amount: input.amount().toString(),
threshold: addressesIndex.length,
addresses: [], // this is empty since the inputs from deserialized transaction don't contain addresses
addressesIndex,
};
});
}
/**
* Convert Utxos into inputs data. Input Objects changes regarding chains. This method return a plain object to be mapped late in chain input.
* Sender is a list of owners address and utxo address must contains all of them.
* Signers is a list of sender cut it in threshold size. Firsts senders are the signers.
*
* Output always get reordered we want to make sure we can always add signatures in the correct location.
* Signatures array store signers address of the expected signature. Tx sign replace the address for the signature.
* So the location of the signatures is guaranteed.
*
* To find the correct location for the signature, we use the output's addresses to create the signatureIdx in the order that we desire
* 0: user key, 1: hsm key, 2: recovery key
*
* @param utxos
* @param sender array of addresses
* @param threshold number of signatures required
* @return {
* inputs: InputData[];
* amount: BN;
* } as total amount and inputs with signatures as signers address to be replaced.
*/
export function utxoToInput(
utxos: DecodedUtxoObj[],
sender: BufferAvax[],
threshold = 2
): {
inputs: InputData[];
amount: BN;
} {
// amount spent so far
let currentTotal: BN = new BN(0);
const inputs = utxos
.filter((utxo) => utxo && utxo.outputID === SECP256K1_Transfer_Output)
.map((utxo) => {
// validate the utxos
const utxoAddresses: BufferAvax[] = utxo.addresses.map((a) => utils.parseAddress(a));
const addressesIndex = sender.map((a) => utxoAddresses.findIndex((u) => a.equals(u)));
// addressesIndex should never have a mismatch
if (addressesIndex.includes(-1)) {
throw new BuildTransactionError('Addresses are inconsistent: ' + utxo.txid);
}
if (utxo.threshold !== threshold) {
throw new BuildTransactionError('Threshold is inconsistent');
}
const txidBuf: BufferAvax = utils.cb58Decode(utxo.txid);
const amount: BN = new BN(utxo.amount);
const outputIdx: BufferAvax = utils.outputidxNumberToBuffer(utxo.outputidx);
currentTotal = currentTotal.add(amount);
const signers = addressesIndex
.slice(0, threshold)
.map((utxoIndex, senderIndex) => ({ utxoIndex, senderIndex }))
.sort((a, b) => a.utxoIndex - b.utxoIndex);
const signatures = signers.map(({ senderIndex }) =>
// TODO(BG-56700): Improve canSign by check in addresses in empty credentials match signer
// HSM require empty signature.
utils.createSig(senderIndex == 1 ? '' : sender[senderIndex].toString('hex'))
);
const signaturesIdx = signers.map(({ utxoIndex }) => utxoIndex);
return { amount, txidBuf, outputIdx, signaturesIdx, signatures };
});
return { inputs, amount: currentTotal };
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!