PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-avaxp/src/lib
Просмотр файла: exportInCTxBuilder.ts
import { BuildTransactionError, NotSupported, TransactionType } from '@bitgo/sdk-core';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { BN, Buffer as BufferAvax } from 'avalanche';
import {
AmountOutput,
EVMConstants,
EVMInput,
Tx as EVMTx,
ExportTx,
SECPTransferOutput,
SelectCredentialClass,
TransferableOutput,
UnsignedTx,
} from 'avalanche/dist/apis/evm';
import { AtomicInCTransactionBuilder } from './atomicInCTransactionBuilder';
import { DeprecatedTransaction } from './deprecatedTransaction';
import { DecodedUtxoObj, DeprecatedBaseTx, DeprecatedTx } from './iface';
import utils from './utils';
export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
private _amount: BN;
private _nonce: BN;
constructor(_coinConfig: Readonly<CoinConfig>) {
super(_coinConfig);
}
/**
* Utxos are not required in Export Tx in C-Chain.
* Override utxos to prevent used by throwing a error.
*
* @param {DecodedUtxoObj[]} value ignored
*/
utxos(value: DecodedUtxoObj[]): this {
throw new BuildTransactionError('utxos are not required in Export Tx in C-Chain');
}
/**
* Amount is a long that specifies the quantity of the asset that this output owns. Must be positive.
* The transaction output amount add a fixed fee that will be paid upon import.
*
* @param {BN | string} amount The withdrawal amount
*/
amount(amount: BN | string): this {
const amountBN = BN.isBN(amount) ? amount : new BN(amount);
this.validateAmount(amountBN);
this._amount = amountBN;
return this;
}
/**
* Set the nonce of C-Chain sender address
*
* @param {number | string} nonce - number that can be only used once
*/
nonce(nonce: number | string): this {
const nonceBN = new BN(nonce);
this.validateNonce(nonceBN);
this._nonce = nonceBN;
return this;
}
/**
* Export tx target P wallet.
*
* @param pAddresses
*/
to(pAddresses: string | string[]): this {
const pubKeys = pAddresses instanceof Array ? pAddresses : pAddresses.split('~');
this.transaction._to = pubKeys.map(utils.parseAddress);
return this;
}
protected get transactionType(): TransactionType {
return TransactionType.Export;
}
initBuilder(tx: DeprecatedTx): this {
const baseTx: DeprecatedBaseTx = tx.getUnsignedTx().getTransaction();
if (
baseTx.getNetworkID() !== this.transaction._networkID ||
!baseTx.getBlockchainID().equals(this.transaction._blockchainID)
) {
throw new Error('Network or blockchain is not equals');
}
if (!this.verifyTxType(baseTx)) {
throw new NotSupported('Transaction cannot be parsed or has an unsupported transaction type');
}
// The outputs is a multisign P-Chain address result.
// It's expected to have only one outputs to the destination P-Chain address.
const outputs = baseTx.getExportedOutputs();
if (outputs.length !== 1) {
throw new BuildTransactionError('Transaction can have one output');
}
const output = outputs[0];
if (!output.getAssetID().equals(this.transaction._assetId)) {
throw new Error('AssetID are not equals');
}
// The inputs is not an utxo.
// It's expected to have only one input form C-Chain address.
const inputs = baseTx.getInputs();
if (inputs.length !== 1) {
throw new BuildTransactionError('Transaction can have one inputs');
}
const input = inputs[0];
this.transaction._to = output.getOutput().getAddresses();
const inputAmount = new BN((input as any).amount);
const outputAmount = (output.getOutput() as AmountOutput).getAmount();
const fee = inputAmount.sub(outputAmount);
this._amount = outputAmount;
this.transaction._fee.feeRate = fee.toNumber() - Number(this.fixedFee);
this.transaction._fee.fee = fee.toString();
this.transaction._fee.size = 1;
this.transaction._fromAddresses = [input.getAddress()];
this._nonce = new BN((input as any).nonce);
this.transaction.setTransaction(tx);
return this;
}
static verifyTxType(baseTx: DeprecatedBaseTx): baseTx is ExportTx {
return baseTx.getTypeID() === EVMConstants.EXPORTTX;
}
verifyTxType(baseTx: DeprecatedBaseTx): baseTx is ExportTx {
return ExportInCTxBuilder.verifyTxType(baseTx);
}
/**
* Build the export in C-chain transaction
* @protected
*/
protected buildAvaxTransaction(): void {
// if tx has credentials, tx shouldn't change
if (this.transaction.hasCredentials) return;
if (this._amount === undefined) {
throw new Error('amount is required');
}
if (this.transaction._fromAddresses.length !== 1) {
throw new Error('sender is one and required');
}
if (this.transaction._to.length === 0) {
throw new Error('to is required');
}
if (!this.transaction._fee.feeRate) {
throw new Error('fee rate is required');
}
if (!this._nonce === undefined) {
throw new Error('nonce is required');
}
const txFee = Number(this.fixedFee);
const fee: number = this.transaction._fee.feeRate + txFee;
this.transaction._fee.fee = fee.toString();
this.transaction._fee.size = 1;
const input = new EVMInput(
this.transaction._fromAddresses[0],
this._amount.addn(fee),
this.transaction._assetId,
this._nonce
);
input.addSignatureIdx(0, this.transaction._fromAddresses[0]);
this.transaction.setTransaction(
new EVMTx(
new UnsignedTx(
new ExportTx(
this.transaction._networkID,
this.transaction._blockchainID,
this._externalChainId,
[input],
[
new TransferableOutput(
this.transaction._assetId,
new SECPTransferOutput(
this._amount,
this.transaction._to,
this.transaction._locktime,
this.transaction._threshold
)
),
]
)
),
// TODO(BG-56700): Improve canSign by check in addresses in empty credentials match signer
[SelectCredentialClass(input.getCredentialID(), [''].map(utils.createSig))]
)
);
}
/** @inheritdoc */
protected fromImplementation(rawTransaction: string): DeprecatedTransaction {
const tx = new EVMTx();
tx.fromBuffer(BufferAvax.from(rawTransaction, 'hex'));
this.initBuilder(tx);
return this.transaction;
}
/**
* Check the amount is positive.
* @param amount
*/
validateNonce(nonce: BN): void {
if (nonce.ltn(0)) {
throw new BuildTransactionError('Nonce must be greater or equal than 0');
}
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!