Skip to content

Commit

Permalink
Merge pull request #274 from tangem/IOS-3478_import_wallet_refactor
Browse files Browse the repository at this point in the history
Refactor import wallet facade and update to the latest v6 minor
  • Loading branch information
tureck1y authored Apr 21, 2023
2 parents d7b131a + 3d5ce9a commit d349643
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 30 deletions.
18 changes: 6 additions & 12 deletions Example/TangemSdkExample/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class AppModel: ObservableObject {
//Wallet creation
@Published var curve: EllipticCurve = .secp256k1
@Published var mnemonicString: String = ""
@Published var passphrase: String = ""
//Sign
@Published var derivationPath: String = ""
@Published var signHashesCount: String = "15"
Expand Down Expand Up @@ -306,18 +307,11 @@ extension AppModel {
return
}

do {
let mnemonic = try Mnemonic(with: mnemonicString)
let seed = try mnemonic.generateSeed()

tangemSdk.importWallet(curve: curve,
cardId: cardId,
seed: seed,
completion: handleCompletion)
}
catch {
self.complete(with: error)
}
tangemSdk.importWallet(curve: curve,
cardId: cardId,
mnemonic: mnemonicString,
passphrase: passphrase,
completion: handleCompletion)
}

func purgeWallet(walletPublicKey: Data) {
Expand Down
4 changes: 4 additions & 0 deletions Example/TangemSdkExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ struct ContentView: View {
TextField("Optional mnemonic", text: $model.mnemonicString)
.textFieldStyle(RoundedBorderTextFieldStyle())
.autocapitalization(.none)

TextField("Optional passphrase", text: $model.passphrase)
.textFieldStyle(RoundedBorderTextFieldStyle())
.autocapitalization(.none)
}
}
.padding()
Expand Down
12 changes: 8 additions & 4 deletions TangemSdk/TangemSdk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@
DC1244E629BB8E580037BC05 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1244E529BB8E580037BC05 /* NetworkType.swift */; };
DC1244E829BB9E0C0037BC05 /* ExtendedKeySerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1244E729BB9E0C0037BC05 /* ExtendedKeySerializer.swift */; };
DC22228729D431AB001129F8 /* SetUserCodeRecoveryAllowed.json in Resources */ = {isa = PBXBuildFile; fileRef = DC22228629D431AB001129F8 /* SetUserCodeRecoveryAllowed.json */; };
DC234CC629F1A3F100082063 /* ImportWalletMnemonic.json in Resources */ = {isa = PBXBuildFile; fileRef = DC234CC529F1A3F100082063 /* ImportWalletMnemonic.json */; };
DC4E442929BF42630088617C /* Base58Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4E442829BF42630088617C /* Base58Tests.swift */; };
DC59CB0429AF597900EC14E1 /* Wordlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0329AF597900EC14E1 /* Wordlist.swift */; };
DC59CB0A29AF6F9C00EC14E1 /* EntropyLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0929AF6F9C00EC14E1 /* EntropyLength.swift */; };
Expand All @@ -323,7 +324,7 @@
DCC0A21429D3201300C45B13 /* SetUserCodeRecoveryAllowedTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0A21329D3201300C45B13 /* SetUserCodeRecoveryAllowedTask.swift */; };
DCC0A21629D3216100C45B13 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0A21529D3216100C45B13 /* UserSettings.swift */; };
DCC6A64829D212E8007BA5B7 /* GetEntropyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC6A64729D212E8007BA5B7 /* GetEntropyCommand.swift */; };
DCE3281729D5DEE500AAC4AC /* ImportWallet.json in Resources */ = {isa = PBXBuildFile; fileRef = DCE3281629D5DEE500AAC4AC /* ImportWallet.json */; };
DCE3281729D5DEE500AAC4AC /* ImportWalletSeed.json in Resources */ = {isa = PBXBuildFile; fileRef = DCE3281629D5DEE500AAC4AC /* ImportWalletSeed.json */; };
DCEA3ABC2875AEBA00B0B0DA /* BiometricsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCEA3ABB2875AEBA00B0B0DA /* BiometricsStorage.swift */; };
DCEA3ABE2875AF0F00B0B0DA /* SecureStorageKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCEA3ABD2875AF0F00B0B0DA /* SecureStorageKey.swift */; };
DCF6188429F069DB001BE133 /* AttestCardKey.json in Resources */ = {isa = PBXBuildFile; fileRef = DCF6188329F069DB001BE133 /* AttestCardKey.json */; };
Expand Down Expand Up @@ -654,6 +655,7 @@
DC1244E529BB8E580037BC05 /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = "<group>"; };
DC1244E729BB9E0C0037BC05 /* ExtendedKeySerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedKeySerializer.swift; sourceTree = "<group>"; };
DC22228629D431AB001129F8 /* SetUserCodeRecoveryAllowed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = SetUserCodeRecoveryAllowed.json; sourceTree = "<group>"; };
DC234CC529F1A3F100082063 /* ImportWalletMnemonic.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ImportWalletMnemonic.json; sourceTree = "<group>"; };
DC4E442829BF42630088617C /* Base58Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base58Tests.swift; sourceTree = "<group>"; };
DC59CB0329AF597900EC14E1 /* Wordlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wordlist.swift; sourceTree = "<group>"; };
DC59CB0929AF6F9C00EC14E1 /* EntropyLength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntropyLength.swift; sourceTree = "<group>"; };
Expand All @@ -665,7 +667,7 @@
DCC0A21329D3201300C45B13 /* SetUserCodeRecoveryAllowedTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetUserCodeRecoveryAllowedTask.swift; sourceTree = "<group>"; };
DCC0A21529D3216100C45B13 /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; };
DCC6A64729D212E8007BA5B7 /* GetEntropyCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetEntropyCommand.swift; sourceTree = "<group>"; };
DCE3281629D5DEE500AAC4AC /* ImportWallet.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ImportWallet.json; sourceTree = "<group>"; };
DCE3281629D5DEE500AAC4AC /* ImportWalletSeed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ImportWalletSeed.json; sourceTree = "<group>"; };
DCEA3ABB2875AEBA00B0B0DA /* BiometricsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricsStorage.swift; sourceTree = "<group>"; };
DCEA3ABD2875AF0F00B0B0DA /* SecureStorageKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureStorageKey.swift; sourceTree = "<group>"; };
DCF6188329F069DB001BE133 /* AttestCardKey.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = AttestCardKey.json; sourceTree = "<group>"; };
Expand Down Expand Up @@ -849,7 +851,8 @@
5D54408D268226B600F7D05B /* Depersonalize.json */,
5D54408F268226BC00F7D05B /* PurgeWallet.json */,
5D5440912682297A00F7D05B /* CreateWallet.json */,
DCE3281629D5DEE500AAC4AC /* ImportWallet.json */,
DCE3281629D5DEE500AAC4AC /* ImportWalletSeed.json */,
DC234CC529F1A3F100082063 /* ImportWalletMnemonic.json */,
DCF6188329F069DB001BE133 /* AttestCardKey.json */,
5D544093268243F700F7D05B /* Card.json */,
);
Expand Down Expand Up @@ -1682,6 +1685,7 @@
5D38D06E26790B1A0052F67C /* Scan.json in Resources */,
DCF6188429F069DB001BE133 /* AttestCardKey.json in Resources */,
5D4B127B26D3D32E006E173C /* ChangeFileSettings.json in Resources */,
DC234CC629F1A3F100082063 /* ImportWalletMnemonic.json in Resources */,
5D4B127926D3CF4F006E173C /* DeleteFiles.json in Resources */,
5D544094268243F700F7D05B /* Card.json in Resources */,
5D5440982682497100F7D05B /* v4.json in Resources */,
Expand All @@ -1691,7 +1695,7 @@
5D2BDF8626DD4869002F7E19 /* TestParseRequest.json in Resources */,
DC1244C329B766B70037BC05 /* mnemonic_valid_test_vectors.json in Resources */,
5D5440922682297A00F7D05B /* CreateWallet.json in Resources */,
DCE3281729D5DEE500AAC4AC /* ImportWallet.json in Resources */,
DCE3281729D5DEE500AAC4AC /* ImportWalletSeed.json in Resources */,
5D54408C2682269400F7D05B /* SetPasscode.json in Resources */,
5D4B127D26D3D351006E173C /* WriteFiles.json in Resources */,
);
Expand Down
2 changes: 1 addition & 1 deletion TangemSdk/TangemSdk/Common/Card/CardSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public extension Card {
public let isHDWalletAllowed: Bool
/// Is allowed to create backup
public let isBackupAllowed: Bool
/// Is allowed to import keys. COS. v6.11+
/// Is allowed to import keys. COS. v6.16+
public let isKeysImportAllowed: Bool
/// Is allowed to delete wallet. COS before v4
@SkipEncoding
Expand Down
2 changes: 1 addition & 1 deletion TangemSdk/TangemSdk/Common/Card/FirmwareVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public extension FirmwareVersion { //todo: move all doubleValue checks to consta
/// Wallet ownership confirmation available
static let walletOwnershipConfirmationAvailable = FirmwareVersion(major: 2, minor: 1)
/// Keys import support
static let keysImportAvailable = FirmwareVersion(major: 6, minor: 11)
static let keysImportAvailable = FirmwareVersion(major: 6, minor: 16)
/// Tmp range for visa cards
static let visaRange = 5.25...5.30
}
Expand Down
14 changes: 13 additions & 1 deletion TangemSdk/TangemSdk/Common/JSON/Handlers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,19 @@ class ImportWalletHandler: JSONRPCHandler {

func makeRunnable(from parameters: [String : Any]) throws -> AnyJSONRPCRunnable {
let curve: EllipticCurve = try parameters.value(for: "curve")
let seed: Data = try parameters.value(for: "seed")

let seedParam: Data? = try parameters.value(for: "seed")

let mnemonicString: String? = try parameters.value(for: "mnemonic")
let passphrase: String = try parameters.value(for: "passphrase") ?? ""
let seedFromMnemonic = try mnemonicString.map { try Mnemonic(with: $0).generateSeed(with: passphrase) }

let seed: Data? = seedParam ?? seedFromMnemonic
guard let seed else {
throw JSONRPCError(.invalidParams,
data: JSONRPCErrorData(.invalidParams, message: "You should pass a seed or a mnemonic and an optional passphrase"))
}

let command = CreateWalletTask(curve: curve, seed: seed)
return command.eraseToAnyRunnable()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ public struct AttestWalletKeyResponse: JSONStringConvertible {
public let walletSignature: Data
/// Challenge, used to check wallet
public let challenge: Data
/// Confirmation signature of the wallet ownership. COS: 2.01+. And a wallet's status for COS: 6.11+.
/// Confirmation signature of the wallet ownership. COS: 2.01+. And a wallet's status for COS: 6.16+.
/// - `ConfirmationMode.none` : No signature will be returned.
/// - `ConfirmationMode.static` : Wallet's public key and wallet's status (COS 6.11+) signed with the card's private key.
/// - `ConfirmationMode.dynamic`: Wallet's public key, wallet's status (COS 6.11+), `challenge`, and `publicKeySalt`, signed with the card's private key.
/// - `ConfirmationMode.static` : Wallet's public key and wallet's status (COS 6.16+) signed with the card's private key.
/// - `ConfirmationMode.dynamic`: Wallet's public key, wallet's status (COS 6.16+), `challenge`, and `publicKeySalt`, signed with the card's private key.
public let cardSignature: Data?
/// Optional random salt, generated by the card for `dynamic` `confirmationMode`. COS: 2.01+.
public let publicKeySalt: Data?
/// Status of the wallet. COS v.6.11+
/// Status of the wallet. COS v.6.16+
public let walletStatus: Card.Wallet.Status?
/// Counter of `AttestWalletKey` command executions. A very big value of this counter may indicate a hacking attempts. COS: 2.01+.
let counter: Int?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

/// Deserialized response from the Tangem card after `SetUserSettingsCommand`. COS v.6.11+
/// Deserialized response from the Tangem card after `SetUserSettingsCommand`. COS v.6.16+
@available(iOS 13.0, *)
struct SetUserSettingsCommandResponse: JSONStringConvertible {
/// Unique Tangem card ID number.
Expand All @@ -17,7 +17,7 @@ struct SetUserSettingsCommandResponse: JSONStringConvertible {
let settings: Card.UserSettings
}

/// Set user serrings on a card. COS v.6.11+
/// Set user serrings on a card. COS v.6.16+
@available(iOS 13.0, *)
class SetUserSettingsCommand: Command {
var preflightReadMode: PreflightReadMode { .readCardOnly }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ final class CreateWalletCommand: Command {
self.privateKey = nil
}

/// Use this initializer to import a key from the seed. COS v6.11+.
/// Use this initializer to import a key from the seed. COS v6.16+.
/// - Parameter curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - Parameter seed: BIP39 seed to create wallet from.
init(curve: EllipticCurve, seed: Data) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class CreateWalletTask: CardSessionRunnable {
self.seed = nil
}

/// Use this initializer to import a key from the seed. COS v6.11+.
/// Use this initializer to import a key from the seed. COS v6.16+.
/// - Parameter curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - Parameter seed: BIP39 seed to create wallet from.
public init(curve: EllipticCurve, seed: Data) {
Expand Down
25 changes: 24 additions & 1 deletion TangemSdk/TangemSdk/TangemSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public extension TangemSdk {
/// - curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - initialMessage: A custom description that shows at the beginning of the NFC session. If nil, default message will be used
/// - cardId: CID, Unique Tangem card ID number.
/// - seed: BIP39 seed to create wallet from. COS v.6.11+.
/// - seed: BIP39 seed to create wallet from. COS v.6.16+.
/// - completion: Returns `Swift.Result<CreateWalletResponse,TangemSdkError>`
func importWallet(curve: EllipticCurve,
cardId: String,
Expand All @@ -181,6 +181,29 @@ public extension TangemSdk {
let command = CreateWalletTask(curve: curve, seed: seed)
startSession(with: command, cardId: cardId, initialMessage: initialMessage, completion: completion)
}

/// This command will import an esisting wallet
/// - Parameters:
/// - curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - initialMessage: A custom description that shows at the beginning of the NFC session. If nil, default message will be used
/// - cardId: CID, Unique Tangem card ID number.
/// - mnemonic: BIP39 mnemonic to create wallet from. COS v.6.16+.
/// - passphrase: BIP39 passphrase to create wallet from. COS v.6.16+. Empty passphrase by default.
/// - completion: Returns `Swift.Result<CreateWalletResponse,TangemSdkError>`
func importWallet(curve: EllipticCurve,
cardId: String,
mnemonic: String,
passphrase: String = "",
initialMessage: Message? = nil,
completion: @escaping CompletionResult<CreateWalletResponse>) {
do {
let seed = try Mnemonic(with: mnemonic).generateSeed(with: passphrase)
let command = CreateWalletTask(curve: curve, seed: seed)
startSession(with: command, cardId: cardId, initialMessage: initialMessage, completion: completion)
} catch {
completion(.failure(error.toTangemSdkError()))
}
}

/// This command deletes all wallet data. If Is_Reusable flag is enabled during personalization,
/// the card changes state to ‘Empty’ and a new wallet can be created by `CREATE_WALLET` command.
Expand Down
19 changes: 17 additions & 2 deletions TangemSdk/TangemSdkTests/JSONRPCTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class JSONRPCTests: XCTestCase {
testMethod(name: "CreateWallet", result: result)
}

func testImportWallet() {
func testImportWalletSeed() {
let result = CreateWalletResponse(cardId: "c000111122223333",
wallet: Card.Wallet(publicKey: Data(hexString: "5130869115a2ff91959774c99d4dc2873f0c41af3e0bb23d027ab16d39de1348"),
chainCode: nil,
Expand All @@ -152,7 +152,22 @@ class JSONRPCTests: XCTestCase {
proof: nil,
isImported: false,
hasBackup: false))
testMethod(name: "ImportWallet", result: result)
testMethod(name: "ImportWalletSeed", result: result)
}

func testImportWalletMnemonic() {
let result = CreateWalletResponse(cardId: "c000111122223333",
wallet: Card.Wallet(publicKey: Data(hexString: "029983A77B155ED3B3B9E1DDD223BD5AA073834C8F61113B2F1B883AAA70971B5F"),
chainCode: Data(hexString: "C7A888C4C670406E7AAEB6E86555CE0C4E738A337F9A9BC239F6D7E475110A4E"),
curve: .secp256k1,
settings: Card.Wallet.Settings(isPermanent: true),
totalSignedHashes: 10,
remainingSignatures: 100,
index: 1,
proof: nil,
isImported: false,
hasBackup: false))
testMethod(name: "ImportWalletMnemonic", result: result)
}

func testPurgeWallet() {
Expand Down
33 changes: 33 additions & 0 deletions TangemSdk/TangemSdkTests/Jsons/ImportWalletMnemonic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"request" : {
"jsonrpc": "2.0",
"id": 1,
"method": "import_wallet",
"params": {
"curve": "secp256k1",
"mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"passphrase": "TREZOR"
}
},
"response" : {
"jsonrpc" : "2.0",
"result" : {
"cardId": "c000111122223333",
"wallet": {
"publicKey": "029983A77B155ED3B3B9E1DDD223BD5AA073834C8F61113B2F1B883AAA70971B5F",
"chainCode": "C7A888C4C670406E7AAEB6E86555CE0C4E738A337F9A9BC239F6D7E475110A4E",
"curve": "secp256k1",
"settings": {
"isPermanent" : true
},
"totalSignedHashes": 10,
"remainingSignatures": 100,
"index": 1,
"hasBackup" : false,
"isImported": false,
"derivedKeys" : []
}
},
"id" : 1
}
}

0 comments on commit d349643

Please sign in to comment.