diff --git a/avail-js/docs/advanced_examples/multisig.ts b/avail-js/docs/advanced_examples/multisig.ts index 959411bfa..6b7d61f86 100644 --- a/avail-js/docs/advanced_examples/multisig.ts +++ b/avail-js/docs/advanced_examples/multisig.ts @@ -1,4 +1,4 @@ -import { SDK, WaitFor, Keyring, BN, KeyringPair, Weight, ParsedTxResult, MultisigTimepoint } from "./../../src/index" +import { SDK, WaitFor, Keyring, BN, KeyringPair, Weight, TxResultDetails, MultisigTimepoint } from "./../../src/index" const main = async () => { const providerEndpoint = "ws://127.0.0.1:9944" @@ -73,7 +73,7 @@ async function firstApproval( threshold: number, otherSignatures: string[], maxWeight: Weight, -): Promise { +): Promise { console.log("Alice is creating a Multisig Transaction...") const maybeTxResult = await sdk.util.firstMultisigApproval( @@ -98,7 +98,7 @@ async function nextApproval( threshold: number, otherSignatures: string[], timepoint: MultisigTimepoint, -): Promise { +): Promise { console.log("Bob is approving the existing Multisig Transaction...") const maybeTxResult = await sdk.util.nextMultisigApproval( @@ -124,7 +124,7 @@ async function lastApproval( timepoint: MultisigTimepoint, callData: string, maxWeight: Weight, -): Promise { +): Promise { console.log("Charlie is approving and executing the existing Multisig Transaction...") const maybeTxResult = await sdk.util.lastMultisigApproval( diff --git a/avail-js/src/sdk/index.ts b/avail-js/src/sdk/index.ts index baef63a51..8bcada9b6 100644 --- a/avail-js/src/sdk/index.ts +++ b/avail-js/src/sdk/index.ts @@ -11,7 +11,7 @@ export { Keyring } from "@polkadot/api" export { KeyringPair } from "@polkadot/keyring/types" export { Bytes } from "@polkadot/types-codec" export { H256, Weight } from "@polkadot/types/interfaces" -export { ParsedTxResult, MultisigTimepoint } from "./utils" +export { TxResultDetails, MultisigTimepoint } from "./utils" export { WaitFor, diff --git a/avail-js/src/sdk/transactions/balances.ts b/avail-js/src/sdk/transactions/balances.ts index 2112b3db4..34573ace5 100644 --- a/avail-js/src/sdk/transactions/balances.ts +++ b/avail-js/src/sdk/transactions/balances.ts @@ -1,42 +1,35 @@ import { ApiPromise } from "@polkadot/api" import { ISubmittableResult } from "@polkadot/types/types/extrinsic" -import { H256, EventRecord } from "@polkadot/types/interfaces/types" +import { EventRecord } from "@polkadot/types/interfaces/types" import { BN } from "@polkadot/util" import { KeyringPair } from "@polkadot/keyring/types" -import { err, Result } from "neverthrow" +import { err, Result, ok } from "neverthrow" import { SignerOptions } from "@polkadot/api/types" -import { decodeError } from "../../helpers" -import { WaitFor, GenericFailure, standardCallback, getBlockHashAndTxHash } from "./common" - -type TransferKeepAliveTxSuccess = { - isErr: false - event: Events.TransferEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +import { WaitFor, standardCallback, TransactionFailed } from "./common" +import { parseTransactionResult, TxResultDetails } from "../utils" + +export class TransferKeepAliveTx { + constructor( + public event: Events.TransferEvent, + public details: TxResultDetails, + ) {} } -type TransferAllowDeathTxSuccess = { - isErr: false - event: Events.TransferEvent - event2?: Events.KilledAccount - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class TransferAllowDeathTx { + constructor( + public event: Events.TransferEvent, + public event2: Events.KilledAccount | undefined, + public details: TxResultDetails, + ) {} } -type TransferAllTxSuccess = { - isErr: false - event: Events.TransferEvent - event2?: Events.KilledAccount - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class TransferAllTx { + constructor( + public event: Events.TransferEvent, + public event2: Events.KilledAccount | undefined, + public details: TxResultDetails, + ) {} } export class Balances { @@ -52,7 +45,7 @@ export class Balances { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.balances @@ -66,29 +59,22 @@ export class Balances { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - - const event = Events.TransferEvent.New(txResult.events) + const event = Events.TransferEvent.New(details.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Transfer event." } as GenericFailure + return err(new TransactionFailed("Failed to find Transfer event", details)) } const event2 = Events.KilledAccount.New(txResult.events) - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, event2, events, txHash, txIndex, blockHash, blockNumber } as TransferAllTxSuccess + return ok(new TransferAllTx(event, event2, details)) } async transferAllowDeath( @@ -97,7 +83,7 @@ export class Balances { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.balances @@ -111,38 +97,22 @@ export class Balances { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - - const event = Events.TransferEvent.New(txResult.events) + const event = Events.TransferEvent.New(details.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Transfer event." } as GenericFailure + return err(new TransactionFailed("Failed to find Transfer event", details)) } const event2 = Events.KilledAccount.New(txResult.events) - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { - isErr: false, - event, - event2, - events, - txHash, - txIndex, - blockHash, - blockNumber, - } as TransferAllowDeathTxSuccess + return ok(new TransferAllowDeathTx(event, event2, details)) } async transferKeepAlive( @@ -151,7 +121,7 @@ export class Balances { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.balances @@ -165,28 +135,21 @@ export class Balances { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - - const event = Events.TransferEvent.New(txResult.events) + const event = Events.TransferEvent.New(details.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Transfer event." } as GenericFailure + return err(new TransactionFailed("Failed to find Transfer event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as TransferKeepAliveTxSuccess + return ok(new TransferKeepAliveTx(event, details)) } } diff --git a/avail-js/src/sdk/transactions/common.ts b/avail-js/src/sdk/transactions/common.ts index 4383b968d..73d979143 100644 --- a/avail-js/src/sdk/transactions/common.ts +++ b/avail-js/src/sdk/transactions/common.ts @@ -2,6 +2,7 @@ import { ApiPromise } from "@polkadot/api" import { ISubmittableResult } from "@polkadot/types/types/extrinsic" import { H256 } from "@polkadot/types/interfaces/types" import { ok, Result } from "neverthrow" +import { TxResultDetails } from "../utils" export enum WaitFor { BlockInclusion, @@ -46,4 +47,9 @@ export async function getBlockHashAndTxHash( return [txHash, txIndex, blockHash, blockNumber] } -export type GenericFailure = { isErr: true; reason: string } +export class TransactionFailed { + constructor( + public reason: string, + public details: TxResultDetails | null, + ) {} +} diff --git a/avail-js/src/sdk/transactions/da.ts b/avail-js/src/sdk/transactions/da.ts index bfa48cacc..401dbc877 100644 --- a/avail-js/src/sdk/transactions/da.ts +++ b/avail-js/src/sdk/transactions/da.ts @@ -1,14 +1,15 @@ import { ApiPromise } from "@polkadot/api" import { ISubmittableResult } from "@polkadot/types/types/extrinsic" -import { H256, EventRecord } from "@polkadot/types/interfaces/types" +import { EventRecord } from "@polkadot/types/interfaces/types" import { BN } from "@polkadot/util" import { KeyringPair } from "@polkadot/keyring/types" -import { err, Result } from "neverthrow" +import { err, Result, ok } from "neverthrow" import * as TransactionData from "./../transaction_data" import { SignerOptions } from "@polkadot/api/types" import { decodeError, fromHexToAscii } from "../../helpers" -import { WaitFor, GenericFailure, standardCallback, getBlockHashAndTxHash } from "./common" +import { WaitFor, standardCallback, TransactionFailed } from "./common" +import { parseTransactionResult, TxResultDetails } from "../utils" export type DispatchFeeModifier = { weightMaximumFee: BN | null @@ -16,51 +17,40 @@ export type DispatchFeeModifier = { weightFeeMultiplier: number | null } -type SubmitDataTxSuccess = { - isErr: false - txData: TransactionData.DataAvailability.SubmitData - event: Events.DataSubmittedEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class SubmitDataTx { + constructor( + public txData: TransactionData.DataAvailability.SubmitData, + public event: Events.DataSubmittedEvent, + public details: TxResultDetails, + ) {} } -type CreateApplicationKeyTxSuccess = { - isErr: false - event: Events.ApplicationKeyCreatedEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class CreateApplicationKeyTx { + constructor( + public event: Events.ApplicationKeyCreatedEvent, + public details: TxResultDetails, + ) {} } -type SetApplicationKeyTxSuccess = { - isErr: false - event: Events.ApplicationKeySetEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class SetApplicationKeyTx { + constructor( + public event: Events.ApplicationKeySetEvent, + public details: TxResultDetails, + ) {} } -type SubmitBlockLengthProposalTxSuccess = { - isErr: false - event: Events.BlockLengthProposalSubmittedEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class SubmitBlockLengthProposalTx { + constructor( + public event: Events.BlockLengthProposalSubmittedEvent, + public details: TxResultDetails, + ) {} } -type SetSubmitDataFeeModifierTxSuccess = { - isErr: false - event: Events.SubmitDataFeeModifierSetEvent - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class SetSubmitDataFeeModifierTx { + constructor( + public event: Events.SubmitDataFeeModifierSetEvent, + public details: TxResultDetails, + ) {} } export class DataAvailability { @@ -75,7 +65,7 @@ export class DataAvailability { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.dataAvailability @@ -89,42 +79,30 @@ export class DataAvailability { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err({ reason: maybeTxResult.error, details: null }) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.DataSubmittedEvent.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find DataSubmitted event." } as GenericFailure + return err(new TransactionFailed("Failed to find DataSubmitted Event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - const maybeTxData = await TransactionData.DataAvailability.SubmitData.New(this.api, txHash, blockHash) + const maybeTxData = await TransactionData.DataAvailability.SubmitData.New( + this.api, + details.txHash, + details.blockHash, + ) if (maybeTxData.isErr()) { - return { isErr: true, reason: maybeTxData.error } as GenericFailure + return err(new TransactionFailed(maybeTxData.error, details)) } - return { - isErr: false, - txData: maybeTxData.value, - event, - events, - txHash, - txIndex, - blockHash, - blockNumber, - } as SubmitDataTxSuccess + return ok(new SubmitDataTx(maybeTxData.value, event, details)) } async createApplicationKey( @@ -132,7 +110,7 @@ export class DataAvailability { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.dataAvailability @@ -146,28 +124,21 @@ export class DataAvailability { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err({ reason: maybeTxResult.error, details: null }) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.ApplicationKeyCreatedEvent.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find ApplicationKeyCreated event." } as GenericFailure + return err(new TransactionFailed("Failed to find ApplicationKeyCreated Event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as CreateApplicationKeyTxSuccess + return ok(new CreateApplicationKeyTx(event, details)) } async setApplicationKey( @@ -176,7 +147,7 @@ export class DataAvailability { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { const call = this.api.tx.dataAvailability.setApplicationKey(oldKey, newKey) @@ -191,38 +162,31 @@ export class DataAvailability { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err({ reason: maybeTxResult.error, details: null }) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const sudoEvent = txResult.events.find((e) => e.event.method == "Sudid") if (sudoEvent == undefined) { - return { isErr: true, reason: "Failed to find Sudid event." } as GenericFailure + return err(new TransactionFailed("Failed to find Sudid Event", details)) } const sudoResult: any = (sudoEvent.event.data as any).sudoResult if (sudoResult.isErr) { - return { isErr: true, isFailure: true, reason: decodeError(this.api, sudoResult.asErr) } as GenericFailure + return err(new TransactionFailed(decodeError(this.api, sudoResult.asErr), details)) } const event = Events.ApplicationKeySetEvent.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find ApplicationKeySet event." } as GenericFailure + return err(new TransactionFailed("Failed to find ApplicationKeySet Event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as SetApplicationKeyTxSuccess + return ok(new SetApplicationKeyTx(event, details)) } async submitBlockLengthProposal( @@ -231,7 +195,7 @@ export class DataAvailability { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { const call = this.api.tx.dataAvailability.submitBlockLengthProposal(rows, cols) @@ -246,46 +210,31 @@ export class DataAvailability { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err({ reason: maybeTxResult.error, details: null }) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const sudoEvent = txResult.events.find((e) => e.event.method == "Sudid") if (sudoEvent == undefined) { - return { isErr: true, reason: "Failed to find Sudid event." } as GenericFailure + return err(new TransactionFailed("Failed to find Sudid Event", details)) } const sudoResult: any = (sudoEvent.event.data as any).sudoResult if (sudoResult.isErr) { - return { isErr: true, isFailure: true, reason: decodeError(this.api, sudoResult.asErr) } as GenericFailure + return err(new TransactionFailed(decodeError(this.api, sudoResult.asErr), details)) } const event = Events.BlockLengthProposalSubmittedEvent.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find BlockLengthProposalSubmitted event." } as GenericFailure + return err(new TransactionFailed("Failed to find BlockLengthProposalSubmitted Event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { - isErr: false, - event, - events, - txHash, - txIndex, - blockHash, - blockNumber, - } as SubmitBlockLengthProposalTxSuccess + return ok(new SubmitBlockLengthProposalTx(event, details)) } async setSubmitDataFeeModifier( @@ -293,7 +242,7 @@ export class DataAvailability { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { const call = this.api.tx.dataAvailability.setSubmitDataFeeModifier(modifier) @@ -308,38 +257,31 @@ export class DataAvailability { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err({ reason: maybeTxResult.error, details: null }) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const sudoEvent = txResult.events.find((e) => e.event.method == "Sudid") if (sudoEvent == undefined) { - return { isErr: true, reason: "Failed to find Sudid event." } as GenericFailure + return err(new TransactionFailed("Failed to find Sudid Event", details)) } const sudoResult: any = (sudoEvent.event.data as any).sudoResult if (sudoResult.isErr) { - return { isErr: true, isFailure: true, reason: decodeError(this.api, sudoResult.asErr) } as GenericFailure + return err(new TransactionFailed(decodeError(this.api, sudoResult.asErr), details)) } const event = Events.SubmitDataFeeModifierSetEvent.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find SubmitDataFeeModifierSet event." } as GenericFailure + return err(new TransactionFailed("Failed to find SubmitDataFeeModifierSet Event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as SetSubmitDataFeeModifierTxSuccess + return ok(new SetSubmitDataFeeModifierTx(event, details)) } } diff --git a/avail-js/src/sdk/transactions/multisig.ts b/avail-js/src/sdk/transactions/multisig.ts new file mode 100644 index 000000000..e69de29bb diff --git a/avail-js/src/sdk/transactions/nomination_pools.ts b/avail-js/src/sdk/transactions/nomination_pools.ts index 5d6947e80..9d6cde8fa 100644 --- a/avail-js/src/sdk/transactions/nomination_pools.ts +++ b/avail-js/src/sdk/transactions/nomination_pools.ts @@ -1,14 +1,13 @@ import { ApiPromise } from "@polkadot/api" import { ISubmittableResult } from "@polkadot/types/types/extrinsic" -import { H256, EventRecord } from "@polkadot/types/interfaces/types" +import { EventRecord } from "@polkadot/types/interfaces/types" import { BN } from "@polkadot/util" import { KeyringPair } from "@polkadot/keyring/types" -import { err, Result } from "neverthrow" +import { err, Result, ok } from "neverthrow" import { SignerOptions } from "@polkadot/api/types" -import { decodeError } from "../../helpers" -import { WaitFor, GenericFailure, standardCallback, getBlockHashAndTxHash } from "./common" -import { commissionNumberToPerbill } from "../utils" +import { WaitFor, standardCallback, TransactionFailed } from "./common" +import { commissionNumberToPerbill, parseTransactionResult, TxResultDetails } from "../utils" export interface BondExtra { FreeBalance?: BN @@ -23,152 +22,99 @@ export interface NewCommission { payee: string } -type PoolCreateTxSuccess = { - isErr: false - event: Events.Created - event2: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class CreateTx { + constructor( + public event: Events.Created, + public event2: Events.Bonded, + public details: TxResultDetails, + ) {} } -type PoolCreateWithPoolIdTxSuccess = { - isErr: false - event: Events.Created - event2: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class CreateWithPoolIdTx { + constructor( + public event: Events.Created, + public event2: Events.Bonded, + public details: TxResultDetails, + ) {} } -type PoolJoinTxSuccess = { - isErr: false - event: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class JoinTx { + constructor( + public event: Events.Bonded, + public details: TxResultDetails, + ) {} } -type PoolNominateTxSuccess = { - isErr: false - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class NominateTx { + constructor(public details: TxResultDetails) {} } -type PoolBondExtraTxSuccess = { - isErr: false - event: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class BondExtraTx { + constructor( + public event: Events.Bonded, + public details: TxResultDetails, + ) {} } -type PoolSetMetadataTxSuccess = { - isErr: false - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class SetMetadataTx { + constructor(public details: TxResultDetails) {} } -type PoolUnbondTxSuccess = { - isErr: false - event?: Events.Unbonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class UnbondTx { + constructor( + public event: Events.Unbonded | undefined, + public details: TxResultDetails, + ) {} } -type PoolChillTxSuccess = { - isErr: false - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class ChillTx { + constructor(public details: TxResultDetails) {} } -type PoolClaimCommissionTxSuccess = { - isErr: false - event: Events.PoolCommissionClaimed - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class ClaimCommissionTx { + constructor( + public event: Events.PoolCommissionClaimed, + public details: TxResultDetails, + ) {} } -type PoolClaimPayoutTxSuccess = { - isErr: false - event?: Events.PaidOut - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class ClaimPayoutTx { + constructor( + public event: Events.PaidOut | undefined, + public details: TxResultDetails, + ) {} } -type PoolClaimPayoutOtherTxSuccess = { - isErr: false - event?: Events.PaidOut - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class ClaimPayoutOtherTx { + constructor( + public event: Events.PaidOut | undefined, + public details: TxResultDetails, + ) {} } -type PoolSetClaimPermissionOtherTxSuccess = { - isErr: false - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class SetClaimPermissionTx { + constructor(public details: TxResultDetails) {} } -type PoolSetCommissionTxSuccess = { - isErr: false - event: Events.PoolCommissionUpdated - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class CommissionTx { + constructor( + public event: Events.PoolCommissionUpdated, + public details: TxResultDetails, + ) {} } -type PoolWithdrawUnbodedTxSuccess = { - isErr: false - event: Events.Withdrawn - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class WithdrawUnbodedTx { + constructor( + public event: Events.Withdrawn, + public details: TxResultDetails, + ) {} } -type PoolSetStateTxSuccess = { - isErr: false - event?: Events.StateChanged - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class SetStateTx { + constructor( + public event: Events.StateChanged | undefined, + public details: TxResultDetails, + ) {} } export class NominationPools { @@ -186,7 +132,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -200,33 +146,25 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Created.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Created event." } as GenericFailure + return err(new TransactionFailed("Failed to find Created event", details)) } - const event2 = Events.Bonded.New(txResult.events) if (event2 == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, event2, events, txHash, txIndex, blockHash, blockNumber } as PoolCreateTxSuccess + return ok(new CreateTx(event, event2, details)) } async createWithPoolId( @@ -238,7 +176,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -252,42 +190,26 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Created.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Created event." } as GenericFailure + return err(new TransactionFailed("Failed to find Created event", details)) } const event2 = Events.Bonded.New(txResult.events) if (event2 == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { - isErr: false, - event, - event2, - events, - txHash, - txIndex, - blockHash, - blockNumber, - } as PoolCreateWithPoolIdTxSuccess + return ok(new CreateWithPoolIdTx(event, event2, details)) } async join( @@ -296,7 +218,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -310,28 +232,21 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Bonded.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolJoinTxSuccess + return ok(new JoinTx(event, details)) } async nominate( @@ -340,7 +255,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -354,23 +269,16 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, events, txHash, txIndex, blockHash, blockNumber } as PoolNominateTxSuccess + return ok(new NominateTx(details)) } async bondExtra( @@ -378,7 +286,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -392,28 +300,21 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Bonded.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolBondExtraTxSuccess + return ok(new BondExtraTx(event, details)) } async setMetadata( @@ -422,7 +323,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -436,23 +337,16 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, events, txHash, txIndex, blockHash, blockNumber } as PoolSetMetadataTxSuccess + return ok(new SetMetadataTx(details)) } async unbond( @@ -461,7 +355,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -475,24 +369,18 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Unbonded.New(txResult.events) - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolUnbondTxSuccess + return ok(new UnbondTx(event, details)) } async chill( @@ -500,7 +388,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -514,23 +402,16 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, events, txHash, txIndex, blockHash, blockNumber } as PoolChillTxSuccess + return ok(new ChillTx(details)) } async claimCommission( @@ -538,7 +419,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -552,35 +433,28 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.PoolCommissionClaimed.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find PoolCommissionClaimed event." } as GenericFailure + return err(new TransactionFailed("Failed to find PoolCommissionClaimed event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolClaimCommissionTxSuccess + return ok(new ClaimCommissionTx(event, details)) } async claimPayout( waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -594,24 +468,17 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - + const details = maybeParsed.value const event = Events.PaidOut.New(txResult.events) - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolClaimPayoutTxSuccess + return ok(new ClaimPayoutTx(event, details)) } async claimPayoutOther( @@ -619,7 +486,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -633,24 +500,17 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - + const details = maybeParsed.value const event = Events.PaidOut.New(txResult.events) - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolClaimPayoutOtherTxSuccess + return ok(new ClaimPayoutOtherTx(event, details)) } async setClaimPermission( @@ -658,7 +518,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -672,23 +532,16 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, events, txHash, txIndex, blockHash, blockNumber } as PoolSetClaimPermissionOtherTxSuccess + return ok(new SetClaimPermissionTx(details)) } async setCommission( @@ -697,14 +550,14 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} let commission: string[] | null = null if (newCommission != null) { const amount = commissionNumberToPerbill(newCommission.amount) if (amount.isErr()) { - return { isErr: true, reason: amount.error } as GenericFailure + return err(new TransactionFailed(amount.error, null)) } commission = [amount.value, newCommission.payee] } @@ -720,28 +573,21 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.PoolCommissionUpdated.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find PoolCommissionUpdated event." } as GenericFailure + return err(new TransactionFailed("Failed to find PoolCommissionUpdated event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolSetCommissionTxSuccess + return ok(new CommissionTx(event, details)) } async withdrawUnbonded( @@ -750,7 +596,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -764,28 +610,21 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Withdrawn.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Withdraw event." } as GenericFailure + return err(new TransactionFailed("Failed to find Withdrawn event", details)) } - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolWithdrawUnbodedTxSuccess + return ok(new WithdrawUnbodedTx(event, details)) } async setState( @@ -794,7 +633,7 @@ export class NominationPools { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.nominationPools @@ -808,24 +647,17 @@ export class NominationPools { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } - - const events = txResult.events - const failed = events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure - } - + const details = maybeParsed.value const event = Events.StateChanged.New(txResult.events) - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as PoolSetStateTxSuccess + return ok(new SetStateTx(event, details)) } } diff --git a/avail-js/src/sdk/transactions/staking.ts b/avail-js/src/sdk/transactions/staking.ts index 3719f0195..acd220e74 100644 --- a/avail-js/src/sdk/transactions/staking.ts +++ b/avail-js/src/sdk/transactions/staking.ts @@ -1,81 +1,65 @@ import { ApiPromise } from "@polkadot/api" import { ISubmittableResult } from "@polkadot/types/types/extrinsic" -import { H256, EventRecord } from "@polkadot/types/interfaces/types" +import { EventRecord } from "@polkadot/types/interfaces/types" import { BN } from "@polkadot/util" import { KeyringPair } from "@polkadot/keyring/types" -import { err, Result } from "neverthrow" +import { err, Result, ok } from "neverthrow" import * as TransactionData from "./../transaction_data" import { SignerOptions } from "@polkadot/api/types" -import { decodeError } from "../../helpers" -import { WaitFor, GenericFailure, standardCallback, getBlockHashAndTxHash } from "./common" -import { commissionNumberToPerbill } from "../utils" +import { WaitFor, standardCallback, TransactionFailed } from "./common" +import { commissionNumberToPerbill, parseTransactionResult, TxResultDetails } from "../utils" type ValidatorPerfs = { commission: string; blocked: boolean } export type StakingRewardDestination = "Staked" | "Stash" | "None" | { account: string } -type BondTxSuccess = { - isErr: false - event: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number +export class BondTx { + constructor( + public event: Events.Bonded, + public details: TxResultDetails, + ) {} } -type BondExtraTxSuccess = { - isErr: false - event: Events.Bonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class BondExtraTx { + constructor( + public event: Events.Bonded, + public details: TxResultDetails, + ) {} } -type ChillTxSuccess = { - isErr: false - event: Events.Chilled - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class ChillTx { + constructor( + public event: Events.Chilled, + public details: TxResultDetails, + ) {} } -type ChillOtherTxSuccess = { - isErr: false - event: Events.Chilled - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class ChillOtherTx { + constructor( + public event: Events.Chilled, + public details: TxResultDetails, + ) {} } -type UnbondTxSuccess = { - isErr: false - event: Events.Unbonded - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class UnbondTx { + constructor( + public event: Events.Unbonded, + public details: TxResultDetails, + ) {} } -type ValidatexSuccess = { - isErr: false - event: Events.ValidatorPrefsSet - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class ValidateTx { + constructor( + public event: Events.ValidatorPrefsSet, + public details: TxResultDetails, + ) {} } -type NominateTxSuccess = { - isErr: false - txData: TransactionData.Staking.Nominate - events: EventRecord[] - txHash: H256 - txIndex: number - blockHash: H256 - blockNumber: number + +export class NominateTx { + constructor( + public txData: TransactionData.Staking.Nominate, + public details: TxResultDetails, + ) {} } export class Staking { @@ -91,7 +75,7 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -105,28 +89,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Bonded.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as BondTxSuccess + return ok(new BondTx(event, details)) } async bondExtra( @@ -134,7 +111,7 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -148,35 +125,28 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Bonded.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Bonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Bonded event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as BondExtraTxSuccess + return ok(new BondExtraTx(event, details)) } async chill( waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -190,28 +160,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Chilled.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Chilled event." } as GenericFailure + return err(new TransactionFailed("Failed to find Chilled event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as ChillTxSuccess + return ok(new ChillTx(event, details)) } async chillOther( @@ -219,7 +182,7 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -233,28 +196,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Chilled.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Chilled event." } as GenericFailure + return err(new TransactionFailed("Failed to find Chilled event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as ChillOtherTxSuccess + return ok(new ChillOtherTx(event, details)) } async nominate( @@ -262,7 +218,7 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -276,36 +232,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - const maybeTxData = await TransactionData.Staking.Nominate.New(this.api, txHash, blockHash) + const maybeTxData = await TransactionData.Staking.Nominate.New(this.api, details.txHash, details.blockHash) if (maybeTxData.isErr()) { - return { isErr: true, reason: maybeTxData.error } as GenericFailure + return err(new TransactionFailed(maybeTxData.error, details)) } - return { - isErr: false, - txData: maybeTxData.value, - events, - txHash, - txIndex, - blockHash, - blockNumber, - } as NominateTxSuccess + return ok(new NominateTx(maybeTxData.value, details)) } async unbond( @@ -313,7 +254,7 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.staking @@ -327,28 +268,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.Unbonded.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find Unbonded event." } as GenericFailure + return err(new TransactionFailed("Failed to find Unbonded event", details)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as UnbondTxSuccess + return ok(new UnbondTx(event, details)) } async validate( @@ -357,10 +291,10 @@ export class Staking { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise { + ): Promise> { const maybeCommission = commissionNumberToPerbill(commission) if (maybeCommission.isErr()) { - return { isErr: true, reason: maybeCommission.error } as GenericFailure + return err(new TransactionFailed(maybeCommission.error, null)) } const validatorPerfs = { commission: maybeCommission.value, blocked } as ValidatorPerfs @@ -377,28 +311,21 @@ export class Staking { }) if (maybeTxResult.isErr()) { - return { isErr: true, reason: maybeTxResult.error } as GenericFailure + return err(new TransactionFailed(maybeTxResult.error, null)) } const txResult = maybeTxResult.value - - if (txResult.isError) { - return { isErr: true, reason: "The transaction was dropped or something." } as GenericFailure - } - - const failed = txResult.events.find((e) => this.api.events.system.ExtrinsicFailed.is(e.event)) - if (failed != undefined) { - return { isErr: true, reason: decodeError(this.api, failed.event.data[0]) } as GenericFailure + const maybeParsed = await parseTransactionResult(this.api, txResult, waitFor) + if (maybeParsed.isErr()) { + return err(maybeParsed.error) } + const details = maybeParsed.value const event = Events.ValidatorPrefsSet.New(txResult.events) if (event == undefined) { - return { isErr: true, reason: "Failed to find ValidatorPrefsSet event." } as GenericFailure + return err(new TransactionFailed("Failed to find ValidatorPrefsSet event.", null)) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, this.api) - - return { isErr: false, event, events, txHash, txIndex, blockHash, blockNumber } as ValidatexSuccess + return ok(new ValidateTx(event, details)) } } diff --git a/avail-js/src/sdk/utils/index.ts b/avail-js/src/sdk/utils/index.ts index abbf942ce..86ef4aed2 100644 --- a/avail-js/src/sdk/utils/index.ts +++ b/avail-js/src/sdk/utils/index.ts @@ -8,7 +8,7 @@ import { createKeyMulti, encodeAddress, sortAddresses } from "@polkadot/util-cry import { KeyringPair } from "@polkadot/keyring/types" import { SignerOptions } from "@polkadot/api/types" -export class ParsedTxResult { +export class TxResultDetails { constructor( public txResult: ISubmittableResult, public events: EventRecord[], @@ -19,6 +19,13 @@ export class ParsedTxResult { ) {} } +export class FailedTxResult { + constructor( + public reason: string, + public details: TxResultDetails | null, + ) {} +} + export interface MultisigTimepoint { height: number index: number @@ -31,12 +38,12 @@ export class Utils { this.api = api } - /// Parses a transaction result. Helper function to get transaction details on + /// Parses a transaction result. Helper function to get transaction details on /// transaction success or an error if the transaction failed async parseTransactionResult( txResult: ISubmittableResult, waitFor: WaitFor, - ): Promise> { + ): Promise> { return await parseTransactionResult(this.api, txResult, waitFor) } @@ -65,7 +72,7 @@ export class Utils { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise> { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.multisig @@ -84,7 +91,7 @@ export class Utils { const txResult = maybeTxResult.value const maybeParsed = await this.parseTransactionResult(txResult, waitFor) if (maybeParsed.isErr()) { - return err(maybeParsed.error) + return err(maybeParsed.error.reason) } const parsed = maybeParsed.value @@ -100,7 +107,7 @@ export class Utils { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise> { + ): Promise> { const maxWeight = { refTime: 0, proofSize: 0 } const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { @@ -120,7 +127,7 @@ export class Utils { const txResult = maybeTxResult.value const maybeParsed = await this.parseTransactionResult(txResult, waitFor) if (maybeParsed.isErr()) { - return err(maybeParsed.error) + return err(maybeParsed.error.reason) } const parsed = maybeParsed.value @@ -137,7 +144,7 @@ export class Utils { waitFor: WaitFor, account: KeyringPair, options?: Partial, - ): Promise> { + ): Promise> { const optionWrapper = options || {} const maybeTxResult = await new Promise>((res, _) => { this.api.tx.multisig @@ -156,7 +163,7 @@ export class Utils { const txResult = maybeTxResult.value const maybeParsed = await this.parseTransactionResult(txResult, waitFor) if (maybeParsed.isErr()) { - return err(maybeParsed.error) + return err(maybeParsed.error.reason) } const parsed = maybeParsed.value @@ -173,20 +180,21 @@ export async function parseTransactionResult( api: ApiPromise, txResult: ISubmittableResult, waitFor: WaitFor, -): Promise> { +): Promise> { if (txResult.isError) { - return err("The transaction was dropped or something.") + return err({ reason: "The transaction was dropped or something.", details: null }) } + const events = txResult.events + const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, api) + const details = new TxResultDetails(txResult, events, txHash, txIndex, blockHash, blockNumber) + const failed = txResult.events.find((e) => api.events.system.ExtrinsicFailed.is(e.event)) if (failed != undefined) { - return err(decodeError(api, failed.event.data[0])) + return err({ reason: decodeError(api, failed.event.data[0]), details }) } - const events = txResult.events - const [txHash, txIndex, blockHash, blockNumber] = await getBlockHashAndTxHash(txResult, waitFor, api) - - return ok(new ParsedTxResult(txResult, events, txHash, txIndex, blockHash, blockNumber)) + return ok(details) } export function commissionNumberToPerbill(value: number): Result {