From 45775dd422cd7cb6a0a697dc9d124d231b55c96b Mon Sep 17 00:00:00 2001 From: Dawid Sowa Date: Fri, 29 Nov 2024 16:15:03 +0100 Subject: [PATCH] feat: add subintent polling [wip] --- packages/common/src/index.ts | 15 +++- .../src/components/card/card.stories.ts | 2 +- .../src/components/card/request-card.ts | 85 ++++++++++++++----- .../src/components/pages/requests.ts | 2 +- packages/dapp-toolkit/src/_types.ts | 1 + .../src/helpers/exponential-backoff.ts | 24 ++++-- .../connect-button/connect-button.module.ts | 20 +++-- .../src/modules/connect-button/subjects.ts | 2 +- .../src/modules/connect-button/types.ts | 2 +- .../src/modules/gateway/gateway.module.ts | 77 ++++++++++++----- .../src/modules/gateway/gateway.service.ts | 11 ++- .../dapp-toolkit/src/modules/gateway/types.ts | 2 + .../request-items/request-item.module.ts | 75 ++++++++++++---- .../resolvers/pre-authorization-response.ts | 3 +- .../resolvers/send-transaction-response.ts | 2 +- .../wallet-request/wallet-request.spec.ts | 18 ++-- .../modules/wallet-request/wallet-request.ts | 35 ++++---- 17 files changed, 262 insertions(+), 114 deletions(-) diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 42c5bfa3..81fe9750 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -28,18 +28,20 @@ export type RadixButtonMode = keyof typeof RadixButtonMode export type PersonaData = { field: string; value: string } export const RequestStatus = { + fail: 'fail', + lookup: 'lookup', + ignored: 'ignored', pending: 'pending', success: 'success', - fail: 'fail', + timedOut: 'timedOut', cancelled: 'cancelled', - ignored: 'ignored', } as const export const RequestItemType = { - loginRequest: 'loginRequest', dataRequest: 'dataRequest', - sendTransaction: 'sendTransaction', proofRequest: 'proofRequest', + loginRequest: 'loginRequest', + sendTransaction: 'sendTransaction', preAuthorizationRequest: 'preAuthorizationRequest', } as const @@ -49,6 +51,10 @@ export type RequestItemTypes = keyof typeof RequestItemType export type RequestStatusTypes = keyof typeof RequestStatus +/** + * Not used in the codebase. Will be removed in the next major release future. + * @deprecated + */ export type WalletRequest< RequestType extends RequestItemTypes, Status extends RequestStatusTypes, @@ -81,3 +87,4 @@ export type RequestItem = { metadata?: Record walletData?: any } + diff --git a/packages/connect-button/src/components/card/card.stories.ts b/packages/connect-button/src/components/card/card.stories.ts index 3e19f7e5..b32c0224 100644 --- a/packages/connect-button/src/components/card/card.stories.ts +++ b/packages/connect-button/src/components/card/card.stories.ts @@ -97,7 +97,7 @@ export const Requests: Story = { console.log('onIgnoreTransactionItem', event) }} ?showCancel="${args.showCancel}" - transactionIntentHash="${args.transactionIntentHash}" + hash="${args.transactionIntentHash}" > `, diff --git a/packages/connect-button/src/components/card/request-card.ts b/packages/connect-button/src/components/card/request-card.ts index c4fe3716..22554d5f 100644 --- a/packages/connect-button/src/components/card/request-card.ts +++ b/packages/connect-button/src/components/card/request-card.ts @@ -45,7 +45,7 @@ export class RadixRequestCard extends LitElement { @property({ type: String, }) - transactionIntentHash: string = '' + hash: string = '' render() { const icon = this.getIconFromStatus() @@ -57,8 +57,10 @@ export class RadixRequestCard extends LitElement { cancelled: 'Transaction Cancelled', ignored: 'Transaction Ignored', success: 'Send transaction', + lookup: '', + timedOut: '', content: html` - ${this.renderTxIntentHash()} + ${this.renderHash()} ${this.status === 'pending' ? html`
Open your Radix Wallet app to review the transaction @@ -73,11 +75,41 @@ export class RadixRequestCard extends LitElement { : ''} `, }, + preAuthorizationRequest: { + pending: 'Preauthorization Pending', + fail: 'Preauthorization Failed', + cancelled: 'Preauthorization Cancelled', + success: 'Preauthorization Request', + ignored: 'Preauthorization Ignored', + lookup: 'Preauthorization Lookup', + timedOut: 'Preauthorization Timed Out', + content: html` + ${this.renderHash()} + ${this.status === 'pending' + ? html`
+ Open your Radix Wallet app to review the preauthorization + ${this.showCancel + ? html`
+ Cancel +
` + : html`
+ Ignore +
`} +
` + : this.status === 'lookup' + ? html`
+
Ignore
+
` + : ''} + `, + }, dataRequest: { pending: 'Data Request Pending', fail: 'Data Request Rejected', cancelled: 'Data Request Rejected', ignored: '', + lookup: '', + timedOut: '', success: 'Data Request', content: this.getRequestContentTemplate( 'Open Your Radix Wallet App to complete the request', @@ -89,6 +121,8 @@ export class RadixRequestCard extends LitElement { cancelled: 'Login Request Rejected', success: 'Login Request', ignored: '', + lookup: '', + timedOut: '', content: this.getRequestContentTemplate( 'Open Your Radix Wallet App to complete the request', ), @@ -99,16 +133,8 @@ export class RadixRequestCard extends LitElement { cancelled: 'Proof Request Rejected', success: 'Proof Request', ignored: '', - content: this.getRequestContentTemplate( - 'Open Your Radix Wallet App to complete the request', - ), - }, - preAuthorizationRequest: { - pending: 'Preauthorization Request Pending', - fail: 'Preauthorization Request Rejected', - cancelled: 'Preauthorization Request Rejected', - success: 'Preauthorization Request', - ignored: '', + lookup: '', + timedOut: '', content: this.getRequestContentTemplate( 'Open Your Radix Wallet App to complete the request', ), @@ -136,7 +162,7 @@ export class RadixRequestCard extends LitElement { : '' } - private isErrorStatus(status: RequestStatusTypes) { + private hasErrorIcon(status: RequestStatusTypes) { return ( [ RequestStatus.cancelled, @@ -146,19 +172,31 @@ export class RadixRequestCard extends LitElement { ).includes(status) } + private hasPendingIcon(status: RequestStatusTypes) { + return ([RequestStatus.pending, RequestStatus.lookup] as string[]).includes( + status, + ) + } + + private hasIgnoredIcon(status: RequestStatusTypes) { + return ( + [RequestStatus.ignored, RequestStatus.timedOut] as string[] + ).includes(status) + } + private getIconFromStatus() { - return this.status === RequestStatus.pending + return this.hasPendingIcon(this.status) ? 'pending' - : this.status === RequestStatus.ignored + : this.hasIgnoredIcon(this.status) ? 'ignored' - : this.isErrorStatus(this.status) + : this.hasErrorIcon(this.status) ? 'error' : 'checked' } private getStylingFromStatus() { return classMap({ - dimmed: this.isErrorStatus(this.status), + dimmed: this.hasErrorIcon(this.status), inverted: this.status === 'pending', }) } @@ -189,12 +227,12 @@ export class RadixRequestCard extends LitElement { ) } - private renderTxIntentHash() { - return this.transactionIntentHash + private renderHash() { + return this.hash ? html`
ID: { event.preventDefault() this.dispatchEvent( @@ -202,8 +240,11 @@ export class RadixRequestCard extends LitElement { bubbles: true, composed: true, detail: { - type: 'transaction', - data: this.transactionIntentHash, + type: + this.type === 'sendTransaction' + ? 'transaction' + : 'subintent', + data: this.hash, }, }), ) diff --git a/packages/connect-button/src/components/pages/requests.ts b/packages/connect-button/src/components/pages/requests.ts index 16c36e29..98f09ba8 100644 --- a/packages/connect-button/src/components/pages/requests.ts +++ b/packages/connect-button/src/components/pages/requests.ts @@ -36,7 +36,7 @@ export class RadixRequestsPage extends LitElement { type="${requestItem.type}" status="${requestItem.status}" id="${requestItem.interactionId}" - transactionIntentHash="${requestItem.transactionIntentHash || ''}" + hash="${requestItem.transactionIntentHash || ''}" ?showCancel="${requestItem.showCancel}" timestamp=${requestItem.createdAt} >`, diff --git a/packages/dapp-toolkit/src/_types.ts b/packages/dapp-toolkit/src/_types.ts index 9c2dba77..68038185 100644 --- a/packages/dapp-toolkit/src/_types.ts +++ b/packages/dapp-toolkit/src/_types.ts @@ -37,6 +37,7 @@ export type Providers = { export type ExplorerConfig = { baseUrl: string transactionPath: string + subintentPath: string accountsPath: string } diff --git a/packages/dapp-toolkit/src/helpers/exponential-backoff.ts b/packages/dapp-toolkit/src/helpers/exponential-backoff.ts index a2a42f37..7ffc8aef 100644 --- a/packages/dapp-toolkit/src/helpers/exponential-backoff.ts +++ b/packages/dapp-toolkit/src/helpers/exponential-backoff.ts @@ -6,7 +6,7 @@ import { map, merge, of, Subject, switchMap, timer } from 'rxjs' export type ExponentialBackoffInput = { multiplier?: number maxDelayTime?: number - timeout?: number + timeout?: number | Date interval?: number } export type ExponentialBackoff = typeof ExponentialBackoff @@ -17,6 +17,7 @@ export const ExponentialBackoff = ({ interval = 2_000, }: ExponentialBackoffInput = {}) => { const trigger = new Subject() + const stop = new Subject() let numberOfRetries = 0 const backoff$ = merge( @@ -36,12 +37,19 @@ export const ExponentialBackoff = ({ ) const withBackoffAndTimeout$: Observable> = - timeout - ? merge( - backoff$, - timer(timeout).pipe(map(() => err({ error: 'timeout' }))), - ) - : backoff$ + merge( + stop.asObservable().pipe(map(() => err({ error: 'stopped' }))), + timeout + ? merge( + backoff$, + timer(timeout).pipe(map(() => err({ error: 'timeout' }))), + ) + : backoff$, + ) - return { trigger, withBackoff$: withBackoffAndTimeout$ } + return { + trigger, + withBackoff$: withBackoffAndTimeout$, + stop: () => stop.next(), + } } diff --git a/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts b/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts index ea527513..d6fa601a 100644 --- a/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts +++ b/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts @@ -66,11 +66,13 @@ export const ConnectButtonModule = ( const logger = input?.logger?.getSubLogger({ name: 'ConnectButtonModule' }) const subjects = input.subjects || ConnectButtonSubjects() const dAppDefinitionAddress = input.dAppDefinitionAddress - const { baseUrl, accountsPath, transactionPath } = input.explorer ?? { - baseUrl: RadixNetworkConfigById[input.networkId].dashboardUrl, - transactionPath: '/transaction/', - accountsPath: '/account/', - } + const { baseUrl, accountsPath, transactionPath, subintentPath } = + input.explorer ?? { + baseUrl: RadixNetworkConfigById[input.networkId].dashboardUrl, + transactionPath: '/transaction/', + subintentPath: '/subintent/', + accountsPath: '/account/', + } const statusStorage = input.providers.storageModule const stateModule = input.providers.stateModule @@ -287,11 +289,15 @@ export const ConnectButtonModule = ( subjects.onLinkClick .pipe( tap(({ type, data }) => { - if (['account', 'transaction'].includes(type)) { + if (['account', 'transaction', 'subintent'].includes(type)) { if (!baseUrl || !window) return const url = `${baseUrl}${ - type === 'transaction' ? transactionPath : accountsPath + type === 'transaction' + ? transactionPath + : type === 'subintent' + ? subintentPath + : accountsPath }${data}` window.open(url) diff --git a/packages/dapp-toolkit/src/modules/connect-button/subjects.ts b/packages/dapp-toolkit/src/modules/connect-button/subjects.ts index 1f842b19..03b97d8f 100644 --- a/packages/dapp-toolkit/src/modules/connect-button/subjects.ts +++ b/packages/dapp-toolkit/src/modules/connect-button/subjects.ts @@ -31,7 +31,7 @@ export const ConnectButtonSubjects = () => ({ personaData: new BehaviorSubject<{ value: string; field: string }[]>([]), dAppName: new BehaviorSubject(''), onLinkClick: new Subject<{ - type: 'account' | 'transaction' | 'setupGuide' | 'showQrCode' | 'getWallet' + type: 'account' | 'transaction' | 'setupGuide' | 'showQrCode' | 'getWallet' | 'subintent' data: string }>(), }) diff --git a/packages/dapp-toolkit/src/modules/connect-button/types.ts b/packages/dapp-toolkit/src/modules/connect-button/types.ts index 0655460c..93bf8cc9 100644 --- a/packages/dapp-toolkit/src/modules/connect-button/types.ts +++ b/packages/dapp-toolkit/src/modules/connect-button/types.ts @@ -23,7 +23,7 @@ export type ConnectButtonModuleOutput = { onShowPopover$: Observable onCancelRequestItem$: Observable onLinkClick$: Observable<{ - type: 'account' | 'transaction' | 'showQrCode' | 'setupGuide' | 'getWallet' + type: 'account' | 'transaction' | 'showQrCode' | 'setupGuide' | 'getWallet' | 'subintent' data: string }> setMode: (value: 'light' | 'dark') => void diff --git a/packages/dapp-toolkit/src/modules/gateway/gateway.module.ts b/packages/dapp-toolkit/src/modules/gateway/gateway.module.ts index a6f2ae8f..4a8d0e1c 100644 --- a/packages/dapp-toolkit/src/modules/gateway/gateway.module.ts +++ b/packages/dapp-toolkit/src/modules/gateway/gateway.module.ts @@ -8,7 +8,7 @@ import { ExponentialBackoff, } from '../../helpers' import { SdkError } from '../../error' -import { TransactionStatus, TransactionStatusResponse } from './types' +import { SubintentStatus, TransactionStatus } from './types' import { GatewayApiClientConfig } from '../../_types' export type GatewayModule = ReturnType @@ -25,17 +25,12 @@ export const GatewayModule = (input: { const gatewayApi = input?.providers?.gatewayApiService ?? GatewayApiService(input.clientConfig) - const pollTransactionStatus = ( - transactionIntentHash: string, - ): ResultAsync => { - const retry = ExponentialBackoff(input.retryConfig) - - const completedTransactionStatus = new Set([ - 'CommittedSuccess', - 'CommittedFailure', - 'Rejected', - ]) - + const poll = ( + hash: string, + apiCall: (hash: string) => ResultAsync, + completedStatus: Set, + retry = ExponentialBackoff(input.retryConfig), + ): ResultAsync => { return ResultAsync.fromPromise( firstValueFrom( retry.withBackoff$.pipe( @@ -43,22 +38,20 @@ export const GatewayModule = (input: { if (result.isErr()) return [ err( - SdkError('failedToPollSubmittedTransaction', '', undefined, { + SdkError('failedToPoll', '', undefined, { error: result.error, context: 'GatewayModule.pollTransactionStatus.retry.withBackoff$', - transactionIntentHash, + hash, }), ), ] logger?.debug(`pollingTxStatus retry #${result.value + 1}`) - return gatewayApi - .getTransactionStatus(transactionIntentHash) + return apiCall(hash) .map((response) => { - if (completedTransactionStatus.has(response.status)) - return response + if (completedStatus.has(response)) return response retry.trigger.next() return @@ -75,17 +68,16 @@ export const GatewayModule = (input: { logger?.debug(response) return err( - SdkError('failedToPollSubmittedTransaction', '', undefined, { + SdkError('failedToPoll', '', undefined, { error: response, - transactionIntentHash, - context: - 'GatewayModule.pollTransactionStatus.getTransactionStatus', + hash, + context: 'GatewayModule.poll', }), ) }) }), filter( - (result): result is Result => + (result): result is Result => (result.isOk() && !!result.value) || result.isErr(), ), first(), @@ -95,7 +87,46 @@ export const GatewayModule = (input: { ).andThen((result) => result) } + const pollTransactionStatus = ( + transactionIntentHash: string, + ): ResultAsync => + poll( + transactionIntentHash, + (hash) => + gatewayApi.getTransactionStatus(hash).map(({ status }) => status), + new Set([ + 'CommittedSuccess', + 'CommittedFailure', + 'Rejected', + ]), + ) as ResultAsync + + const pollSubintentStatus = ( + subintentHash: string, + expirationTimestamp: number, + ) => { + const backoff = ExponentialBackoff({ + ...input.retryConfig, + maxDelayTime: 60_000, + timeout: new Date(expirationTimestamp * 1000), + }) + + return { + backoff, + result: poll( + subintentHash, + (hash) => + gatewayApi + .getSubintentStatus(hash) + .map(({ subintent_status }) => subintent_status), + new Set(['CommittedSuccess']), + backoff, + ) as ResultAsync, + } + } + return { + pollSubintentStatus, pollTransactionStatus, gatewayApi, configuration: input.clientConfig, diff --git a/packages/dapp-toolkit/src/modules/gateway/gateway.service.ts b/packages/dapp-toolkit/src/modules/gateway/gateway.service.ts index 73b70dae..263ae6a2 100644 --- a/packages/dapp-toolkit/src/modules/gateway/gateway.service.ts +++ b/packages/dapp-toolkit/src/modules/gateway/gateway.service.ts @@ -1,4 +1,4 @@ -import { EntityMetadataItem, TransactionStatus } from './types' +import { EntityMetadataItem, SubintentStatus, TransactionStatus } from './types' import { fetchWrapper } from '../../helpers' import { __VERSION__ } from '../../version' import { GatewayApiClientConfig } from '../../_types' @@ -32,12 +32,21 @@ export const GatewayApiService = ({ intent_hash: transactionIntentHash, }) + const getSubintentStatus = (subintentHash: string) => + fetchWithHeaders<{ subintent_status: SubintentStatus }>( + '/transaction/subintent-status', + { + subintent_hash: subintentHash, + }, + ) + const getEntityMetadataPage = (address: string) => fetchWithHeaders<{ items: EntityMetadataItem[] }>('/state/entity/page/metadata', { address }) return { + getSubintentStatus, getTransactionStatus, getEntityMetadataPage, } diff --git a/packages/dapp-toolkit/src/modules/gateway/types.ts b/packages/dapp-toolkit/src/modules/gateway/types.ts index 2e7ce320..1439760f 100644 --- a/packages/dapp-toolkit/src/modules/gateway/types.ts +++ b/packages/dapp-toolkit/src/modules/gateway/types.ts @@ -8,6 +8,8 @@ export const TransactionStatus = { Rejected: 'Rejected', } as const +export type SubintentStatus = Extract + export type MetadataStringValue = { type: 'String' value: string diff --git a/packages/dapp-toolkit/src/modules/wallet-request/request-items/request-item.module.ts b/packages/dapp-toolkit/src/modules/wallet-request/request-items/request-item.module.ts index dac84ad0..13d268f1 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/request-items/request-item.module.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/request-items/request-item.module.ts @@ -1,7 +1,8 @@ +import { GatewayModule } from './../../gateway/gateway.module' import { RequestStatus, type RequestItem, - type RequestStatusTypes, + RequestStatusTypes, } from 'radix-connect-common' import { Subscription, filter, map, switchMap } from 'rxjs' import { Logger } from '../../../helpers' @@ -10,16 +11,23 @@ import { WalletInteraction } from '../../../schemas' import type { StorageModule } from '../../storage' import { ResultAsync, errAsync } from 'neverthrow' import { WalletData } from '../../state' + +type ActivePolling = ReturnType export type RequestItemModuleInput = { logger?: Logger - providers: { storageModule: StorageModule } + providers: { + gatewayModule: GatewayModule + storageModule: StorageModule + } } export type RequestItemModule = ReturnType export const RequestItemModule = (input: RequestItemModuleInput) => { const logger = input?.logger?.getSubLogger({ name: 'RequestItemModule' }) const subscriptions = new Subscription() const storageModule = input.providers.storageModule + const signals = new Map void>() + const activePolling = new Map() const createItem = ({ type, @@ -82,6 +90,9 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { return patch(id, { status: 'fail', error: ErrorType.canceledByUser }) } + const isWalletInteractionRequired = (status: RequestStatusTypes) => + ([RequestStatus.pending, RequestStatus.lookup] as string[]).includes(status) + const updateStatus = ({ id, status, @@ -102,9 +113,39 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { .mapErr(() => ({ reason: 'couldNotReadFromStore' })) .andThen((item) => { if (item) { + if (status === RequestStatus.lookup) { + const polling = input.providers.gatewayModule.pollSubintentStatus( + transactionIntentHash!, + metadata.expirationTimestamp as number, + ) + activePolling.set(id, polling) + polling.result.andTee((result) => { + updateStatus({ + id, + status: RequestStatus.success, + metadata, + walletData, + transactionIntentHash, + }) + }) + + } + if (status === RequestStatus.ignored) { + if (activePolling.has(id)) { + const polling = activePolling.get(id) + polling?.backoff.stop() + activePolling.delete(id) + } + + if (signals.has(id)) { + signals.delete(id) + } + } const updated = { ...item, walletData, + transactionIntentHash, + error, status: item.status === RequestStatus.ignored ? item.status : status, metadata: item.metadata @@ -112,21 +153,10 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { : metadata, } as RequestItem - if (updated.status === 'fail') { - updated.transactionIntentHash = transactionIntentHash! - updated.error = error! - } - if ( - updated.status === 'success' && - updated.type === 'sendTransaction' - ) { - updated.transactionIntentHash = transactionIntentHash! - } - if ( - ['success', 'fail', 'ignored', 'cancelled'].includes(updated.status) - ) { + if (!isWalletInteractionRequired(updated.status)) { delete updated.walletInteraction } + logger?.debug({ method: 'updateRequestItemStatus', updated }) return storageModule .setItems({ [id]: updated }) @@ -136,6 +166,11 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { }) } + const getLookedUp = () => + storageModule + .getItemList() + .map((items) => items.filter((item) => item.status === 'lookup')) + const getPending = () => storageModule .getItemList() @@ -149,6 +184,15 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { filter((items): items is RequestItem[] => !!items), ) + const expireLookedUp = async () => { + + // getLookedUp().map((items) => {}) + // TODO: iterate over items and check if they are expired + // if expired, update status to 'timedOut' and stop polling and remove signal + } + + expireLookedUp() + return { add, cancel, @@ -156,6 +200,7 @@ export const RequestItemModule = (input: RequestItemModuleInput) => { patch, maybeGetSignal, getById: (id: string) => storageModule.getItemById(id), + getLookedUp, getPending, requests$, clear: storageModule.clear, diff --git a/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/pre-authorization-response.ts b/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/pre-authorization-response.ts index 1e274e8a..fb29f6af 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/pre-authorization-response.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/pre-authorization-response.ts @@ -37,7 +37,8 @@ export const preAuthorizationResponseResolver = return requestItemModule .updateStatus({ id: interactionId, - status: 'success', + status: RequestStatus.lookup, + transactionIntentHash: subintentHash, metadata: { signedPartialTransaction, expirationTimestamp, diff --git a/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/send-transaction-response.ts b/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/send-transaction-response.ts index 21efa10f..7de8849a 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/send-transaction-response.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/request-resolver/resolvers/send-transaction-response.ts @@ -55,7 +55,7 @@ export const sendTransactionResponseResolver = ), ) .andThen(() => gatewayModule.pollTransactionStatus(transactionIntentHash)) - .andThen(({ status }) => { + .andThen((status) => { const isFailedTransaction = determineFailedTransaction(status) const requestItemStatus = isFailedTransaction ? 'fail' : 'success' diff --git a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts index bfebdcc4..1e93d48a 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts @@ -14,25 +14,25 @@ import { delayAsync } from '../../test-helpers/delay-async' const createMockEnvironment = () => { const storageModule = LocalStorageModule(`rdt:${crypto.randomUUID()}:1`) - const requestItemModule = RequestItemModule({ - providers: { - storageModule, - }, - }) const gatewayModule = { pollTransactionStatus: (hash: string) => ResultAsync.fromSafePromise(delayAsync(2000)).map(() => ok({ status: 'success' as TransactionStatus }), ), } as any + const requestItemModule = RequestItemModule({ + providers: { + gatewayModule, + storageModule, + }, + }) + const updateConnectButtonStatus = () => {} - const stateModule = {} as any return { storageModule, requestItemModule, gatewayModule, updateConnectButtonStatus, - stateModule, } } @@ -45,13 +45,10 @@ describe('WalletRequestModule', () => { requestItemModule, gatewayModule, updateConnectButtonStatus, - stateModule, } = createMockEnvironment() const requestResolverModule = RequestResolverModule({ providers: { - stateModule, - gatewayModule, storageModule, requestItemModule, resolvers: [ @@ -61,7 +58,6 @@ describe('WalletRequestModule', () => { updateConnectButtonStatus, }), ], - updateConnectButtonStatus, }, }) diff --git a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts index 5f043df9..fc87af4d 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts @@ -11,7 +11,11 @@ import { import { validateRolaChallenge, type Logger } from '../../helpers' import { TransactionStatus } from '../gateway' import { ResultAsync, err, ok, okAsync } from 'neverthrow' -import type { MessageLifeCycleEvent, WalletInteraction } from '../../schemas' +import type { + MessageLifeCycleEvent, + SubintentResponseItem, + WalletInteraction, +} from '../../schemas' import { SdkError } from '../../error' import { DataRequestBuilderItem, @@ -83,6 +87,7 @@ export const WalletRequestModule = (input: { RequestItemModule({ logger, providers: { + gatewayModule, storageModule: storageModule.getPartition('requests'), }, }) @@ -100,7 +105,6 @@ export const WalletRequestModule = (input: { providers: { storageModule, requestItemModule, - stateModule, resolvers: [ sendTransactionResponseResolver({ gatewayModule, @@ -122,10 +126,6 @@ export const WalletRequestModule = (input: { updateConnectButtonStatus, }), ], - updateConnectButtonStatus: (status) => { - interactionStatusChangeSubject.next(status) - }, - gatewayModule, }, }) @@ -171,7 +171,11 @@ export const WalletRequestModule = (input: { filter((event) => event === 'receivedByWallet'), map(() => getRequest()), tap((request) => { - if (request.items.discriminator === 'transaction') + if ( + ['transaction', 'preAuthorizationRequest'].includes( + request.items.discriminator, + ) + ) requestItemModule.patch(id, { showCancel: false }) }), ), @@ -303,12 +307,7 @@ export const WalletRequestModule = (input: { const sendPreAuthorizationRequest = ( value: SendPreAuthorizationRequestInput, - ): ResultAsync< - { - signedPartialTransaction: string - }, - SdkError - > => { + ): ResultAsync => { const walletInteraction = walletRequestSdk.createWalletInteraction({ discriminator: 'preAuthorizationRequest', request: value.toRequestItem(), @@ -316,10 +315,12 @@ export const WalletRequestModule = (input: { return addNewRequest('preAuthorizationRequest', walletInteraction, false) .andThen(() => sendRequestAndAwaitResponse(walletInteraction)) - .map((requestItem) => ({ - signedPartialTransaction: requestItem.metadata - ?.signedPartialTransaction as string, - })) + .map( + (requestItem) => + ({ + ...requestItem.metadata, + }) as SubintentResponseItem, + ) } const sendRequest = ({