Skip to content

Commit

Permalink
Sargon: Add method to read Mnemonic, UniFFI exported, Improve iOS exa…
Browse files Browse the repository at this point in the history
…mple app
  • Loading branch information
Sajjon committed Feb 17, 2024
1 parent e915b63 commit 30f134d
Show file tree
Hide file tree
Showing 26 changed files with 779 additions and 199 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extension AppearanceID: CaseIterable {
public static var allCases: [Self] {
appearanceIdsAll()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extension BagOfBytes {
public init(data: Data) {
self = newBagOfBytesFrom(bytes: data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extension DisplayName {
public init(validating name: String) throws {
self = try newDisplayName(name: name)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extension Mnemonic {
public var phrase: String {
mnemonicPhrase(from: self)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
public typealias AppearanceID = AppearanceId

extension AppearanceID: Sendable {}
extension AppearanceID: CaseIterable {
public static var allCases: [Self] {
appearanceIdsAll()
extension AppearanceID: Identifiable {
public typealias ID = UInt8
public var id: ID {
value
}
}
extension AppearanceID: CustomStringConvertible {
public var description: String {
value.description
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
extension BagOfBytes {
public init(data: Data) {
self = newBagOfBytesFrom(bytes: data)
}
public static func random(byteCount: Int) -> Self {
var data = Data(repeating: 0, count: byteCount)
data.withUnsafeMutableBytes {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
extension DisplayName: Sendable {}
extension DisplayName {
public init(validating name: String) throws {
self = try newDisplayName(name: name)
}
}

#if DEBUG
extension DisplayName: ExpressibleByStringLiteral {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extension Mnemonic: Sendable {}
43 changes: 43 additions & 0 deletions apple/Sources/UniFFI/Sargon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,18 @@ public protocol WalletProtocol: AnyObject {
*/
func jsonSnapshot() -> String

/**
* Tries to load the `MnemonicWithPassphrase` for the main "Babylon"
* `DeviceFactorSource` from secure storage.
*/
func mainBdfsMnemonicWithPassphrase() throws -> MnemonicWithPassphrase

/**
* Tries to load a `MnemonicWithPassphrase` from secure storage
* by `factor_source_id`.
*/
func mnemonicWithPassphraseOfDeviceFactorSourceByFactorSourceId(factorSourceId: FactorSourceId) throws -> MnemonicWithPassphrase

/**
* Clone the profile and return it.
*/
Expand Down Expand Up @@ -881,6 +893,31 @@ public class Wallet:
)
}

/**
* Tries to load the `MnemonicWithPassphrase` for the main "Babylon"
* `DeviceFactorSource` from secure storage.
*/
public func mainBdfsMnemonicWithPassphrase() throws -> MnemonicWithPassphrase {
return try FfiConverterTypeMnemonicWithPassphrase.lift(
rustCallWithError(FfiConverterTypeCommonError.lift) {
uniffi_sargon_fn_method_wallet_main_bdfs_mnemonic_with_passphrase(self.uniffiClonePointer(), $0)
}
)
}

/**
* Tries to load a `MnemonicWithPassphrase` from secure storage
* by `factor_source_id`.
*/
public func mnemonicWithPassphraseOfDeviceFactorSourceByFactorSourceId(factorSourceId: FactorSourceId) throws -> MnemonicWithPassphrase {
return try FfiConverterTypeMnemonicWithPassphrase.lift(
rustCallWithError(FfiConverterTypeCommonError.lift) {
uniffi_sargon_fn_method_wallet_mnemonic_with_passphrase_of_device_factor_source_by_factor_source_id(self.uniffiClonePointer(),
FfiConverterTypeFactorSourceID.lower(factorSourceId), $0)
}
)
}

/**
* Clone the profile and return it.
*/
Expand Down Expand Up @@ -10307,6 +10344,12 @@ private var initializationResult: InitializationResult {
if uniffi_sargon_checksum_method_wallet_json_snapshot() != 24850 {
return InitializationResult.apiChecksumMismatch
}
if uniffi_sargon_checksum_method_wallet_main_bdfs_mnemonic_with_passphrase() != 59906 {
return InitializationResult.apiChecksumMismatch
}
if uniffi_sargon_checksum_method_wallet_mnemonic_with_passphrase_of_device_factor_source_by_factor_source_id() != 48090 {
return InitializationResult.apiChecksumMismatch
}
if uniffi_sargon_checksum_method_wallet_profile() != 5221 {
return InitializationResult.apiChecksumMismatch
}
Expand Down
21 changes: 18 additions & 3 deletions examples/iOS/Planbok.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/iOS/Sources/Planbok/Features/AppFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public struct AppFeature {
}
return .none

case let .onboarding(.createdAccount(walletHolder)):
case let .onboarding(.delegate(.createdAccount(with: walletHolder))):
state = .main(MainFeature.State(walletHolder: walletHolder))
return .none

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@Reducer
public struct CreateAccountFlowFeature {

@Reducer(state: .equatable)
public enum Path {
case selectGradient(SelectGradientFeature)
}

@ObservableState
public struct State: Equatable {
public let walletHolder: WalletHolder
public var path = StackState<Path.State>()
public var nameAccount: NameNewAccountFeature.State

public init(walletHolder: WalletHolder) {
self.walletHolder = walletHolder
self.nameAccount = NameNewAccountFeature.State(walletHolder: walletHolder)
}

public init(wallet: Wallet) {
self.init(walletHolder: .init(wallet: wallet))
}
}

public enum Action {
public enum DelegateAction {
case createdAccount
}
case path(StackAction<Path.State, Path.Action>)
case nameAccount(NameNewAccountFeature.Action)
case delegate(DelegateAction)
}

public struct View: SwiftUI.View {
@Bindable var store: StoreOf<CreateAccountFlowFeature>
public init(store: StoreOf<CreateAccountFlowFeature>) {
self.store = store
}
public var body: some SwiftUI.View {
NavigationStack(path: $store.scope(state: \.path, action: \.path)) {
NameNewAccountFeature.View(
store: store.scope(state: \.nameAccount, action: \.nameAccount)
)
} destination: { store in
switch store.state {
case .selectGradient:
if let store = store.scope(state: \.selectGradient, action: \.selectGradient) {
SelectGradientFeature.View(store: store)
}
}
}
}
}

public init() {}

public var body: some ReducerOf<Self> {
Scope(state: \.nameAccount, action: \.nameAccount) {
NameNewAccountFeature()
}

Reduce { state, action in
switch action {

case let .nameAccount(.delegate(.named(name))):
state.path.append(.selectGradient(.init(name: name)))
return .none

case .path(let pathAction):
switch pathAction {

case let .element(
id: _,
action: .selectGradient(.delegate(.selected(appearanceID, displayName)))
):
do {
let wallet = state.walletHolder.wallet
var account = try wallet.createNewAccount(
networkId: .mainnet,
name: displayName
)
account.appearanceId = appearanceID

try wallet.addAccount(account: account)

return .send(.delegate(.createdAccount))

} catch {
fatalError("TODO error handling: \(error)")
}

case .element(id: _, action: _):
return .none
case .popFrom(id: _):
return .none
case .push(id: _, state: _):
return .none
}
return .none

case .nameAccount(.view):
return .none

case .delegate:
return .none
}
}
.forEach(\.path, action: \.path)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@Reducer
public struct CreateAccountFeature {
public struct NameNewAccountFeature {

@ObservableState
public struct State: Equatable {
Expand All @@ -14,33 +14,41 @@ public struct CreateAccountFeature {
}
}

public enum Action {
case accountNameChanged(String)
case createAccountButtonTapped
case createdAccount
public enum Action: ViewAction {
public enum Delegate {
case named(DisplayName)
}
@CasePathable
public enum ViewAction {
case accountNameChanged(String)
case continueButtonTapped
}
case delegate(Delegate)
case view(ViewAction)
}

@ViewAction(for: NameNewAccountFeature.self)
public struct View: SwiftUI.View {
@Bindable var store: StoreOf<CreateAccountFeature>
public init(store: StoreOf<CreateAccountFeature>) {
@Bindable public var store: StoreOf<NameNewAccountFeature>
public init(store: StoreOf<NameNewAccountFeature>) {
self.store = store
}
public var body: some SwiftUI.View {
VStack {
Text("Create Account").font(.largeTitle)
Text("Name Account").font(.largeTitle)
Spacer()
LabeledTextField(label: "Account Name", text: $store.accountName.sending(\.accountNameChanged))
LabeledTextField(label: "Account Name", text: $store.accountName.sending(\.view.accountNameChanged))
if let error = store.state.errorMessage {
Text("\(error)")
.foregroundStyle(Color.red)
.font(.footnote)
.fontWeight(.bold)
}
Spacer()
Button("Create Account") {
store.send(.createAccountButtonTapped)
Button("Continue") {
send(.continueButtonTapped)
}

.buttonStyle(.borderedProminent)
}
.padding()
}
Expand All @@ -51,44 +59,25 @@ public struct CreateAccountFeature {
public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case let .accountNameChanged(name):
case let .view(.accountNameChanged(name)):
state.errorMessage = nil
state.accountName = name
return .none

case .createAccountButtonTapped:
case .view(.continueButtonTapped):
state.errorMessage = nil
do {
let displayName = try DisplayName(validating: state.accountName)
do {
_ = try state.walletHolder.wallet.createAndSaveNewAccount(
networkId: .mainnet,
name: displayName
)
return .send(.createdAccount)
} catch {
state.errorMessage = "Failed to create and save account. This is really bad."
return .none
}
return .send(.delegate(.named(displayName)))
} catch {
state.errorMessage = "Invalid DisplayName, can't be empty or too long."
return .none
}

case .createdAccount:
case .delegate:
return .none

}
}
}
}

public struct LabeledTextField: SwiftUI.View {
public let label: LocalizedStringKey
@Binding public var text: String
public var body: some View {
VStack {
Text(label)
TextField(label, text: $text)
}
}
}
Loading

0 comments on commit 30f134d

Please sign in to comment.