diff --git a/catalyst_voices/apps/voices/integration_test/suites/account_test.dart b/catalyst_voices/apps/voices/integration_test/suites/account_test.dart index d15536aa9ed..f670c0837a3 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/account_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/account_test.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices/app/view/app.dart'; import 'package:catalyst_voices/configs/bootstrap.dart'; import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:patrol_finders/patrol_finders.dart'; @@ -20,6 +21,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const DiscoveryRoute().location); }); diff --git a/catalyst_voices/apps/voices/integration_test/suites/app_test.dart b/catalyst_voices/apps/voices/integration_test/suites/app_test.dart index bf45ed6b05d..b79a245e03e 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/app_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/app_test.dart @@ -22,6 +22,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const DiscoveryRoute().location); }); diff --git a/catalyst_voices/apps/voices/integration_test/suites/discovery_test.dart b/catalyst_voices/apps/voices/integration_test/suites/discovery_test.dart index f52317a2dd6..cf6c057b672 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/discovery_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/discovery_test.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices/app/view/app.dart'; import 'package:catalyst_voices/configs/bootstrap.dart'; import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:patrol_finders/patrol_finders.dart'; @@ -18,6 +19,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const DiscoveryRoute().location); }); diff --git a/catalyst_voices/apps/voices/integration_test/suites/onboarding_restore_test.dart b/catalyst_voices/apps/voices/integration_test/suites/onboarding_restore_test.dart index 76fec601ee0..9fed2a9e7ab 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/onboarding_restore_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/onboarding_restore_test.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices/app/view/app.dart'; import 'package:catalyst_voices/configs/bootstrap.dart'; import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:patrol_finders/patrol_finders.dart'; @@ -27,6 +28,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const DiscoveryRoute().location); }); diff --git a/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart b/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart index f6562041b19..8e20e794275 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart @@ -2,6 +2,7 @@ import 'package:catalyst_voices/app/view/app.dart'; import 'package:catalyst_voices/configs/bootstrap.dart'; import 'package:catalyst_voices/routes/routes.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart' as blocs; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:patrol_finders/patrol_finders.dart'; @@ -38,6 +39,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const DiscoveryRoute().location); }); diff --git a/catalyst_voices/apps/voices/integration_test/suites/proposals_test.dart b/catalyst_voices/apps/voices/integration_test/suites/proposals_test.dart index ff3f760f697..aeb3e202218 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/proposals_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/proposals_test.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices/app/view/app.dart'; import 'package:catalyst_voices/configs/bootstrap.dart'; import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:patrol_finders/patrol_finders.dart'; @@ -17,6 +18,7 @@ void main() async { setUp(() async { await registerDependencies(); + registerConfig(AppConfig.dev()); router.go(const ProposalsRoute().location); }); diff --git a/catalyst_voices/apps/voices/lib/configs/bootstrap.dart b/catalyst_voices/apps/voices/lib/configs/bootstrap.dart index a0c399a9af3..00912283e2a 100644 --- a/catalyst_voices/apps/voices/lib/configs/bootstrap.dart +++ b/catalyst_voices/apps/voices/lib/configs/bootstrap.dart @@ -45,14 +45,14 @@ Future bootstrap({ environment ??= AppEnvironment.fromEnv(); await _cleanupOldStorages(); - await registerDependencies(environment: environment, config: null); + await registerDependencies(environment: environment); await _initCryptoUtils(); final configSource = ApiConfigSource(Dependencies.instance.get()); final configService = ConfigService(ConfigRepository(configSource)); final config = await configService.getAppConfig(env: environment.type); - Dependencies.instance.registerConfig(config); + registerConfig(config); router ??= buildAppRouter(); @@ -96,20 +96,20 @@ GoRouter buildAppRouter({ ); } +@visibleForTesting +void registerConfig(AppConfig config) { + Dependencies.instance.registerConfig(config); +} + @visibleForTesting Future registerDependencies({ AppEnvironment environment = const AppEnvironment.dev(), - AppConfig? config = const AppConfig.dev(), }) async { if (!Dependencies.instance.isInitialized) { await Dependencies.instance.init( environment: environment, ); } - - if (config != null) { - Dependencies.instance.registerConfig(config); - } } @visibleForTesting diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart index 9229984b322..b8ecf47b49e 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart @@ -26,7 +26,6 @@ final class RegistrationCubit extends Cubit final UserService _userService; final RegistrationService _registrationService; final RegistrationProgressNotifier _progressNotifier; - final BlockchainConfig _blockchainConfig; CatalystId? _accountId; Keychain? _keychain; @@ -42,7 +41,6 @@ final class RegistrationCubit extends Cubit }) : _userService = userService, _registrationService = registrationService, _progressNotifier = progressNotifier, - _blockchainConfig = blockchainConfig, _baseProfileCubit = BaseProfileCubit(), _keychainCreationCubit = KeychainCreationCubit( downloaderService: downloaderService, @@ -258,7 +256,6 @@ final class RegistrationCubit extends Cubit final transaction = await _registrationService.prepareRegistration( wallet: wallet, - networkId: _blockchainConfig.networkId, masterKey: masterKey, roles: transactionRoles, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart index 1b57d3eafe2..01641b6d932 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart @@ -38,7 +38,7 @@ void main() { keychainProvider = VaultKeychainProvider( secureStorage: const FlutterSecureStorage(), sharedPreferences: SharedPreferencesAsync(), - cacheConfig: const AppConfig.dev().cache, + cacheConfig: AppConfig.dev().cache, ); userRepository = _FakeUserRepository(); userObserver = StreamUserObserver(); diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/blockchain/blockchain_slot_config.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/blockchain/blockchain_slot_config.dart index 560d73bca21..663517e7f5b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/blockchain/blockchain_slot_config.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/blockchain/blockchain_slot_config.dart @@ -47,4 +47,16 @@ final class BlockchainSlotNumberConfig extends Equatable { systemStartSlot, slotLength, ]; + + BlockchainSlotNumberConfig copyWith({ + DateTime? systemStartTimestamp, + SlotBigNum? systemStartSlot, + Duration? slotLength, + }) { + return BlockchainSlotNumberConfig( + systemStartTimestamp: systemStartTimestamp ?? this.systemStartTimestamp, + systemStartSlot: systemStartSlot ?? this.systemStartSlot, + slotLength: slotLength ?? this.slotLength, + ); + } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/config/app_config.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/config/app_config.dart index e5b37d17c99..44a09fe73b6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/config/app_config.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/config/app_config.dart @@ -28,7 +28,7 @@ final class AppConfig extends Equatable { required this.blockchain, }); - const AppConfig.dev() + AppConfig.dev() : this( version: '0.0.1', cache: const CacheConfig( @@ -50,23 +50,24 @@ final class AppConfig extends Equatable { debug: true, diagnosticLevel: 'debug', ), - blockchain: const BlockchainConfig( + blockchain: BlockchainConfig( networkId: NetworkId.testnet, host: CatalystIdHost.cardanoPreprod, transactionBuilderConfig: _defaultTransactionBuilderConfig, + slotNumberConfig: BlockchainSlotNumberConfig.testnet(), ), ); factory AppConfig.env(AppEnvironmentType env) { return switch (env) { - AppEnvironmentType.dev => const AppConfig.dev(), - AppEnvironmentType.preprod => const AppConfig.preprod(), - AppEnvironmentType.prod => const AppConfig.prod(), - AppEnvironmentType.relative => const AppConfig.dev(), + AppEnvironmentType.dev => AppConfig.dev(), + AppEnvironmentType.preprod => AppConfig.preprod(), + AppEnvironmentType.prod => AppConfig.prod(), + AppEnvironmentType.relative => AppConfig.dev(), }; } - const AppConfig.preprod() + AppConfig.preprod() : this( version: '0.0.1', cache: const CacheConfig( @@ -88,14 +89,15 @@ final class AppConfig extends Equatable { debug: false, diagnosticLevel: 'warning', ), - blockchain: const BlockchainConfig( + blockchain: BlockchainConfig( networkId: NetworkId.testnet, host: CatalystIdHost.cardanoPreprod, transactionBuilderConfig: _defaultTransactionBuilderConfig, + slotNumberConfig: BlockchainSlotNumberConfig.testnet(), ), ); - const AppConfig.prod() + AppConfig.prod() : this( version: '0.0.1', cache: const CacheConfig( @@ -117,10 +119,11 @@ final class AppConfig extends Equatable { debug: false, diagnosticLevel: 'error', ), - blockchain: const BlockchainConfig( - networkId: NetworkId.testnet, + blockchain: BlockchainConfig( + networkId: NetworkId.mainnet, host: CatalystIdHost.cardano, transactionBuilderConfig: _defaultTransactionBuilderConfig, + slotNumberConfig: BlockchainSlotNumberConfig.mainnet(), ), ); @@ -154,26 +157,35 @@ final class BlockchainConfig extends Equatable { final NetworkId networkId; final CatalystIdHost host; final TransactionBuilderConfig transactionBuilderConfig; + final BlockchainSlotNumberConfig slotNumberConfig; const BlockchainConfig({ required this.networkId, required this.host, required this.transactionBuilderConfig, + required this.slotNumberConfig, }); @override - List get props => [networkId, host, transactionBuilderConfig]; + List get props => [ + networkId, + host, + transactionBuilderConfig, + slotNumberConfig, + ]; BlockchainConfig copyWith({ NetworkId? networkId, CatalystIdHost? host, TransactionBuilderConfig? transactionBuilderConfig, + BlockchainSlotNumberConfig? slotNumberConfig, }) { return BlockchainConfig( networkId: networkId ?? this.networkId, host: host ?? this.host, transactionBuilderConfig: transactionBuilderConfig ?? this.transactionBuilderConfig, + slotNumberConfig: slotNumberConfig ?? this.slotNumberConfig, ); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/app_config_factory.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/app_config_factory.dart index fb8ea0af45c..93559d5b8cb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/app_config_factory.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/app_config_factory.dart @@ -41,6 +41,14 @@ final class AppConfigFactory { remoteTransactionBuilderConfig?.selectionStrategy?.build(), ); + // Slot Number Config + final remoteSlotNumberConfig = remoteBlockchainConfig?.slotNumberConfig; + final effectiveSlotNumberConfig = blockchain.slotNumberConfig.copyWith( + systemStartTimestamp: remoteSlotNumberConfig?.systemStartTimestamp, + systemStartSlot: remoteSlotNumberConfig?.systemStartSlot?.asSlotBigNum(), + slotLength: remoteSlotNumberConfig?.slotLength?.asDuration(), + ); + return defaultEnvConfig.copyWith( version: remote.version, cache: defaultEnvConfig.cache.copyWith( @@ -65,6 +73,7 @@ final class AppConfigFactory { networkId: remoteBlockchainConfig?.networkId?.tryParseNetworkId(), host: remoteBlockchainConfig?.host?.tryParseCatalystIdHost(), transactionBuilderConfig: effectiveTransactionBuilderConfig, + slotNumberConfig: effectiveSlotNumberConfig, ), ); } @@ -82,6 +91,8 @@ extension on int { Coin asCoin() => Coin(this); Duration asDuration() => Duration(seconds: this); + + SlotBigNum asSlotBigNum() => SlotBigNum(this); } extension on RemoteTransactionSelectionStrategyType { diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/config/remote_blockchain_config.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/config/remote_blockchain_config.dart index 306651de1d1..b33cd8a5979 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/config/remote_blockchain_config.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/config/remote_blockchain_config.dart @@ -7,11 +7,13 @@ final class RemoteBlockchainConfig { final String? networkId; final String? host; final RemoteTransactionBuilderConfig? transactionBuilderConfig; + final RemoteSlotNumberConfig? slotNumberConfig; RemoteBlockchainConfig({ this.networkId, this.host, this.transactionBuilderConfig, + this.slotNumberConfig, }); factory RemoteBlockchainConfig.fromJson(Map json) { @@ -19,6 +21,23 @@ final class RemoteBlockchainConfig { } } +@JsonSerializable(createToJson: false) +final class RemoteSlotNumberConfig { + final DateTime? systemStartTimestamp; + final int? systemStartSlot; + final int? slotLength; + + RemoteSlotNumberConfig({ + this.systemStartTimestamp, + this.systemStartSlot, + this.slotLength, + }); + + factory RemoteSlotNumberConfig.fromJson(Map json) { + return _$RemoteSlotNumberConfigFromJson(json); + } +} + @JsonSerializable(createToJson: false) final class RemoteTransactionBuilderConfig { final RemoteTransactionTieredFee? feeAlgo; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/configs.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/configs.dart index 33884ef78cb..59f243501a2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/configs.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/configs.dart @@ -65,6 +65,37 @@ abstract class Configs { "diagnosticLevel": "error" } } +'''; + + static String mainnetBlockchainSlotNumber = ''' +{ + "version": "0.1.0", + "createdAt": "2025-04-02T12:59:50.841808Z", + "blockchain": { + "networkId": "mainnet", + "host": "cardano", + "slotNumberConfig": { + "systemStartTimestamp":"2020-07-29T21:44:51.000000Z", + "systemStartSlot":4492800, + "slotLength":1 + } + } +} +'''; + static String testnetBlockchainSlotNumber = ''' +{ + "version": "0.1.0", + "createdAt": "2025-04-02T12:59:50.841808Z", + "blockchain": { + "networkId": "testnet", + "host": "cardano", + "slotNumberConfig": { + "systemStartTimestamp":"2022-06-21T00:00:00.000000Z", + "systemStartSlot":86400, + "slotLength":1 + } + } +} '''; const Configs._(); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/config_repository_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/config_repository_test.dart index a6023bba051..0803232425e 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/config_repository_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/config_repository_test.dart @@ -63,7 +63,7 @@ void main() { final remoteConfig = RemoteConfig.fromJson(configJson); const env = AppEnvironmentType.dev; - const expectedConfig = AppConfig.dev(); + final expectedConfig = AppConfig.dev(); // When when(remoteSource.get).thenAnswer((_) => Future.value(remoteConfig)); @@ -73,6 +73,54 @@ void main() { // Then expect(config, equals(expectedConfig)); }); + + test('mainnet blockchain slot number config is decoded correctly', + () async { + // Given + final configJson = jsonDecode(Configs.mainnetBlockchainSlotNumber) + as Map; + final remoteConfig = RemoteConfig.fromJson(configJson); + + final systemStartTimestamp = DateTime.utc(2020, 7, 29, 21, 44, 51); + const systemStartSlot = 4492800; + const slotLength = Duration(seconds: 1); + + // When + when(remoteSource.get).thenAnswer((_) => Future.value(remoteConfig)); + + // Then + final config = await repository.getConfig(env: AppEnvironmentType.dev); + + final slotNumberConfig = config.blockchain.slotNumberConfig; + + expect(slotNumberConfig.systemStartTimestamp, systemStartTimestamp); + expect(slotNumberConfig.systemStartSlot, systemStartSlot); + expect(slotNumberConfig.slotLength, slotLength); + }); + + test('testnet blockchain slot number config is decoded correctly', + () async { + // Given + final configJson = jsonDecode(Configs.testnetBlockchainSlotNumber) + as Map; + final remoteConfig = RemoteConfig.fromJson(configJson); + + final systemStartTimestamp = DateTime.utc(2022, 6, 21, 0, 0, 0); + const systemStartSlot = 86400; + const slotLength = Duration(seconds: 1); + + // When + when(remoteSource.get).thenAnswer((_) => Future.value(remoteConfig)); + + // Then + final config = await repository.getConfig(env: AppEnvironmentType.dev); + + final slotNumberConfig = config.blockchain.slotNumberConfig; + + expect(slotNumberConfig.systemStartTimestamp, systemStartTimestamp); + expect(slotNumberConfig.systemStartSlot, systemStartSlot); + expect(slotNumberConfig.slotLength, slotLength); + }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/blockchain/blockchain_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/blockchain/blockchain_service.dart index aa0f327ecd7..1219ace7167 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/blockchain/blockchain_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/blockchain/blockchain_service.dart @@ -4,12 +4,13 @@ import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; // TODO(dtscalac): move most blockchain/wallet related code to here abstract interface class BlockchainService { - const factory BlockchainService(BlockchainRepository blockchainRepository) = - BlockchainServiceImpl; + const factory BlockchainService( + BlockchainRepository blockchainRepository, + ) = BlockchainServiceImpl; Future calculateSlotNumber({ required DateTime targetDateTime, - required NetworkId networkId, + required BlockchainSlotNumberConfig config, }); Future getWalletBalance({ @@ -22,18 +23,15 @@ abstract interface class BlockchainService { final class BlockchainServiceImpl implements BlockchainService { final BlockchainRepository _blockchainRepository; - const BlockchainServiceImpl(this._blockchainRepository); + const BlockchainServiceImpl( + this._blockchainRepository, + ); @override Future calculateSlotNumber({ required DateTime targetDateTime, - required NetworkId networkId, + required BlockchainSlotNumberConfig config, }) async { - final config = switch (networkId) { - NetworkId.mainnet => BlockchainSlotNumberConfig.mainnet(), - NetworkId.testnet => BlockchainSlotNumberConfig.testnet(), - }; - final diff = targetDateTime.millisecondsSinceEpoch - config.systemStartTimestamp.millisecondsSinceEpoch; diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/registration/registration_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/registration/registration_service.dart index 3e6c7ed4a75..01111a0f30d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/registration/registration_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/registration/registration_service.dart @@ -54,7 +54,6 @@ abstract interface class RegistrationService { /// Throws a subclass of [RegistrationException] in case of a failure. Future prepareRegistration({ required CardanoWallet wallet, - required NetworkId networkId, required CatalystPrivateKey masterKey, required Set roles, }); @@ -163,7 +162,6 @@ final class RegistrationServiceImpl implements RegistrationService { @override Future prepareRegistration({ required CardanoWallet wallet, - required NetworkId networkId, required CatalystPrivateKey masterKey, required Set roles, }) async { @@ -171,9 +169,9 @@ final class RegistrationServiceImpl implements RegistrationService { final config = _blockchainConfig.transactionBuilderConfig; final enabledWallet = await wallet.enable(); final walletNetworkId = await enabledWallet.getNetworkId(); - if (walletNetworkId != networkId) { + if (walletNetworkId != _blockchainConfig.networkId) { throw RegistrationNetworkIdMismatchException( - targetNetworkId: networkId, + targetNetworkId: _blockchainConfig.networkId, ); } @@ -185,7 +183,7 @@ final class RegistrationServiceImpl implements RegistrationService { ), ); - final slotNumber = await _getRegistrationSlotNumberTtl(networkId); + final slotNumber = await _getRegistrationSlotNumberTtl(); final previousTransactionId = await _fetchPreviousTransactionId( isFirstRegistration: roles.isFirstRegistration, @@ -195,7 +193,7 @@ final class RegistrationServiceImpl implements RegistrationService { transactionConfig: config, keyDerivationService: _keyDerivationService, masterKey: masterKey, - networkId: networkId, + networkId: _blockchainConfig.networkId, slotNumberTtl: slotNumber, roles: roles, changeAddress: changeAddress, @@ -429,13 +427,15 @@ final class RegistrationServiceImpl implements RegistrationService { /// /// It's a common security practice to configure transactions /// to expire after a certain duration. - Future _getRegistrationSlotNumberTtl(NetworkId networkId) async { + Future _getRegistrationSlotNumberTtl() async { final registrationTransactionExpiration = DateTimeExt.now().add(const Duration(hours: 3)); + final config = _blockchainConfig.slotNumberConfig; + return _blockchainService.calculateSlotNumber( targetDateTime: registrationTransactionExpiration, - networkId: networkId, + config: config, ); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/blockchain/blockchain_service_test.dart b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/blockchain/blockchain_service_test.dart index 2dbcc721956..465f49fc812 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/blockchain/blockchain_service_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/blockchain/blockchain_service_test.dart @@ -12,7 +12,9 @@ void main() { setUp(() { walletRepository = _FakeWalletRepository(); - service = BlockchainService(walletRepository); + service = BlockchainService( + walletRepository, + ); }); test('getWalletBalance', () async { @@ -40,12 +42,12 @@ void main() { Future testSlotNumber({ required DateTime targetDateTime, - required NetworkId networkId, + required BlockchainSlotNumberConfig config, required SlotBigNum expected, }) async { final actual = await service.calculateSlotNumber( targetDateTime: targetDateTime, - networkId: networkId, + config: config, ); expect(actual, equals(expected)); @@ -55,7 +57,7 @@ void main() { test('https://preprod.cardanoscan.io/block/46', () async { await testSlotNumber( targetDateTime: DateTime.utc(2022, 6, 21, 0, 0, 0), - networkId: NetworkId.testnet, + config: BlockchainSlotNumberConfig.testnet(), expected: const SlotBigNum(86400), ); }); @@ -63,7 +65,7 @@ void main() { test('https://preprod.cardanoscan.io/block/2000000', () async { await testSlotNumber( targetDateTime: DateTime.utc(2024, 3, 4, 7, 17, 24), - networkId: NetworkId.testnet, + config: BlockchainSlotNumberConfig.testnet(), expected: const SlotBigNum(53853444), ); }); @@ -71,7 +73,7 @@ void main() { test('https://preprod.cardanoscan.io/block/3456000', () async { await testSlotNumber( targetDateTime: DateTime.utc(2025, 5, 8, 4, 54, 40), - networkId: NetworkId.testnet, + config: BlockchainSlotNumberConfig.testnet(), expected: const SlotBigNum(90996880), ); }); @@ -81,7 +83,7 @@ void main() { test('https://cardanoscan.io/block/4490511', () async { await testSlotNumber( targetDateTime: DateTime.utc(2020, 7, 29, 21, 44, 51), - networkId: NetworkId.mainnet, + config: BlockchainSlotNumberConfig.mainnet(), expected: const SlotBigNum(4492800), ); }); @@ -89,7 +91,7 @@ void main() { test('https://cardanoscan.io/block/8547193', () async { await testSlotNumber( targetDateTime: DateTime.utc(2023, 3, 21, 21, 44, 34), - networkId: NetworkId.mainnet, + config: BlockchainSlotNumberConfig.mainnet(), expected: const SlotBigNum(87868783), ); }); @@ -97,7 +99,7 @@ void main() { test('https://cardanoscan.io/block/10547193', () async { await testSlotNumber( targetDateTime: DateTime.utc(2024, 7, 8, 16, 57, 22), - networkId: NetworkId.mainnet, + config: BlockchainSlotNumberConfig.mainnet(), expected: const SlotBigNum(128891551), ); }); @@ -105,7 +107,7 @@ void main() { test('https://cardanoscan.io/block/11837000', () async { await testSlotNumber( targetDateTime: DateTime.utc(2025, 5, 8, 9, 34, 28), - networkId: NetworkId.mainnet, + config: BlockchainSlotNumberConfig.mainnet(), expected: const SlotBigNum(155130577), ); }); diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart index 451999d74d9..95733be4449 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart @@ -28,7 +28,7 @@ void main() { keychainProvider = VaultKeychainProvider( secureStorage: const FlutterSecureStorage(), sharedPreferences: SharedPreferencesAsync(), - cacheConfig: const AppConfig.dev().cache, + cacheConfig: AppConfig.dev().cache, ); userObserver = StreamUserObserver(); }); diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/test/src/keychain/vault_keychain_provider_test.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/test/src/keychain/vault_keychain_provider_test.dart index 7e765dd629a..c23c60bfc69 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/test/src/keychain/vault_keychain_provider_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/test/src/keychain/vault_keychain_provider_test.dart @@ -26,7 +26,7 @@ void main() { provider = VaultKeychainProvider( secureStorage: const FlutterSecureStorage(), sharedPreferences: SharedPreferencesAsync(), - cacheConfig: const AppConfig.dev().cache, + cacheConfig: AppConfig.dev().cache, ); }); diff --git a/config/dev/config.json b/config/dev/config.json index 6311e7cc3db..f8f04d8e4d7 100644 --- a/config/dev/config.json +++ b/config/dev/config.json @@ -1,38 +1,43 @@ { - "version":"0.0.1", - "cache":{ - "expiryDuration":{ - "keychainUnlock":3600 - } - }, - "sentry":{ - "dsn":"https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", - "environment":"dev", - "release":"catalyst-voices@dev", - "tracesSampleRate":1.0, - "profilesSampleRate":1.0, - "enableAutoSessionTracking":true, - "attachScreenshot":true, - "attachViewHierarchy":true, - "debug":true, - "diagnosticLevel":"debug" - }, - "blockchain":{ - "networkId":"testnet", - "host":"preprod.cardano", - "transactionBuilderConfig":{ - "feeAlgo":{ - "constant":155381, - "coefficient":44, - "multiplier":1.2, - "sizeIncrement":25600, - "refScriptByteCost":15, - "maxRefScriptSize":204800 - }, - "maxTxSize":16384, - "maxValueSize":5000, - "coinsPerUtxoByte":4310, - "selectionStrategy":"greedy" - } - } + "version": "0.0.1", + "cache": { + "expiryDuration": { + "keychainUnlock": 3600 + } + }, + "sentry": { + "dsn": "https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", + "environment": "dev", + "release": "catalyst-voices@dev", + "tracesSampleRate": 1.0, + "profilesSampleRate": 1.0, + "enableAutoSessionTracking": true, + "attachScreenshot": true, + "attachViewHierarchy": true, + "debug": true, + "diagnosticLevel": "debug" + }, + "blockchain": { + "networkId": "testnet", + "host": "preprod.cardano", + "transactionBuilderConfig": { + "feeAlgo": { + "constant": 155381, + "coefficient": 44, + "multiplier": 1.2, + "sizeIncrement": 25600, + "refScriptByteCost": 15, + "maxRefScriptSize": 204800 + }, + "maxTxSize": 16384, + "maxValueSize": 5000, + "coinsPerUtxoByte": 4310, + "selectionStrategy": "greedy" + }, + "slotNumberConfig": { + "systemStartTimestamp": "2022-06-21T00:00:00.000000Z", + "systemStartSlot": 86400, + "slotLength": 1 + } + } } \ No newline at end of file diff --git a/config/preprod/config.json b/config/preprod/config.json index ec69c9194dd..a2eca373105 100644 --- a/config/preprod/config.json +++ b/config/preprod/config.json @@ -1,38 +1,43 @@ { - "version":"0.0.1", - "cache":{ - "expiryDuration":{ - "keychainUnlock":3600 - } - }, - "sentry":{ - "dsn":"https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", - "environment":"preprod", - "release":"catalyst-voices@preprod", - "tracesSampleRate":0.2, - "profilesSampleRate":0.2, - "enableAutoSessionTracking":true, - "attachScreenshot":true, - "attachViewHierarchy":true, - "debug":false, - "diagnosticLevel":"warning" - }, - "blockchain":{ - "networkId":"testnet", - "host":"preprod.cardano", - "transactionBuilderConfig":{ - "feeAlgo":{ - "constant":155381, - "coefficient":44, - "multiplier":1.2, - "sizeIncrement":25600, - "refScriptByteCost":15, - "maxRefScriptSize":204800 - }, - "maxTxSize":16384, - "maxValueSize":5000, - "coinsPerUtxoByte":4310, - "selectionStrategy":"greedy" - } - } + "version": "0.0.1", + "cache": { + "expiryDuration": { + "keychainUnlock": 3600 + } + }, + "sentry": { + "dsn": "https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", + "environment": "preprod", + "release": "catalyst-voices@preprod", + "tracesSampleRate": 0.2, + "profilesSampleRate": 0.2, + "enableAutoSessionTracking": true, + "attachScreenshot": true, + "attachViewHierarchy": true, + "debug": false, + "diagnosticLevel": "warning" + }, + "blockchain": { + "networkId": "testnet", + "host": "preprod.cardano", + "transactionBuilderConfig": { + "feeAlgo": { + "constant": 155381, + "coefficient": 44, + "multiplier": 1.2, + "sizeIncrement": 25600, + "refScriptByteCost": 15, + "maxRefScriptSize": 204800 + }, + "maxTxSize": 16384, + "maxValueSize": 5000, + "coinsPerUtxoByte": 4310, + "selectionStrategy": "greedy" + }, + "slotNumberConfig": { + "systemStartTimestamp": "2022-06-21T00:00:00.000000Z", + "systemStartSlot": 86400, + "slotLength": 1 + } + } } \ No newline at end of file diff --git a/config/prod/config.json b/config/prod/config.json index 413dadafb35..13c329b2c75 100644 --- a/config/prod/config.json +++ b/config/prod/config.json @@ -1,38 +1,43 @@ { - "version":"0.0.1", - "cache":{ - "expiryDuration":{ - "keychainUnlock":3600 - } - }, - "sentry":{ - "dsn":"https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", - "environment":"prod", - "release":"catalyst-voices@prod", - "tracesSampleRate":0.1, - "profilesSampleRate":0.1, - "enableAutoSessionTracking":true, - "attachScreenshot":false, - "attachViewHierarchy":false, - "debug":false, - "diagnosticLevel":"error" - }, - "blockchain":{ - "networkId":"mainnet", - "host":"cardano", - "transactionBuilderConfig":{ - "feeAlgo":{ - "constant":155381, - "coefficient":44, - "multiplier":1.2, - "sizeIncrement":25600, - "refScriptByteCost":15, - "maxRefScriptSize":204800 - }, - "maxTxSize":16384, - "maxValueSize":5000, - "coinsPerUtxoByte":4310, - "selectionStrategy":"greedy" - } - } + "version": "0.0.1", + "cache": { + "expiryDuration": { + "keychainUnlock": 3600 + } + }, + "sentry": { + "dsn": "https://8e333ddbed1e096c70e4ed006892c355@o622089.ingest.us.sentry.io/4507113601433600", + "environment": "prod", + "release": "catalyst-voices@prod", + "tracesSampleRate": 0.1, + "profilesSampleRate": 0.1, + "enableAutoSessionTracking": true, + "attachScreenshot": false, + "attachViewHierarchy": false, + "debug": false, + "diagnosticLevel": "error" + }, + "blockchain": { + "networkId": "mainnet", + "host": "cardano", + "transactionBuilderConfig": { + "feeAlgo": { + "constant": 155381, + "coefficient": 44, + "multiplier": 1.2, + "sizeIncrement": 25600, + "refScriptByteCost": 15, + "maxRefScriptSize": 204800 + }, + "maxTxSize": 16384, + "maxValueSize": 5000, + "coinsPerUtxoByte": 4310, + "selectionStrategy": "greedy" + }, + "slotNumberConfig": { + "systemStartTimestamp": "2020-07-29T21:44:51.000000Z", + "systemStartSlot": 4492800, + "slotLength": 1 + } + } } \ No newline at end of file