Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PE-6985: create new ArNS undername in the file ArNS name assignment flow #1947

Merged
merged 15 commits into from
Jan 22, 2025
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
1 change: 0 additions & 1 deletion deploy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@
"dependencies": {
"permaweb-deploy": "1.1.6"
}

}
56 changes: 56 additions & 0 deletions lib/arns/domain/arns_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';

import 'package:ardrive/arns/data/arns_dao.dart';
import 'package:ardrive/arns/domain/exceptions.dart';
import 'package:ardrive/authentication/ardrive_auth.dart';
import 'package:ardrive/core/arfs/repository/file_repository.dart';
import 'package:ardrive/entities/profile_types.dart';
Expand All @@ -21,6 +22,7 @@ abstract class ARNSRepository {
required String processId,
bool uploadNewRevision = true,
});
Future<void> createUndername({required ARNSUndername undername});
Future<List<sdk.ANTRecord>> getAntRecordsForWallet(String address,
{bool update = false});
Future<List<sdk.ARNSUndername>> getARNSUndernames(sdk.ANTRecord record,
Expand All @@ -34,6 +36,7 @@ abstract class ARNSRepository {
Future<void> waitForARNSRecordsToUpdate();
Future<sdk.ARNSUndername> getUndernameByDomainAndName(
String domain, String name);
Future<List<sdk.ArNSNameModel>> getARNSNameModelsForWallet(String address);
Future<PrimaryNameDetails> getPrimaryName(String address,
{bool update = false, bool getLogo = true});

Expand Down Expand Up @@ -185,6 +188,53 @@ class _ARNSRepository implements ARNSRepository {
}
}

@override
Future<void> createUndername({
required ARNSUndername undername,
}) async {
// verify if the undername already exists
final undernames = _cachedUndernames[undername.domain]!;

if (undernames.containsKey(undername.name)) {
throw UndernameAlreadyExistsException();
}

if (_auth.currentUser.profileType == ProfileType.arConnect) {
logger.d('Setting undername with ArConnect');

final id = await _sdk.setUndernameWithArConnect(
txId: undername.record.transactionId,
domain: undername.domain,
undername: undername.name,
);

logger.d('Undername set with ArConnect: $id');
} else {
await _sdk.setUndername(
jwtString: _auth.getJWTAsString(),
domain: undername.domain,
txId: undername.record.transactionId,
undername: undername.name,
);
}

_cachedUndernames[undername.domain]![undername.name] = undername;

await _arnsDao.saveARNSRecord(
domain: undername.domain,
transactionId: undername.record.transactionId,
isActive: true,
undername: undername.name,
ttl: undername.record.ttlSeconds,
fileId: '', // we don't have a file id for the undername
);

await updateARNSRecordsActiveStatus(
domain: undername.domain,
name: undername.name,
);
}

Completer<List<sdk.ANTRecord>>? _getARNSUndernamesCompleter;

@override
Expand Down Expand Up @@ -397,6 +447,12 @@ class _ARNSRepository implements ARNSRepository {
return undername;
}

@override
Future<List<sdk.ArNSNameModel>> getARNSNameModelsForWallet(
String address) async {
return _sdk.getArNSNames(address);
}

@override
Future<PrimaryNameDetails> getPrimaryName(String address,
{bool update = false, bool getLogo = true}) async {
Expand Down
1 change: 1 addition & 0 deletions lib/arns/domain/exceptions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class UndernameAlreadyExistsException implements Exception {}
121 changes: 86 additions & 35 deletions lib/arns/presentation/assign_name_bloc/assign_name_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class AssignNameBloc extends Bloc<AssignNameEvent, AssignNameState> {
final ARNSRepository _arnsRepository;
final ArDriveAuth _auth;
ARNSUndername? _selectedUndername;
ANTRecord? _selectedANTRecord;
// TODO: remove this later
ArNSNameModel? _selectedNameModel;

AssignNameBloc({
required ArDriveAuth auth,
Expand All @@ -23,61 +24,99 @@ class AssignNameBloc extends Bloc<AssignNameEvent, AssignNameState> {
}) : _auth = auth,
_arnsRepository = arnsRepository,
super(AssignNameInitial()) {
on<LoadNames>((event, emit) async {
try {
emit(LoadingNames());

final walletAddress = await _auth.getWalletAddress();

final names =
await _arnsRepository.getAntRecordsForWallet(walletAddress!);

if (names.isEmpty) {
emit(AssignNameEmptyState());
} else {
emit(NamesLoaded(names: names));
on<LoadNames>(
(event, emit) async {
try {
logger.d('Loading names');
emit(LoadingNames());

final walletAddress = await _auth.getWalletAddress();

final names = await _arnsRepository
.getAntRecordsForWallet(walletAddress!, update: false);

final nameModels =
await _arnsRepository.getARNSNameModelsForWallet(walletAddress);

if (names.isEmpty) {
emit(AssignNameEmptyState());
} else {
logger.d('Names loaded');
emit(NamesLoaded(nameModels: nameModels));
}
} catch (e) {
logger.e('Failed to load ArNS names', e);
emit(LoadingNamesFailed());
}
} catch (e) {
logger.e('Failed to load ArNS names', e);
emit(LoadingNamesFailed());
}
});
},
);

on<SelectName>((event, emit) async {
_selectedANTRecord = event.name;

if (state is NamesLoaded) {
emit(
(state as NamesLoaded).copyWith(
selectedName: event.name,
selectedName: event.nameModel,
),
);
}
if (state is UndernamesLoaded) {

if (state is UndernamesLoaded &&
_selectedNameModel?.name == event.nameModel.name) {
emit(
NamesLoaded(
names: (state as UndernamesLoaded).names,
selectedName: _selectedANTRecord),
nameModels: (state as UndernamesLoaded).nameModels,
selectedName: _selectedNameModel,
),
);
}

_selectedNameModel = event.nameModel;
});

on<LoadUndernames>(
(event, emit) async {
final names = (state as NamesLoaded).names;
if (state is UndernamesLoaded) {
final undernames = await _arnsRepository.getARNSUndernames(
ANTRecord(
domain: _selectedNameModel!.name,
processId: _selectedNameModel!.processId,
),
);

if (undernames.length > 1) {
undernames.removeWhere((element) => element.name == '@');
}

emit(
UndernamesLoaded(
nameModels: (state as UndernamesLoaded).nameModels,
selectedName: _selectedNameModel!,
undernames: undernames,
selectedUndername: null,
),
);

return;
}

final names = (state as NamesLoaded).nameModels;
emit(LoadingUndernames());

final undernames =
await _arnsRepository.getARNSUndernames(_selectedANTRecord!);
final undernames = await _arnsRepository.getARNSUndernames(
ANTRecord(
domain: _selectedNameModel!.name,
processId: _selectedNameModel!.processId,
),
);

if (undernames.length > 1) {
undernames.removeWhere((element) => element.name == '@');
}

emit(
UndernamesLoaded(
selectedName: _selectedANTRecord!,
names: names,
nameModels: names,
selectedName: _selectedNameModel!,
undernames: undernames,
selectedUndername: null,
),
Expand Down Expand Up @@ -111,7 +150,7 @@ class AssignNameBloc extends Bloc<AssignNameEvent, AssignNameState> {
name: '@',
record: ARNSRecord(
transactionId: fileDataTableItem.dataTxId, ttlSeconds: 3600),
domain: _selectedANTRecord!.domain,
domain: _selectedNameModel!.name,
);
} else {
undername = ARNSUndername(
Expand All @@ -120,19 +159,19 @@ class AssignNameBloc extends Bloc<AssignNameEvent, AssignNameState> {
transactionId: fileDataTableItem.dataTxId,
ttlSeconds: 3600,
),
domain: _selectedANTRecord!.domain,
domain: _selectedNameModel!.name,
);
}

await _arnsRepository.setUndernamesToFile(
undername: undername,
fileId: fileDataTableItem.fileId,
driveId: fileDataTableItem.driveId,
processId: _selectedANTRecord!.processId,
processId: _selectedNameModel!.processId,
);

final (address, arAddress) = getAddressesFromArns(
domain: _selectedANTRecord!.domain,
domain: _selectedNameModel!.name,
undername: _selectedUndername?.name,
);

Expand All @@ -146,9 +185,21 @@ class AssignNameBloc extends Bloc<AssignNameEvent, AssignNameState> {
}
});

on<ShowSuccessModal>((event, emit) async {
final (address, arAddress) = getAddressesFromArns(
domain: event.undername.domain,
undername: event.undername.name,
);

emit(NameAssignedWithSuccess(
address: address,
arAddress: arAddress,
));
});

on<ConfirmSelection>((event, emit) async {
emit(SelectionConfirmed(
selectedName: _selectedANTRecord!,
selectedName: _selectedNameModel!,
selectedUndername: _selectedUndername,
));
});
Expand Down
17 changes: 13 additions & 4 deletions lib/arns/presentation/assign_name_bloc/assign_name_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ final class LoadNames extends AssignNameEvent {
final class CloseAssignName extends AssignNameEvent {}

final class SelectName extends AssignNameEvent {
final ANTRecord name;

const SelectName(this.name);
final ArNSNameModel nameModel;
const SelectName(this.nameModel);

@override
List<Object> get props => [name];
List<Object> get props => [nameModel];
}

final class LoadUndernames extends AssignNameEvent {
Expand All @@ -47,3 +46,13 @@ final class SelectUndername extends AssignNameEvent {
final class ConfirmSelectionAndUpload extends AssignNameEvent {}

final class ConfirmSelection extends AssignNameEvent {}

final class ShowSuccessModal extends AssignNameEvent {
final ARNSUndername undername;

const ShowSuccessModal({required this.undername});

@override
List<Object> get props => [undername];
}
//
Loading
Loading