Giter Club home page Giter Club logo

nthkey-ios's Introduction

Nth Key for iOs Build Status

Use your iOs device as part of a Bitcoin multi-signature setup.

Best used with Specter Desktop.

Uses LibWally via a Swift wrapper.

Build

Install dependencies:

brew install gnu-sed

Install Ruby, e.g. using RBenv:

rbenv install `cat .ruby-version`
bundle install
bundle exec pod install --verbose

To preview documentation:

bundle exec jekyll server --incremental --source docs

To get the simulator working directory, export your public key in Settings. The path is printed in the log.

Usage

Download from the App Store and follow the tutorial.

Known issues

nthkey-ios's People

Contributors

amfathi avatar dependabot[bot] avatar sjors avatar w-i-n-s avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

nthkey-ios's Issues

Verify input SPV proofs

It might be useful if the device can verify that inputs being spent actually exist(ed in the past). But it may not be very practical.

  1. The PSBT standard would need to be expanded to adding SPV proofs (can use proprietary field)
  2. Specter has to support it (bigger QR code is a problem?)
  3. App has to obtain and verify the headers, probably easiest to download via the p2p network, but this requires new code (rust bitcoin?)

Error deliver in UI

The user should see any error which can be a result of his/her steps in UI. Like if the app receives not the correct QR then the user should see the alert "QR is wrong" or something similar.

Layout constraint error

On the iPhone 12 mini simulator I often see layout constraint errors.

In aditionaddition, the addresses sometimes end in ellipses:

Schermafbeelding 2021-03-06 om 09 21 55

This was tested with #7, but I think it happened on master too.

2021-03-06 09:20:31.163725+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.191147+0100 NthKey[90155:17206710] Metal API Validation Enabled
2021-03-06 09:20:31.417162+0100 NthKey[90155:17206710] The filter 'CIPortraitEffectSpillCorrection' is not implemented in the bundle at /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/CoreImage/PortraitFilters.cifilter.
2021-03-06 09:20:31.446079+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.446377+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.446540+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.446673+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.446827+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.447074+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-06 09:20:31.461530+0100 NthKey[90155:17206710] [LayoutConstraints] Unable to simultaneously satisfy constraints.
	Probably at least one of the constraints in the following list is one you don't want. 
	Try this: 
		(1) look at each constraint and try to figure out which you don't expect; 
		(2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x60000105f890 'BIB_Trailing_CB_Leading' H:[_UIModernBarButton:0x7fb37bc33ea0]-(6)-[_UIModernBarButton:0x7fb37bc31160'Address']   (active)>",
    "<NSLayoutConstraint:0x60000105f8e0 'CB_Trailing_Trailing' _UIModernBarButton:0x7fb37bc31160'Address'.trailing <= _UIButtonBarButton:0x7fb37bc30990.trailing   (active)>",
    "<NSLayoutConstraint:0x600001048640 'UINav_static_button_horiz_position' _UIModernBarButton:0x7fb37bc33ea0.leading == UILayoutGuide:0x600000a71b20'UIViewLayoutMarginsGuide'.leading   (active)>",
    "<NSLayoutConstraint:0x600001048690 'UINavItemContentGuide-leading' H:[_UIButtonBarButton:0x7fb37bc30990]-(0)-[UILayoutGuide:0x600000a71a40'UINavigationBarItemContentLayoutGuide']   (active)>",
    "<NSLayoutConstraint:0x600001055090 'UINavItemContentGuide-trailing' UILayoutGuide:0x600000a71a40'UINavigationBarItemContentLayoutGuide'.trailing == _UINavigationBarContentView:0x7fb37bd22c80.trailing   (active)>",
    "<NSLayoutConstraint:0x600001048e10 'UIView-Encapsulated-Layout-Width' _UINavigationBarContentView:0x7fb37bd22c80.width == 0   (active)>",
    "<NSLayoutConstraint:0x600001055450 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x600000a71b20'UIViewLayoutMarginsGuide'](LTR)   (active, names: '|':_UINavigationBarContentView:0x7fb37bd22c80 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000105f890 'BIB_Trailing_CB_Leading' H:[_UIModernBarButton:0x7fb37bc33ea0]-(6)-[_UIModernBarButton:0x7fb37bc31160'Address']   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
2021-03-06 09:20:31.618760+0100 NthKey[90155:17206710] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)

Don't filter wallet list by network

There's now three areas:

  1. Announce: (let's move the tab above the "In Specter go..." text)
  2. Import wallet
  3. Wallets

So I think there's no need to filter by network in (3).

Schermafbeelding 2021-04-26 om 11 51 05

Later on we can move (1) and (2) into their own views, so there won't be a network toggle on this page anymore at all.

Change UX of mark an address as used

When the user tap on the address it gets the strike-through. It should only happen if I tap on the checkmark.

Let's drop the "Address" header at the top, so "Scan to check" is at the top. It already says "Addresses" in the tab bar below, so it's redundant.

Originally posted by @Sjors in #58 (comment)

[Feature] Specter address verification

  • Copy address from addresses tab to the clipboard for share
  • Verify address from Specter (scan the address from Specter and app should check if it matches) #34
  • Possibility to mark the address as used (by gesture on addresses tab)

Discussion:

Being able to select an address, copy it to clipboard and/or share, is nice.
The primary goal is to verify the address that Specter shows.
So it would be nice if we can scan the address from Specter and then say it matches.
And we should be able to mark an address as used (maybe using the swipe to delete gesture)

Fix handling large QR code

When a transaction has several inputs it seems to get too large for our current QR generating code:

 [filter] initQRCodeForInputByteSize cannot find proper rs block info (input data too big?)

IMG_8024

Consider BIP 87 for new wallets

We currently use m/48h/0h/2h. The new BIP 87 suggests a simpler derivation path m/87h/0h.

This requires checking:

  • if Specter supports it
  • if other hardware wallet special case m/48h/0h/2h or if they don't care
  • storing our path in Core Data, rather than hardcoding it in Signer.getSignerUs and SeedManager.ourPubKey (in order not to break existing wallets)

Display current wallet on sign screen

If there is more than 1 wallet, display the currently selected wallet name on the sign screen. This reduces confusion if sign button is disabled (but we should also improve error messages there).

Select wallet based on unsigned transaction info

In the implementation of the persistent store and supporting multi-wallet configuration we assume that sign transaction flow can take place for selected wallet only. But it can be tricky for the user to select the right one.

Better to autoselect wallet in case if the app can catch all the required info from PSBT

Deterministic builds

I'd like to be able to prove that the TestFlight and App Store binaries are actually derived from this source code.

As a first step I've uploaded the binary to the release tag: https://github.com/Sjors/nthkey-ios/releases/tag/v0.0.1

I didn't check if that matches the binary that end users download from TestFlight, or whether Apple injects some signature magic.

Because the binary is signed by me, it's not possible for someone else to reproduce the exact same binary. However perhaps it's possible to generate a binary, strip the signature data and then perform the comparison.

The v0.0.1 release uses a temporary branch of upstream libwally-core and libwally-swift. These commits won't exist anymore after a while, at least Github won't serve them. This is a temporary issue; by the time this app is ready for the App Store I plan to use only tagged releases for dependencies; those should remain available on Github.

Implement CoreData persistent store

Original task:

Implementing multi-wallet. Should use Core Data as ORM. Only unique entropyMask can stay in defaults for whole app. For each wallet:
- which network (testnet, mainnet, and later also Signet)
- the threshold (how many signatures are required)
- information about each co-signer: their xpub and derivation path
- a list of pre-derived addresses

Empty sign screen

As reported by a beta tester.

It's unclear what could cause this....

Schermafbeelding 2021-05-27 om 15 37 00

Possible explanations:

  1. The destination address is marked as change. We hide the change address, but perhaps the user is trying to send coins to their own wallet.

Subscription for mainnet

Once #19 is ready, when creating a mainnet wallet it should prompt for a subscription.

When cancelling a subscription, the wallet should remain available, but the transaction Sign button should prompt for a new subscription. The user can always export their mnemonic and use a different (hardware) wallet to sign, so they are never locked out of their coins.

Drop unused LibWally imports

There's a couple of import LibWally lines that are no longer used:

  • AppDelegate.swift
  • SceneDelegate.swift
  • ContentView.swift
  • SettingsView.swift
  • DocumentPickerManager.swift

Multiple wallet support

A wallet can be configured in Specter and then imported in the app. Each wallet has:

  • a network (mainnet, testnet, signet)
  • for each cosigner (info that's currently in Signer model)
    • fingerprint
    • xpub
    • derivation
    • name
  • threshold (current in UserDefaults)

The following is still global state:

  • our fingerprint, seed hex, entropy mask (and mnemonic)

Since there is no app store version yet, there's no need for a graceful migration from the current UserDefaults to Core Data.

When the user installs the app from scratch, we have zero wallets. So the user has to add a wallet. They should explicitly choose which network to use. We can sanity check this choice with what we get from Specter.

The current "Feeling reckless?" and "You need to wipe your existing testnet wallet first" stuff can go away, since we no longer delete the testnet wallet. However, I do want to keep the warning for a while. In stead of "Switch to mainnet?" the warning title should be "Create mainnet wallet?". In the detail message the last sentence can be dropped ("Switching back to testnet requires deleting and reinstalling the app.").

See also #12.

Make libwally values easier to debug

Perhaps this should be done upstream in libwally-swift.

Is it possible to produce more useful previews of things like HDKey and fingerprints for debugging?

Schermafbeelding 2021-04-19 om 11 22 33

Implement airdrop share

In terms of have issue with Specter QR recognition - we can use SD card import and receive JSON file directly from iPhone app via AirDrop

Screen parameters are unexpected (simulator console)

I still get a bunch of noise in the console, but that's a seperate issue probably:

2021-03-07 17:05:35.283735+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.309439+0100 NthKey[7417:17891608] Metal API Validation Enabled
2021-03-07 17:05:35.455422+0100 NthKey[7417:17891608] The filter 'CIPortraitEffectSpillCorrection' is not implemented in the bundle at /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/CoreImage/PortraitFilters.cifilter.
2021-03-07 17:05:35.484019+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.484207+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.484363+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.484517+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.484655+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.484929+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)
2021-03-07 17:05:35.621031+0100 NthKey[7417:17891608] screen parameters are unexpected: MGScreenClass1125x2436x3x495 SCREEN_TYPE(1125,2436,3,495)

Originally posted by @Sjors in #17 (comment)

Crash when clicking Load PSBT

This seems to happen every 2nd time I click it.

precondition(activeFileViewControllerManager == nil) fails in SignViewController openPSBT

Mark addresses as used

A user should be able to mark an addresss as used, so they're reminded to not use it again. Maybe with a swipe gesture, confirmed with "mark as used?", similar to how delete works in a tableview.

We should not hide the address. A light strike-through is probably good enough.

Scan to check should be case insensitive and ignore URI stuff

When I scan a BIP 21 QR code it complains that the address is not found in the list.

This is probably because the format is bitcoin:BC1Q...?label=blah

When parsing an address, I suggest the following:

  1. check if it contains only alphanumeric characters: process as now
  2. parse it as a URI and obtain only the main part of it. Ideally use something like NSURL for this, rather than "manually" processing it, since that's safer.

Don't validate IAP receipt on device?

Details on documentations

Warning
Do not call the App Store server verifyReceipt endpoint from your app. You can't build a trusted connection between a user’s device and the App Store directly, because you don’t control either end of that connection, which makes it susceptible to a man-in-the-middle attack.

To solve it we can follow 3 cases (pros/cons) details from apple:

  • Forget about receipt validation (0 min / jailbroked devices can used app for free)
  • Implement in-app check (everything inside app / isn't fast and simple to decrypt receipt file)
  • Add backend to just validate receipt (right way / need backend)
  • Use current setup SubscriptionManager.swift

Add Signet

I'd like to add Signet support:

Schermafbeelding 2021-04-05 om 12 55 36

Signet is identical to testnet in terms of addresses and transaction signature. So internally LibWally can be used with .testnet and the same with Specter.

Explain why sign button is disabled

The sign button is disabled when psbt.canSign returns false. We should make it more clear why this happens. This may require a PR to libwally-swift.

canSign is implemented here:
https://github.com/blockchain/libwally-swift/blob/master/LibWally/PSBT.swift#L54-L73

Some reasons why it can fail:

  • wrong network: the network is not specified in the PSBT, but you can tell from the derivation path, e.g. m/84h/0h is mainnet and m/84h/1h is testnet
  • change address derivation is not what we expect
  • we don't have matching keys (wrong derivation path?); this might be where we should check if any of the other wallets do match

[Refactoring] All refactoring tasks for the moment

  • AppState god object. Injected in every view. Contain every manager/store. Breaks the "single responsibility principle" because it becomes the source of truth for every view.
  • Implement MVC or MVVM (with "finite state automata"). Possible with reducers [TBC]
  • Take care about error presenting on UI [TBC].
  • Make a user action atomic and consistent (App should not show a QR code with invalid stuff in it). App model should be consistent, but without implementing force unwrapping or assertions. Possible using SwiftLint
  • (migrated into #12) Implementing multi-wallet. Should use Core Data as ORM. Only unique entropyMask can stay in defaults for whole app. For each wallet:
    • which network (testnet, mainnet, and later also Signet)
    • the threshold (how many signatures are required)
    • information about each co-signer: their xpub and derivation path
    • a list of pre-derived addresses
  • Change the way how the app starts (AppDelegate and SceneDelegate -> App/WindowGroup iOS14)

Minor issues to fix before AppStore release

Purchase flow need loaders between screens and additional notifications which allow user to understand what happen (and debug purpose)
IMG_7336
- [ ] Loader in 2-3
- [ ] Loader in 3-4
- [ ] Implement Status view for display purchasePublisher value
- [ ] Check additional SKPaymentTransactionObserver methods if it can help in UX improvements
[edit] Doen't make sense after 0c9ed45


Originally posted by @Sjors in #44 (comment)

I was able to make a purchase using the sandbox user. However the "Use real Bitcoin (mainnet)" dialog doesn't close when the purchase is complete.

  • Close the dialog when user make payment e0e0df0

I also suggest making the "Subscribe Now" button grey while the purchase is in progress.

I see, but a month is not 30 days, so that bit has to be more accurate.
Right, so we just check if: current time > expirationDateFromResponse (stored in UserDefaults)

  • check current calendar and set the date according to it 258c96b
  • Ask status after this date da8f237

So we do something like this?

  1. When user makes a purchase, store the expiration date
  2. When app wakes up check if time > expiration date
  3. When time > experitation date, fetch (???) from Apple:
    a) update expiration date (??)
    b) turn off subscription if it wasn't renewed
    (if connection to Apple fails, just ignore and try later)

Снимок экрана 2021-06-03 в 21 39 41


Only minor suggestion (can wait): when the purchase (or restore) is complete, jump to the mainnet tab. If it's easier: do this for both the Announce and Import sections.

  • mark requested tab after purchase 1cc14fb

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.