This repository showcases an example iOS wallet that utilizes a Safari Web Extension to enable wallet signing within the Safari browser. This is a proof of concept and its implementation of key storage is unencrypted and should not be replicated in a real wallet.
Video of a Jupiter Exchange swap (outdated video needs updating to Popup UI).
- Download Xcode
- Build the Extension's JS bundle:
cd js-extension && npm install && npm run build:publish
- Follow the "Enable App Groups" steps below.
- Open the project in Xcode, choose your simulator/device, build and run.
In order for the Safari Extension to read the same UserDefaults
or Keychain as the iOS app, they need to use a shared App group.
- In Xcode, select the project > Signing & Capabilities > App Groups
- At the bottom, add an App Group identifier.
- In
/Shared/KeypairUtil.swift
, edit thesharedUserDefaults()
function to use your app group identifier.
func sharedUserDefaults() -> UserDefaults? {
return UserDefaults(suiteName: "group.your.app")
}
Now your native app and extension handler can read and write to the same UserDefaults!
- In Safari, press the Aa menu and click Manage Extensions
- In the extensions list, find the name, "Solana Safari Extension Wallet", and enable it.
- Back in the Aa menu, press new "Solana Safari Extension Wallet" button.
- Select "Always allow" then "Always allow on every website".
js-extension
: All the JS in the web extension is built from this directory (i.e Approval UI, page/content/background scripts, wallet standard, etc). The JS is bundled into raw minified .js
scripts which are exported to the Safari Extension folder with npm run build:publish
.
js-extension/Approval
: React components and logic for the Approval Popup UI.
SolanaSafariWalletExtension Extension
: The Safari Web Extension Swift code. This contains the bundled js
and html
from the js-extension
folder and also the Extension handler code, which acts as a bridge between JS and the native app.
SolanaSafariWalletExtension
: The native iOS wallet app built with SwiftUI.
A Safari Web Extension allows an iOS app to add customized functionality to the Safari mobile browser. Similar to a Chrome browser extension, the Safari Web Extension can run background/content scripts and inject javascript into the web page.
The key benefit of the web extension on mobile is that it is able to communicate with the native iOS app, relay information to the web page, and render a bottom sheet pop up for a no-context switch signing experience.
Just like Chrome extension wallets, this uses Wallet-standard to subscribe and respond to requests from the dApp. It is automatically compatible with existing Solana web dApps.
-
On page load, the JS extension injects a page script (
injected.ts
) that registers the wallet implementation towindow
using Wallet-standard'sregisterWallet
. -
When a standard Connect event is emitted, the wallet provider (
provider.ts
) relays it to the Extension's content script (content.ts
) withwindow.postMessage
. -
The content script forwards this message to the Extension's background script (
background.ts
) usingbrowser.runtime.sendMessage
. -
The background script initializes the Approval UI (
approval.tsx
) usingbrowser.action.openPopup()
API. -
The Approval UI is able to communicate and fetch necessary data from the native app with
browser.runtime.sendNativeMessage
. -
On approve, the Approval UI tab sends the connect response back to the page with
browser.tabs.sendMessage(originTabId, response)
.