diff --git a/src/config/entities/__tests__/configuration.ts b/src/config/entities/__tests__/configuration.ts index 95c9f8222c..638ffa1826 100644 --- a/src/config/entities/__tests__/configuration.ts +++ b/src/config/entities/__tests__/configuration.ts @@ -117,6 +117,7 @@ export default (): ReturnType => ({ confirmationView: false, eventsQueue: false, delegatesV2: false, + counterfactualBalances: false, }, httpClient: { requestTimeout: faker.number.int() }, locking: { diff --git a/src/config/entities/configuration.ts b/src/config/entities/configuration.ts index dc14328c4d..d1a6cf14d3 100644 --- a/src/config/entities/configuration.ts +++ b/src/config/entities/configuration.ts @@ -183,6 +183,8 @@ export default () => ({ process.env.FF_CONFIRMATION_VIEW?.toLowerCase() === 'true', eventsQueue: process.env.FF_EVENTS_QUEUE?.toLowerCase() === 'true', delegatesV2: process.env.FF_DELEGATES_V2?.toLowerCase() === 'true', + counterfactualBalances: + process.env.FF_COUNTERFACTUAL_BALANCES?.toLowerCase() === 'true', }, httpClient: { // Timeout in milliseconds to be used for the HTTP client. diff --git a/src/datasources/balances-api/balances-api.manager.spec.ts b/src/datasources/balances-api/balances-api.manager.spec.ts index 5901be4729..f26fa06673 100644 --- a/src/datasources/balances-api/balances-api.manager.spec.ts +++ b/src/datasources/balances-api/balances-api.manager.spec.ts @@ -73,6 +73,7 @@ beforeEach(() => { configurationServiceMock.getOrThrow.mockImplementation((key) => { if (key === 'features.zerionBalancesChainIds') return ZERION_BALANCES_CHAIN_IDS; + if (key === 'features.counterfactualBalances') return true; }); }); @@ -156,6 +157,7 @@ describe('Balances API Manager Tests', () => { return notFoundExpireTimeSeconds; else if (key === 'features.zerionBalancesChainIds') return ZERION_BALANCES_CHAIN_IDS; + else if (key === 'features.counterfactualBalances') return true; throw new Error(`Unexpected key: ${key}`); }); configApiMock.getChain.mockResolvedValue(chain); diff --git a/src/datasources/balances-api/balances-api.manager.ts b/src/datasources/balances-api/balances-api.manager.ts index 9d5927a9f3..19af491642 100644 --- a/src/datasources/balances-api/balances-api.manager.ts +++ b/src/datasources/balances-api/balances-api.manager.ts @@ -18,6 +18,7 @@ import { ITransactionApiManager } from '@/domain/interfaces/transaction-api.mana @Injectable() export class BalancesApiManager implements IBalancesApiManager { private safeBalancesApiMap: Record = {}; + private readonly isCounterFactualBalancesEnabled: boolean; private readonly zerionChainIds: string[]; private readonly zerionBalancesApi: IBalancesApi; private readonly useVpcUrl: boolean; @@ -34,6 +35,10 @@ export class BalancesApiManager implements IBalancesApiManager { @Inject(ITransactionApiManager) private readonly transactionApiManager: ITransactionApiManager, ) { + this.isCounterFactualBalancesEnabled = + this.configurationService.getOrThrow( + 'features.counterfactualBalances', + ); this.zerionChainIds = this.configurationService.getOrThrow( 'features.zerionBalancesChainIds', ); @@ -51,16 +56,20 @@ export class BalancesApiManager implements IBalancesApiManager { return this.zerionBalancesApi; } - // SafeBalancesApi will be returned only if TransactionApi returns the Safe data. - // Otherwise ZerionBalancesApi will be returned as the Safe is considered counterfactual/not deployed. - try { - const transactionApi = - await this.transactionApiManager.getTransactionApi(chainId); - await transactionApi.getSafe(safeAddress); - return this._getSafeBalancesApi(chainId); - } catch { - return this.zerionBalancesApi; + if (this.isCounterFactualBalancesEnabled) { + // SafeBalancesApi will be returned only if TransactionApi returns the Safe data. + // Otherwise ZerionBalancesApi will be returned as the Safe is considered counterfactual/not deployed. + try { + const transactionApi = + await this.transactionApiManager.getTransactionApi(chainId); + await transactionApi.getSafe(safeAddress); + return this._getSafeBalancesApi(chainId); + } catch { + return this.zerionBalancesApi; + } } + + return this._getSafeBalancesApi(chainId); } async getFiatCodes(): Promise { diff --git a/src/routes/balances/__tests__/controllers/zerion-balances.controller.spec.ts b/src/routes/balances/__tests__/controllers/zerion-balances.controller.spec.ts index 2ce03e7b5a..734b33e1db 100644 --- a/src/routes/balances/__tests__/controllers/zerion-balances.controller.spec.ts +++ b/src/routes/balances/__tests__/controllers/zerion-balances.controller.spec.ts @@ -62,6 +62,10 @@ describe('Balances Controller (Unit)', () => { }, }, }, + features: { + ...defaultConfiguration.features, + counterfactualBalances: true, + }, }); const moduleFixture: TestingModule = await Test.createTestingModule({ diff --git a/src/routes/balances/balances.controller.spec.ts b/src/routes/balances/balances.controller.spec.ts index f6e9dce21b..220d09d4f9 100644 --- a/src/routes/balances/balances.controller.spec.ts +++ b/src/routes/balances/balances.controller.spec.ts @@ -38,8 +38,17 @@ describe('Balances Controller (Unit)', () => { beforeEach(async () => { jest.resetAllMocks(); + const defaultConfiguration = configuration(); + const testConfiguration = (): typeof defaultConfiguration => ({ + ...defaultConfiguration, + features: { + ...defaultConfiguration.features, + counterfactualBalances: true, + }, + }); + const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule.register(configuration)], + imports: [AppModule.register(testConfiguration)], }) .overrideModule(AccountDataSourceModule) .useModule(TestAccountDataSourceModule) diff --git a/src/routes/collectibles/collectibles.controller.spec.ts b/src/routes/collectibles/collectibles.controller.spec.ts index ca4583db47..be601be122 100644 --- a/src/routes/collectibles/collectibles.controller.spec.ts +++ b/src/routes/collectibles/collectibles.controller.spec.ts @@ -44,8 +44,17 @@ describe('Collectibles Controller (Unit)', () => { beforeEach(async () => { jest.resetAllMocks(); + const defaultConfiguration = configuration(); + const testConfiguration = (): typeof defaultConfiguration => ({ + ...defaultConfiguration, + features: { + ...defaultConfiguration.features, + counterfactualBalances: false, + }, + }); + const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule.register(configuration)], + imports: [AppModule.register(testConfiguration)], }) .overrideModule(AccountDataSourceModule) .useModule(TestAccountDataSourceModule) @@ -154,7 +163,7 @@ describe('Collectibles Controller (Unit)', () => { ) .expect(200); - expect(networkService.get.mock.calls[2][0].networkRequest).toStrictEqual({ + expect(networkService.get.mock.calls[1][0].networkRequest).toStrictEqual({ params: { limit: 10, offset: 20, @@ -200,7 +209,7 @@ describe('Collectibles Controller (Unit)', () => { ) .expect(200); - expect(networkService.get.mock.calls[2][0].networkRequest).toStrictEqual({ + expect(networkService.get.mock.calls[1][0].networkRequest).toStrictEqual({ params: { limit: PaginationData.DEFAULT_LIMIT, offset: PaginationData.DEFAULT_OFFSET, diff --git a/src/routes/safes/safes.controller.overview.spec.ts b/src/routes/safes/safes.controller.overview.spec.ts index 55f71c66ac..da27d1d546 100644 --- a/src/routes/safes/safes.controller.overview.spec.ts +++ b/src/routes/safes/safes.controller.overview.spec.ts @@ -52,6 +52,10 @@ describe('Safes Controller Overview (Unit)', () => { maxOverviews: 3, }, }, + features: { + ...configuration().features, + counterfactualBalances: true, + }, }); const moduleFixture: TestingModule = await Test.createTestingModule({