Skip to content

Commit

Permalink
refactor: WT-1811 parallelise get ERC20 and Native balances when usin…
Browse files Browse the repository at this point in the history
…g the indexer (#1044)
  • Loading branch information
andrearampin authored Oct 24, 2023
1 parent f171ee6 commit c48d97e
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 45 deletions.
2 changes: 1 addition & 1 deletion packages/checkout/sdk/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const config: Config = {
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
transformIgnorePatterns: [],
transformIgnorePatterns: []
};

export default config;
11 changes: 6 additions & 5 deletions packages/checkout/sdk/src/balances/balances.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ describe('balances', () => {
expect(getAllBalancesResult.balances).toEqual([]);
});

const testcases = [{
const testCases = [{
errorMessage: 'test',
expectedErrorMessage: 'test',
},
Expand All @@ -585,14 +585,15 @@ describe('balances', () => {
expectedErrorMessage: 'InternalServerError | getTokensByWalletAddress',
}];

testcases.forEach((testcase) => {
testCases.forEach(async (testCase) => {
it('should call getIndexerBalance and throw error', async () => {
getTokensByWalletAddressMock = jest.fn().mockRejectedValue(
{ code: HttpStatusCode.Forbidden, message: testcase.errorMessage },
{ code: HttpStatusCode.Forbidden, message: testCase.errorMessage },
);

(Blockscout as unknown as jest.Mock).mockReturnValue({
getTokensByWalletAddress: getTokensByWalletAddressMock,
getNativeTokenByWalletAddress: getNativeTokenByWalletAddressMock,
});

const chainId = Object.keys(BLOCKSCOUT_CHAIN_URL_MAP)[0] as unknown as ChainId;
Expand Down Expand Up @@ -621,11 +622,11 @@ describe('balances', () => {

expect(getTokensByWalletAddressMock).toHaveBeenCalledTimes(1);

expect(message).toEqual(testcase.expectedErrorMessage);
expect(message).toEqual(testCase.expectedErrorMessage);
expect(type).toEqual(CheckoutErrorType.GET_INDEXER_BALANCE_ERROR);
expect(data).toEqual({
code: HttpStatusCode.Forbidden,
message: testcase.errorMessage,
message: testCase.errorMessage,
});
});
});
Expand Down
90 changes: 51 additions & 39 deletions packages/checkout/sdk/src/balances/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { getTokenAllowList } from '../tokens';
import { CheckoutConfiguration, getL1ChainId } from '../config';
import {
Blockscout,
BlockscoutToken,
BlockscoutTokens,
BlockscoutTokenType,
} from '../client';
Expand Down Expand Up @@ -114,58 +115,69 @@ export const getIndexerBalance = async (
}

// Hold the items in an array for post-fetching processing
const items = [];
const items: BlockscoutToken[] = [];

const tokenType = BlockscoutTokenType.ERC20;
// Given that the widgets aren't yet designed to support pagination,
// fetch all the possible tokens associated to a given wallet address.
let resp: BlockscoutTokens | undefined;
try {
do {

const erc20Balances = async (client: Blockscout) => {
// Given that the widgets aren't yet designed to support pagination,
// fetch all the possible tokens associated to a given wallet address.
let resp: BlockscoutTokens | undefined;
try {
do {
// eslint-disable-next-line no-await-in-loop
resp = await blockscoutClient.getTokensByWalletAddress({
walletAddress,
tokenType,
nextPage: resp?.next_page_params,
});
items.push(...resp.items);
} while (resp.next_page_params);
} catch (err: any) {
resp = await client.getTokensByWalletAddress({
walletAddress,
tokenType,
nextPage: resp?.next_page_params,
});
items.push(...resp.items);
} while (resp.next_page_params);
} catch (err: any) {
// In case of a 404, the wallet is a new wallet that hasn't been indexed by
// the Blockscout just yet. This happens when a wallet hasn't had any
// activity on the chain. In this case, simply ignore the error and return
// no currencies.
// In case of a malformed wallet address, Blockscout returns a 422, which
// means we are safe to assume that a 404 is a missing wallet due to inactivity
// or simply an incorrect wallet address was provided.
if (err?.code !== HttpStatusCode.NotFound) {
throw new CheckoutError(
err.message || 'InternalServerError | getTokensByWalletAddress',
CheckoutErrorType.GET_INDEXER_BALANCE_ERROR,
err,
);
if (err?.code !== HttpStatusCode.NotFound) {
throw new CheckoutError(
err.message || 'InternalServerError | getTokensByWalletAddress',
CheckoutErrorType.GET_INDEXER_BALANCE_ERROR,
err,
);
}
}
}
};

try {
const respNative = await blockscoutClient.getNativeTokenByWalletAddress({ walletAddress });
items.push(respNative);
} catch (err: any) {
// In case of a 404, the wallet is a new wallet that hasn't been indexed by
// the Blockscout just yet. This happens when a wallet hasn't had any
// activity on the chain. In this case, simply ignore the error and return
// no currencies.
// In case of a malformed wallet address, Blockscout returns a 422, which
// means we are safe to assume that a 404 is a missing wallet due to inactivity
// or simply an incorrect wallet address was provided.
if (err?.code !== HttpStatusCode.NotFound) {
throw new CheckoutError(
err.message || 'InternalServerError | getNativeTokenByWalletAddress',
CheckoutErrorType.GET_INDEXER_BALANCE_ERROR,
err,
);
const nativeBalances = async (client: Blockscout) => {
try {
const respNative = await client.getNativeTokenByWalletAddress({ walletAddress });
items.push(respNative);
} catch (err: any) {
// In case of a 404, the wallet is a new wallet that hasn't been indexed by
// the Blockscout just yet. This happens when a wallet hasn't had any
// activity on the chain. In this case, simply ignore the error and return
// no currencies.
// In case of a malformed wallet address, Blockscout returns a 422, which
// means we are safe to assume that a 404 is a missing wallet due to inactivity
// or simply an incorrect wallet address was provided.
if (err?.code !== HttpStatusCode.NotFound) {
throw new CheckoutError(
err.message || 'InternalServerError | getNativeTokenByWalletAddress',
CheckoutErrorType.GET_INDEXER_BALANCE_ERROR,
err,
);
}
}
}
};

// Promise all() rather than allSettled() so that the function can fail fast.
await Promise.all([
erc20Balances(blockscoutClient),
nativeBalances(blockscoutClient),
]);

const balances: GetBalanceResult[] = [];
items.forEach((item) => {
Expand Down

0 comments on commit c48d97e

Please sign in to comment.