Skip to content

Latest commit

 

History

History
183 lines (143 loc) · 6.35 KB

WALLET.MD

File metadata and controls

183 lines (143 loc) · 6.35 KB

Tesseract

Tesseract on iOS for Wallet developers

Integration of Tesseract into your wallet allows any dApp to request your wallet to sign a transaction. Currently Tesseract enables native dApps to integrate with wallets through IPC, which from the user perspective is just a modal screen from the wallet.

Getting started

Getting Tesseract to work in iOS wallet is different from everywhere else only by the transports set it supports.

Currently we provide IPC transport, which allows the wallets to present their screens on top of iOS applications on request and sign the transactions.

Installation

Add Extension target

Add new Action Extension target to the your Wallet project. This will be your Wallet interface for the dApps.

Add Tesseract.swift dependency

  1. Add Tesseract.swift repository dependency through File -> Add Package menu in Xcode.
  2. Add TesseractService framework dependency to your Extension target.

Add supported network protocols to your targets

  • Edit Extension target attributes in its Info.plist and add supported ptorocols (in this example test and substrate-v1 protocol.)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSExtension</key>
	<dict>
		<key>NSExtensionAttributes</key>
		<dict>
			<key>NSExtensionServiceRoleType</key>
			<string>NSExtensionServiceRoleTypeEditor</string>
			<key>NSExtensionActivationRule</key>
			<string>
				SUBQUERY(
					extensionItems, 
					$item,
					SUBQUERY(
						$item.attachments,
						$att,
						ANY $att.registeredTypeIdentifiers UTI-CONFORMS-TO "one.tesseract.test"
						OR ANY $att.registeredTypeIdentifiers UTI-CONFORMS-TO "one.tesseract.substrate-v1"
					).@count == $item.attachments.@count
				).@count == 1
			</string>
			<key>NSExtensionServiceAllowsFinderPreviewItem</key>
			<true/>
			<key>NSExtensionServiceAllowsTouchBarItem</key>
			<true/>
			<key>NSExtensionServiceFinderPreviewIconName</key>
			<string>NSActionTemplate</string>
			<key>NSExtensionServiceTouchBarBezelColorName</key>
			<string>TouchBarBezel</string>
			<key>NSExtensionServiceTouchBarIconName</key>
			<string>NSActionTemplate</string>
		</dict>
		<key>NSExtensionMainStoryboard</key>
		<string>MainInterface</string>
		<key>NSExtensionPointIdentifier</key>
		<string>com.apple.ui-services</string>
	</dict>
</dict>
</plist>
  • Add URL schemes to your Info.plist of the Wallet target
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>CFBundleURLName</key>
			<string>one.tesseract</string>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>tesseract+test</string>
				<string>tesseract+substrate-v1</string>
			</array>
		</dict>
	</array>
</dict>
</plist>

Services

Through Tesseract, wallets serve the dApps by providing services accessible from the outside. A service implementation is responsible for understanding requests, providing the user with confirmation UI and replying back.

To make Tesseract work in your wallet, you need to describe, how exactly the wallet wants to react when a dApp needs something.

In Tesseract this is done via services. One service per blockchain protocol. The way the wallet signs transactions i.e. for Subsrate and for Ethereum is very different, thus every service has its own API to implement.

Let's take a look at the TestService implementation example from Examples.:

import TesseractService

protocol TestSigningServiceDelegate: AnyObject {
    func acceptTx(tx: String) async throws -> Bool
}

class TestSigningService: TestService {
    var signature: String
    weak var delegate: TestSigningServiceDelegate?
    
    init(delegate: TestSigningServiceDelegate, signature: String) {
        self.delegate = delegate
        self.signature = signature
    }
    
    func signTransation(req: String) async throws -> String {
        guard let delegate = self.delegate else {
            throw TesseractError.null(TestSigningServiceDelegate.self)
        }
        guard try await delegate.acceptTx(tx: req) else {
            throw TesseractError.cancelled
        }
        return req + signature
    }
}

The wallet is responsible to present the user with the relevant UI and reply with a response in case the user agrees to proced. Otherwise just throw TesseractError.cancelled. Or any other error if, in example, the request data is malformed.

Transport

For now Tesseract supports only iOS IPC transport which called IPCTransportIOS.

Transport should be created and provided to the Tesseract instance. See example bellow.

Full documentation on Transports development can be found here: Transports How To

Initialization

Here is a typical Tesseract initialization snippet (the example is taken from Example):

ActionViewController is a root ViewController provided in Extension Info.plist file.

import TesseractService

class ActionViewController: UIViewController, TestSigningServiceDelegate {
    var tesseract: Tesseract!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let data = WalletData()
        let service = TestSigningService(delegate: self, signature: data.signature)
        
        self.tesseract = try! Tesseract()
            .transport(IPCTransportIOS(self))
            .service(service)
            // add all supported services through .service() calls
    }

    @MainActor
    func acceptTx(tx: String) async throws -> Bool {
        // Show UI
    }
}

Conclusion

We tried our best to present an API as easy for the wallet developer as we could and handled all the edge cases we know of inside the library. At least we improved it to the point that it satisfied us while building the dev-wallet.swift.

If you have any suggestions, please, create an issue or submit a PR.

Thanks!