Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/SmartTransactionsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@

controller.timeoutHandle = setTimeout(() => ({}));

controller.poll(1000);

Check warning on line 450 in src/SmartTransactionsController.test.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 450 in src/SmartTransactionsController.test.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

expect(updateSmartTransactionsSpy).toHaveBeenCalled();
});
Expand Down Expand Up @@ -722,6 +722,105 @@
expect(submittedSmartTransaction.deviceModel).toBe('ledger');
});
});

it('submits a batch of signed transactions', async () => {
await withController(async ({ controller }) => {
const signedTransaction1 = createSignedTransaction();
const signedTransaction2 = createSignedTransaction();
const submitTransactionsApiResponse =
createSubmitTransactionsApiResponse(); // It has uuid.
nock(API_BASE_URL)
.post(
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
)
.reply(200, submitTransactionsApiResponse);

const txParams = createTxParams();
const result = await controller.submitSignedTransactions({
signedTransactions: [signedTransaction1, signedTransaction2],
txParams,
});

// Check response has both txHash and txHashes
expect(result.uuid).toBe('dP23W7c2kt4FK9TmXOkz1UM2F20');
expect(result.txHash).toBeDefined();
expect(result.txHashes).toBeDefined();
expect(result.txHashes?.length).toBe(2);

// Check smart transaction has correct properties
const submittedSmartTransaction =
controller.state.smartTransactionsState.smartTransactions[
ChainId.mainnet
][0];
expect(submittedSmartTransaction.uuid).toBe(
'dP23W7c2kt4FK9TmXOkz1UM2F20',
);
expect(submittedSmartTransaction.txHashes).toBeDefined();
expect(submittedSmartTransaction.txHashes?.length).toBe(2);
expect(submittedSmartTransaction.txHash).toBe(result.txHashes[0]);
});
});

it('works with optional signedCanceledTransactions', async () => {
await withController(async ({ controller }) => {
const signedTransaction = createSignedTransaction();
const submitTransactionsApiResponse =
createSubmitTransactionsApiResponse();

// Verify that the request body has empty rawCancelTxs array when signedCanceledTransactions is omitted
let requestBody: any;
nock(API_BASE_URL)
.post(
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
(body) => {
requestBody = body;
return true;
},
)
.reply(200, submitTransactionsApiResponse);

await controller.submitSignedTransactions({
signedTransactions: [signedTransaction],
txParams: createTxParams(),
// No signedCanceledTransactions provided
});

// Verify the request was made with an empty rawCancelTxs array
expect(requestBody).toBeDefined();
expect(requestBody.rawCancelTxs).toStrictEqual([]);
});
});

it('works without txParams', async () => {
await withController(async ({ controller }) => {
const signedTransaction = createSignedTransaction();
const submitTransactionsApiResponse =
createSubmitTransactionsApiResponse();

nock(API_BASE_URL)
.post(
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
)
.reply(200, submitTransactionsApiResponse);

// This should not throw an error when txParams is missing
const result = await controller.submitSignedTransactions({
signedTransactions: [signedTransaction],
// No txParams provided
});

expect(result.uuid).toBe('dP23W7c2kt4FK9TmXOkz1UM2F20');

// The transaction should still be created in state
const submittedSmartTransaction =
controller.state.smartTransactionsState.smartTransactions[
ChainId.mainnet
][0];
expect(submittedSmartTransaction.uuid).toBe(
'dP23W7c2kt4FK9TmXOkz1UM2F20',
);
});
});
});

describe('fetchSmartTransactionsStatus', () => {
Expand Down Expand Up @@ -2163,7 +2262,7 @@
triggerNetworStateChange,
});
} finally {
controller.stop();

Check warning on line 2265 in src/SmartTransactionsController.test.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 2265 in src/SmartTransactionsController.test.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
controller.stopAllPolling();
}
}
20 changes: 13 additions & 7 deletions src/SmartTransactionsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,9 @@
isSmartTransactionPending,
);
if (!this.timeoutHandle && pendingTransactions?.length > 0) {
this.poll();

Check warning on line 351 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 351 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
} else if (this.timeoutHandle && pendingTransactions?.length === 0) {
this.stop();

Check warning on line 353 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 353 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}
}

Expand All @@ -375,7 +375,7 @@
}

this.timeoutHandle = setInterval(() => {
safelyExecute(async () => this.updateSmartTransactions());

Check warning on line 378 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 378 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}, this.#interval);
await safelyExecute(async () => this.updateSmartTransactions());
}
Expand Down Expand Up @@ -442,7 +442,7 @@
ethQuery = new EthQuery(provider);
}

this.#createOrUpdateSmartTransaction(smartTransaction, {

Check warning on line 445 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 445 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
chainId,
ethQuery,
});
Expand Down Expand Up @@ -721,7 +721,7 @@
: originalTxMeta;

if (this.#doesTransactionNeedConfirmation(txHash)) {
this.#confirmExternalTransaction(

Check warning on line 724 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (18.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check warning on line 724 in src/SmartTransactionsController.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test / Lint (20.x)

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
// TODO: Replace 'as' assertion with correct typing for `txMeta`
txMeta as TransactionMeta,
transactionReceipt,
Expand Down Expand Up @@ -916,11 +916,11 @@
transactionMeta,
txParams,
signedTransactions,
signedCanceledTransactions,
signedCanceledTransactions = [],
networkClientId,
}: {
signedTransactions: SignedTransaction[];
signedCanceledTransactions: SignedCanceledTransaction[];
signedCanceledTransactions?: SignedCanceledTransaction[];
transactionMeta?: TransactionMeta;
txParams?: TransactionParams;
networkClientId?: NetworkClientId;
Expand Down Expand Up @@ -948,10 +948,12 @@
const time = Date.now();
let preTxBalance;
try {
const preTxBalanceBN = await query(ethQuery, 'getBalance', [
txParams?.from,
]);
preTxBalance = new BigNumber(preTxBalanceBN).toString(16);
if (txParams?.from) {
const preTxBalanceBN = await query(ethQuery, 'getBalance', [
txParams.from,
]);
preTxBalance = new BigNumber(preTxBalanceBN).toString(16);
}
} catch (error) {
console.error('provider error', error);
}
Expand All @@ -970,9 +972,12 @@
nonceDetails = nonceLock.nonceDetails;
txParams.nonce ??= nonce;
}

const txHashes = signedTransactions.map((tx) => getTxHash(tx));
const submitTransactionResponse = {
...data,
txHash: getTxHash(signedTransactions[0]),
txHash: txHashes[0], // For backward compatibility
txHashes,
};

try {
Expand All @@ -990,6 +995,7 @@
type: transactionMeta?.type ?? 'swap',
transactionId: transactionMeta?.id,
networkClientId: selectedNetworkClientId,
txHashes, // Add support for multiple transaction hashes
},
{ chainId, ethQuery },
);
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export type SmartTransactionsStatus = {
export type SmartTransaction = {
uuid: string;
txHash?: string;
txHashes?: string[];
chainId?: string;
destinationTokenAddress?: string;
destinationTokenDecimals?: string;
Expand Down
Loading