mirror of
https://github.com/lil-org/tokenary.git
synced 2024-12-15 15:05:15 +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 */; };
|
||||
2C901C4D268A033100D0926A /* GasService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C4C268A033100D0926A /* GasService.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 */; };
|
||||
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8946E269A2E8C00879245 /* SessionStorage.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -189,6 +193,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2C1995552674D0F300A8E370 /* Ethereum.swift */,
|
||||
2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */,
|
||||
2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */,
|
||||
2CE3D014267F73E80032A62E /* LegacyAccountWithKey.swift */,
|
||||
2CE3D011267F73C00032A62E /* Transaction.swift */,
|
||||
);
|
||||
@ -396,11 +402,13 @@
|
||||
2CC0CDBE2692027E0072922A /* PriceService.swift in Sources */,
|
||||
2C8A09C6267513FC00993638 /* Agent.swift in Sources */,
|
||||
2C8A09D42675184700993638 /* Window.swift in Sources */,
|
||||
2C9F0B6526BDC9AF008FA3D6 /* EthereumNetwork.swift in Sources */,
|
||||
2C208A9F26813408005BA500 /* Secrets.swift in Sources */,
|
||||
2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */,
|
||||
0DC850E726B73A5900809E82 /* AuthenticationReason.swift in Sources */,
|
||||
2CD0669126B5537B00728C20 /* InkWallet.swift in Sources */,
|
||||
2C8A09D726751A0C00993638 /* WalletConnect.swift in Sources */,
|
||||
2C9F0B6826BDCB2E008FA3D6 /* EthereumChain.swift in Sources */,
|
||||
2C03D1D2269B407900EF10EA /* NetworkMonitor.swift in Sources */,
|
||||
2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */,
|
||||
2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */,
|
||||
@ -570,7 +578,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 23;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
||||
@ -579,7 +587,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.4;
|
||||
MARKETING_VERSION = 1.0.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -597,7 +605,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 23;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
DEVELOPMENT_TEAM = XWNXDSM6BU;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Encrypted Ink/Supporting Files/Info.plist";
|
||||
@ -606,7 +614,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.4;
|
||||
MARKETING_VERSION = 1.0.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = ink.encrypted.macos;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -77,9 +77,9 @@ class Agent: NSObject {
|
||||
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 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 {
|
||||
self?.askAuthentication(on: windowController.window, onStart: false, reason: .sendTransaction) { success in
|
||||
completion(success ? transaction : nil)
|
||||
@ -119,7 +119,7 @@ class Agent: NSObject {
|
||||
showInitialScreen(wcSession: session)
|
||||
}
|
||||
|
||||
func getWalletSelectionCompletionIfShouldSelect() -> ((InkWallet) -> Void)? {
|
||||
func getWalletSelectionCompletionIfShouldSelect() -> ((Int, InkWallet) -> Void)? {
|
||||
let session = getSessionFromPasteboard()
|
||||
return onSelectedWallet(session: session)
|
||||
}
|
||||
@ -131,7 +131,7 @@ class Agent: NSObject {
|
||||
let howToItem = NSMenuItem(title: "How to WalletConnect?", action: #selector(showInstructionsAlert), 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 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")
|
||||
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 }
|
||||
return { [weak self] wallet in
|
||||
self?.connectWallet(session: session, wallet: wallet)
|
||||
return { [weak self] chainId, wallet in
|
||||
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 window = windowController.window
|
||||
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 {
|
||||
Window.closeAllAndActivateBrowser()
|
||||
}
|
||||
|
@ -1,8 +1,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>
|
||||
<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"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@ -818,13 +818,13 @@ DQ
|
||||
</textFieldCell>
|
||||
</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">
|
||||
<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">
|
||||
<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"/>
|
||||
<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">
|
||||
<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"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" 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"/>
|
||||
</connections>
|
||||
</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>
|
||||
<constraints>
|
||||
<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 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 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="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="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"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<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="titleLabel" destination="dkh-kG-EFj" id="xDn-bP-HWG"/>
|
||||
</connections>
|
||||
@ -1599,11 +1627,13 @@ DQ
|
||||
<connections>
|
||||
<outlet property="fastSpeedLabel" destination="WJV-V3-GWm" id="lzX-wu-MdJ"/>
|
||||
<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="okButton" destination="JBO-6Q-5eC" id="JHm-Kl-fys"/>
|
||||
<outlet property="peerLogoImageView" destination="g8t-xf-H1l" id="CqE-7d-LAU"/>
|
||||
<outlet property="peerNameLabel" destination="Ji7-6C-gUp" id="J9c-ml-tXd"/>
|
||||
<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="titleLabel" destination="g2G-lh-X1F" id="NWt-Lq-go1"/>
|
||||
</connections>
|
||||
|
@ -19,10 +19,7 @@ struct Ethereum {
|
||||
|
||||
static let shared = Ethereum()
|
||||
|
||||
private let network: Network = AlchemyNetwork(
|
||||
chain: "mainnet",
|
||||
apiKey: Secrets.alchemy
|
||||
)
|
||||
private let networks = EthereumNetwork.allByChain
|
||||
|
||||
func sign(message: String, wallet: InkWallet) throws -> String {
|
||||
guard let privateKeyString = wallet.ethereumPrivateKeyString else { throw Error.keyNotFound }
|
||||
@ -58,8 +55,9 @@ struct Ethereum {
|
||||
return signed
|
||||
}
|
||||
|
||||
func send(transaction: Transaction, wallet: InkWallet) throws -> String {
|
||||
let bytes = try signedTransactionBytes(transaction: transaction, wallet: wallet)
|
||||
func send(transaction: Transaction, wallet: InkWallet, chain: EthereumChain) throws -> String {
|
||||
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()
|
||||
guard let hash = response["result"].string else {
|
||||
throw Error.failedToSendTransaction
|
||||
@ -67,7 +65,8 @@ struct Ethereum {
|
||||
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 }
|
||||
let senderKey = EthPrivateKey(hex: privateKeyString)
|
||||
let contractAddress = EthAddress(hex: transaction.to)
|
||||
@ -106,11 +105,11 @@ struct Ethereum {
|
||||
return bytes
|
||||
}
|
||||
|
||||
func prepareTransaction(_ transaction: Transaction, completion: @escaping (Transaction) -> Void) {
|
||||
func prepareTransaction(_ transaction: Transaction, chain: EthereumChain, completion: @escaping (Transaction) -> Void) {
|
||||
var transaction = transaction
|
||||
|
||||
if transaction.nonce == nil {
|
||||
getNonce(from: transaction.from) { nonce in
|
||||
getNonce(chain: chain, from: transaction.from) { nonce in
|
||||
transaction.nonce = nonce
|
||||
completion(transaction)
|
||||
}
|
||||
@ -118,7 +117,7 @@ struct Ethereum {
|
||||
|
||||
func getGasIfNeeded(gasPrice: String) {
|
||||
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
|
||||
completion(transaction)
|
||||
}
|
||||
@ -127,7 +126,7 @@ struct Ethereum {
|
||||
if let gasPrice = transaction.gasPrice {
|
||||
getGasIfNeeded(gasPrice: gasPrice)
|
||||
} else {
|
||||
getGasPrice { gasPrice in
|
||||
getGasPrice(chain: chain) { gasPrice in
|
||||
transaction.gasPrice = gasPrice
|
||||
completion(transaction)
|
||||
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 {
|
||||
let gas = try? EthGasEstimate(
|
||||
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 {
|
||||
let gasPrice = try? EthGasPrice(network: network).value().toHexString()
|
||||
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 {
|
||||
let nonce = try? EthTransactions(network: network, address: EthAddress(hex: from), blockChainState: PendingBlockChainState()).count().value().toHexString()
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
if let gasPrice = gasPrice,
|
||||
let gas = gas,
|
||||
let a = try? EthNumber(hex: gasPrice).value().toNormalizedDecimal(power: 18),
|
||||
let b = try? EthNumber(hex: gas).value().toDecimal() {
|
||||
let c = NSDecimalNumber(decimal: a).multiplying(by: NSDecimalNumber(decimal: b))
|
||||
let costString = cost(value: c, price: ethPrice)
|
||||
fee = c.stringValue.prefix(7) + " ETH" + costString
|
||||
let costString = showUSDPrice ? cost(value: c, price: ethPrice) : ""
|
||||
fee = c.stringValue.prefix(7) + " \(symbol)" + costString
|
||||
} else {
|
||||
fee = "Calculating…"
|
||||
}
|
||||
var result = [String]()
|
||||
if let decimal = try? weiAmount.value().toNormalizedDecimal(power: 18) {
|
||||
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) {
|
||||
result.append("\(value) ETH" + costString)
|
||||
result.append("\(value) \(symbol)" + costString)
|
||||
}
|
||||
}
|
||||
result.append("Fee: " + fee)
|
||||
|
@ -8,7 +8,8 @@ class AccountsListViewController: NSViewController {
|
||||
private let walletsManager = WalletsManager.shared
|
||||
private var cellModels = [CellModel]()
|
||||
|
||||
var onSelectedWallet: ((InkWallet) -> Void)?
|
||||
private var chain = EthereumChain.main
|
||||
var onSelectedWallet: ((Int, InkWallet) -> Void)?
|
||||
var newWalletId: String?
|
||||
|
||||
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! {
|
||||
didSet {
|
||||
let menu = NSMenu()
|
||||
@ -53,7 +57,7 @@ class AccountsListViewController: NSViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupAccountsMenu()
|
||||
reloadTitle()
|
||||
reloadHeader()
|
||||
updateCellModels()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: NSApplication.didBecomeActiveNotification, object: nil)
|
||||
}
|
||||
@ -76,9 +80,15 @@ class AccountsListViewController: NSViewController {
|
||||
tableView.menu = menu
|
||||
}
|
||||
|
||||
private func reloadTitle() {
|
||||
titleLabel.stringValue = onSelectedWallet != nil && !wallets.isEmpty ? "Select\nAccount" : "Accounts"
|
||||
private func reloadHeader() {
|
||||
let canSelectAccount = onSelectedWallet != nil && !wallets.isEmpty
|
||||
titleLabel.stringValue = canSelectAccount ? "Select\nAccount" : "Accounts"
|
||||
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() {
|
||||
@ -86,7 +96,14 @@ class AccountsListViewController: NSViewController {
|
||||
if let completion = agent.getWalletSelectionCompletionIfShouldSelect() {
|
||||
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) {
|
||||
@ -107,13 +124,25 @@ class AccountsListViewController: NSViewController {
|
||||
}
|
||||
|
||||
@objc private func didClickCreateAccount() {
|
||||
let wallet = try? walletsManager.createWallet()
|
||||
newWalletId = wallet?.id
|
||||
reloadTitle()
|
||||
let alert = Alert()
|
||||
alert.messageText = "Back up new account."
|
||||
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()
|
||||
tableView.reloadData()
|
||||
blinkNewWalletCellIfNeeded()
|
||||
// TODO: show backup phrase
|
||||
showKey(wallet: wallet, mnemonic: true)
|
||||
}
|
||||
|
||||
private func blinkNewWalletCellIfNeeded() {
|
||||
@ -184,8 +213,10 @@ class AccountsListViewController: NSViewController {
|
||||
}
|
||||
|
||||
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
|
||||
if mnemonic, let mnemonicString = try? walletsManager.exportMnemonic(wallet: wallet) {
|
||||
secret = mnemonicString
|
||||
@ -213,7 +244,7 @@ class AccountsListViewController: NSViewController {
|
||||
private func removeAccountAtIndex(_ index: Int) {
|
||||
let wallet = wallets[index]
|
||||
try? walletsManager.delete(wallet: wallet)
|
||||
reloadTitle()
|
||||
reloadHeader()
|
||||
updateCellModels()
|
||||
tableView.reloadData()
|
||||
}
|
||||
@ -240,7 +271,7 @@ extension AccountsListViewController: NSTableViewDelegate {
|
||||
case .wallet:
|
||||
let wallet = wallets[row]
|
||||
if let onSelectedWallet = onSelectedWallet {
|
||||
onSelectedWallet(wallet)
|
||||
onSelectedWallet(chain.id, wallet)
|
||||
} else {
|
||||
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { [weak self] _ in
|
||||
var point = NSEvent.mouseLocation
|
||||
|
@ -6,7 +6,10 @@ import Kingfisher
|
||||
|
||||
class ApproveTransactionViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var infoTextViewBottomConstraint: NSLayoutConstraint!
|
||||
@IBOutlet weak var speedContainerStackView: NSStackView!
|
||||
@IBOutlet weak var gweiLabel: NSTextField!
|
||||
|
||||
@IBOutlet weak var titleLabel: NSTextField!
|
||||
@IBOutlet var metaTextView: NSTextView!
|
||||
@IBOutlet weak var okButton: NSButton!
|
||||
@ -26,12 +29,14 @@ class ApproveTransactionViewController: NSViewController {
|
||||
private let priceService = PriceService.shared
|
||||
private var currentGasInfo: GasService.Info?
|
||||
private var transaction: Transaction!
|
||||
private var chain: EthereumChain!
|
||||
private var completion: ((Transaction?) -> Void)!
|
||||
private var didEnableSpeedConfiguration = false
|
||||
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)
|
||||
new.chain = chain
|
||||
new.transaction = transaction
|
||||
new.completion = completion
|
||||
new.peerMeta = peerMeta
|
||||
@ -58,15 +63,21 @@ class ApproveTransactionViewController: NSViewController {
|
||||
}
|
||||
|
||||
private func prepareTransaction() {
|
||||
ethereum.prepareTransaction(transaction) { [weak self] updated in
|
||||
ethereum.prepareTransaction(transaction, chain: chain) { [weak self] updated in
|
||||
self?.transaction = updated
|
||||
self?.updateInterface()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateInterface() {
|
||||
if chain != .main {
|
||||
speedContainerStackView.isHidden = true
|
||||
gweiLabel.isHidden = true
|
||||
infoTextViewBottomConstraint.constant = 30
|
||||
}
|
||||
|
||||
enableSpeedConfigurationIfNeeded()
|
||||
let meta = transaction.description(ethPrice: priceService.currentPrice)
|
||||
let meta = transaction.description(chain: chain, ethPrice: priceService.currentPrice)
|
||||
if metaTextView.string != meta {
|
||||
metaTextView.string = meta
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import Cocoa
|
||||
class ImportViewController: NSViewController {
|
||||
|
||||
private let walletsManager = WalletsManager.shared
|
||||
var onSelectedWallet: ((InkWallet) -> Void)?
|
||||
var onSelectedWallet: ((Int, InkWallet) -> Void)?
|
||||
private var inputValidationResult = WalletsManager.InputValidationResult.invalid
|
||||
|
||||
@IBOutlet weak var textField: NSTextField! {
|
||||
|
@ -7,6 +7,7 @@ class SessionStorage {
|
||||
|
||||
struct Item: Codable {
|
||||
let session: WCSession
|
||||
let chainId: Int?
|
||||
let walletId: String
|
||||
let clientId: String
|
||||
let sessionDetails: WCSessionRequestParam
|
||||
@ -51,8 +52,8 @@ class SessionStorage {
|
||||
}
|
||||
}
|
||||
|
||||
func add(interactor: WCInteractor, walletId: String, sessionDetails: WCSessionRequestParam) {
|
||||
let item = Item(session: interactor.session, walletId: walletId, clientId: interactor.clientId, sessionDetails: sessionDetails)
|
||||
func add(interactor: WCInteractor, chainId: Int, walletId: String, sessionDetails: WCSessionRequestParam) {
|
||||
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)
|
||||
Defaults.storedSessions[interactor.clientId] = item
|
||||
didInteractWith(clientId: interactor.clientId)
|
||||
|
@ -24,10 +24,10 @@ class WalletConnect {
|
||||
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 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
|
||||
completion(connected)
|
||||
@ -45,7 +45,7 @@ class WalletConnect {
|
||||
|
||||
for item in items {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -83,17 +83,16 @@ class WalletConnect {
|
||||
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 }
|
||||
let accounts = [address]
|
||||
let chainId = 1
|
||||
|
||||
|
||||
interactor.onError = { _ in }
|
||||
|
||||
interactor.onSessionRequest = { [weak self, weak interactor] (id, peerParam) in
|
||||
guard let interactor = interactor else { return }
|
||||
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()
|
||||
}
|
||||
|
||||
@ -109,7 +108,7 @@ class WalletConnect {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -125,17 +124,17 @@ class WalletConnect {
|
||||
}
|
||||
}
|
||||
|
||||
private func approveTransaction(id: Int64, wct: WCEthereumTransaction, walletId: String, interactor: WCInteractor?) {
|
||||
guard let to = wct.to else {
|
||||
private func approveTransaction(id: Int64, wct: WCEthereumTransaction, walletId: String, chainId: Int, interactor: WCInteractor?) {
|
||||
guard let to = wct.to, let chain = EthereumChain(rawValue: chainId) else {
|
||||
rejectRequest(id: id, interactor: interactor, message: "Something went wrong.")
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
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 {
|
||||
self?.sendTransaction(transaction, walletId: walletId, requestId: id, interactor: interactor)
|
||||
self?.sendTransaction(transaction, walletId: walletId, chainId: chainId, requestId: id, interactor: interactor)
|
||||
} else {
|
||||
self?.rejectRequest(id: id, interactor: interactor, message: "Cancelled")
|
||||
}
|
||||
@ -174,12 +173,12 @@ class WalletConnect {
|
||||
interactor?.rejectRequest(id: id, message: message).cauterize()
|
||||
}
|
||||
|
||||
private func sendTransaction(_ transaction: Transaction, walletId: String, requestId: Int64, interactor: WCInteractor?) {
|
||||
guard let wallet = walletsManager.getWallet(id: walletId) else {
|
||||
private func sendTransaction(_ transaction: Transaction, walletId: String, chainId: Int, requestId: Int64, interactor: WCInteractor?) {
|
||||
guard let wallet = walletsManager.getWallet(id: walletId), let chain = EthereumChain(rawValue: chainId) else {
|
||||
rejectRequest(id: requestId, interactor: interactor, message: "Something went wrong.")
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
14
Podfile.lock
14
Podfile.lock
@ -2,7 +2,7 @@ PODS:
|
||||
- BigInt (5.2.0)
|
||||
- BlockiesSwift (0.1.2)
|
||||
- CryptoSwift (1.4.1)
|
||||
- Kingfisher (6.3.0)
|
||||
- Kingfisher (6.3.1)
|
||||
- PromiseKit (6.15.3):
|
||||
- PromiseKit/CorePromise (= 6.15.3)
|
||||
- PromiseKit/Foundation (= 6.15.3)
|
||||
@ -14,11 +14,11 @@ PODS:
|
||||
- Starscream (3.1.1)
|
||||
- SwiftProtobuf (1.17.0)
|
||||
- SwiftyJSON (4.3.0)
|
||||
- TrustWalletCore (2.6.16):
|
||||
- TrustWalletCore/Core (= 2.6.16)
|
||||
- TrustWalletCore/Core (2.6.16):
|
||||
- TrustWalletCore (2.6.17):
|
||||
- TrustWalletCore/Core (= 2.6.17)
|
||||
- TrustWalletCore/Core (2.6.17):
|
||||
- TrustWalletCore/Types
|
||||
- TrustWalletCore/Types (2.6.16):
|
||||
- TrustWalletCore/Types (2.6.17):
|
||||
- SwiftProtobuf
|
||||
- WalletConnect (0.1.0):
|
||||
- CryptoSwift
|
||||
@ -70,13 +70,13 @@ SPEC CHECKSUMS:
|
||||
BigInt: f668a80089607f521586bbe29513d708491ef2f7
|
||||
BlockiesSwift: 22d8d56dd187e6bfd16cb8c8fbd4fd4896c3e65d
|
||||
CryptoSwift: 0bc800a7e6a24c4fc9ebeab97d44b0d5f73a78bd
|
||||
Kingfisher: 6c3df386db71d82c0817a429d2c9421a77396529
|
||||
Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74
|
||||
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
|
||||
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
|
||||
Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0
|
||||
SwiftProtobuf: 9c85136c6ba74b0a1b84279dbf0f6db8efb714e0
|
||||
SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
|
||||
TrustWalletCore: 9d3842328ccb07c05abaf7e1cb2c19bdc3d52331
|
||||
TrustWalletCore: 48472eb39dab56bc5a94e626b24160c88bfb1ebf
|
||||
WalletConnect: 1df75d4355b1cacfc27d7ef2416fae43862d0eb4
|
||||
Web3Swift.io: 18fd06aed9d56df9c704f9c6f87b06675bb05b53
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user