diff --git a/src/app/modules/shared_modules/keycard_popup/controller.nim b/src/app/modules/shared_modules/keycard_popup/controller.nim index 55d5d45c2e..c5e9b806f3 100644 --- a/src/app/modules/shared_modules/keycard_popup/controller.nim +++ b/src/app/modules/shared_modules/keycard_popup/controller.nim @@ -420,12 +420,18 @@ proc runStoreMetadataFlow*(self: Controller, cardName: string, pin: string, wall self.cancelCurrentFlow() self.keycardService.startStoreMetadataFlow(cardName, pin, walletPaths) -proc runDeriveAccountFlow*(self: Controller, bip44Path = "", pin = "") = +proc runDeriveAccountFlow*(self: Controller, bip44Path: string, pin: string) = if not serviceApplicable(self.keycardService): return self.cancelCurrentFlow() self.keycardService.startExportPublicFlow(bip44Path, exportMasterAddr=true, exportPrivateAddr=false, pin) +proc runDeriveAccountFlow*(self: Controller, bip44Paths: seq[string], pin: string) = + if not serviceApplicable(self.keycardService): + return + self.cancelCurrentFlow() + self.keycardService.startExportPublicFlow(bip44Paths, exportMasterAddr=true, exportPrivateAddr=false, pin) + proc runAuthenticationFlow*(self: Controller, keyUid = "") = ## For signing a transaction we need to provide a key uid of a keypair that an account we want to sign a transaction ## for belongs to. If we're just doing an authentication for a logged in user, then default key uid is always the key diff --git a/src/app/modules/shared_modules/keycard_popup/internal/creating_account_new_seed_phrase_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/creating_account_new_seed_phrase_state.nim index de31955483..9252c85343 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/creating_account_new_seed_phrase_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/creating_account_new_seed_phrase_state.nim @@ -2,18 +2,10 @@ type CreatingAccountNewSeedPhraseState* = ref object of State paths: seq[string] addresses: seq[string] - addingAccountsToWalletDone: bool - addingAccountsToWalletOk: bool - addingMigratedKeypairDone: bool - addingMigratedKeypairOk: bool proc newCreatingAccountNewSeedPhraseState*(flowType: FlowType, backState: State): CreatingAccountNewSeedPhraseState = result = CreatingAccountNewSeedPhraseState() result.setup(flowType, StateType.CreatingAccountNewSeedPhrase, backState) - result.addingAccountsToWalletDone = false - result.addingAccountsToWalletOk = false - result.addingMigratedKeypairDone = false - result.addingMigratedKeypairOk = false proc delete*(self: CreatingAccountNewSeedPhraseState) = self.State.delete @@ -26,17 +18,28 @@ proc resolvePaths(self: CreatingAccountNewSeedPhraseState, controller: Controlle self.paths.add(account.getPath()) i.inc -proc resolveAddressesForPaths(self: CreatingAccountNewSeedPhraseState, controller: Controller) = +proc findIndexForPath(self: CreatingAccountNewSeedPhraseState, path: string): int = + var ind = -1 + for p in self.paths: + ind.inc + if p == path: + return ind + return ind + +proc resolveAddresses(self: CreatingAccountNewSeedPhraseState, controller: Controller, keycardEvent: KeycardEvent): bool = + if keycardEvent.generatedWalletAccounts.len != self.paths.len: + return false let kpForPRocessing = controller.getKeyPairForProcessing() - let generatedAccount = controller.generateAccountsFromSeedPhrase(controller.getSeedPhrase(), self.paths) for account in kpForPRocessing.getAccountsModel().getItems(): - if not generatedAccount.derivedAccounts.derivations.hasKey(account.getPath()): - return - kpForPRocessing.setDerivedFrom(generatedAccount.address) - let accDetails = generatedAccount.derivedAccounts.derivations[account.getPath()] - account.setAddress(accDetails.address) - account.setPubKey(accDetails.publicKey) - self.addresses.add(accDetails.address) + let index = self.findIndexForPath(account.getPath()) + if index == -1: + ## should never be here + return false + kpForPRocessing.setDerivedFrom(keycardEvent.masterKeyAddress) + account.setAddress(keycardEvent.generatedWalletAccounts[index].address) + account.setPubKey(keycardEvent.generatedWalletAccounts[index].publicKey) + self.addresses.add(keycardEvent.generatedWalletAccounts[index].address) + return true proc addAccountsToWallet(self: CreatingAccountNewSeedPhraseState, controller: Controller): bool = let kpForPRocessing = controller.getKeyPairForProcessing() @@ -68,32 +71,18 @@ proc runStoreMetadataFlow(self: CreatingAccountNewSeedPhraseState, controller: C method executePrePrimaryStateCommand*(self: CreatingAccountNewSeedPhraseState, controller: Controller) = if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase: - if not self.addingAccountsToWalletDone: - self.addingAccountsToWalletDone = true - self.resolvePaths(controller) - self.resolveAddressesForPaths(controller) - if self.paths.len != self.addresses.len: - return - self.addingAccountsToWalletOk = self.addAccountsToWallet(controller) - if self.addingAccountsToWalletOk: - self.doMigration(controller) + self.resolvePaths(controller) + controller.runDeriveAccountFlow(bip44Paths = self.paths, controller.getPin()) method executePreSecondaryStateCommand*(self: CreatingAccountNewSeedPhraseState, controller: Controller) = - ## Secondary action is called after each async action during migration process. - if not self.addingMigratedKeypairDone: - self.addingMigratedKeypairDone = true - self.addingMigratedKeypairOk = controller.getAddingMigratedKeypairSuccess() - if self.addingMigratedKeypairOk: - self.runStoreMetadataFlow(controller) - -method getNextPrimaryState*(self: CreatingAccountNewSeedPhraseState, controller: Controller): State = + ## Secondary action is called after each async action during migration process, in this case after `addMigratedKeyPair`. if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase: - if self.addingAccountsToWalletDone and not self.addingAccountsToWalletOk: - return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil) + if controller.getAddingMigratedKeypairSuccess(): + self.runStoreMetadataFlow(controller) method getNextSecondaryState*(self: CreatingAccountNewSeedPhraseState, controller: Controller): State = if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase: - if self.addingMigratedKeypairDone and not self.addingMigratedKeypairOk: + if not controller.getAddingMigratedKeypairSuccess(): return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil) method resolveKeycardNextState*(self: CreatingAccountNewSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -102,6 +91,17 @@ method resolveKeycardNextState*(self: CreatingAccountNewSeedPhraseState, keycard if not state.isNil: return state if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase: - if keycardFlowType == ResponseTypeValueKeycardFlowResult and - keycardEvent.error.len == 0: - return createState(StateType.CreatingAccountNewSeedPhraseSuccess, self.flowType, nil) \ No newline at end of file + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.ExportPublic: + if keycardFlowType == ResponseTypeValueKeycardFlowResult and + keycardEvent.error.len == 0: + if not self.resolveAddresses(controller, keycardEvent): + return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil) + if not self.addAccountsToWallet(controller): + return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil) + self.doMigration(controller) + return nil # returning nil, cause we need to remain in this state + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata: + if keycardFlowType == ResponseTypeValueKeycardFlowResult and + keycardEvent.error.len == 0: + return createState(StateType.CreatingAccountNewSeedPhraseSuccess, self.flowType, nil) + return createState(StateType.CreatingAccountNewSeedPhraseSuccess, self.flowType, nil) \ No newline at end of file diff --git a/src/app_service/service/keycard/internal.nim b/src/app_service/service/keycard/internal.nim index c40ad98434..196af4b038 100644 --- a/src/app_service/service/keycard/internal.nim +++ b/src/app_service/service/keycard/internal.nim @@ -42,6 +42,7 @@ type pukRetries*: int cardMetadata*: CardMetadata generatedWalletAccount*: GeneratedWalletAccount + generatedWalletAccounts*: seq[GeneratedWalletAccount] txSignature*: TransactionSignature eip1581Key*: KeyDetails encryptionKey*: KeyDetails @@ -127,8 +128,12 @@ proc toKeycardEvent(jsonObj: JsonNode): KeycardEvent = if(jsonObj.getProp(ResponseParamCardMeta, obj)): result.cardMetadata = toCardMetadata(obj) - if(jsonObj.getProp(ResponseParamExportedKey, obj)): - result.generatedWalletAccount = toGeneratedWalletAccount(obj) + if jsonObj.getProp(ResponseParamExportedKey, obj): + if obj.kind == JArray: + for o in obj: + result.generatedWalletAccounts.add(toGeneratedWalletAccount(o)) + else: + result.generatedWalletAccount = toGeneratedWalletAccount(obj) if(jsonObj.getProp(ResponseParamTXSignature, obj)): result.txSignature = toTransactionSignature(obj) \ No newline at end of file diff --git a/src/app_service/service/keycard/service.nim b/src/app_service/service/keycard/service.nim index 7fba2babe3..d05ea7530b 100644 --- a/src/app_service/service/keycard/service.nim +++ b/src/app_service/service/keycard/service.nim @@ -242,6 +242,8 @@ QtObject: self.startFlow(payload) proc startExportPublicFlow*(self: Service, path: string, exportMasterAddr = false, exportPrivateAddr = false, pin = "") = + ## Exports addresses for passed `path`. Result of this flow sets instance of `GeneratedWalletAccount` under + ## `generatedWalletAccount` property in `KeycardEvent`. if exportPrivateAddr and not path.startsWith(DefaultEIP1581Path): error "in order to export private address path must not be outside of eip1581 tree" return @@ -258,6 +260,28 @@ QtObject: self.currentFlow = KCSFlowType.ExportPublic self.startFlow(payload) + proc startExportPublicFlow*(self: Service, paths: seq[string], exportMasterAddr = false, exportPrivateAddr = false, pin = "") = + ## Exports addresses for passed `path`. Result of this flow sets array of `GeneratedWalletAccount` under + ## `generatedWalletAccounts` property in `KeycardEvent`. The order of keys set in `generatedWalletAccounts` array + ## mathch the order of `paths` sent to this flow. + if exportPrivateAddr: + for p in paths: + if not p.startsWith(DefaultEIP1581Path): + error "one of paths in the list refers to a private address path which is not in eip1581 tree" + return + + var payload = %* { + RequestParamBIP44Path: DefaultBIP44Path, + RequestParamExportMasterAddress: exportMasterAddr, + RequestParamExportPrivate: exportPrivateAddr + } + if paths.len > 0: + payload[RequestParamBIP44Path] = %* paths + if pin.len > 0: + payload[RequestParamPIN] = %* pin + self.currentFlow = KCSFlowType.ExportPublic + self.startFlow(payload) + proc startStoreMetadataFlow*(self: Service, cardName: string, pin: string, walletPaths: seq[string]) = var name = cardName if cardName.len > CardNameLength: diff --git a/vendor/status-keycard-go b/vendor/status-keycard-go index e4fef0fb36..b50cfe22ac 160000 --- a/vendor/status-keycard-go +++ b/vendor/status-keycard-go @@ -1 +1 @@ -Subproject commit e4fef0fb362ca5e48292d916c83c8aaefa7ac6fa +Subproject commit b50cfe22ac3802d508e34b0561095c7100f6efa8