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

Use tokenType as derivation/addressType identifier in .btcAddress accountType #5439

Merged
merged 1 commit into from
Dec 7, 2023
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
4 changes: 0 additions & 4 deletions UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2722,8 +2722,6 @@
D0D5BCBD2976CB9F00587FDB /* PasswordInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D5BCBB2976CB9F00587FDB /* PasswordInputView.swift */; };
D0D5BCC02976D3B300587FDB /* PsswordInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D5BCBF2976D3B300587FDB /* PsswordInputCell.swift */; };
D0D5BCC12976D3B300587FDB /* PsswordInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D5BCBF2976D3B300587FDB /* PsswordInputCell.swift */; };
D0D90ADC2B1DA7DF0047C320 /* ScriptType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D90ADB2B1DA7DF0047C320 /* ScriptType.swift */; };
D0D90ADD2B1DA7DF0047C320 /* ScriptType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D90ADB2B1DA7DF0047C320 /* ScriptType.swift */; };
D0DA740D272A6EFC0072BE86 /* IDNSDK in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA740C272A6EFC0072BE86 /* IDNSDK */; };
D0DA740F272A6EFC0072BE86 /* UnicodeURL in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA740E272A6EFC0072BE86 /* UnicodeURL */; };
D0DA7411272A6F180072BE86 /* IDNSDK in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA7410272A6F180072BE86 /* IDNSDK */; };
Expand Down Expand Up @@ -4417,7 +4415,6 @@
D0C226182A66A703007101F7 /* PersonalSupportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalSupportViewModel.swift; sourceTree = "<group>"; };
D0D5BCBB2976CB9F00587FDB /* PasswordInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordInputView.swift; sourceTree = "<group>"; };
D0D5BCBF2976D3B300587FDB /* PsswordInputCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PsswordInputCell.swift; sourceTree = "<group>"; };
D0D90ADB2B1DA7DF0047C320 /* ScriptType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptType.swift; sourceTree = "<group>"; };
D0EE557D2934B0D60027AAD3 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
D0EE557E2934B0D60027AAD3 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
D31C4759238BF175008CB818 /* MnemonicDerivation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicDerivation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4981,7 +4978,6 @@
ABC9A830FE79DBF62FD63CC4 /* ThemeMode.swift */,
ABC9A3DFC1E03CB2E6C12F2C /* Encodable.swift */,
11B35D813B2B43683404CCD6 /* Kmm.swift */,
D0D90ADB2B1DA7DF0047C320 /* ScriptType.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ class BitcoinAdapter: BitcoinBaseAdapter {
confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold,
logger: logger
)
case let .btcAddress(address, _, mnemonicDerivation):
case let .btcAddress(address, _, tokenType):
guard let purpose = tokenType.derivation?.purpose else {
throw AdapterError.wrongParameters
}

bitcoinKit = try BitcoinKit.Kit(
watchAddress: address,
purpose: mnemonicDerivation.purpose,
purpose: purpose,
walletId: wallet.account.id,
syncMode: syncMode,
networkType: networkType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,14 @@ class LitecoinAdapter: BitcoinBaseAdapter {
confirmationsThreshold: BitcoinBaseAdapter.confirmationsThreshold,
logger: logger
)
case let .btcAddress(address, _, mnemonicDerivation):
case let .btcAddress(address, _, tokenType):
guard let purpose = tokenType.derivation?.purpose else {
throw AdapterError.wrongParameters
}

litecoinKit = try LitecoinKit.Kit(
watchAddress: address,
purpose: mnemonicDerivation.purpose,
purpose: purpose,
walletId: wallet.account.id,
syncMode: syncMode,
hasher: hasher,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,40 @@ class BitcoinAddressParserItem {
// avoid plugin data to validate all addresses
do {
switch parserType {
case let .adapter(adapter):
try adapter.validate(address: address, pluginData: [:]) // validate
return Single.just(Address(raw: address, domain: nil, blockchainType: blockchainType))
case let .converter(converter):
let btcAddress = try converter.convert(address: address)
guard let mnemonicDerivation = btcAddress.scriptType.mnemonicDerivation else {
throw ParseError.couldNotInfereDerivation
}
return Single.just(BitcoinAddress(raw: address, domain: nil, blockchainType: blockchainType, mnemonicDerivation: mnemonicDerivation))
case let .adapter(adapter):
try adapter.validate(address: address, pluginData: [:]) // validate
return Single.just(Address(raw: address, domain: nil, blockchainType: blockchainType))
case let .converter(converter):
let btcAddress = try converter.convert(address: address)
guard let tokenType = tokenType(scriptType: btcAddress.scriptType) else {
throw ParseError.couldNotInfereDerivation
}
return Single.just(BitcoinAddress(raw: address, domain: nil, blockchainType: blockchainType, tokenType: tokenType))
}
} catch {
return Single.error(error)
}
}

private func tokenType(scriptType: ScriptType) -> TokenType? {
switch blockchainType {
case .dash:
return .native

case .bitcoinCash, .ecash:
return .addressType(type: .type145)

case .bitcoin, .litecoin:
switch scriptType {
case .p2pkh: return .derived(derivation: .bip44)
case .p2sh, .p2wpkhSh: return .derived(derivation: .bip49)
case .p2wsh, .p2wpkh: return .derived(derivation: .bip84)
case .p2tr: return .derived(derivation: .bip86)
default: return nil
}
default: return nil
}
}
}

extension BitcoinAddressParserItem: IAddressParserItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ class AccountStorage {
return nil
}

guard let mnemonicDerivationValue = record.dataKey,
let mnemonicDerivation = MnemonicDerivation(rawValue: mnemonicDerivationValue),
guard let tokenTypeId = record.dataKey,
let tokenType = TokenType(id: tokenTypeId),
let blockchainTypeUid = record.saltKey
else {
return nil
}

type = .btcAddress(address: address, blockchainType: BlockchainType(uid: blockchainTypeUid), mnemonicDerivation: mnemonicDerivation)
type = .btcAddress(address: address, blockchainType: BlockchainType(uid: blockchainTypeUid), tokenType: tokenType)
case .cex:
guard let data = recoverData(id: id, typeName: typeName, keyName: .data) else {
return nil
Expand Down Expand Up @@ -146,11 +146,11 @@ class AccountStorage {
if let data = cexAccount.uniqueId.data(using: .utf8) {
dataKey = try store(data: data, id: id, typeName: typeName, keyName: .data)
}
case let .btcAddress(address, blockchainType, mnemonicDerivation):
case let .btcAddress(address, blockchainType, tokenType):
typeName = .btcAddress
wordsKey = address
saltKey = blockchainType.uid
dataKey = mnemonicDerivation.rawValue
dataKey = tokenType.id
}

return AccountRecord(
Expand Down
13 changes: 0 additions & 13 deletions UnstoppableWallet/UnstoppableWallet/Extensions/ScriptType.swift

This file was deleted.

25 changes: 13 additions & 12 deletions UnstoppableWallet/UnstoppableWallet/Models/AccountType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum AccountType {
case tronAddress(address: TronKit.Address)
case tonAddress(address: String)
case hdExtendedKey(key: HDExtendedKey)
case btcAddress(address: String, blockchainType: BlockchainType, mnemonicDerivation: MnemonicDerivation)
case btcAddress(address: String, blockchainType: BlockchainType, tokenType: TokenType)
case cex(cexAccount: CexAccount)

var mnemonicSeed: Data? {
Expand Down Expand Up @@ -50,8 +50,8 @@ enum AccountType {
privateData = address.hs.data
case let .hdExtendedKey(key):
privateData = key.serialized
case let .btcAddress(address, blockchainType, mnemonicDerivation):
privateData = "\(address)&\(blockchainType.uid)|\(mnemonicDerivation.rawValue)".data(using: .utf8) ?? Data()
case let .btcAddress(address, blockchainType, tokenType):
privateData = "\(address)&\(blockchainType.uid)|\(tokenType.id)".data(using: .utf8) ?? Data()
case let .cex(cexAccount):
privateData = cexAccount.uniqueId.data(using: .utf8) ?? Data() // always non-null
}
Expand Down Expand Up @@ -125,8 +125,9 @@ enum AccountType {
case (.ton, .native): return true
default: return false
}
case let .btcAddress(_, blockchainType, _):
return token.blockchainType == blockchainType
case let .btcAddress(_, blockchainType, tokenType):
return token.blockchainType == blockchainType && token.type == tokenType

default:
return false
}
Expand Down Expand Up @@ -275,12 +276,12 @@ extension AccountType {
}
case .btcAddress:
let (address, details) = split(string, separator: "&")
let (mnemonicDerivationValue, blockchainTypeUid) = split(details, separator: "|")
guard let mnemonicDerivation = MnemonicDerivation(rawValue: mnemonicDerivationValue) else {
let (tokenTypeValue, blockchainTypeUid) = split(details, separator: "|")
guard let tokenType = TokenType(id: tokenTypeValue) else {
return nil
}

return AccountType.btcAddress(address: address, blockchainType: BlockchainType(uid: blockchainTypeUid), mnemonicDerivation: mnemonicDerivation)
return AccountType.btcAddress(address: address, blockchainType: BlockchainType(uid: blockchainTypeUid), tokenType: tokenType)
case .evmAddress:
return (try? EvmKit.Address(hex: string)).map { AccountType.evmAddress(address: $0) }
case .tronAddress:
Expand Down Expand Up @@ -336,8 +337,8 @@ extension AccountType: Hashable {
return lhsAddress == rhsAddress
case let (.hdExtendedKey(lhsKey), .hdExtendedKey(rhsKey)):
return lhsKey == rhsKey
case let (.btcAddress(lhsAddress, lhsBlockchainType, lhsMnemonicDerivation), .btcAddress(rhsAddress, rhsBlockchainType, rhsMnemonicDerivation)):
return lhsAddress == rhsAddress && lhsBlockchainType == rhsBlockchainType && lhsMnemonicDerivation == rhsMnemonicDerivation
case let (.btcAddress(lhsAddress, lhsBlockchainType, lhsTokenType), .btcAddress(rhsAddress, rhsBlockchainType, rhsTokenType)):
return lhsAddress == rhsAddress && lhsBlockchainType == rhsBlockchainType && lhsTokenType == rhsTokenType
case let (.cex(lhsCexAccount), .cex(rhsCexAccount)):
return lhsCexAccount == rhsCexAccount
default: return false
Expand Down Expand Up @@ -366,11 +367,11 @@ extension AccountType: Hashable {
case let .hdExtendedKey(key):
hasher.combine("hdExtendedKey")
hasher.combine(key)
case let .btcAddress(address, blockchainType, mnemonicDerivation):
case let .btcAddress(address, blockchainType, tokenType):
hasher.combine("btcAddress")
hasher.combine(address)
hasher.combine(blockchainType)
hasher.combine(mnemonicDerivation)
hasher.combine(tokenType)
case let .cex(cexAccount):
hasher.combine("cex")
hasher.combine(cexAccount)
Expand Down
6 changes: 3 additions & 3 deletions UnstoppableWallet/UnstoppableWallet/Models/Address.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ open class Address: Equatable {
}

class BitcoinAddress: Address {
let mnemonicDerivation: MnemonicDerivation
let tokenType: TokenType

init(raw: String, domain: String? = nil, blockchainType: BlockchainType, mnemonicDerivation: MnemonicDerivation) {
self.mnemonicDerivation = mnemonicDerivation
init(raw: String, domain: String? = nil, blockchainType: BlockchainType, tokenType: TokenType) {
self.tokenType = tokenType

super.init(raw: raw, domain: domain, blockchainType: blockchainType)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,14 @@ class ManageWalletsService {
private func fetchTokens() -> [Token] {
do {
if filter.trimmingCharacters(in: .whitespaces).isEmpty {
let list = BlockchainType.supported.map(\.defaultTokenQuery)
let tokens = try marketKit.tokens(queries: list)
let tokenQueries: [TokenQuery]
if case .hdExtendedKey = account.type {
tokenQueries = BtcBlockchainManager.blockchainTypes.map(\.nativeTokenQueries).flatMap { $0 }
} else {
tokenQueries = BlockchainType.supported.map(\.defaultTokenQuery)
}

let tokens = try marketKit.tokens(queries: tokenQueries)
let featuredTokens = tokens.filter { account.type.supports(token: $0) }
let enabledTokens = wallets.map(\.token)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,9 @@ class ChooseWatchService {
return nil
}

let blockchainTypes: [BlockchainType] = [.bitcoin, .bitcoinCash, .ecash, .litecoin, .dash]
tokenQueries = blockchainTypes.map(\.nativeTokenQueries).flatMap { $0 }

case let .btcAddress(_, blockchainType, mnemonicDerivation):
let tokenType: TokenType

switch blockchainType {
case .bitcoin, .litecoin:
tokenType = TokenType.derived(derivation: mnemonicDerivation.derivation)
case .bitcoinCash, .ecash:
tokenType = TokenType.addressType(type: .type145)
case .dash:
tokenType = TokenType.native
default:
return nil
}
tokenQueries = BtcBlockchainManager.blockchainTypes.map(\.nativeTokenQueries).flatMap { $0 }

case let .btcAddress(_, blockchainType, tokenType):
tokenQueries = [TokenQuery(blockchainType: blockchainType, tokenType: tokenType)]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class WatchService {
do {
let accountType: AccountType
if let bitcoinAddress = address as? BitcoinAddress, let blockchainType = bitcoinAddress.blockchainType {
accountType = .btcAddress(address: bitcoinAddress.raw, blockchainType: blockchainType, mnemonicDerivation: bitcoinAddress.mnemonicDerivation)
accountType = .btcAddress(address: bitcoinAddress.raw, blockchainType: blockchainType, tokenType: bitcoinAddress.tokenType)
} else {
switch address.blockchainType {
case let evmAddress where EvmBlockchainManager.blockchainTypes.contains(where: { $0 == evmAddress }):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1673,6 +1673,7 @@
"watch_address.error.not_supported" = "Address format is not supported";
"watch_address.error.non_public_key" = "Watching by private key is not allowed";
"watch_address.error.not_supported_derived_type" = "Derived type is not supported";
"watch_address.watch_data.placeholder" = "Enter Your EVM, TRON, TON or Public Address (Bitcoin, Litecoin, Bitcoin Cash) or Account xPubKey.";
"watch_address.choose_blockchain" = "Choose Blockchain";
"watch_address.choose_coin" = "Choose Coin";

Expand Down