diff --git a/packages/app-123code/src/Transfer.tsx b/packages/app-123code/src/Transfer.tsx index f7c2fa4782..364b586a22 100644 --- a/packages/app-123code/src/Transfer.tsx +++ b/packages/app-123code/src/Transfer.tsx @@ -4,9 +4,7 @@ import BN from 'bn.js'; import React from 'react'; -import { Button, InputAddress, InputBalance } from '@polkadot/ui-app/index'; - -import TxButton from './TxButton'; +import { Button, InputAddress, InputBalance, TxButton } from '@polkadot/ui-app/index'; type Props = { accountId?: string diff --git a/packages/ui-app/src/Status/Queue.tsx b/packages/ui-app/src/Status/Queue.tsx index c06b714bac..753704cac8 100644 --- a/packages/ui-app/src/Status/Queue.tsx +++ b/packages/ui-app/src/Status/Queue.tsx @@ -155,13 +155,16 @@ export default class Queue extends React.Component { return id; } - queueExtrinsic = ({ accountId, extrinsic, signerCallback, signerOptions, isUnsigned }: PartialQueueTx$Extrinsic): number => { + queueExtrinsic = ({ accountId, extrinsic, signerCb, signerOptions, txFailedCb, txSuccessCb, txUpdateCb, isUnsigned }: PartialQueueTx$Extrinsic): number => { return this.queueAdd({ accountId, extrinsic, isUnsigned, - signerCallback, - signerOptions + signerCb, + signerOptions, + txFailedCb, + txSuccessCb, + txUpdateCb }); } diff --git a/packages/ui-app/src/Status/types.ts b/packages/ui-app/src/Status/types.ts index ed78a644ce..874886646b 100644 --- a/packages/ui-app/src/Status/types.ts +++ b/packages/ui-app/src/Status/types.ts @@ -2,6 +2,7 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { SubmittableResult } from '@polkadot/api/SubmittableExtrinsic'; import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; import { RpcMethod } from '@polkadot/jsonrpc/types'; import { AccountId, Address } from '@polkadot/types'; @@ -24,6 +25,8 @@ export type QueueTx$Status = 'future' | 'ready' | 'finalised' | 'usurped' | 'dro export type SignerCallback = (id: number, isSigned: boolean) => void; +export type TxCallback = (status: SubmittableResult) => void; + export type QueueTx = AccountInfo & { error?: Error, extrinsic?: SubmittableExtrinsic, @@ -31,8 +34,11 @@ export type QueueTx = AccountInfo & { isUnsigned?: boolean, result?: any, rpc: RpcMethod, - signerCallback?: SignerCallback, + signerCb?: SignerCallback, signerOptions?: SignatureOptions, + txFailedCb?: TxCallback, + txSuccessCb?: TxCallback, + txUpdateCb?: TxCallback, values?: Array, status: QueueTx$Status }; @@ -63,8 +69,11 @@ export type PartialAccountInfo = { export type PartialQueueTx$Extrinsic = PartialAccountInfo & { extrinsic: SubmittableExtrinsic, - signerCallback?: SignerCallback, + signerCb?: SignerCallback, signerOptions?: SignatureOptions, + txFailedCb?: TxCallback, + txSuccessCb?: TxCallback, + txUpdateCb?: TxCallback, isUnsigned?: boolean }; diff --git a/packages/app-123code/src/TxButton.tsx b/packages/ui-app/src/TxButton.tsx similarity index 75% rename from packages/app-123code/src/TxButton.tsx rename to packages/ui-app/src/TxButton.tsx index 5b1bf84755..b4a6bc3d3c 100644 --- a/packages/app-123code/src/TxButton.tsx +++ b/packages/ui-app/src/TxButton.tsx @@ -3,14 +3,15 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ApiProps } from '@polkadot/ui-api/types'; -import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-app/Status/types'; +import { QueueTx$ExtrinsicAdd, TxCallback } from './Status/types'; import React from 'react'; -import { Button } from '@polkadot/ui-app/index'; -import { QueueConsumer } from '@polkadot/ui-app/Status/Context'; import { withApi } from '@polkadot/ui-api/index'; import { assert } from '@polkadot/util'; +import { QueueConsumer } from './Status/Context'; +import Button from './Button'; + type InjectedProps = { queueExtrinsic: QueueTx$ExtrinsicAdd; }; @@ -19,6 +20,9 @@ type Props = ApiProps & { accountId?: string, isDisabled?: boolean, label: React.ReactNode, + onFailed?: TxCallback, + onSuccess?: TxCallback, + onUpdate?: TxCallback, params: Array, tx: string }; @@ -38,14 +42,17 @@ class TxButtonInner extends React.PureComponent { } private send = (): void => { - const { accountId, api, params, queueExtrinsic, tx } = this.props; + const { accountId, api, onFailed, onSuccess, onUpdate, params, queueExtrinsic, tx } = this.props; const [section, method] = tx.split('.'); assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`); queueExtrinsic({ accountId, - extrinsic: api.tx[section][method](...params) as any // ??? + extrinsic: api.tx[section][method](...params) as any, // ??? + txFailedCb: onFailed, + txSuccessCb: onSuccess, + txUpdateCb: onUpdate }); } } diff --git a/packages/ui-app/src/index.tsx b/packages/ui-app/src/index.tsx index 406e91fdfb..04b0a3cb17 100644 --- a/packages/ui-app/src/index.tsx +++ b/packages/ui-app/src/index.tsx @@ -35,3 +35,4 @@ export { default as Progress } from './Progress'; export { default as Static } from './Static'; export { default as Status } from './Status'; export { default as Tabs } from './Tabs'; +export { default as TxButton } from './TxButton'; diff --git a/packages/ui-signer/src/ApiSigner.ts b/packages/ui-signer/src/ApiSigner.ts index 50d00e6ff4..7cf028cb06 100644 --- a/packages/ui-signer/src/ApiSigner.ts +++ b/packages/ui-signer/src/ApiSigner.ts @@ -25,7 +25,7 @@ export default class ApiSigner implements Signer { accountId, extrinsic, signerOptions, - signerCallback: (id: number, isSigned: boolean): void => { + signerCb: (id: number, isSigned: boolean): void => { if (isSigned) { resolve(id); } else { diff --git a/packages/ui-signer/src/Modal.tsx b/packages/ui-signer/src/Modal.tsx index 442308077f..d543e45756 100644 --- a/packages/ui-signer/src/Modal.tsx +++ b/packages/ui-signer/src/Modal.tsx @@ -8,16 +8,15 @@ import { ApiProps } from '@polkadot/ui-api/types'; import { I18nProps, BareProps } from '@polkadot/ui-app/types'; import { RpcMethod } from '@polkadot/jsonrpc/types'; import { KeyringPair } from '@polkadot/keyring/types'; -import { SignatureOptions } from '@polkadot/types/types'; import { SubjectInfo } from '@polkadot/ui-keyring/observable/types'; -import { QueueTx, QueueTx$MessageSetStatus, QueueTx$Result, QueueTx$Status, SignerCallback } from '@polkadot/ui-app/Status/types'; +import { QueueTx, QueueTx$MessageSetStatus, QueueTx$Result, QueueTx$Status } from '@polkadot/ui-app/Status/types'; import React from 'react'; import { Button, Modal } from '@polkadot/ui-app/index'; import keyring from '@polkadot/ui-keyring'; import { withApi, withMulti, withObservable } from '@polkadot/ui-api/index'; import accountObservable from '@polkadot/ui-keyring/observable/accounts'; -import { assert } from '@polkadot/util'; +import { assert, isFunction } from '@polkadot/util'; import { format } from '@polkadot/util/logger'; import Transaction from './Transaction'; @@ -230,10 +229,13 @@ class Signer extends React.PureComponent { return; } - const { id, signerCallback } = currentItem; + const { id, signerCb } = currentItem; queueSetTxStatus(id, 'cancelled'); - signerCallback && signerCallback(id, false); + + if (isFunction(signerCb)) { + signerCb(id, false); + } } private onSend = async (): Promise => { @@ -261,7 +263,9 @@ class Signer extends React.PureComponent { queueSetTxStatus(id, status, result, error); } - private async sendExtrinsic ({ accountId, extrinsic, id, signerCallback, signerOptions, isUnsigned }: QueueTx, password?: string): Promise { + private async sendExtrinsic (queueTx: QueueTx, password?: string): Promise { + const { accountId, extrinsic, id, signerOptions, isUnsigned } = queueTx; + assert(extrinsic, 'Expected an extrinsic to be supplied to sendExtrinsic'); if (!isUnsigned) { @@ -281,12 +285,12 @@ class Signer extends React.PureComponent { queueSetTxStatus(id, 'sending'); if (isUnsigned) { - return this.makeExtrinsicCall(submittable, id, submittable.send); + return this.makeExtrinsicCall(submittable, queueTx, submittable.send); } else if (signerOptions) { - return this.makeExtrinsicSignature(submittable, id, keyring.getPair(accountId as string), signerOptions, signerCallback); + return this.makeExtrinsicSignature(submittable, queueTx, keyring.getPair(accountId as string)); } - return this.makeExtrinsicCall(submittable, id, submittable.signAndSend, keyring.getPair(accountId as string)); + return this.makeExtrinsicCall(submittable, queueTx, submittable.signAndSend, keyring.getPair(accountId as string)); } private async submitRpc ({ method, section }: RpcMethod, values: Array): Promise { @@ -311,7 +315,7 @@ class Signer extends React.PureComponent { } } - private async makeExtrinsicCall (extrinsic: SubmittableExtrinsic, id: number, extrinsicCall: (...params: Array) => any, ..._params: Array): Promise { + private async makeExtrinsicCall (extrinsic: SubmittableExtrinsic, { id, txFailedCb, txSuccessCb, txUpdateCb }: QueueTx, extrinsicCall: (...params: Array) => any, ..._params: Array): Promise { const { queueSetTxStatus } = this.props; console.log('makeExtrinsicCall: extrinsic ::', extrinsic.toHex()); @@ -328,22 +332,38 @@ class Signer extends React.PureComponent { queueSetTxStatus(id, status, result); + if (isFunction(txUpdateCb)) { + txUpdateCb(result); + } + if (status === 'finalised') { unsubscribe(); + + result.events + .filter(({ event: { section } }) => section === 'system') + .forEach(({ event: { method } }) => { + if (isFunction(txFailedCb) && method === 'ExtrinsicFailed') { + txFailedCb(result); + } else if (isFunction(txSuccessCb) && method === 'ExtrinsicSuccess') { + txSuccessCb(result); + } + }); } }]); } catch (error) { - console.error('error.message', error.message); + console.error('makeExtrinsicCall: error:', error.message); queueSetTxStatus(id, 'error', {}, error); } } - private async makeExtrinsicSignature (extrinsic: SubmittableExtrinsic, id: number, pair: KeyringPair, options: SignatureOptions, signerCallback?: SignerCallback): Promise { + private async makeExtrinsicSignature (extrinsic: SubmittableExtrinsic, { id, signerCb, signerOptions }: QueueTx, pair: KeyringPair): Promise { console.log('makeExtrinsicSignature: extrinsic ::', extrinsic.toHex()); - extrinsic.sign(pair, options); + extrinsic.sign(pair, signerOptions || {}); - signerCallback && signerCallback(id, true); + if (isFunction(signerCb)) { + signerCb(id, true); + } } }