PHP WebShell
Текущая директория: /opt/BitGoJS/modules/abstract-cosmos/src/lib
Просмотр файла: transactionBuilder.ts
import {
BaseAddress,
BaseKey,
BaseTransactionBuilder,
BuildTransactionError,
InvalidTransactionError,
PublicKey as BasePublicKey,
SigningError,
TransactionType,
} from '@bitgo/sdk-core';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { Secp256k1 } from '@cosmjs/crypto';
import { makeSignBytes } from '@cosmjs/proto-signing';
import BigNumber from 'bignumber.js';
import { CosmosTransactionMessage, FeeData, MessageData } from './iface';
import { CosmosKeyPair as KeyPair } from './keyPair';
import { CosmosTransaction } from './transaction';
import { CosmosUtils } from './utils';
export abstract class CosmosTransactionBuilder<CustomMessage = never> extends BaseTransactionBuilder {
protected _transaction: CosmosTransaction<CustomMessage>;
protected _sequence: number;
protected _messages: MessageData<CustomMessage>[];
protected _gasBudget: FeeData;
protected _accountNumber?: number;
protected _signature: Buffer;
protected _chainId?: string;
protected _publicKey?: string;
protected _signer: KeyPair;
protected _memo?: string;
protected _utils: CosmosUtils<CustomMessage>;
constructor(_coinConfig: Readonly<CoinConfig>, _utils: CosmosUtils<CustomMessage>) {
super(_coinConfig);
this._transaction = new CosmosTransaction(_coinConfig, _utils);
}
/**
* The transaction type.
*/
protected abstract get transactionType(): TransactionType;
/** @inheritdoc */
protected get transaction(): CosmosTransaction<CustomMessage> {
return this._transaction;
}
/** @inheritdoc */
protected set transaction(transaction: CosmosTransaction<CustomMessage>) {
this._transaction = transaction;
}
/** @inheritDoc */
addSignature(publicKey: BasePublicKey, signature: Buffer): void {
this._signature = signature;
this._publicKey = publicKey.pub;
}
/**
* Sets sequence of this transaction.
* @param {number} sequence - sequence data for tx signer
* @returns {TransactionBuilder} This transaction builder
*/
sequence(sequence: number): this {
this._utils.validateSequence(sequence);
this._sequence = sequence;
return this;
}
/**
* Sets messages to the transaction body. Message type will be different based on the transaction type
* - For @see TransactionType.StakingActivate required type is @see DelegateOrUndelegeteMessage
* - For @see TransactionType.StakingDeactivate required type is @see DelegateOrUndelegeteMessage
* - For @see TransactionType.Send required type is @see SendMessage
* - For @see TransactionType.StakingWithdraw required type is @see WithdrawDelegatorRewardsMessage
* - For @see TransactionType.ContractCall required type is @see ExecuteContractMessage
* @param {CosmosTransactionMessage[]} messages
* @returns {TransactionBuilder} This transaction builder
*/
abstract messages(messages: CosmosTransactionMessage<CustomMessage>[]): this;
publicKey(publicKey: string | undefined): this {
this._publicKey = publicKey;
return this;
}
accountNumber(accountNumber: number | undefined): this {
this._accountNumber = accountNumber;
return this;
}
chainId(chainId: string | undefined): this {
this._chainId = chainId;
return this;
}
memo(memo: string | undefined): this {
this._memo = memo;
return this;
}
/** @inheritdoc */
protected signImplementation(key: BaseKey): CosmosTransaction<CustomMessage> {
this.validateKey(key);
if (this._accountNumber === undefined) {
throw new SigningError('accountNumber is required before signing');
}
if (this._chainId === undefined) {
throw new SigningError('chainId is required before signing');
}
this._signer = new KeyPair({ prv: key.key });
this._publicKey = this._signer.getKeys().pub;
return this.transaction;
}
/** @inheritdoc */
validateValue(value: BigNumber): void {
if (value.isLessThan(0)) {
throw new BuildTransactionError('Value cannot be less than zero');
}
}
/** @inheritdoc */
validateKey(key: BaseKey): void {
try {
new KeyPair({ prv: key.key });
} catch {
throw new BuildTransactionError(`Key validation failed`);
}
}
/**
* Sets gas budget of this transaction
* Gas budget consist of fee amount and gas limit. Division feeAmount/gasLimit represents
* the gas-fee and it should be more than minimum required gas-fee to process the transaction
* @param {FeeData} gasBudget
* @returns {TransactionBuilder} this transaction builder
*/
gasBudget(gasBudget: FeeData): this {
this._utils.validateGasBudget(gasBudget);
this._gasBudget = gasBudget;
return this;
}
/**
* Initialize the transaction builder fields using the decoded transaction data
* @param {CosmosTransaction} tx the transaction data
*/
initBuilder(tx: CosmosTransaction<CustomMessage>): void {
this._transaction = tx;
const txData = tx.toJson();
this.gasBudget(txData.gasBudget);
this.messages(
txData.sendMessages.map((message) => {
return message.value;
})
);
this.sequence(txData.sequence);
this.publicKey(txData.publicKey);
this.accountNumber(txData.accountNumber);
this.chainId(txData.chainId);
this.memo(txData.memo);
if (tx.signature && tx.signature.length > 0) {
this.addSignature({ pub: txData.publicKey } as any, Buffer.from(tx.signature[0], 'hex'));
}
}
/**
* Creates a new CosmosTransaction instance
*/
protected newTransaction(): CosmosTransaction<CustomMessage> {
return new CosmosTransaction<CustomMessage>(this._coinConfig, this._utils);
}
/** @inheritdoc */
protected fromImplementation(rawTransaction: string): CosmosTransaction<CustomMessage> {
const tx = this.newTransaction();
tx.enrichTransactionDetailsFromRawTransaction(rawTransaction);
this.initBuilder(tx);
return this.transaction;
}
/** @inheritdoc */
protected async buildImplementation(): Promise<CosmosTransaction<CustomMessage>> {
this.transaction.transactionType = this.transactionType;
if (this._accountNumber) {
this.transaction.accountNumber = this._accountNumber;
}
if (this._chainId) {
this.transaction.chainId = this._chainId;
}
this.transaction.cosmosLikeTransaction = this._utils.createTransaction(
this._sequence,
this._messages,
this._gasBudget,
this._publicKey,
this._memo
);
const privateKey = this._signer?.getPrivateKey();
if (privateKey !== undefined && this.transaction.cosmosLikeTransaction.publicKey !== undefined) {
const signDoc = this._utils.createSignDoc(
this.transaction.cosmosLikeTransaction,
this._accountNumber,
this._chainId
);
const txnHash = Uint8Array.from(this._utils.getHashFunction().update(makeSignBytes(signDoc)).digest());
const signature = await Secp256k1.createSignature(txnHash, privateKey);
const compressedSig = Buffer.concat([signature.r(), signature.s()]);
this.addSignature({ pub: this.transaction.cosmosLikeTransaction.publicKey }, compressedSig);
}
if (this._signature !== undefined) {
this.transaction.addSignature(this._signature.toString('hex'));
this.transaction.cosmosLikeTransaction = this._utils.createTransactionWithHash(
this._sequence,
this._messages,
this._gasBudget,
this._publicKey,
this._signature,
this._memo
);
}
this.transaction.loadInputsAndOutputs();
return this.transaction;
}
/** @inheritdoc */
validateAddress(address: BaseAddress, addressFormat?: string): void {
if (!(this._utils.isValidAddress(address.address) || this._utils.isValidValidatorAddress(address.address))) {
throw new BuildTransactionError('transactionBuilder: address isValidAddress check failed: ' + address.address);
}
}
/** @inheritdoc */
validateRawTransaction(rawTransaction: string): void {
if (!rawTransaction) {
throw new InvalidTransactionError('Invalid raw transaction: Undefined rawTransaction');
}
try {
} catch (e) {
throw new InvalidTransactionError('Invalid raw transaction: ' + e.message);
}
const cosmosTransaction = this._utils.deserializeTransaction(rawTransaction);
this._utils.validateTransaction(cosmosTransaction);
}
/** @inheritdoc */
validateTransaction(transaction: CosmosTransaction<CustomMessage>): void {
this._utils.validateTransaction({
sequence: this._sequence,
sendMessages: this._messages,
gasBudget: this._gasBudget,
publicKey: this._publicKey,
});
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!