mirror of
https://github.com/lil-org/tokenary.git
synced 2024-12-16 08:02:53 +03:00
Merge branch 'main'
This commit is contained in:
commit
f60c334f30
@ -38,6 +38,8 @@
|
|||||||
2C901C4A2689F01700D0926A /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C492689F01700D0926A /* Strings.swift */; };
|
2C901C4A2689F01700D0926A /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C492689F01700D0926A /* Strings.swift */; };
|
||||||
2C901C4D268A033100D0926A /* GasService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C4C268A033100D0926A /* GasService.swift */; };
|
2C901C4D268A033100D0926A /* GasService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C4C268A033100D0926A /* GasService.swift */; };
|
||||||
2C917429267D2A6E00049075 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C917428267D2A6E00049075 /* Keychain.swift */; };
|
2C917429267D2A6E00049075 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C917428267D2A6E00049075 /* Keychain.swift */; };
|
||||||
|
2C9F0B6526BDC9AF008FA3D6 /* EthereumNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */; };
|
||||||
|
2C9F0B6826BDCB2E008FA3D6 /* EthereumChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */; };
|
||||||
2CC0CDBE2692027E0072922A /* PriceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC0CDBD2692027E0072922A /* PriceService.swift */; };
|
2CC0CDBE2692027E0072922A /* PriceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC0CDBD2692027E0072922A /* PriceService.swift */; };
|
||||||
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8946E269A2E8C00879245 /* SessionStorage.swift */; };
|
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8946E269A2E8C00879245 /* SessionStorage.swift */; };
|
||||||
2CC89471269A334A00879245 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC89470269A334A00879245 /* UserDefaults.swift */; };
|
2CC89471269A334A00879245 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC89470269A334A00879245 /* UserDefaults.swift */; };
|
||||||
@ -84,6 +86,8 @@
|
|||||||
2C901C492689F01700D0926A /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
|
2C901C492689F01700D0926A /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
|
||||||
2C901C4C268A033100D0926A /* GasService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GasService.swift; sourceTree = "<group>"; };
|
2C901C4C268A033100D0926A /* GasService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GasService.swift; sourceTree = "<group>"; };
|
||||||
2C917428267D2A6E00049075 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
2C917428267D2A6E00049075 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
||||||
|
2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumNetwork.swift; sourceTree = "<group>"; };
|
||||||
|
2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumChain.swift; sourceTree = "<group>"; };
|
||||||
2CC0CDBD2692027E0072922A /* PriceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceService.swift; sourceTree = "<group>"; };
|
2CC0CDBD2692027E0072922A /* PriceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceService.swift; sourceTree = "<group>"; };
|
||||||
2CC8946E269A2E8C00879245 /* SessionStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionStorage.swift; sourceTree = "<group>"; };
|
2CC8946E269A2E8C00879245 /* SessionStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionStorage.swift; sourceTree = "<group>"; };
|
||||||
2CC89470269A334A00879245 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
|
2CC89470269A334A00879245 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
|
||||||
@ -189,6 +193,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2C1995552674D0F300A8E370 /* Ethereum.swift */,
|
2C1995552674D0F300A8E370 /* Ethereum.swift */,
|
||||||
|
2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */,
|
||||||
|
2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */,
|
||||||
2CE3D014267F73E80032A62E /* LegacyAccountWithKey.swift */,
|
2CE3D014267F73E80032A62E /* LegacyAccountWithKey.swift */,
|
||||||
2CE3D011267F73C00032A62E /* Transaction.swift */,
|
2CE3D011267F73C00032A62E /* Transaction.swift */,
|
||||||
);
|
);
|
||||||
@ -396,11 +402,13 @@
|
|||||||
2CC0CDBE2692027E0072922A /* PriceService.swift in Sources */,
|
2CC0CDBE2692027E0072922A /* PriceService.swift in Sources */,
|
||||||
2C8A09C6267513FC00993638 /* Agent.swift in Sources */,
|
2C8A09C6267513FC00993638 /* Agent.swift in Sources */,
|
||||||
2C8A09D42675184700993638 /* Window.swift in Sources */,
|
2C8A09D42675184700993638 /* Window.swift in Sources */,
|
||||||
|
2C9F0B6526BDC9AF008FA3D6 /* EthereumNetwork.swift in Sources */,
|
||||||
2C208A9F26813408005BA500 /* Secrets.swift in Sources */,
|
2C208A9F26813408005BA500 /* Secrets.swift in Sources */,
|
||||||
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */,
|
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */,
|
||||||
0DC850E726B73A5900809E82 /* AuthenticationReason.swift in Sources */,
|
0DC850E726B73A5900809E82 /* AuthenticationReason.swift in Sources */,
|
||||||
2CD0669126B5537B00728C20 /* InkWallet.swift in Sources */,
|
2CD0669126B5537B00728C20 /* InkWallet.swift in Sources */,
|
||||||
2C8A09D726751A0C00993638 /* WalletConnect.swift in Sources */,
|
2C8A09D726751A0C00993638 /* WalletConnect.swift in Sources */,
|
||||||
|
2C9F0B6826BDCB2E008FA3D6 /* EthereumChain.swift in Sources */,
|
||||||
2C03D1D2269B407900EF10EA /* NetworkMonitor.swift in Sources */,
|
2C03D1D2269B407900EF10EA /* NetworkMonitor.swift in Sources */,
|
||||||
2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */,
|
2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */,
|
||||||
2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */,
|
2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */,
|
||||||
@ -570,7 +578,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 23;
|
CURRENT_PROJECT_VERSION = 26;
|
||||||
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
||||||
@ -579,7 +587,7 @@
|
|||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||||
MARKETING_VERSION = 1.0.4;
|
MARKETING_VERSION = 1.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -597,7 +605,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 23;
|
CURRENT_PROJECT_VERSION = 26;
|
||||||
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
||||||
@ -606,7 +614,7 @@
|
|||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||||
MARKETING_VERSION = 1.0.4;
|
MARKETING_VERSION = 1.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
@ -77,9 +77,9 @@ class Agent: NSObject {
|
|||||||
windowController.contentViewController = accountsList
|
windowController.contentViewController = accountsList
|
||||||
}
|
}
|
||||||
|
|
||||||
func showApprove(transaction: Transaction, peerMeta: WCPeerMeta?, completion: @escaping (Transaction?) -> Void) {
|
func showApprove(transaction: Transaction, chain: EthereumChain, peerMeta: WCPeerMeta?, completion: @escaping (Transaction?) -> Void) {
|
||||||
let windowController = Window.showNew()
|
let windowController = Window.showNew()
|
||||||
let approveViewController = ApproveTransactionViewController.with(transaction: transaction, peerMeta: peerMeta) { [weak self] transaction in
|
let approveViewController = ApproveTransactionViewController.with(transaction: transaction, chain: chain, peerMeta: peerMeta) { [weak self] transaction in
|
||||||
if transaction != nil {
|
if transaction != nil {
|
||||||
self?.askAuthentication(on: windowController.window, onStart: false, reason: .sendTransaction) { success in
|
self?.askAuthentication(on: windowController.window, onStart: false, reason: .sendTransaction) { success in
|
||||||
completion(success ? transaction : nil)
|
completion(success ? transaction : nil)
|
||||||
@ -119,7 +119,7 @@ class Agent: NSObject {
|
|||||||
showInitialScreen(wcSession: session)
|
showInitialScreen(wcSession: session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getWalletSelectionCompletionIfShouldSelect() -> ((InkWallet) -> Void)? {
|
func getWalletSelectionCompletionIfShouldSelect() -> ((Int, InkWallet) -> Void)? {
|
||||||
let session = getSessionFromPasteboard()
|
let session = getSessionFromPasteboard()
|
||||||
return onSelectedWallet(session: session)
|
return onSelectedWallet(session: session)
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ class Agent: NSObject {
|
|||||||
let howToItem = NSMenuItem(title: "How to WalletConnect?", action: #selector(showInstructionsAlert), keyEquivalent: "")
|
let howToItem = NSMenuItem(title: "How to WalletConnect?", action: #selector(showInstructionsAlert), keyEquivalent: "")
|
||||||
let mailItem = NSMenuItem(title: "Drop us a line…", action: #selector(didSelectMailMenuItem), keyEquivalent: "")
|
let mailItem = NSMenuItem(title: "Drop us a line…", action: #selector(didSelectMailMenuItem), keyEquivalent: "")
|
||||||
let githubItem = NSMenuItem(title: "View on GitHub…", action: #selector(didSelectGitHubMenuItem), keyEquivalent: "")
|
let githubItem = NSMenuItem(title: "View on GitHub…", action: #selector(didSelectGitHubMenuItem), keyEquivalent: "")
|
||||||
let twitterItem = NSMenuItem(title: "Follow on Twitter…", action: #selector(didSelectTwitterMenuItem), keyEquivalent: "")
|
let twitterItem = NSMenuItem(title: "View on Twitter…", action: #selector(didSelectTwitterMenuItem), keyEquivalent: "")
|
||||||
let quitItem = NSMenuItem(title: "Quit", action: #selector(didSelectQuitMenuItem), keyEquivalent: "q")
|
let quitItem = NSMenuItem(title: "Quit", action: #selector(didSelectQuitMenuItem), keyEquivalent: "q")
|
||||||
showItem.attributedTitle = NSAttributedString(string: "👀 Show Encrypted Ink", attributes: [.font: NSFont.systemFont(ofSize: 15, weight: .semibold)])
|
showItem.attributedTitle = NSAttributedString(string: "👀 Show Encrypted Ink", attributes: [.font: NSFont.systemFont(ofSize: 15, weight: .semibold)])
|
||||||
|
|
||||||
@ -222,10 +222,10 @@ class Agent: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func onSelectedWallet(session: WCSession?) -> ((InkWallet) -> Void)? {
|
private func onSelectedWallet(session: WCSession?) -> ((Int, InkWallet) -> Void)? {
|
||||||
guard let session = session else { return nil }
|
guard let session = session else { return nil }
|
||||||
return { [weak self] wallet in
|
return { [weak self] chainId, wallet in
|
||||||
self?.connectWallet(session: session, wallet: wallet)
|
self?.connectWallet(session: session, chainId: chainId, wallet: wallet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,12 +284,12 @@ class Agent: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func connectWallet(session: WCSession, wallet: InkWallet) {
|
private func connectWallet(session: WCSession, chainId: Int, wallet: InkWallet) {
|
||||||
let windowController = Window.showNew()
|
let windowController = Window.showNew()
|
||||||
let window = windowController.window
|
let window = windowController.window
|
||||||
windowController.contentViewController = WaitingViewController.withReason("Connecting")
|
windowController.contentViewController = WaitingViewController.withReason("Connecting")
|
||||||
|
|
||||||
WalletConnect.shared.connect(session: session, walletId: wallet.id) { [weak window] _ in
|
WalletConnect.shared.connect(session: session, chainId: chainId, walletId: wallet.id) { [weak window] _ in
|
||||||
if window?.isVisible == true {
|
if window?.isVisible == true {
|
||||||
Window.closeAllAndActivateBrowser()
|
Window.closeAllAndActivateBrowser()
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
@ -818,13 +818,13 @@ DQ
|
|||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="40" horizontalPageScroll="0.0" verticalLineScroll="40" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="7bs-Kr-ija">
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="40" horizontalPageScroll="0.0" verticalLineScroll="40" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="7bs-Kr-ija">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="250" height="272"/>
|
<rect key="frame" x="0.0" y="0.0" width="250" height="247"/>
|
||||||
<clipView key="contentView" ambiguous="YES" id="RjU-hi-SHx">
|
<clipView key="contentView" ambiguous="YES" id="RjU-hi-SHx">
|
||||||
<rect key="frame" x="1" y="1" width="248" height="270"/>
|
<rect key="frame" x="1" y="1" width="248" height="245"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="40" rowSizeStyle="automatic" viewBased="YES" id="glA-FK-Kdd" customClass="RightClickTableView" customModule="Encrypted_Ink" customModuleProvider="target">
|
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="40" rowSizeStyle="automatic" viewBased="YES" id="glA-FK-Kdd" customClass="RightClickTableView" customModule="Encrypted_Ink" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="248" height="270"/>
|
<rect key="frame" x="0.0" y="0.0" width="248" height="245"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -928,21 +928,49 @@ DQ
|
|||||||
<action selector="addButtonTapped:" target="29s-Rd-OUf" id="MKz-Ok-RUY"/>
|
<action selector="addButtonTapped:" target="29s-Rd-OUf" id="MKz-Ok-RUY"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="YAr-gV-Zhp">
|
||||||
|
<rect key="frame" x="0.0" y="247" width="250" height="40"/>
|
||||||
|
<subviews>
|
||||||
|
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WBh-Qb-dhA">
|
||||||
|
<rect key="frame" x="47" y="6" width="157" height="25"/>
|
||||||
|
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="center" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="A9Y-mW-lqk">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" id="bIv-hX-xgQ"/>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="chainButtonSelectionChanged:" target="29s-Rd-OUf" id="saG-Ti-VJD"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="WBh-Qb-dhA" firstAttribute="leading" secondItem="YAr-gV-Zhp" secondAttribute="leading" constant="50" id="9XO-wX-7KM"/>
|
||||||
|
<constraint firstAttribute="height" constant="40" id="HaA-yk-eCj"/>
|
||||||
|
<constraint firstItem="WBh-Qb-dhA" firstAttribute="centerX" secondItem="YAr-gV-Zhp" secondAttribute="centerX" id="qJ6-QA-Eul"/>
|
||||||
|
<constraint firstItem="WBh-Qb-dhA" firstAttribute="centerY" secondItem="YAr-gV-Zhp" secondAttribute="centerY" id="yed-DU-Dih"/>
|
||||||
|
</constraints>
|
||||||
|
</customView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="ngQ-Bn-Kwd" firstAttribute="leading" secondItem="dkh-kG-EFj" secondAttribute="trailing" constant="10" id="2jH-ov-jln"/>
|
<constraint firstItem="ngQ-Bn-Kwd" firstAttribute="leading" secondItem="dkh-kG-EFj" secondAttribute="trailing" constant="10" id="2jH-ov-jln"/>
|
||||||
<constraint firstItem="7bs-Kr-ija" firstAttribute="leading" secondItem="Yjc-Zm-uZY" secondAttribute="leading" id="3n0-jB-KwV"/>
|
<constraint firstItem="7bs-Kr-ija" firstAttribute="leading" secondItem="Yjc-Zm-uZY" secondAttribute="leading" id="3n0-jB-KwV"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="7bs-Kr-ija" secondAttribute="trailing" id="6m3-S7-WJp"/>
|
<constraint firstAttribute="trailing" secondItem="7bs-Kr-ija" secondAttribute="trailing" id="6m3-S7-WJp"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="ngQ-Bn-Kwd" secondAttribute="trailing" constant="12" id="Ln4-b5-NfT"/>
|
<constraint firstAttribute="trailing" secondItem="ngQ-Bn-Kwd" secondAttribute="trailing" constant="12" id="Ln4-b5-NfT"/>
|
||||||
|
<constraint firstItem="7bs-Kr-ija" firstAttribute="top" secondItem="YAr-gV-Zhp" secondAttribute="bottom" id="N0R-Qm-X3z"/>
|
||||||
<constraint firstItem="ngQ-Bn-Kwd" firstAttribute="firstBaseline" secondItem="dkh-kG-EFj" secondAttribute="firstBaseline" id="RDE-f4-Heb"/>
|
<constraint firstItem="ngQ-Bn-Kwd" firstAttribute="firstBaseline" secondItem="dkh-kG-EFj" secondAttribute="firstBaseline" id="RDE-f4-Heb"/>
|
||||||
|
<constraint firstItem="YAr-gV-Zhp" firstAttribute="top" secondItem="dkh-kG-EFj" secondAttribute="bottom" constant="5" id="eSI-xz-s5L"/>
|
||||||
|
<constraint firstItem="YAr-gV-Zhp" firstAttribute="centerX" secondItem="Yjc-Zm-uZY" secondAttribute="centerX" id="ju9-P1-aBa"/>
|
||||||
|
<constraint firstItem="YAr-gV-Zhp" firstAttribute="width" secondItem="Yjc-Zm-uZY" secondAttribute="width" id="mzg-kX-V5F"/>
|
||||||
<constraint firstItem="dkh-kG-EFj" firstAttribute="top" secondItem="Yjc-Zm-uZY" secondAttribute="top" constant="24" id="oaa-yR-g0U"/>
|
<constraint firstItem="dkh-kG-EFj" firstAttribute="top" secondItem="Yjc-Zm-uZY" secondAttribute="top" constant="24" id="oaa-yR-g0U"/>
|
||||||
<constraint firstItem="dkh-kG-EFj" firstAttribute="centerX" secondItem="Yjc-Zm-uZY" secondAttribute="centerX" id="qoF-Dr-xWA"/>
|
<constraint firstItem="dkh-kG-EFj" firstAttribute="centerX" secondItem="Yjc-Zm-uZY" secondAttribute="centerX" id="qoF-Dr-xWA"/>
|
||||||
<constraint firstItem="7bs-Kr-ija" firstAttribute="top" secondItem="dkh-kG-EFj" secondAttribute="bottom" constant="20" id="w9v-GA-ZtN"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="7bs-Kr-ija" secondAttribute="bottom" id="zCE-cx-u4r"/>
|
<constraint firstAttribute="bottom" secondItem="7bs-Kr-ija" secondAttribute="bottom" id="zCE-cx-u4r"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="addButton" destination="ngQ-Bn-Kwd" id="FlT-oq-C5e"/>
|
<outlet property="addButton" destination="ngQ-Bn-Kwd" id="FlT-oq-C5e"/>
|
||||||
|
<outlet property="chainButton" destination="WBh-Qb-dhA" id="Fyv-PN-1Ln"/>
|
||||||
|
<outlet property="chainButtonContainer" destination="YAr-gV-Zhp" id="0qy-nB-KfB"/>
|
||||||
|
<outlet property="chainButtonHeightConstraint" destination="HaA-yk-eCj" id="2KM-mU-OO6"/>
|
||||||
<outlet property="tableView" destination="glA-FK-Kdd" id="9aW-Qr-UuF"/>
|
<outlet property="tableView" destination="glA-FK-Kdd" id="9aW-Qr-UuF"/>
|
||||||
<outlet property="titleLabel" destination="dkh-kG-EFj" id="xDn-bP-HWG"/>
|
<outlet property="titleLabel" destination="dkh-kG-EFj" id="xDn-bP-HWG"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -1599,11 +1627,13 @@ DQ
|
|||||||
<connections>
|
<connections>
|
||||||
<outlet property="fastSpeedLabel" destination="WJV-V3-GWm" id="lzX-wu-MdJ"/>
|
<outlet property="fastSpeedLabel" destination="WJV-V3-GWm" id="lzX-wu-MdJ"/>
|
||||||
<outlet property="gweiLabel" destination="xby-TM-Wec" id="3LN-nr-WNA"/>
|
<outlet property="gweiLabel" destination="xby-TM-Wec" id="3LN-nr-WNA"/>
|
||||||
|
<outlet property="infoTextViewBottomConstraint" destination="fxj-xB-6jl" id="f2p-uL-Wac"/>
|
||||||
<outlet property="metaTextView" destination="EuZ-5b-EGk" id="UyV-K8-7Og"/>
|
<outlet property="metaTextView" destination="EuZ-5b-EGk" id="UyV-K8-7Og"/>
|
||||||
<outlet property="okButton" destination="JBO-6Q-5eC" id="JHm-Kl-fys"/>
|
<outlet property="okButton" destination="JBO-6Q-5eC" id="JHm-Kl-fys"/>
|
||||||
<outlet property="peerLogoImageView" destination="g8t-xf-H1l" id="CqE-7d-LAU"/>
|
<outlet property="peerLogoImageView" destination="g8t-xf-H1l" id="CqE-7d-LAU"/>
|
||||||
<outlet property="peerNameLabel" destination="Ji7-6C-gUp" id="J9c-ml-tXd"/>
|
<outlet property="peerNameLabel" destination="Ji7-6C-gUp" id="J9c-ml-tXd"/>
|
||||||
<outlet property="slowSpeedLabel" destination="Jcz-Um-efA" id="TBN-lQ-Njc"/>
|
<outlet property="slowSpeedLabel" destination="Jcz-Um-efA" id="TBN-lQ-Njc"/>
|
||||||
|
<outlet property="speedContainerStackView" destination="pLD-2z-PFP" id="PV3-l7-3pR"/>
|
||||||
<outlet property="speedSlider" destination="oWb-y6-1VO" id="cLg-Yg-DPd"/>
|
<outlet property="speedSlider" destination="oWb-y6-1VO" id="cLg-Yg-DPd"/>
|
||||||
<outlet property="titleLabel" destination="g2G-lh-X1F" id="NWt-Lq-go1"/>
|
<outlet property="titleLabel" destination="g2G-lh-X1F" id="NWt-Lq-go1"/>
|
||||||
</connections>
|
</connections>
|
||||||
|
@ -19,10 +19,7 @@ struct Ethereum {
|
|||||||
|
|
||||||
static let shared = Ethereum()
|
static let shared = Ethereum()
|
||||||
|
|
||||||
private let network: Network = AlchemyNetwork(
|
private let networks = EthereumNetwork.allByChain
|
||||||
chain: "mainnet",
|
|
||||||
apiKey: Secrets.alchemy
|
|
||||||
)
|
|
||||||
|
|
||||||
func sign(message: String, wallet: InkWallet) throws -> String {
|
func sign(message: String, wallet: InkWallet) throws -> String {
|
||||||
guard let privateKeyString = wallet.ethereumPrivateKeyString else { throw Error.keyNotFound }
|
guard let privateKeyString = wallet.ethereumPrivateKeyString else { throw Error.keyNotFound }
|
||||||
@ -58,8 +55,9 @@ struct Ethereum {
|
|||||||
return signed
|
return signed
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(transaction: Transaction, wallet: InkWallet) throws -> String {
|
func send(transaction: Transaction, wallet: InkWallet, chain: EthereumChain) throws -> String {
|
||||||
let bytes = try signedTransactionBytes(transaction: transaction, wallet: wallet)
|
guard let network = networks[chain] else { throw Error.invalidInputData }
|
||||||
|
let bytes = try signedTransactionBytes(transaction: transaction, wallet: wallet, chain: chain)
|
||||||
let response = try SendRawTransactionProcedure(network: network, transactionBytes: bytes).call()
|
let response = try SendRawTransactionProcedure(network: network, transactionBytes: bytes).call()
|
||||||
guard let hash = response["result"].string else {
|
guard let hash = response["result"].string else {
|
||||||
throw Error.failedToSendTransaction
|
throw Error.failedToSendTransaction
|
||||||
@ -67,7 +65,8 @@ struct Ethereum {
|
|||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
private func signedTransactionBytes(transaction: Transaction, wallet: InkWallet) throws -> EthContractCallBytes {
|
private func signedTransactionBytes(transaction: Transaction, wallet: InkWallet, chain: EthereumChain) throws -> EthContractCallBytes {
|
||||||
|
guard let network = networks[chain] else { throw Error.invalidInputData }
|
||||||
guard let privateKeyString = wallet.ethereumPrivateKeyString else { throw Error.keyNotFound }
|
guard let privateKeyString = wallet.ethereumPrivateKeyString else { throw Error.keyNotFound }
|
||||||
let senderKey = EthPrivateKey(hex: privateKeyString)
|
let senderKey = EthPrivateKey(hex: privateKeyString)
|
||||||
let contractAddress = EthAddress(hex: transaction.to)
|
let contractAddress = EthAddress(hex: transaction.to)
|
||||||
@ -106,11 +105,11 @@ struct Ethereum {
|
|||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareTransaction(_ transaction: Transaction, completion: @escaping (Transaction) -> Void) {
|
func prepareTransaction(_ transaction: Transaction, chain: EthereumChain, completion: @escaping (Transaction) -> Void) {
|
||||||
var transaction = transaction
|
var transaction = transaction
|
||||||
|
|
||||||
if transaction.nonce == nil {
|
if transaction.nonce == nil {
|
||||||
getNonce(from: transaction.from) { nonce in
|
getNonce(chain: chain, from: transaction.from) { nonce in
|
||||||
transaction.nonce = nonce
|
transaction.nonce = nonce
|
||||||
completion(transaction)
|
completion(transaction)
|
||||||
}
|
}
|
||||||
@ -118,7 +117,7 @@ struct Ethereum {
|
|||||||
|
|
||||||
func getGasIfNeeded(gasPrice: String) {
|
func getGasIfNeeded(gasPrice: String) {
|
||||||
guard transaction.gas == nil else { return }
|
guard transaction.gas == nil else { return }
|
||||||
getGas(from: transaction.from, to: transaction.to, gasPrice: gasPrice, weiAmount: transaction.weiAmount, data: transaction.data) { gas in
|
getGas(chain: chain, from: transaction.from, to: transaction.to, gasPrice: gasPrice, weiAmount: transaction.weiAmount, data: transaction.data) { gas in
|
||||||
transaction.gas = gas
|
transaction.gas = gas
|
||||||
completion(transaction)
|
completion(transaction)
|
||||||
}
|
}
|
||||||
@ -127,7 +126,7 @@ struct Ethereum {
|
|||||||
if let gasPrice = transaction.gasPrice {
|
if let gasPrice = transaction.gasPrice {
|
||||||
getGasIfNeeded(gasPrice: gasPrice)
|
getGasIfNeeded(gasPrice: gasPrice)
|
||||||
} else {
|
} else {
|
||||||
getGasPrice { gasPrice in
|
getGasPrice(chain: chain) { gasPrice in
|
||||||
transaction.gasPrice = gasPrice
|
transaction.gasPrice = gasPrice
|
||||||
completion(transaction)
|
completion(transaction)
|
||||||
if let gasPrice = gasPrice {
|
if let gasPrice = gasPrice {
|
||||||
@ -138,7 +137,8 @@ struct Ethereum {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getGas(from: String, to: String, gasPrice: String, weiAmount: EthNumber, data: String, completion: @escaping (String?) -> Void) {
|
private func getGas(chain: EthereumChain, from: String, to: String, gasPrice: String, weiAmount: EthNumber, data: String, completion: @escaping (String?) -> Void) {
|
||||||
|
guard let network = networks[chain] else { return }
|
||||||
queue.async {
|
queue.async {
|
||||||
let gas = try? EthGasEstimate(
|
let gas = try? EthGasEstimate(
|
||||||
network: network,
|
network: network,
|
||||||
@ -162,7 +162,8 @@ struct Ethereum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getGasPrice(completion: @escaping (String?) -> Void) {
|
private func getGasPrice(chain: EthereumChain, completion: @escaping (String?) -> Void) {
|
||||||
|
guard let network = networks[chain] else { return }
|
||||||
queue.async {
|
queue.async {
|
||||||
let gasPrice = try? EthGasPrice(network: network).value().toHexString()
|
let gasPrice = try? EthGasPrice(network: network).value().toHexString()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@ -171,7 +172,8 @@ struct Ethereum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getNonce(from: String, completion: @escaping (String?) -> Void) {
|
private func getNonce(chain: EthereumChain, from: String, completion: @escaping (String?) -> Void) {
|
||||||
|
guard let network = networks[chain] else { return }
|
||||||
queue.async {
|
queue.async {
|
||||||
let nonce = try? EthTransactions(network: network, address: EthAddress(hex: from), blockChainState: PendingBlockChainState()).count().value().toHexString()
|
let nonce = try? EthTransactions(network: network, address: EthAddress(hex: from), blockChainState: PendingBlockChainState()).count().value().toHexString()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
33
Encrypted Ink/Ethereum/EthereumChain.swift
Normal file
33
Encrypted Ink/Ethereum/EthereumChain.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright © 2021 Encrypted Ink. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum EthereumChain: Int {
|
||||||
|
case main = 1
|
||||||
|
case arbitrum = 42161
|
||||||
|
case polygon = 137
|
||||||
|
case optimism = 10
|
||||||
|
case binance = 56
|
||||||
|
|
||||||
|
var id: Int {
|
||||||
|
return rawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
static let all: [EthereumChain] = [.main, .polygon, .optimism, .binance]
|
||||||
|
|
||||||
|
var name: String {
|
||||||
|
switch self {
|
||||||
|
case .main:
|
||||||
|
return "Ethereum Mainnet"
|
||||||
|
case .arbitrum:
|
||||||
|
return "Arbitrum"
|
||||||
|
case .optimism:
|
||||||
|
return "Optimism"
|
||||||
|
case .polygon:
|
||||||
|
return "Polygon"
|
||||||
|
case .binance:
|
||||||
|
return "Binance Smart Chain"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
Encrypted Ink/Ethereum/EthereumNetwork.swift
Normal file
30
Encrypted Ink/Ethereum/EthereumNetwork.swift
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright © 2021 Encrypted Ink. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Web3Swift
|
||||||
|
|
||||||
|
final class EthereumNetwork: Network {
|
||||||
|
|
||||||
|
static let allByChain: [EthereumChain: Network] = [
|
||||||
|
.main: EthereumNetwork(url: "https://eth-mainnet.alchemyapi.io/v2/" + Secrets.alchemy),
|
||||||
|
.polygon: EthereumNetwork(url: "https://polygon-mainnet.g.alchemy.com/v2/" + Secrets.alchemy),
|
||||||
|
.arbitrum: EthereumNetwork(url: "https://arb-mainnet.g.alchemy.com/v2/" + Secrets.alchemy),
|
||||||
|
.optimism: EthereumNetwork(url: "https://mainnet.optimism.io"),
|
||||||
|
.binance: EthereumNetwork(url: "https://bsc-dataseed.binance.org/")
|
||||||
|
]
|
||||||
|
|
||||||
|
private let origin: GethNetwork
|
||||||
|
|
||||||
|
init(url: String) {
|
||||||
|
origin = GethNetwork(url: url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func id() throws -> IntegerScalar {
|
||||||
|
return try origin.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(method: String, params: [EthParameter]) throws -> Data {
|
||||||
|
return try origin.call(method: method, params: params)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -31,24 +31,39 @@ struct Transaction {
|
|||||||
return Int(current)
|
return Int(current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func description(ethPrice: Double?) -> String {
|
func description(chain: EthereumChain, ethPrice: Double?) -> String {
|
||||||
|
let symbol: String
|
||||||
|
let showUSDPrice: Bool
|
||||||
|
|
||||||
|
switch chain {
|
||||||
|
case .main, .arbitrum, .optimism:
|
||||||
|
symbol = "ETH"
|
||||||
|
showUSDPrice = true
|
||||||
|
case .polygon:
|
||||||
|
symbol = "MATIC"
|
||||||
|
showUSDPrice = false
|
||||||
|
case .binance:
|
||||||
|
symbol = "BNB"
|
||||||
|
showUSDPrice = false
|
||||||
|
}
|
||||||
|
|
||||||
let fee: String
|
let fee: String
|
||||||
if let gasPrice = gasPrice,
|
if let gasPrice = gasPrice,
|
||||||
let gas = gas,
|
let gas = gas,
|
||||||
let a = try? EthNumber(hex: gasPrice).value().toNormalizedDecimal(power: 18),
|
let a = try? EthNumber(hex: gasPrice).value().toNormalizedDecimal(power: 18),
|
||||||
let b = try? EthNumber(hex: gas).value().toDecimal() {
|
let b = try? EthNumber(hex: gas).value().toDecimal() {
|
||||||
let c = NSDecimalNumber(decimal: a).multiplying(by: NSDecimalNumber(decimal: b))
|
let c = NSDecimalNumber(decimal: a).multiplying(by: NSDecimalNumber(decimal: b))
|
||||||
let costString = cost(value: c, price: ethPrice)
|
let costString = showUSDPrice ? cost(value: c, price: ethPrice) : ""
|
||||||
fee = c.stringValue.prefix(7) + " ETH" + costString
|
fee = c.stringValue.prefix(7) + " \(symbol)" + costString
|
||||||
} else {
|
} else {
|
||||||
fee = "Calculating…"
|
fee = "Calculating…"
|
||||||
}
|
}
|
||||||
var result = [String]()
|
var result = [String]()
|
||||||
if let decimal = try? weiAmount.value().toNormalizedDecimal(power: 18) {
|
if let decimal = try? weiAmount.value().toNormalizedDecimal(power: 18) {
|
||||||
let decimalNumber = NSDecimalNumber(decimal: decimal)
|
let decimalNumber = NSDecimalNumber(decimal: decimal)
|
||||||
let costString = cost(value: decimalNumber, price: ethPrice)
|
let costString = showUSDPrice ? cost(value: decimalNumber, price: ethPrice) : ""
|
||||||
if let value = ethString(decimalNumber: decimalNumber) {
|
if let value = ethString(decimalNumber: decimalNumber) {
|
||||||
result.append("\(value) ETH" + costString)
|
result.append("\(value) \(symbol)" + costString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.append("Fee: " + fee)
|
result.append("Fee: " + fee)
|
||||||
|
@ -8,7 +8,8 @@ class AccountsListViewController: NSViewController {
|
|||||||
private let walletsManager = WalletsManager.shared
|
private let walletsManager = WalletsManager.shared
|
||||||
private var cellModels = [CellModel]()
|
private var cellModels = [CellModel]()
|
||||||
|
|
||||||
var onSelectedWallet: ((InkWallet) -> Void)?
|
private var chain = EthereumChain.main
|
||||||
|
var onSelectedWallet: ((Int, InkWallet) -> Void)?
|
||||||
var newWalletId: String?
|
var newWalletId: String?
|
||||||
|
|
||||||
enum CellModel {
|
enum CellModel {
|
||||||
@ -29,6 +30,9 @@ class AccountsListViewController: NSViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBOutlet weak var chainButtonHeightConstraint: NSLayoutConstraint!
|
||||||
|
@IBOutlet weak var chainButtonContainer: NSView!
|
||||||
|
@IBOutlet weak var chainButton: NSPopUpButton!
|
||||||
@IBOutlet weak var addButton: NSButton! {
|
@IBOutlet weak var addButton: NSButton! {
|
||||||
didSet {
|
didSet {
|
||||||
let menu = NSMenu()
|
let menu = NSMenu()
|
||||||
@ -53,7 +57,7 @@ class AccountsListViewController: NSViewController {
|
|||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
setupAccountsMenu()
|
setupAccountsMenu()
|
||||||
reloadTitle()
|
reloadHeader()
|
||||||
updateCellModels()
|
updateCellModels()
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: NSApplication.didBecomeActiveNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: NSApplication.didBecomeActiveNotification, object: nil)
|
||||||
}
|
}
|
||||||
@ -76,9 +80,15 @@ class AccountsListViewController: NSViewController {
|
|||||||
tableView.menu = menu
|
tableView.menu = menu
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reloadTitle() {
|
private func reloadHeader() {
|
||||||
titleLabel.stringValue = onSelectedWallet != nil && !wallets.isEmpty ? "Select\nAccount" : "Accounts"
|
let canSelectAccount = onSelectedWallet != nil && !wallets.isEmpty
|
||||||
|
titleLabel.stringValue = canSelectAccount ? "Select\nAccount" : "Accounts"
|
||||||
addButton.isHidden = wallets.isEmpty
|
addButton.isHidden = wallets.isEmpty
|
||||||
|
chainButtonHeightConstraint.constant = canSelectAccount ? 40 : 15
|
||||||
|
chainButtonContainer.isHidden = !canSelectAccount
|
||||||
|
if canSelectAccount, chainButton.numberOfItems == 0 {
|
||||||
|
chainButton.addItems(withTitles: EthereumChain.all.map { $0.name })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func didBecomeActive() {
|
@objc private func didBecomeActive() {
|
||||||
@ -86,7 +96,14 @@ class AccountsListViewController: NSViewController {
|
|||||||
if let completion = agent.getWalletSelectionCompletionIfShouldSelect() {
|
if let completion = agent.getWalletSelectionCompletionIfShouldSelect() {
|
||||||
onSelectedWallet = completion
|
onSelectedWallet = completion
|
||||||
}
|
}
|
||||||
reloadTitle()
|
reloadHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func chainButtonSelectionChanged(_ sender: Any) {
|
||||||
|
guard let selectedItem = chainButton.selectedItem else { return }
|
||||||
|
let index = chainButton.index(of: selectedItem)
|
||||||
|
guard index >= 0 && index < EthereumChain.all.count else { return }
|
||||||
|
chain = EthereumChain.all[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func addButtonTapped(_ sender: NSButton) {
|
@IBAction func addButtonTapped(_ sender: NSButton) {
|
||||||
@ -107,13 +124,25 @@ class AccountsListViewController: NSViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func didClickCreateAccount() {
|
@objc private func didClickCreateAccount() {
|
||||||
let wallet = try? walletsManager.createWallet()
|
let alert = Alert()
|
||||||
newWalletId = wallet?.id
|
alert.messageText = "Back up new account."
|
||||||
reloadTitle()
|
alert.informativeText = "You will see 12 secret words."
|
||||||
|
alert.alertStyle = .critical
|
||||||
|
alert.addButton(withTitle: "OK")
|
||||||
|
alert.addButton(withTitle: "Cancel")
|
||||||
|
if alert.runModal() == .alertFirstButtonReturn {
|
||||||
|
createNewAccountAndShowSecretWords()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func createNewAccountAndShowSecretWords() {
|
||||||
|
guard let wallet = try? walletsManager.createWallet() else { return }
|
||||||
|
newWalletId = wallet.id
|
||||||
|
reloadHeader()
|
||||||
updateCellModels()
|
updateCellModels()
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
blinkNewWalletCellIfNeeded()
|
blinkNewWalletCellIfNeeded()
|
||||||
// TODO: show backup phrase
|
showKey(wallet: wallet, mnemonic: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func blinkNewWalletCellIfNeeded() {
|
private func blinkNewWalletCellIfNeeded() {
|
||||||
@ -184,8 +213,10 @@ class AccountsListViewController: NSViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func showKey(index: Int, mnemonic: Bool) {
|
private func showKey(index: Int, mnemonic: Bool) {
|
||||||
let wallet = wallets[index]
|
showKey(wallet: wallets[index], mnemonic: mnemonic)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showKey(wallet: InkWallet, mnemonic: Bool) {
|
||||||
let secret: String
|
let secret: String
|
||||||
if mnemonic, let mnemonicString = try? walletsManager.exportMnemonic(wallet: wallet) {
|
if mnemonic, let mnemonicString = try? walletsManager.exportMnemonic(wallet: wallet) {
|
||||||
secret = mnemonicString
|
secret = mnemonicString
|
||||||
@ -213,7 +244,7 @@ class AccountsListViewController: NSViewController {
|
|||||||
private func removeAccountAtIndex(_ index: Int) {
|
private func removeAccountAtIndex(_ index: Int) {
|
||||||
let wallet = wallets[index]
|
let wallet = wallets[index]
|
||||||
try? walletsManager.delete(wallet: wallet)
|
try? walletsManager.delete(wallet: wallet)
|
||||||
reloadTitle()
|
reloadHeader()
|
||||||
updateCellModels()
|
updateCellModels()
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
}
|
}
|
||||||
@ -240,7 +271,7 @@ extension AccountsListViewController: NSTableViewDelegate {
|
|||||||
case .wallet:
|
case .wallet:
|
||||||
let wallet = wallets[row]
|
let wallet = wallets[row]
|
||||||
if let onSelectedWallet = onSelectedWallet {
|
if let onSelectedWallet = onSelectedWallet {
|
||||||
onSelectedWallet(wallet)
|
onSelectedWallet(chain.id, wallet)
|
||||||
} else {
|
} else {
|
||||||
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { [weak self] _ in
|
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { [weak self] _ in
|
||||||
var point = NSEvent.mouseLocation
|
var point = NSEvent.mouseLocation
|
||||||
|
@ -6,7 +6,10 @@ import Kingfisher
|
|||||||
|
|
||||||
class ApproveTransactionViewController: NSViewController {
|
class ApproveTransactionViewController: NSViewController {
|
||||||
|
|
||||||
|
@IBOutlet weak var infoTextViewBottomConstraint: NSLayoutConstraint!
|
||||||
|
@IBOutlet weak var speedContainerStackView: NSStackView!
|
||||||
@IBOutlet weak var gweiLabel: NSTextField!
|
@IBOutlet weak var gweiLabel: NSTextField!
|
||||||
|
|
||||||
@IBOutlet weak var titleLabel: NSTextField!
|
@IBOutlet weak var titleLabel: NSTextField!
|
||||||
@IBOutlet var metaTextView: NSTextView!
|
@IBOutlet var metaTextView: NSTextView!
|
||||||
@IBOutlet weak var okButton: NSButton!
|
@IBOutlet weak var okButton: NSButton!
|
||||||
@ -26,12 +29,14 @@ class ApproveTransactionViewController: NSViewController {
|
|||||||
private let priceService = PriceService.shared
|
private let priceService = PriceService.shared
|
||||||
private var currentGasInfo: GasService.Info?
|
private var currentGasInfo: GasService.Info?
|
||||||
private var transaction: Transaction!
|
private var transaction: Transaction!
|
||||||
|
private var chain: EthereumChain!
|
||||||
private var completion: ((Transaction?) -> Void)!
|
private var completion: ((Transaction?) -> Void)!
|
||||||
private var didEnableSpeedConfiguration = false
|
private var didEnableSpeedConfiguration = false
|
||||||
private var peerMeta: WCPeerMeta?
|
private var peerMeta: WCPeerMeta?
|
||||||
|
|
||||||
static func with(transaction: Transaction, peerMeta: WCPeerMeta?, completion: @escaping (Transaction?) -> Void) -> ApproveTransactionViewController {
|
static func with(transaction: Transaction, chain: EthereumChain, peerMeta: WCPeerMeta?, completion: @escaping (Transaction?) -> Void) -> ApproveTransactionViewController {
|
||||||
let new = instantiate(ApproveTransactionViewController.self)
|
let new = instantiate(ApproveTransactionViewController.self)
|
||||||
|
new.chain = chain
|
||||||
new.transaction = transaction
|
new.transaction = transaction
|
||||||
new.completion = completion
|
new.completion = completion
|
||||||
new.peerMeta = peerMeta
|
new.peerMeta = peerMeta
|
||||||
@ -58,15 +63,21 @@ class ApproveTransactionViewController: NSViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func prepareTransaction() {
|
private func prepareTransaction() {
|
||||||
ethereum.prepareTransaction(transaction) { [weak self] updated in
|
ethereum.prepareTransaction(transaction, chain: chain) { [weak self] updated in
|
||||||
self?.transaction = updated
|
self?.transaction = updated
|
||||||
self?.updateInterface()
|
self?.updateInterface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateInterface() {
|
private func updateInterface() {
|
||||||
|
if chain != .main {
|
||||||
|
speedContainerStackView.isHidden = true
|
||||||
|
gweiLabel.isHidden = true
|
||||||
|
infoTextViewBottomConstraint.constant = 30
|
||||||
|
}
|
||||||
|
|
||||||
enableSpeedConfigurationIfNeeded()
|
enableSpeedConfigurationIfNeeded()
|
||||||
let meta = transaction.description(ethPrice: priceService.currentPrice)
|
let meta = transaction.description(chain: chain, ethPrice: priceService.currentPrice)
|
||||||
if metaTextView.string != meta {
|
if metaTextView.string != meta {
|
||||||
metaTextView.string = meta
|
metaTextView.string = meta
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import Cocoa
|
|||||||
class ImportViewController: NSViewController {
|
class ImportViewController: NSViewController {
|
||||||
|
|
||||||
private let walletsManager = WalletsManager.shared
|
private let walletsManager = WalletsManager.shared
|
||||||
var onSelectedWallet: ((InkWallet) -> Void)?
|
var onSelectedWallet: ((Int, InkWallet) -> Void)?
|
||||||
private var inputValidationResult = WalletsManager.InputValidationResult.invalid
|
private var inputValidationResult = WalletsManager.InputValidationResult.invalid
|
||||||
|
|
||||||
@IBOutlet weak var textField: NSTextField! {
|
@IBOutlet weak var textField: NSTextField! {
|
||||||
|
@ -7,6 +7,7 @@ class SessionStorage {
|
|||||||
|
|
||||||
struct Item: Codable {
|
struct Item: Codable {
|
||||||
let session: WCSession
|
let session: WCSession
|
||||||
|
let chainId: Int?
|
||||||
let walletId: String
|
let walletId: String
|
||||||
let clientId: String
|
let clientId: String
|
||||||
let sessionDetails: WCSessionRequestParam
|
let sessionDetails: WCSessionRequestParam
|
||||||
@ -51,8 +52,8 @@ class SessionStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(interactor: WCInteractor, walletId: String, sessionDetails: WCSessionRequestParam) {
|
func add(interactor: WCInteractor, chainId: Int, walletId: String, sessionDetails: WCSessionRequestParam) {
|
||||||
let item = Item(session: interactor.session, walletId: walletId, clientId: interactor.clientId, sessionDetails: sessionDetails)
|
let item = Item(session: interactor.session, chainId: chainId, walletId: walletId, clientId: interactor.clientId, sessionDetails: sessionDetails)
|
||||||
WCSessionStore.store(interactor.session, peerId: sessionDetails.peerId, peerMeta: sessionDetails.peerMeta)
|
WCSessionStore.store(interactor.session, peerId: sessionDetails.peerId, peerMeta: sessionDetails.peerMeta)
|
||||||
Defaults.storedSessions[interactor.clientId] = item
|
Defaults.storedSessions[interactor.clientId] = item
|
||||||
didInteractWith(clientId: interactor.clientId)
|
didInteractWith(clientId: interactor.clientId)
|
||||||
|
@ -24,10 +24,10 @@ class WalletConnect {
|
|||||||
return WCSession.from(string: link)
|
return WCSession.from(string: link)
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect(session: WCSession, walletId: String, uuid: UUID = UUID(), completion: @escaping ((Bool) -> Void)) {
|
func connect(session: WCSession, chainId: Int, walletId: String, uuid: UUID = UUID(), completion: @escaping ((Bool) -> Void)) {
|
||||||
let clientMeta = WCPeerMeta(name: "Encrypted Ink", url: "https://encrypted.ink", description: "Ethereum agent for macOS", icons: ["https://encrypted.ink/icon.png"])
|
let clientMeta = WCPeerMeta(name: "Encrypted Ink", url: "https://encrypted.ink", description: "Ethereum agent for macOS", icons: ["https://encrypted.ink/icon.png"])
|
||||||
let interactor = WCInteractor(session: session, meta: clientMeta, uuid: uuid)
|
let interactor = WCInteractor(session: session, meta: clientMeta, uuid: uuid)
|
||||||
configure(interactor: interactor, walletId: walletId)
|
configure(interactor: interactor, chainId: chainId, walletId: walletId)
|
||||||
|
|
||||||
interactor.connect().done { connected in
|
interactor.connect().done { connected in
|
||||||
completion(connected)
|
completion(connected)
|
||||||
@ -45,7 +45,7 @@ class WalletConnect {
|
|||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
guard let uuid = UUID(uuidString: item.clientId) else { continue }
|
guard let uuid = UUID(uuidString: item.clientId) else { continue }
|
||||||
connect(session: item.session, walletId: item.walletId, uuid: uuid) { _ in }
|
connect(session: item.session, chainId: item.chainId ?? 1, walletId: item.walletId, uuid: uuid) { _ in }
|
||||||
peers[item.clientId] = item.sessionDetails.peerMeta
|
peers[item.clientId] = item.sessionDetails.peerMeta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,17 +83,16 @@ class WalletConnect {
|
|||||||
return peers[id]
|
return peers[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func configure(interactor: WCInteractor, walletId: String) {
|
private func configure(interactor: WCInteractor, chainId: Int, walletId: String) {
|
||||||
guard let address = walletsManager.getWallet(id: walletId)?.ethereumAddress else { return }
|
guard let address = walletsManager.getWallet(id: walletId)?.ethereumAddress else { return }
|
||||||
let accounts = [address]
|
let accounts = [address]
|
||||||
let chainId = 1
|
|
||||||
|
|
||||||
interactor.onError = { _ in }
|
interactor.onError = { _ in }
|
||||||
|
|
||||||
interactor.onSessionRequest = { [weak self, weak interactor] (id, peerParam) in
|
interactor.onSessionRequest = { [weak self, weak interactor] (id, peerParam) in
|
||||||
guard let interactor = interactor else { return }
|
guard let interactor = interactor else { return }
|
||||||
self?.peers[interactor.clientId] = peerParam.peerMeta
|
self?.peers[interactor.clientId] = peerParam.peerMeta
|
||||||
self?.sessionStorage.add(interactor: interactor, walletId: walletId, sessionDetails: peerParam)
|
self?.sessionStorage.add(interactor: interactor, chainId: chainId, walletId: walletId, sessionDetails: peerParam)
|
||||||
interactor.approveSession(accounts: accounts, chainId: chainId).cauterize()
|
interactor.approveSession(accounts: accounts, chainId: chainId).cauterize()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ class WalletConnect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interactor.eth.onTransaction = { [weak self, weak interactor] (id, event, transaction) in
|
interactor.eth.onTransaction = { [weak self, weak interactor] (id, event, transaction) in
|
||||||
self?.approveTransaction(id: id, wct: transaction, walletId: walletId, interactor: interactor)
|
self?.approveTransaction(id: id, wct: transaction, walletId: walletId, chainId: chainId, interactor: interactor)
|
||||||
self?.sessionStorage.didInteractWith(clientId: interactor?.clientId)
|
self?.sessionStorage.didInteractWith(clientId: interactor?.clientId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,17 +124,17 @@ class WalletConnect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func approveTransaction(id: Int64, wct: WCEthereumTransaction, walletId: String, interactor: WCInteractor?) {
|
private func approveTransaction(id: Int64, wct: WCEthereumTransaction, walletId: String, chainId: Int, interactor: WCInteractor?) {
|
||||||
guard let to = wct.to else {
|
guard let to = wct.to, let chain = EthereumChain(rawValue: chainId) else {
|
||||||
rejectRequest(id: id, interactor: interactor, message: "Something went wrong.")
|
rejectRequest(id: id, interactor: interactor, message: "Something went wrong.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let peer = getPeerOfInteractor(interactor)
|
let peer = getPeerOfInteractor(interactor)
|
||||||
let transaction = Transaction(from: wct.from, to: to, nonce: wct.nonce, gasPrice: wct.gasPrice, gas: wct.gas, value: wct.value, data: wct.data)
|
let transaction = Transaction(from: wct.from, to: to, nonce: wct.nonce, gasPrice: wct.gasPrice, gas: wct.gas, value: wct.value, data: wct.data)
|
||||||
Agent.shared.showApprove(transaction: transaction, peerMeta: peer) { [weak self, weak interactor] transaction in
|
Agent.shared.showApprove(transaction: transaction, chain: chain, peerMeta: peer) { [weak self, weak interactor] transaction in
|
||||||
if let transaction = transaction {
|
if let transaction = transaction {
|
||||||
self?.sendTransaction(transaction, walletId: walletId, requestId: id, interactor: interactor)
|
self?.sendTransaction(transaction, walletId: walletId, chainId: chainId, requestId: id, interactor: interactor)
|
||||||
} else {
|
} else {
|
||||||
self?.rejectRequest(id: id, interactor: interactor, message: "Cancelled")
|
self?.rejectRequest(id: id, interactor: interactor, message: "Cancelled")
|
||||||
}
|
}
|
||||||
@ -174,12 +173,12 @@ class WalletConnect {
|
|||||||
interactor?.rejectRequest(id: id, message: message).cauterize()
|
interactor?.rejectRequest(id: id, message: message).cauterize()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sendTransaction(_ transaction: Transaction, walletId: String, requestId: Int64, interactor: WCInteractor?) {
|
private func sendTransaction(_ transaction: Transaction, walletId: String, chainId: Int, requestId: Int64, interactor: WCInteractor?) {
|
||||||
guard let wallet = walletsManager.getWallet(id: walletId) else {
|
guard let wallet = walletsManager.getWallet(id: walletId), let chain = EthereumChain(rawValue: chainId) else {
|
||||||
rejectRequest(id: requestId, interactor: interactor, message: "Something went wrong.")
|
rejectRequest(id: requestId, interactor: interactor, message: "Something went wrong.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let hash = try? ethereum.send(transaction: transaction, wallet: wallet) else {
|
guard let hash = try? ethereum.send(transaction: transaction, wallet: wallet, chain: chain) else {
|
||||||
rejectRequest(id: requestId, interactor: interactor, message: "Failed to send")
|
rejectRequest(id: requestId, interactor: interactor, message: "Failed to send")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
14
Podfile.lock
14
Podfile.lock
@ -2,7 +2,7 @@ PODS:
|
|||||||
- BigInt (5.2.0)
|
- BigInt (5.2.0)
|
||||||
- BlockiesSwift (0.1.2)
|
- BlockiesSwift (0.1.2)
|
||||||
- CryptoSwift (1.4.1)
|
- CryptoSwift (1.4.1)
|
||||||
- Kingfisher (6.3.0)
|
- Kingfisher (6.3.1)
|
||||||
- PromiseKit (6.15.3):
|
- PromiseKit (6.15.3):
|
||||||
- PromiseKit/CorePromise (= 6.15.3)
|
- PromiseKit/CorePromise (= 6.15.3)
|
||||||
- PromiseKit/Foundation (= 6.15.3)
|
- PromiseKit/Foundation (= 6.15.3)
|
||||||
@ -14,11 +14,11 @@ PODS:
|
|||||||
- Starscream (3.1.1)
|
- Starscream (3.1.1)
|
||||||
- SwiftProtobuf (1.17.0)
|
- SwiftProtobuf (1.17.0)
|
||||||
- SwiftyJSON (4.3.0)
|
- SwiftyJSON (4.3.0)
|
||||||
- TrustWalletCore (2.6.16):
|
- TrustWalletCore (2.6.17):
|
||||||
- TrustWalletCore/Core (= 2.6.16)
|
- TrustWalletCore/Core (= 2.6.17)
|
||||||
- TrustWalletCore/Core (2.6.16):
|
- TrustWalletCore/Core (2.6.17):
|
||||||
- TrustWalletCore/Types
|
- TrustWalletCore/Types
|
||||||
- TrustWalletCore/Types (2.6.16):
|
- TrustWalletCore/Types (2.6.17):
|
||||||
- SwiftProtobuf
|
- SwiftProtobuf
|
||||||
- WalletConnect (0.1.0):
|
- WalletConnect (0.1.0):
|
||||||
- CryptoSwift
|
- CryptoSwift
|
||||||
@ -70,13 +70,13 @@ SPEC CHECKSUMS:
|
|||||||
BigInt: f668a80089607f521586bbe29513d708491ef2f7
|
BigInt: f668a80089607f521586bbe29513d708491ef2f7
|
||||||
BlockiesSwift: 22d8d56dd187e6bfd16cb8c8fbd4fd4896c3e65d
|
BlockiesSwift: 22d8d56dd187e6bfd16cb8c8fbd4fd4896c3e65d
|
||||||
CryptoSwift: 0bc800a7e6a24c4fc9ebeab97d44b0d5f73a78bd
|
CryptoSwift: 0bc800a7e6a24c4fc9ebeab97d44b0d5f73a78bd
|
||||||
Kingfisher: 6c3df386db71d82c0817a429d2c9421a77396529
|
Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74
|
||||||
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
|
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
|
||||||
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
|
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
|
||||||
Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0
|
Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0
|
||||||
SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0
|
SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0
|
||||||
SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
|
SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
|
||||||
TrustWalletCore: 9d3842328ccb07c05abaf7e1cb2c19bdc3d52331
|
TrustWalletCore: 48472eb39dab56bc5a94e626b24160c88bfb1ebf
|
||||||
WalletConnect: 1df75d4355b1cacfc27d7ef2416fae43862d0eb4
|
WalletConnect: 1df75d4355b1cacfc27d7ef2416fae43862d0eb4
|
||||||
Web3Swift.io: 18fd06aed9d56df9c704f9c6f87b06675bb05b53
|
Web3Swift.io: 18fd06aed9d56df9c704f9c6f87b06675bb05b53
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user