Skip to content

Commit

Permalink
Add a "transactionId" param to an STX, accept new functions in a cons…
Browse files Browse the repository at this point in the history
…tructor, make clientId param mandatory
  • Loading branch information
dan437 committed Nov 25, 2024
1 parent bfb16b9 commit 17f09d3
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/SmartTransactionsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,8 @@ async function withController<ReturnValue>(
deviceModel: 'ledger',
});
}),
getFeatureFlags: jest.fn(),
updateTransaction: jest.fn(),
...options,
});

Expand Down
59 changes: 48 additions & 11 deletions src/SmartTransactionsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import type {
UnsignedTransaction,
GetTransactionsOptions,
MetaMetricsProps,
FeatureFlags,
ClientId,
} from './types';
import { APIType, SmartTransactionStatuses } from './types';
import {
Expand All @@ -53,11 +55,11 @@ import {
getTxHash,
getSmartTransactionMetricsProperties,
getSmartTransactionMetricsSensitiveProperties,
getReturnTxHashAsap,
} from './utils';

const SECOND = 1000;
export const DEFAULT_INTERVAL = SECOND * 5;
const DEFAULT_CLIENT_ID = 'default';
const ETH_QUERY_ERROR_MSG =
'`ethQuery` is not defined on SmartTransactionsController';

Expand Down Expand Up @@ -178,7 +180,7 @@ export type SmartTransactionsControllerMessenger =

type SmartTransactionsControllerOptions = {
interval?: number;
clientId?: string;
clientId: ClientId;
chainId?: Hex;
supportedChainIds?: Hex[];
getNonceLock: TransactionController['getNonceLock'];
Expand All @@ -198,6 +200,8 @@ type SmartTransactionsControllerOptions = {
messenger: SmartTransactionsControllerMessenger;
getTransactions: (options?: GetTransactionsOptions) => TransactionMeta[];
getMetaMetricsProps: () => Promise<MetaMetricsProps>;
getFeatureFlags: () => FeatureFlags;
updateTransaction: (transaction: TransactionMeta, note: string) => void;
};

export type SmartTransactionsControllerPollingInput = {
Expand All @@ -211,7 +215,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
> {
#interval: number;

#clientId: string;
#clientId: ClientId;

#chainId: Hex;

Expand All @@ -233,6 +237,10 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo

readonly #getMetaMetricsProps: () => Promise<MetaMetricsProps>;

#getFeatureFlags: SmartTransactionsControllerOptions['getFeatureFlags'];

#updateTransaction: SmartTransactionsControllerOptions['updateTransaction'];

/* istanbul ignore next */
async #fetch(request: string, options?: RequestInit) {
const fetchOptions = {
Expand All @@ -248,7 +256,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo

constructor({
interval = DEFAULT_INTERVAL,
clientId = DEFAULT_CLIENT_ID,
clientId,
chainId: InitialChainId = ChainId.mainnet,
supportedChainIds = [ChainId.mainnet, ChainId.sepolia],
getNonceLock,
Expand All @@ -258,6 +266,8 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
messenger,
getTransactions,
getMetaMetricsProps,
getFeatureFlags,
updateTransaction,
}: SmartTransactionsControllerOptions) {
super({
name: controllerName,
Expand All @@ -279,6 +289,8 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
this.#getRegularTransactions = getTransactions;
this.#trackMetaMetricsEvent = trackMetaMetricsEvent;
this.#getMetaMetricsProps = getMetaMetricsProps;
this.#getFeatureFlags = getFeatureFlags;
this.#updateTransaction = updateTransaction;

this.initializeSmartTransactionsForChainId();

Expand Down Expand Up @@ -519,6 +531,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
cancelledNonceIndex > -1
? currentSmartTransactions
.slice(0, cancelledNonceIndex)
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
.concat(currentSmartTransactions.slice(cancelledNonceIndex + 1))
.concat(historifiedSmartTransaction)
: currentSmartTransactions.concat(historifiedSmartTransaction);
Expand All @@ -530,24 +543,47 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
return;
}

const currentSmartTransaction = currentSmartTransactions[currentIndex];
const nextSmartTransaction = {
...currentSmartTransaction,
...smartTransaction,
};

// We have to emit this event here, because then a txHash is returned to the TransactionController once it's available
// and the #doesTransactionNeedConfirmation function will work properly, since it will find the txHash in the regular transactions list.
this.messagingSystem.publish(
`SmartTransactionsController:smartTransaction`,
smartTransaction,
nextSmartTransaction,
);

if (nextSmartTransaction.status === SmartTransactionStatuses.CANCELLED) {
const returnTxHashAsap = getReturnTxHashAsap(
this.#clientId,
this.#getFeatureFlags()?.smartTransactions,
);
if (returnTxHashAsap && nextSmartTransaction.transactionId) {
const foundTransaction = this.#getRegularTransactions().find(
(transaction) =>
transaction.id === nextSmartTransaction.transactionId,
);
if (foundTransaction) {
const updatedTransaction = {
...foundTransaction,
status: TransactionStatus.failed,
};
this.#updateTransaction(
updatedTransaction as TransactionMeta,
'Smart transaction cancelled',
);
}
}
}

if (
(smartTransaction.status === SmartTransactionStatuses.SUCCESS ||
smartTransaction.status === SmartTransactionStatuses.REVERTED) &&
!smartTransaction.confirmed
) {
// confirm smart transaction
const currentSmartTransaction = currentSmartTransactions[currentIndex];
const nextSmartTransaction = {
...currentSmartTransaction,
...smartTransaction,
};
await this.#confirmSmartTransaction(nextSmartTransaction, {
chainId,
ethQuery,
Expand Down Expand Up @@ -892,6 +928,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
txHash: submitTransactionResponse.txHash,
cancellable: true,
type: transactionMeta?.type ?? 'swap',
transactionId: transactionMeta?.id,
},
{ chainId, ethQuery },
);
Expand Down
4 changes: 4 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SmartTransactionsController, {
type AllowedActions,
type AllowedEvents,
} from './SmartTransactionsController';
import { ClientId } from './types';

describe('default export', () => {
it('exports SmartTransactionsController', () => {
Expand All @@ -30,6 +31,9 @@ describe('default export', () => {
getMetaMetricsProps: jest.fn(async () => {
return Promise.resolve({});
}),
getFeatureFlags: jest.fn(),
updateTransaction: jest.fn(),
clientId: ClientId.Extension,
});
expect(controller).toBeInstanceOf(SmartTransactionsController);
jest.clearAllTimers();
Expand Down
13 changes: 13 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export enum SmartTransactionStatuses {
RESOLVED = 'resolved',
}

export enum ClientId {
Mobile = 'mobile',
Extension = 'extension',
}

export const cancellationReasonToStatusMap = {
[SmartTransactionCancellationReason.WOULD_REVERT]:
SmartTransactionStatuses.CANCELLED_WOULD_REVERT,
Expand Down Expand Up @@ -97,6 +102,7 @@ export type SmartTransaction = {
accountHardwareType?: string;
accountType?: string;
deviceModel?: string;
transactionId?: string; // It's an ID for a regular transaction from the TransactionController.
};

export type Fee = {
Expand Down Expand Up @@ -140,3 +146,10 @@ export type MetaMetricsProps = {
accountType?: string;
deviceModel?: string;
};

export type FeatureFlags = {
smartTransactions?: {
mobileReturnTxHashAsap?: boolean;
extensionReturnTxHashAsap?: boolean;
};
};
19 changes: 18 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import _ from 'lodash';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
import { API_BASE_URL, SENTINEL_API_BASE_URL_MAP } from './constants';
import type { SmartTransaction, SmartTransactionsStatus } from './types';
import type {
SmartTransaction,
SmartTransactionsStatus,
FeatureFlags,
} from './types';
import {
APIType,
SmartTransactionStatuses,
SmartTransactionCancellationReason,
SmartTransactionMinedTx,
cancellationReasonToStatusMap,
ClientId,
} from './types';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Expand Down Expand Up @@ -263,3 +268,15 @@ export const getSmartTransactionMetricsSensitiveProperties = (
device_model: smartTransaction.deviceModel,
};
};

export const getReturnTxHashAsap = (
clientId: ClientId,
smartTransactionsFeatureFlags: FeatureFlags['smartTransactions'],
) => {
if (!clientId) {
return false;
}
return clientId === ClientId.Extension
? smartTransactionsFeatureFlags?.extensionReturnTxHashAsap
: smartTransactionsFeatureFlags?.mobileReturnTxHashAsap;
};

0 comments on commit 17f09d3

Please sign in to comment.