Skip to content

Commit

Permalink
IOS-3219 Add precheck for duplicated wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
tureck1y committed Mar 27, 2023
1 parent c530f58 commit 9e36f87
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 20 deletions.
2 changes: 2 additions & 0 deletions TangemSdk/TangemSdk/Common/Core/TangemSdkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ public enum TangemSdkError: Error, LocalizedError, Encodable {
case walletNotFound
case cardWithMaxZeroWallets
case walletCannotBeCreated
case walletAlreadyCreated

// MARK: Backup errors
case backupFailedCardNotLinked
Expand Down Expand Up @@ -344,6 +345,7 @@ public enum TangemSdkError: Error, LocalizedError, Encodable {
case .accessCodeRequired: return 40401
case .walletCannotBeCreated: return 40403
case .cardWithMaxZeroWallets: return 40404
case .walletAlreadyCreated: return 40405

case .alreadyCreated: return 40501
case .unsupportedCurve: return 40502
Expand Down
30 changes: 21 additions & 9 deletions TangemSdk/TangemSdk/Operations/Wallet/CreateWalletCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,19 @@ final class CreateWalletCommand: Command {
var walletIndex: Int = 0

private let curve: EllipticCurve
private let seed: Data?
private let externalKey: ExtendedPrivateKey?
private let signingMethod = SigningMethod.signHash

/// Default initializer
/// - Parameter curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - Parameter seed: An optional BIP39 seed to create wallet from. COS v6.10+.
init(curve: EllipticCurve, seed: Data?) {
init(curve: EllipticCurve, seed: Data?) throws {
self.curve = curve
self.seed = seed
if let seed {
self.externalKey = try BIP32().makeMasterKey(from: seed, curve: curve)
} else {
self.externalKey = nil
}
}

deinit {
Expand All @@ -64,14 +68,24 @@ final class CreateWalletCommand: Command {
}
}

if seed != nil {
if externalKey != nil {
if card.firmwareVersion < .isExternalWalletsAvailable {
return TangemSdkError.notSupportedFirmwareVersion
}

if !card.settings.isExternalWalletsAllowed {
return TangemSdkError.externalWalletsDisabled
}

do {
// This check will fail for compressed secp256r1 keys
if let extendedKey = try externalKey?.makePublicKey(for: curve),
card.wallets[extendedKey.publicKey] != nil {
return TangemSdkError.walletAlreadyCreated
}
} catch {
return error.toTangemSdkError()
}
}

return nil
Expand Down Expand Up @@ -130,11 +144,9 @@ final class CreateWalletCommand: Command {
.append(.walletIndex, value: walletIndex)
}

if let seed {
let key = try BIP32().makeMasterKey(from: seed, curve: curve)

try tlvBuilder.append(.walletPrivateKey, value: key.privateKey)
try tlvBuilder.append(.walletHDChain, value: key.chainCode)
if let externalKey {
try tlvBuilder.append(.walletPrivateKey, value: externalKey.privateKey)
try tlvBuilder.append(.walletHDChain, value: externalKey.chainCode)
}

return CommandApdu(.createWallet, tlv: tlvBuilder.serialize())
Expand Down
26 changes: 15 additions & 11 deletions TangemSdk/TangemSdk/Operations/Wallet/CreateWalletTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,23 @@ public class CreateWalletTask: CardSessionRunnable {
}

public func run(in session: CardSession, completion: @escaping CompletionResult<CreateWalletResponse>) {
let command = CreateWalletCommand(curve: curve, seed: seed)
command.run(in: session) { result in
switch result {
case .success(let response):
self.deriveKeysIfNeeded(for: response, in: session, completion: completion)
case .failure(let error):
if case .invalidState = error { //Wallet already created but we didn't get the proper response from the card. Rescan and retrieve the wallet
Log.debug("Received wallet creation error. Try rescan and retrieve created wallet")
self.scanAndRetrieveCreatedWallet(at: command.walletIndex, in: session, completion: completion)
} else {
completion(.failure(error))
do {
let command = try CreateWalletCommand(curve: curve, seed: seed)
command.run(in: session) { result in
switch result {
case .success(let response):
self.deriveKeysIfNeeded(for: response, in: session, completion: completion)
case .failure(let error):
if case .invalidState = error { //Wallet already created but we didn't get the proper response from the card. Rescan and retrieve the wallet
Log.debug("Received wallet creation error. Try rescan and retrieve created wallet")
self.scanAndRetrieveCreatedWallet(at: command.walletIndex, in: session, completion: completion)
} else {
completion(.failure(error))
}
}
}
} catch {
completion(.failure(error.toTangemSdkError()))
}
}

Expand Down

0 comments on commit 9e36f87

Please sign in to comment.