Files
sxchnge/frontend/packages/sxchnge_wallet/lib/src/destinations/models.dart
T

256 lines
6.5 KiB
Dart

enum DestinationType { crypto, card, russianBank }
enum EligibilityState {
eligible,
temporarilyUnavailable,
requiresAction,
unsupported,
}
enum DestinationIssue {
invalid,
unavailable,
uncertain,
conflict,
removed,
expired,
bankChanged,
authorization,
unsupported,
duplicate,
replacementRequired,
}
enum SaveOutcome { created, duplicate }
enum BindingState { ready, expired, revoked, unavailable }
class DestinationException implements Exception {
const DestinationException(this.issue, {this.field});
final DestinationIssue issue;
final String? field;
}
sealed class DestinationDetails {
const DestinationDetails();
DestinationType get type;
String get display;
String get review;
}
class CryptoDestination extends DestinationDetails {
const CryptoDestination({
required this.assetId,
required this.networkId,
required this.address,
this.memo = '',
required this.assetLabel,
required this.networkLabel,
});
final String assetId, networkId, address, memo, assetLabel, networkLabel;
@override
DestinationType get type => DestinationType.crypto;
@override
String get display =>
'$assetLabel · $networkLabel · ${address.length > 14 ? '${address.substring(0, 6)}…${address.substring(address.length - 6)}' : address}';
@override
String get review =>
'$assetLabel · $networkLabel\n$address${memo.isEmpty ? '' : '\n$memo'}';
}
/// Secure capture references are short lived, not PAN/CVV or destination IDs.
class CardDestination extends DestinationDetails {
const CardDestination({
this.capture = '',
this.identity = '',
required this.brand,
required this.last4,
required this.expiryMonth,
required this.expiryYear,
});
final String capture, identity, brand, last4;
final int expiryMonth, expiryYear;
@override
DestinationType get type => DestinationType.card;
@override
String get display => '$brand · •••• $last4';
@override
String get review => display;
}
class RussianBankDestination extends DestinationDetails {
const RussianBankDestination({
required this.firstName,
required this.lastName,
this.patronymic = '',
required this.bank,
required this.account,
});
final String firstName, lastName, patronymic, account;
final Bank bank;
String get holder =>
[firstName, lastName, patronymic].where((s) => s.isNotEmpty).join(' ');
@override
DestinationType get type => DestinationType.russianBank;
@override
String get display =>
'${bank.name} · •••• ${account.length < 4 ? account : account.substring(account.length - 4)}';
@override
String get review =>
'$holder\n${bank.name}\n${bank.bik}\n$account\n${bank.correspondent}';
}
class Bank {
const Bank({
required this.bik,
required this.name,
required this.city,
required this.correspondent,
required this.revision,
this.supported = true,
});
final String bik, name, city, correspondent, revision;
final bool supported;
}
class CryptoAsset {
const CryptoAsset(
this.id,
this.label,
this.networkId,
this.networkLabel, {
this.memoRequired = false,
this.memoSupported = false,
});
final String id, label, networkId, networkLabel;
final bool memoRequired, memoSupported;
}
class ProviderBinding {
const ProviderBinding({
required this.reference,
required this.state,
required this.reusable,
this.recoverable = false,
this.expiresAt,
});
final String reference;
final BindingState state;
final bool reusable, recoverable;
final DateTime? expiresAt;
}
class OwnershipAssessment {
const OwnershipAssessment({
this.declaredOwn = true,
this.verified = false,
this.actionRequired = false,
});
final bool declaredOwn, verified, actionRequired;
}
class SavedDestination {
SavedDestination({
required this.id,
required this.details,
this.nickname = '',
this.metadataRevision = 1,
this.executionRevision = 1,
this.removed = false,
this.lastUsed,
this.ownership = const OwnershipAssessment(),
List<ProviderBinding> bindings = const [],
}) : bindings = List.unmodifiable(bindings);
final String id, nickname;
final DestinationDetails details;
final int metadataRevision, executionRevision;
final bool removed;
final DateTime? lastUsed;
final OwnershipAssessment ownership;
final List<ProviderBinding> bindings;
String get label => nickname.isEmpty ? details.display : nickname;
SavedReference get input => SavedReference(id, executionRevision);
}
sealed class DestinationInput {
const DestinationInput();
}
class SavedReference extends DestinationInput {
const SavedReference(this.id, this.executionRevision);
final String id;
final int executionRevision;
}
class OneTimeDestination extends DestinationInput {
const OneTimeDestination(this.details);
final DestinationDetails details;
}
class PayoutContext {
const PayoutContext(this.source, {this.amount});
final String source;
final int? amount;
}
class PayoutEligibility {
const PayoutEligibility(this.state, {this.reason, this.canSave = true});
final EligibilityState state;
final DestinationIssue? reason;
final bool canSave;
bool get eligible => state == EligibilityState.eligible;
}
class DestinationValidation {
const DestinationValidation(this.details);
final DestinationDetails details;
}
class DestinationCapabilities {
DestinationCapabilities({
List<DestinationType> types = const [],
List<CryptoAsset> assets = const [],
this.reusableCards = false,
this.cardRecovery = false,
this.simulated = false,
}) : types = List.unmodifiable(types),
assets = List.unmodifiable(assets);
final List<DestinationType> types;
final List<CryptoAsset> assets;
final bool reusableCards, cardRecovery, simulated;
}
/// Outcome identity never changes when a record is later renamed or removed.
class CreationResult {
const CreationResult(this.outcome, this.destinationId);
final SaveOutcome outcome;
final String destinationId;
}
class DestinationLease {
const DestinationLease({
required this.input,
required this.snapshot,
required this.context,
required this.requirementsRevision,
required this.expiresAt,
});
final DestinationInput input;
final DestinationDetails snapshot;
final PayoutContext context;
final int requirementsRevision;
final DateTime expiresAt;
}
class DestinationAudit {
const DestinationAudit(
this.actor,
this.reference,
this.action,
this.outcome,
this.at,
);
final String actor, reference, action, outcome;
final DateTime at;
}