Build a viable browser extension Ethereum wallet for Safari on macOS and especially iOS

Related tags

Cryptocurrency ui
Overview

Safari Wallet

This is an experiment to see whether we can build a viable browser extension Ethereum wallet for Safari on macOS and especially iOS.

Overview

A diagram might be useful, but basically the current plan/rundown is:

  • The window.ethereum object (EIP-1193 JavaScript API) will be injected into each page. This way, the wallet will automatically work with all apps/dApps that support MetaMask.

  • For the interface, the native Safari extension popover is used, in tandem with the WebExtensions API.

The bulk of the development is currently going on in the Shared (App and Extension) and Shared (App) folders.

It is important to read these files:

  • Shared (App) > Shared (Extension) > Resources > README.md

  • Shared (App) > Shared (Extension) > Resources > ethereum > README.md

  • test-dapp > README.md

Popover

Setting up the popover

  1. Open this repo as a project in Xcode

  2. From the menu bar: File > Packages > Update to Latest Package Versions

  3. In the leftmost top bar breadcrumb, which should be on "macOS" by default, switch it to "iOS"

  4. Set the following breadcrumb to a mobile device, perhaps "iPhone 13 Pro"?

  5. Click the play button to start the emulator

  6. Once the emulator has loaded (it might take a few minutes), open the Settings app

  7. Settings > Safari > Extensions > Wallet Extension

  8. Switch to on

Then, to test the popover, navigate to https://safari-wallet-test-dapp.vercel.app in Safari (or http://localhost:3000/, if you're running the local dev server)

You can also set up the local dev server here (WIP): https://github.com/natclark/safari-wallet-test-dapp

Keys

Use your own Alchemy or Infura keys by creating a file called keys.swift in the Shared (App and Extension) directory. The filename is added to .gitignore so won't be committed.

// Shared (App and Extension)/keys.swift
let alchemyRopstenKey: String = "
    
     "
    
let alchemyMainnetKey: String = "
    
     "
    
let infuraRopstenKey: String = "
    
     "
    
let infuraMainnetKey: String = "
    
     "
    
let covalentKey: String = "
    
     "
    
Comments
  • Early-stage JS messaging refactoring

    Early-stage JS messaging refactoring

    This PR starts to standardise the messaging format between the different JS files, with the goal of being able to validate and type messages from cradle to grave, from JS to Swift and back again.

    The core idea is that all JS files communicate with the following object:

    type Message = { destination: "background" | "content" | "popup";  method: string; params: any; sessionId: string; }
    

    destination is used to multiplex the browser runtime events channel, and permit more generic method names. method is currently general-purpose, but will later be typed, ditto params. sessionId is currently unused.

    It also:

    • simplifies the view rendering logic
    • removes much of the global state from background, content and popup, preferring a more injected, localised and functional approach
    • adds tab-specific sessionId generation, which is stored in and read from localStorage
    • adds a lot of logging to the frontend code
    • adds a very rough loading state for initial popup load

    My approach here has been to try to build in an 'invisible' way, so the extension should work mostly as it did before. Signing wasn't working for me before, so I've been unable to test it properly.

    Explicitly not included in this PR:

    • TypeScript
    • Reusability of messaging primatives between JS files (ie there is some duplication right now)
    • Unit testing of messaging primatives
    • Standardisation of the JS <-> Swift interface
    • Session-specific network connections

    The above list provides a pretty good roadmap for what I'll be working on this week :)

    opened by jamierumbelow 3
  • Swift <> TypeScript Messaging

    Swift <> TypeScript Messaging

    This PR introduces a fixed format for messaging between Swift and TypeScript.

    Messaging between Swift and Typescript is governed by a fixed and typed interface. The basic object sent over the wire is of the form:

    {
      "method": string,
      "params": object
    }
    

    Typings need to be defined on both sides of the interface.

    TypeScript

    On the TypeScript side, messages are defined in src/messaging/index.ts and the src/messaging/messages/*.ts files.

    src/messaging/index.ts stores some utility types, and the NativeMessages type, which maps method names (its keys) to a message object.

    The src/messaging/messages/*.ts files store the individual message objects, which specify the shape of the message, most importantly its parameters:

    export type EthGetBalanceMessage = {
        method: "eth_getBalance";
        params: {
            address: string;
            block?: string;
        };
    }
    

    It is then added to the NativeMessages object like so:

    export type NativeMessages = {
        eth_getBalance: EthGetBalanceMessage;
    

    This exposes the message to the Messenger interface, which gives you eg type checking:

    const balance = await Messenger.sendToNative(
        'eth_getBalance',
        sessionId,
        {
            unknownProperty: "foo" // Error: Property 'unknownProperty' is missing in type 'EthGetBalanceMessage'
        }
    );
    

    The Messenger bus will handle serialisation, validation, error checking etc.

    Swift

    On the Swift side, messages are defined in Messages.swift and the Messages/*.swift files.

    Messages.swift defines the NativeMessage and NativeMessageMethod types, and the NativeMessageParams protocol.

    The Messages/*.swift files define the individual message params structs, which provide typing around each message's params:

    struct helloFrenMessageParams: NativeMessageParams {
        let foo: String
        let bar: Int
        let wagmi: Bool?
        
        func execute(with userSettings: UserSettings) async throws -> Any {
            if let wagmi = self.wagmi {
                return wagmi ? "wagmi" : "ngmi"
            }
            return "ngmi"
        }
    }
    

    The message param structs also implement the execute method, which is called by the SafariWebExtensionHandler#handle method. execute is passed the user settings, and returns a promise that resolves to the result of the message.

    This allows the message params struct to pass on control to other parts of the Swift extension or core library in a type-safe way:

    struct SomeParamsObject: NativeMessageParams {
        func execute(with userSettings: UserSettings) async throws -> Any {
            doSomething(with: self)
        }
    }
    
    func doSomething(with params: SomeParamsObject) {
        // ...
    }
    

    Whatever is resolved from the execute method is returned as a JSON response, wrapped in a message key.

    NativeMessageParams adheres to the Decodable protocol, which allows you to customise the decoding behaviour:

    struct MessageWithDefaultParameterMessageParams: NativeMessageParams {
        let foo: String
    
        private enum CodingKeys: CodingKey {
            case foo
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            if let foo = try container.decode(String.self, forKey: .address) {
                self.foo = foo
            } else {
                self.foo = "default"
            }
        }
    }
    

    Explicitly not included in this PR, but up next, is:

    • typing the return values
    • adding stubs for the remaining methods exposed in ProviderAPI
    opened by jamierumbelow 2
  • Add extension tutorial and fix MVVM

    Add extension tutorial and fix MVVM

    • Add tutorial how to enable the extension designed by KaL and Anton
    • Fix MVVM-related bug in SendView where view model and user settings were out of sync
    opened by ronaldmannak 1
  • WalletManager refactor

    WalletManager refactor

    This is a big one. WalletManager is completely refactored and renamed to UserSettings for better SwiftUI support. There are still a few issues in SettingsView and signing I will need to fix in the next few days.

    I've cleaned up project file and it can be merged without any issues.

    The code changes are quite big. If anyone has questions, I'm happy to walk anyone through the changes in a Zoom call.

    WARNING: BACK UP YOUR KEYS BEFORE USING THIS VERSION

    Both the address storage and HDWallet storage formats have changed in this version. If you use a specific dev wallet, you will have to restore your wallet. Otherwise, simply create new keys.

    WARNING: Running the unit tests removes all wallets

    opened by ronaldmannak 1
  • Jest support

    Jest support

    This PR adds jest support:

    • It adds jest, ts-jest and jsdom dependencies to package.json
    • It checks in yarn.lock as we transition to using yarn for package management
    • It adds a small test for the utils.$ function, to demonstrate it working

    It closes #17.

    opened by jamierumbelow 1
  • ext/resources: use standardised frontend messaging

    ext/resources: use standardised frontend messaging

    This PR starts to standardise the messaging format between the different JS files, with the goal of being able to validate and type messages from cradle to grave, from JS to Swift and back again.

    Since each component has its own communication method and security policies, this PR introduces a Messenger object that is defined in terms of the component it is in:

    const Messenger = getMessenger('background');
    

    This Messenger abstraction knows for a given (source, destination) pair how to send messages, and over which pipeline (either browser.runtime or browser.tabs or window.sendMessage).

    Currently, it's not responsible for listening to these messages, though that is a natural next step.

    It also:

    • simplifies the view rendering logic
    • removes much of the global state from background, content and popup, preferring a more injected, localised and functional approach
    • adds tab-specific sessionId generation, which is stored in and read from localStorage
    • adds a lot of logging to the frontend code
    • adds a very rough loading state for initial popup load

    Explicitly not included in this PR:

    • Unit testing of messaging primatives
    • Standardisation of the JS <-> Swift interface
    • Session-specific network connections

    There are probably more things missing, or code that's unclear here. The PR was starting to get big, so I figured it'd be better to merge earlier. Feel free to pop any questions in here / Twist and I'll get back to you soon!

    opened by jamierumbelow 1
  • Display all transactions grouped by transaction hash

    Display all transactions grouped by transaction hash

    This PR displays all transactions from Covalent, Unmarshal, and Alchemy on the transactions tab.

    Each row groups all the transaction of the same hash and displays how many sources it has. When selecting a row it takes you to a screen that displays all the raw data returned by these transactions and their corresponding source.

    There is lots of clean up to be done, but this should get us started with playing around with the various data sources.

    simulator_screenshot_BA7F52E3-19FB-4CF7-AC8E-483832916926

    simulator_screenshot_8CBEB1E3-116C-4E99-BD1D-02F2877B4A08

    opened by tvongerlach 1
  • quick fix out of range error

    quick fix out of range error

    @bejitono ran into an out of range exception in the viewModel. Added a simple range check in SettingsView.

    The root cause is likely the complexity of the viewModel. I'm not sure what the best way is to use view models in SwiftUI, this may be something we need to look into later.

    opened by ronaldmannak 0
  • Disable HMR

    Disable HMR

    I'm reasonably convinced that HMR won't work for at least background.js, and it's quite possible that its interaction with the upcoming xcode builds and the broader Safari Extension system will cause some issues. So I think it's probably a good idea to just disable, at least for the time being, until we can get clearer on how it might break.

    opened by jamierumbelow 0
  • Move to Zerion / Refactor logic & UI

    Move to Zerion / Refactor logic & UI

    This PR replaces Umarshal with Zerion and refactors business logic & UI for transaction history.

    It does so by:

    • Removing Transaction Group models used for demo purposes and defining a new Transaction Activity model.
    • Replacing Unmarshal Client with Zerion Client.
    • Implements view mapping logic (show appropriate asset based on tx type, currency/date formatting, etc.)
    • Updates views based on latest designs. Adds a basic detail screen to inspect the tx on Etherscan.

    Motivations for switching to Zerion:

    • It gives us more granular details about assets being swapped, price in fiat terms, nft assets, etc. Umarshal was too basic for our needs (only a description along with Eth value)
    • Zerion has almost everything you’d want to arrive at feature parity with other wallets (for some tx's it even provides you with tx inputs, e.g. for ENS registrations). Since it provides most of what we need it will allow us to experiment with new features quickly until we have our own proper input decoding.
    • It will be a good benchmark for our own tx categorization.

    simulator_screenshot_CCDB7EAD-027D-4788-9633-A9BF7FAFA3EB

    Notes: You need to apply to get a Zerion api key (https://help.zerion.io/en/articles/5351183-how-can-i-get-a-zerion-api-key). I applied for a key to be used in the test flight app. Use the demo api key for testing purposes: Demo.ukEVQp6L5vfgxcz4sBke7XvS873GMYHy

    opened by bejitono 0
  • Add Jest

    Add Jest

    For testing JavaScript code.

    Should be integrated with npm test/yarn test and there should be a simple test that can be run to confirm that it's been set up correctly.

    opened by DimitarNestorov 0
  • Transaction Decoding / Input Formatting

    Transaction Decoding / Input Formatting

    • [ ] Transaction decoding (more detailed specs to follow)

    • Look up method byte signature and to retrieve method signature (e.g. through 4bytes)

    • Parse method parameter types

    • Decode tx based on parameter types to get tx input values

    • Further ideas from Metamask: https://twitter.com/gnidan/status/1471992703575539714?s=12

    • [ ] Input formatting (more detailed specs to follow)

    • Setup a separate repository (Hancock) that specifies string formats which the client can use to format the tx input

    • Format the tx inputs based on the string format

    A full discussion on some of the above points can be found in the following Discord thread: https://discord.com/channels/922963239241928705/924671137420546058

    opened by bejitono 0
  • Finalize transaction history

    Finalize transaction history

    The following items are still open for a first viable version for ETHDenver:

    • [x] Remove hard-coded address and connect to user settings to fetch the wallet’s tx history
    • [x] Handle different networks (for now mainnet/ropsten)
    • [ ] Handle new confirmed transactions
    • [ ] Possibly, handle pending transactions from the extension
      • For this we would need the Safari extension to pass transactions through the shared container so the containing app can start polling for transaction confirmation
    • [x] Show message on screen for empty transactions
    • [x] Follow up for the Zerion API key for the test flight version
    • [ ] Fix async continuation issues when Zerion client tries to connect more than once (listenForConnections)
    • [x] Handle address and network changes
    opened by bejitono 0
  • Sign messages

    Sign messages

    Closes #23

    To do:

    • [x] eth_signTypedData_v3
    • [x] eth_signTypedData_v4
    • [x] eth_sign
    • [x] personal_sign
    • [ ] Remove hardcoded password
    • [ ] UI
    • [x] Update test dapp to include eth_signTypedData_v4 and eth_sign buttons
    • [x] Update test dapp to verify signatures

    Core package PR: https://github.com/Safari-Wallet/core/pull/15

    opened by DimitarNestorov 1
An iOS application that helps the user to track his/her investments and maintain portfolios.

CryptoX Technology has changed the way people work, communicate, shop, pay and collaborate. One such transformation was the origin of cryptocurrency.

Anant Kanchan 32 Aug 21, 2022
The app encrypts or decrypts user's text input with basic encryption and decryption algorithms

Objective-C Wrapper Project About The Project The app encrypts or decrypts user's text input with basic encryption and decryption algorithms. Purpose

Can Yoldas 0 Dec 5, 2021
CryptoLux - An app that ranks crypto currency based on current price and tracks btc

CryptoLux An app that ranks crypto currency based on current price and tracks bt

Khidr Brinkley 0 Feb 12, 2022
Clutch is a high-speed iOS decryption tool.

Clutch is a high-speed iOS decryption tool. Clutch supports the iPhone, iPod Touch, and iPad as well as all iOS version, architecture types, and most binaries. Clutch is meant only for educational purposes and security research.

null 3 May 16, 2021
Ethereum browser extension wallet for Safari on macOS & iOS.

Safari Wallet This is an experiment to see whether we can build a viable browser extension Ethereum wallet for Safari on macOS and especially iOS. Ove

nathan.eth 56 Oct 9, 2022
Ethereum Wallet Toolkit for iOS - You can implement an Ethereum wallet without a server and blockchain knowledge.

Introduction EtherWalletKit is an Ethereum Wallet Toolkit for iOS. I hope cryptocurrency and decentralized token economy become more widely adapted. H

Sung Woo Chang 136 Dec 25, 2022
Ethereum Wallet Toolkit for iOS - You can implement an Ethereum wallet without a server and blockchain knowledge.

Introduction EtherWalletKit is an Ethereum Wallet Toolkit for iOS. I hope cryptocurrency and decentralized token economy become more widely adapted. H

Sung Woo Chang 136 Dec 25, 2022
Ethereum-wallet: 100% native ethereum wallet, created with iOS version of Geth client

Ethereum-wallet: 100% native ethereum wallet, created with iOS version of Geth client

DE MINING 4 Dec 11, 2022
Wei Wallet - Ethereum wallet app for iOS

Wei Wallet - Ethereum wallet app for iOS Getting Started Download the latest Xcode Clone this repository Install Carthage, Cocoapods Run make bootstra

Popshoot, Inc. 277 Nov 17, 2022
Trust - Ethereum Wallet and Web3 DApp Browser for iOS

Trust - Ethereum Wallet and Web3 DApp Browser for iOS Welcome to Trust's open source iOS app! Getting Started Download the Xcode 9 release. Clone this

Trust Wallet 1.4k Dec 31, 2022
AlphaWallet - Advanced, Open Source Ethereum Mobile Wallet & dApp Browser for iOS

AlphaWallet - Advanced, Open Source Ethereum Mobile Wallet & dApp Browser for iOS

AlphaWallet 475 Jan 5, 2023
This is an iOS Safari Extension Sample that adds a "Develop menu" to Safari on iOS to allow you to analyze websites.

Develop Menu for Mobile Safari This is an iOS Safari Extension that adds a "Develop menu" to Safari on iOS to allow you to analyze websites. This is a

Watanabe Toshinori 1 Dec 7, 2022
BTTV-for-Safari - Unofficial BTTV/ FFZ Safari Extension for Twitch

BTTV for Safari This unofficial Safari exention adds support for BTTV and FFZ emotes on Twitch. The extension simply injects the BTTV script from the

Philipp Bolte 14 Dec 26, 2022
A browser extension for Safari that makes sure that cut, copy, and paste are enabled.

Paste for Safari A browser extension for Safari that makes sure that cut, copy, and paste are enabled. Notes This is pretty rough and does work. The v

Mark Ferlatte 1 Dec 20, 2022
Browser-ext - Safari Extension Container App

browser-ext See article on dev.to. Please refer to Safari Web Extensions on how

Bing Qiao 4 Jul 18, 2022
BRD - the simple and secure wallet for bitcoin, ethereum, and other digital assets

BRD is the simple and secure wallet for bitcoin, ethereum, and other digital assets. Today, BRD is one of the largest non-custodial mobile wallets used by over 6 million users and protects an estimated nearly $7B USD.

bread 647 Jan 7, 2023
Multi-wallet for Bitcoin, Ethereum, Binance Smart Chain and other emerging blockchains

Multi-wallet for Bitcoin, Ethereum, Binance Smart Chain and other emerging blockchains. Non-custodial storage, decentralized exchange, and extensive analytics for thousands of tokens and NFTs. Implemented on Swift.

Horizontal Systems 446 Jan 3, 2023
Rainbow - 🌈the Ethereum wallet that lives in your pocket

??️ the Ethereum wallet that lives in your pocket! ??️ Available on the iOS App Store. ?? Android Beta available on Google Play Store ??️ Foll

Rainbow 3.2k Jan 3, 2023
An open-source Ethereum wallet built with SwiftUI

lil wallet welcome to lil wallet. it's an open-source Ethereum wallet built with SwiftUI there are two main views - coins and objects. coins are your

Jordan Singer 140 Jan 3, 2023
Trackable is a simple analytics integration helper library. It’s especially designed for easy and comfortable integration with existing projects.

Trackable Trackable is a simple analytics integration helper library. It’s especially designed for easy and comfortable integration with existing proj

Vojta Stavik 145 Apr 14, 2022