PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-sui/src/lib
Просмотр файла: unstakingBuilder.ts
import { BCS } from '@mysten/bcs';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { BaseKey, BuildTransactionError, TransactionType } from '@bitgo/sdk-core';
import {
SuiTransaction,
RequestWithdrawStakedSui,
SuiTransactionType,
UnstakingProgrammableTransaction,
} from './iface';
import { TransactionBuilder } from './transactionBuilder';
import { Transaction } from './transaction';
import assert from 'assert';
import { TransferTransaction } from './transferTransaction';
import { TransactionBlock as ProgrammingTransactionBlockBuilder, Inputs } from './mystenlab/builder';
import {
SUI_STAKING_POOL_MODULE_NAME,
SUI_STAKING_POOL_SPLIT_FUN_NAME,
SUI_SYSTEM_ADDRESS,
SUI_SYSTEM_MODULE_NAME,
SUI_SYSTEM_STATE_OBJECT,
WITHDRAW_STAKE_FUN_NAME,
} from './mystenlab/framework';
import { UnstakingTransaction } from './unstakingTransaction';
import utils from './utils';
import { normalizeSuiObjectId, SuiObjectRef } from './mystenlab/types';
import { SerializedTransactionDataBuilder } from './mystenlab/builder/TransactionDataBlock';
export class UnstakingBuilder extends TransactionBuilder<UnstakingProgrammableTransaction> {
protected _withdrawDelegation: RequestWithdrawStakedSui;
constructor(_coinConfig: Readonly<CoinConfig>) {
super(_coinConfig);
this._transaction = new UnstakingTransaction(_coinConfig);
}
/**
* Build a MoveCall transaction ready to be signed and executed.
*
* @returns {BitGoSuiTransaction} an unsigned Sui transaction
*/
protected buildUnstakeTransaction(): SuiTransaction<UnstakingProgrammableTransaction> {
return {
type: SuiTransactionType.WithdrawStake,
sender: this._sender,
tx: {
inputs: [],
transactions: [],
},
gasData: this._gasData,
};
}
/**
* Get staking transaction type
*
* @return {TransactionType}
* @protected
*/
protected get transactionType(): TransactionType {
return TransactionType.StakingClaim;
}
/** @inheritdoc */
validateTransaction(transaction: TransferTransaction): void {
if (!transaction.suiTransaction) {
return;
}
this.validateTransactionFields();
}
/** @inheritdoc */
sign(key: BaseKey) {
this.transaction.setSuiTransaction(this.buildSuiTransaction());
super.sign(key);
}
/**
* Create a new transaction for withdrawing coins ready to be signed
*
* @param {RequestWithdrawStakedSui} request
*/
unstake(request: RequestWithdrawStakedSui): this {
this.validateSuiObjectRef(request.stakedSui, 'stakedSui');
if (request.amount !== undefined) {
if (!utils.isValidAmount(request.amount)) {
throw new Error(`invalid amount: ${request.amount}`);
}
}
this._withdrawDelegation = request;
return this;
}
/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction<UnstakingProgrammableTransaction> {
const tx = new UnstakingTransaction(this._coinConfig);
this.validateRawTransaction(rawTransaction);
tx.fromRawTransaction(rawTransaction);
this.initBuilder(tx);
return this.transaction;
}
/** @inheritdoc */
protected async buildImplementation(): Promise<Transaction<UnstakingProgrammableTransaction>> {
this.transaction.setSuiTransaction(this.buildSuiTransaction());
this.transaction.transactionType(this.transactionType);
if (this._signer) {
this.transaction.sign(this._signer);
}
this._signatures.forEach((signature) => {
this.transaction.addSignature(signature.publicKey, signature.signature);
});
this.transaction.loadInputsAndOutputs();
return this.transaction;
}
/**
* Initialize the transaction builder fields using the decoded transaction data
*
* @param {StakingTransaction} tx the transaction data
*/
initBuilder(tx: Transaction<UnstakingProgrammableTransaction>): void {
this._transaction = tx;
if (tx.signature && tx.signature.length > 0) {
this._signatures = [tx.suiSignature];
}
const txData = tx.toJson();
this.type(SuiTransactionType.WithdrawStake);
this.sender(txData.sender);
this.gasData(txData.gasData);
const parsed = UnstakingTransaction.parseTransaction(tx.suiTransaction.tx);
this.unstake({
stakedSui: {
// it is a bit unclear why we have to normalize this way
...parsed.stakedObjectRef,
objectId: normalizeSuiObjectId(parsed.stakedObjectRef.objectId),
version: Number(parsed.stakedObjectRef.version),
},
amount: parsed.amount === undefined ? undefined : Number(parsed.amount),
});
}
/**
* Validates all fields are defined
*/
private validateTransactionFields(): void {
assert(this._type, new BuildTransactionError('type is required before building'));
assert(this._sender, new BuildTransactionError('sender is required before building'));
assert(
this._withdrawDelegation.stakedSui,
new BuildTransactionError('stakedSui object is required before building')
);
assert(this._gasData, new BuildTransactionError('gasData is required before building'));
this.validateGasData(this._gasData);
}
static getTransactionBlockData(objectRef: SuiObjectRef, amount?: bigint): SerializedTransactionDataBuilder {
const txb = new ProgrammingTransactionBlockBuilder();
const targetSplit =
`${SUI_SYSTEM_ADDRESS}::${SUI_STAKING_POOL_MODULE_NAME}::${SUI_STAKING_POOL_SPLIT_FUN_NAME}` as `${string}::${string}::${string}`;
const targetWithdrawStake =
`${SUI_SYSTEM_ADDRESS}::${SUI_SYSTEM_MODULE_NAME}::${WITHDRAW_STAKE_FUN_NAME}` as `${string}::${string}::${string}`;
if (amount === undefined) {
txb.moveCall({
target: targetWithdrawStake,
arguments: [txb.object(Inputs.SharedObjectRef(SUI_SYSTEM_STATE_OBJECT)), txb.pure(Inputs.ObjectRef(objectRef))],
});
} else {
txb.moveCall({
target: targetSplit,
arguments: [txb.object(Inputs.ObjectRef(objectRef)), txb.pure(amount)],
});
txb.moveCall({
target: targetWithdrawStake,
arguments: [
txb.object(Inputs.SharedObjectRef(SUI_SYSTEM_STATE_OBJECT)),
{ kind: 'NestedResult', index: 0, resultIndex: 0 },
],
});
}
return txb.blockData;
}
static getTransactionBlockDataReserialized(
objectRef: SuiObjectRef,
amount: bigint
): { inputs: unknown[]; transactions: unknown[] } {
const inputs = [
{ Object: { ImmOrOwned: objectRef } },
Inputs.Pure(amount, BCS.U64),
{
Object: {
Shared: {
objectId: '0000000000000000000000000000000000000000000000000000000000000005',
initialSharedVersion: '1',
mutable: true,
},
},
},
];
const transactions = [
{
kind: 'MoveCall',
target: '0000000000000000000000000000000000000000000000000000000000000003::staking_pool::split',
arguments: [
{
kind: 'Input',
index: 0,
},
{
kind: 'Input',
index: 1,
},
],
typeArguments: [],
},
{
kind: 'MoveCall',
target: '0000000000000000000000000000000000000000000000000000000000000003::sui_system::request_withdraw_stake',
arguments: [
{
kind: 'Input',
index: 2,
},
{
kind: 'NestedResult',
index: 0,
resultIndex: 0,
},
],
typeArguments: [],
},
];
return { inputs, transactions };
}
/**
* Build SuiTransaction
*
* @return {SuiTransaction<UnstakingProgrammableTransaction>}
* @protected
*/
protected buildSuiTransaction(): SuiTransaction<UnstakingProgrammableTransaction> {
this.validateTransactionFields();
const txData = UnstakingBuilder.getTransactionBlockData(
this._withdrawDelegation.stakedSui,
this._withdrawDelegation.amount === undefined ? undefined : BigInt(this._withdrawDelegation.amount)
);
return {
type: this._type,
sender: this._sender,
tx: {
inputs: [...txData.inputs],
transactions: [...txData.transactions],
},
gasData: {
...this._gasData,
},
};
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!