Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
Open
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
12 changes: 11 additions & 1 deletion Features/Transfer/Sources/Services/ConfirmService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ChainService
import AddressNameService
import ActivityService
import EventPresenterService
import WalletService

public struct ConfirmService: Sendable {
private let metadataProvider: any TransferMetadataProvidable
Expand All @@ -16,6 +17,7 @@ public struct ConfirmService: Sendable {
private let keystore: any Keystore
private let chainService: any ChainServiceable
private let explorerService: any ExplorerLinkFetchable
private let walletService: WalletService
private let addressNameService: AddressNameService
private let activityService: ActivityService
private let eventPresenterService: EventPresenterService
Expand All @@ -27,6 +29,7 @@ public struct ConfirmService: Sendable {
transferExecutor: any TransferExecutable,
keystore: any Keystore,
chainService: any ChainServiceable,
walletService: WalletService,
addressNameService: AddressNameService,
activityService: ActivityService,
eventPresenterService: EventPresenterService
Expand All @@ -37,6 +40,7 @@ public struct ConfirmService: Sendable {
self.transferExecutor = transferExecutor
self.keystore = keystore
self.chainService = chainService
self.walletService = walletService
self.addressNameService = addressNameService
self.activityService = activityService
self.eventPresenterService = eventPresenterService
Expand Down Expand Up @@ -86,6 +90,12 @@ public struct ConfirmService: Sendable {
}

public func getAddressName(chain: Chain, address: String) throws -> AddressName? {
try addressNameService.getAddressName(chain: chain, address: address)
if let addressName = try addressNameService.getAddressName(chain: chain, address: address) {
return addressName
}
if let wallet = try walletService.getWallet(chain: chain, address: address) {
return AddressName(chain: chain, address: address, name: wallet.name, type: .internalWallet, status: .verified)
}
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import AddressNameService
import ActivityService
import EventPresenterService
import AssetsService
import WalletService

public struct ConfirmServiceFactory {
public static func create(
Expand All @@ -25,6 +26,7 @@ public struct ConfirmServiceFactory {
assetsService: AssetsService,
priceService: PriceService,
transactionStateService: TransactionStateService,
walletService: WalletService,
addressNameService: AddressNameService,
activityService: ActivityService,
eventPresenterService: EventPresenterService,
Expand All @@ -47,10 +49,13 @@ public struct ConfirmServiceFactory {
chainService: chainService,
assetsEnabler: assetsEnabler,
balanceService: balanceService,
transactionStateService: transactionStateService
transactionStateService: transactionStateService,
walletService: walletService,
addressNameService: addressNameService
),
keystore: keystore,
chainService: chainService,
walletService: walletService,
addressNameService: addressNameService,
activityService: activityService,
eventPresenterService: eventPresenterService
Expand Down
30 changes: 29 additions & 1 deletion Features/Transfer/Sources/Services/TransferExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Foundation
import Primitives
import Signer
import TransactionStateService
import WalletService
import AddressNameService

public protocol TransferExecutable: Sendable {
func execute(input: TransferConfirmationInput) async throws
Expand All @@ -20,19 +22,25 @@ public struct TransferExecutor: TransferExecutable {
private let assetsEnabler: any AssetsEnabler
private let balanceService: BalanceService
private let transactionStateService: TransactionStateService
private let walletService: WalletService
private let addressNameService: AddressNameService

public init(
signer: any TransactionSigneable,
chainService: any ChainServiceable,
assetsEnabler: any AssetsEnabler,
balanceService: BalanceService,
transactionStateService: TransactionStateService
transactionStateService: TransactionStateService,
walletService: WalletService,
addressNameService: AddressNameService
) {
self.signer = signer
self.chainService = chainService
self.assetsEnabler = assetsEnabler
self.balanceService = balanceService
self.transactionStateService = transactionStateService
self.walletService = walletService
self.addressNameService = addressNameService
}

public func execute(input: TransferConfirmationInput) async throws {
Expand Down Expand Up @@ -87,6 +95,7 @@ extension TransferExecutor {
totalTransactions: totalTransactions
)

try saveInternalWalletAddressName(input: input)
try transactionStateService.addTransactions(wallet: input.wallet, transactions: transactions)
Task {
do {
Expand Down Expand Up @@ -154,4 +163,23 @@ extension TransferExecutor {
default: .milliseconds(500)
}
}

private func saveInternalWalletAddressName(input: TransferConfirmationInput) throws {
switch input.data.type {
case .transfer, .transferNft:
break
case .swap, .tokenApprove, .stake, .account, .perpetual, .earn, .generic, .deposit, .withdrawal:
return
}
Comment on lines +168 to +173
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For improved readability and conciseness, you can simplify this switch statement by using a default case to handle all transaction types that should cause an early return. This avoids explicitly listing all of them and makes the intent clearer.

Suggested change
switch input.data.type {
case .transfer, .transferNft:
break
case .swap, .tokenApprove, .stake, .account, .perpetual, .earn, .generic, .deposit, .withdrawal:
return
}
switch input.data.type {
case .transfer, .transferNft:
break
default:
return
}


let chain = input.data.chain
if let senderAddress = try? input.wallet.account(for: chain).address, senderAddress.isNotEmpty {
try addressNameService.addWalletAddressName(wallet: input.wallet, chain: chain, address: senderAddress)
}

let recipientAddress = input.data.recipientData.recipient.address
if recipientAddress.isNotEmpty, let recipientWallet = try walletService.getWallet(chain: chain, address: recipientAddress) {
try addressNameService.addWalletAddressName(wallet: recipientWallet, chain: chain, address: recipientAddress)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extension ConfirmRecipientViewModel {
private var addressNameImage: AssetImage? {
switch addressName?.type {
case .contact: .image(Images.System.person)
case .internalWallet: .image(Images.System.wallet)
case .address, .contract, .validator, .none: nil
}
}
Expand Down
18 changes: 14 additions & 4 deletions Features/Transfer/Tests/Services/TransferExecutorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import SignerTestKit
import BalanceServiceTestKit
import TransactionStateService
import TransactionStateServiceTestKit
import AddressNameServiceTestKit
import WalletServiceTestKit
import Store
import StoreTestKit
import ChainServiceTestKit
Expand All @@ -25,7 +27,9 @@ struct TransferExecutorTests {
chainService: ChainServiceMock.mock(broadcastResponses: ["hash0", "hash1", "hash2", "hash3"]),
assetsEnabler: .mock(),
balanceService: .mock(),
transactionStateService: .mock(transactionStore: transactionStore)
transactionStateService: .mock(transactionStore: transactionStore),
walletService: .mock(),
addressNameService: .mock()
)

let input = TransferConfirmationInput(
Expand All @@ -51,7 +55,9 @@ struct TransferExecutorTests {
chainService: ChainServiceMock.mock(broadcastResponses: ["hash0", "hash1"]),
assetsEnabler: .mock(),
balanceService: .mock(),
transactionStateService: .mock(transactionStore: transactionStore)
transactionStateService: .mock(transactionStore: transactionStore),
walletService: .mock(),
addressNameService: .mock()
)

let input = TransferConfirmationInput(
Expand All @@ -77,7 +83,9 @@ struct TransferExecutorTests {
chainService: ChainServiceMock.mock(broadcastResponses: ["hash"]),
assetsEnabler: .mock(),
balanceService: .mock(),
transactionStateService: .mock(transactionStore: transactionStore)
transactionStateService: .mock(transactionStore: transactionStore),
walletService: .mock(),
addressNameService: .mock()
)

let input = TransferConfirmationInput(
Expand All @@ -104,7 +112,9 @@ struct TransferExecutorTests {
chainService: ChainServiceMock.mock(broadcastResponses: ["hash"]),
assetsEnabler: .mock(),
balanceService: .mock(),
transactionStateService: .mock(transactionStore: transactionStore)
transactionStateService: .mock(transactionStore: transactionStore),
walletService: .mock(),
addressNameService: .mock()
)

let input = TransferConfirmationInput(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ private extension ConfirmTransferSceneViewModel {
assetsService: .mock(),
priceService: .mock(),
transactionStateService: .mock(),
walletService: .mock(),
addressNameService: addressNameService,
activityService: .mock(),
eventPresenterService: .mock(),
Expand Down
1 change: 1 addition & 0 deletions Gem/Services/ViewModelFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public struct ViewModelFactory: Sendable {
assetsService: assetsService,
priceService: priceService,
transactionStateService: transactionStateService,
walletService: walletService,
addressNameService: addressNameService,
activityService: activityService,
eventPresenterService: eventPresenterService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public struct AddressNameService: Sendable {
try addressStore.getAddressName(chain: chain, address: address)
}

public func addWalletAddressName(wallet: Wallet, chain: Chain, address: String) throws {
try addressStore.addWalletAddressName(wallet: wallet, chain: chain, address: address)
}

public func getAddressNames(requests: [ChainAddress]) async throws -> [ChainAddress: AddressName] {
let requests = uniqueRequests(requests)
guard !requests.isEmpty else {
Expand Down
4 changes: 4 additions & 0 deletions Packages/FeatureServices/WalletService/WalletService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public struct WalletService: Sendable {
try walletSessionService.getWallet(walletId: walletId)
}

public func getWallet(chain: Chain, address: String) throws -> Wallet? {
try walletStore.getWallet(chain: chain, address: address)
}

public func acceptTerms() {
preferences.isAcceptTermsCompleted = true
}
Expand Down
1 change: 1 addition & 0 deletions Packages/Primitives/Sources/Scan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ public enum AddressType: String, Codable, Equatable, Sendable {
case contract
case validator
case contact
case internalWallet
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ public struct AddressListItemViewModel {

public var assetImageStyle: AssetImageView.Style? {
switch account.addressType {
case .contact: AssetImageView.Style(foregroundColor: Colors.secondaryText, cornerRadius: 0)
case .contact, .internalWallet: AssetImageView.Style(foregroundColor: Colors.secondaryText, cornerRadius: 0)
case .address, .contract, .validator, .none: nil
}
}

public var assetImageSize: CGFloat {
switch account.addressType {
case .contact: .list.accessory
case .contact, .internalWallet: .list.accessory
case .address, .contract, .validator, .none: .list.image
}
}
Expand Down
7 changes: 7 additions & 0 deletions Packages/Store/Sources/Migrations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,13 @@ struct Migrations {
try? FiatTransactionRecord.create(db: db)
}

migrator.registerMigration("Add walletId to \(AddressRecord.databaseTableName)") { db in
try? db.alter(table: AddressRecord.databaseTableName) {
$0.add(column: AddressRecord.Columns.walletId.name, .text)
.references(WalletRecord.databaseTableName, onDelete: .cascade, onUpdate: .cascade)
}
}

try migrator.migrate(dbQueue)
}
}
6 changes: 6 additions & 0 deletions Packages/Store/Sources/Models/AddressRecord.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,30 @@ struct AddressRecord: Codable, FetchableRecord, PersistableRecord, Sendable {
enum Columns {
static let chain = Column("chain")
static let address = Column("address")
static let walletId = Column("walletId")
static let name = Column("name")
static let type = Column("type")
static let status = Column("status")
}

let chain: Chain
let address: String
let walletId: String?
let name: String
let type: AddressType?
let status: VerificationStatus

init(
chain: Chain,
address: String,
walletId: String?,
name: String,
type: AddressType?,
status: VerificationStatus
) {
self.chain = chain
self.address = address
self.walletId = walletId
self.name = name
self.type = type
self.status = status
Expand All @@ -44,6 +48,8 @@ extension AddressRecord: CreateTable {
.references(AssetRecord.databaseTableName, onDelete: .cascade, onUpdate: .cascade)
$0.column(Columns.address.name, .text)
.notNull()
$0.column(Columns.walletId.name, .text)
.references(WalletRecord.databaseTableName, onDelete: .cascade, onUpdate: .cascade)
$0.column(Columns.name.name, .text)
.notNull()
$0.column(Columns.type.name, .text)
Expand Down
40 changes: 26 additions & 14 deletions Packages/Store/Sources/Stores/AddressStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Primitives

public struct AddressStore: Sendable {

let db: DatabaseQueue
private let db: DatabaseQueue

public init(db: DB) {
self.db = db.dbQueue
Expand All @@ -15,23 +15,22 @@ public struct AddressStore: Sendable {
public func addAddressNames(_ addressNames: [AddressName]) throws {
try db.write { db in
for addressName in addressNames {
try AddressRecord(
chain: addressName.chain,
address: addressName.address,
name: addressName.name,
type: addressName.type,
status: addressName.status
).save(db, onConflict: .replace)
try save(addressName: addressName, walletId: nil, db: db)
}
}
}

func deleteAddress(chain: Chain, address: String) throws -> Int {

public func addWalletAddressName(wallet: Wallet, chain: Chain, address: String) throws {
let addressName = AddressName(
chain: chain,
address: address,
name: wallet.name,
type: .internalWallet,
status: .verified
)

try db.write { db in
try AddressRecord
.filter(AddressRecord.Columns.chain == chain.rawValue)
.filter(AddressRecord.Columns.address == address)
.deleteAll(db)
try save(addressName: addressName, walletId: wallet.id, db: db)
}
}

Expand All @@ -44,4 +43,17 @@ public struct AddressStore: Sendable {
.asPrimitive()
}
}

// MARK: - Private

private func save(addressName: AddressName, walletId: String?, db: Database) throws {
try AddressRecord(
chain: addressName.chain,
address: addressName.address,
walletId: walletId,
name: addressName.name,
type: addressName.type,
status: addressName.status
).save(db, onConflict: .replace)
}
}
Loading
Loading