Merge pull request #107 from zeriontech/feature/custom-rpc

custom rpc
This commit is contained in:
ivan grachev 2023-11-02 20:51:47 +03:00 committed by GitHub
commit fc78b1125f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1216 additions and 216 deletions

View File

@ -21,8 +21,8 @@ extension SafariRequest {
let method: Method
let address: String
let chain: EthereumNetwork?
let switchToChain: EthereumNetwork?
let currentChainId: Int?
let switchToChainId: Int?
let parameters: [String: Any]?
init?(name: String, json: [String: Any]) {
@ -32,21 +32,19 @@ extension SafariRequest {
self.address = address
self.method = method
if let network = json["networkId"] as? String, let networkId = Int(network) {
self.chain = EthereumNetwork(rawValue: networkId)
if let currentChainId = json["chainId"] as? String, let chainId = Int(hexString: currentChainId) {
self.currentChainId = chainId
} else {
self.chain = nil
self.currentChainId = nil
}
let parameters = json["object"] as? [String: Any]
self.parameters = parameters
if let chainId = parameters?["chainId"] as? String,
let networkId = Int(hexString: chainId),
let chain = EthereumNetwork(rawValue: networkId) {
self.switchToChain = chain
if let toChainId = parameters?["chainId"] as? String, let chainId = Int(hexString: toChainId) {
self.switchToChainId = chainId
} else {
self.switchToChain = nil
self.switchToChainId = nil
}
}

View File

@ -14,7 +14,7 @@ extension SafariRequest {
struct ProviderConfiguration {
let provider: InpageProvider
let address: String
let network: EthereumNetwork?
let chainId: String?
}
let method: Method
@ -37,7 +37,7 @@ extension SafariRequest {
case .ethereum:
guard let response = try? jsonDecoder.decode(ResponseToExtension.Ethereum.self, from: data),
let address = response.results?.first else { continue }
configurations.append(ProviderConfiguration(provider: provider, address: address, network: EthereumNetwork.withChainId(response.chainId)))
configurations.append(ProviderConfiguration(provider: provider, address: address, chainId: response.chainId))
case .unknown, .multiple:
continue
}

File diff suppressed because one or more lines are too long

View File

@ -39,8 +39,9 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
self.context = context
if case let .ethereum(ethereumRequest) = request.body,
ethereumRequest.method == .switchEthereumChain || ethereumRequest.method == .addEthereumChain {
if let chain = ethereumRequest.switchToChain {
let responseBody = ResponseToExtension.Ethereum(results: [ethereumRequest.address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString)
if let switchToChainId = ethereumRequest.switchToChainId, let rpcURL = Nodes.getNode(chainId: switchToChainId) {
let chainId = String.hex(switchToChainId, withPrefix: true)
let responseBody = ResponseToExtension.Ethereum(results: [ethereumRequest.address], chainId: chainId, rpcURL: rpcURL)
let response = ResponseToExtension(for: request, body: .ethereum(responseBody))
respond(with: response.json)
} else {

View File

@ -22,7 +22,7 @@ class TokenaryEthereum extends EventEmitter {
constructor() {
super();
const config = {address: "", chainId: "0x1", rpcUrl: "https://mainnet.infura.io/v3/3f99b6096fda424bbb26e17866dcddfc"};
const config = {address: "", chainId: "0x1", rpcUrl: "https://eth.llamarpc.com"};
this.setConfig(config);
this.idMapping = new IdMapping();
this.callbacks = new Map();
@ -381,7 +381,7 @@ class TokenaryEthereum extends EventEmitter {
let object = {
object: data,
address: this.address,
networkId: this.net_version()
chainId: this.chainId
};
window.tokenary.postMessage(handler, id, object, "ethereum");
} else {

View File

@ -4,7 +4,7 @@
"name": "__MSG_extension_name__",
"description": "__MSG_extension_description__",
"version": "2.0.19",
"version": "2.0.20",
"icons": {
"48": "images/icon-48.png",
@ -40,6 +40,7 @@
"nativeMessaging",
"browserAction",
"storage",
"https://*.llamarpc.com/",
"https://*.infura.io/",
"https://*.infura.io/*",
"https://*.infura.io/*/*",

View File

@ -4,7 +4,7 @@
"name": "__MSG_extension_name__",
"description": "__MSG_extension_description__",
"version": "2.0.19",
"version": "2.0.20",
"icons": {
"48": "images/icon-48.png",
@ -38,6 +38,7 @@
"permissions": [
"nativeMessaging",
"storage",
"https://*.llamarpc.com/",
"https://*.infura.io/",
"https://*.infura.io/*",
"https://*.infura.io/*/*",

View File

@ -96,7 +96,7 @@ struct Ethereum {
let gasPriceHex = transaction.gasPrice?.cleanEvenHex,
let gasHex = transaction.gas?.cleanEvenHex,
let valueHex = transaction.value?.cleanEvenHex,
let chainID = Data(hexString: network.hexStringId.cleanEvenHex),
let chainID = Data(hexString: network.chainIdHexString.cleanEvenHex),
let nonce = Data(hexString: nonceHex),
let gasPrice = Data(hexString: gasPriceHex),
let gasLimit = Data(hexString: gasHex),

View File

@ -2,154 +2,19 @@
import Foundation
enum EthereumNetwork: Int {
case ethereum = 1
case arbitrum = 42161
case polygon = 137
case optimism = 10
case binance = 56
case avalanche = 43114
case gnosisChain = 100
case fantomOpera = 250
case celo = 42220
case aurora = 1313161554
case neon = 245022934
case base = 8453
case zora = 7777777
case klaytn = 8217
case scroll = 534352
struct EthereumNetwork: Codable, Equatable {
// Testnets
case arbitrumRinkeby = 421611
case arbitrumKovan = 144545313136048
case optimisticKovan = 69
case ethereumGoerli = 5
case polygonMumbai = 80001
case binanceTestnet = 97
case avalancheFuji = 43113
case fantomTestnet = 4002
case fantomSonicOpen = 64240
case neonDevnet = 245022926
case scrollSepolia = 534351
let chainId: Int
let name: String
let symbol: String
let nodeURLString: String
let isTestnet: Bool
let mightShowPrice: Bool
var id: Int {
return rawValue
}
var symbolIsETH: Bool { return symbol == "ETH" }
var chainIdHexString: String { String.hex(chainId, withPrefix: true) }
var isEthMainnet: Bool { return chainId == EthereumNetwork.ethMainnetChainId }
var hexStringId: String {
return String.hex(id, withPrefix: true)
}
static func withChainId(_ chainId: String?) -> EthereumNetwork? {
guard let chainId = chainId else { return nil }
if let rawValue = Int(hexString: chainId) {
return EthereumNetwork(rawValue: rawValue)
} else {
return nil
}
}
static let allMainnets: [EthereumNetwork] = [.ethereum, .zora, .base, .klaytn, .polygon, .optimism, .binance, .arbitrum, .avalanche, .gnosisChain, .fantomOpera, .celo, .aurora, .neon, .scroll]
static let allTestnets: [EthereumNetwork] = [.ethereumGoerli, .optimisticKovan, .arbitrumKovan, .arbitrumRinkeby, .polygonMumbai, .binanceTestnet, .avalancheFuji, .fantomTestnet, .neonDevnet, .fantomSonicOpen, .scrollSepolia]
var name: String {
switch self {
case .ethereum: return "Ethereum"
case .zora: return "Zora"
case .klaytn: return "Klaytn"
case .base: return "Base"
case .arbitrum: return "Arbitrum"
case .optimism: return "Optimism"
case .polygon: return "Polygon"
case .binance: return "BNB Smart Chain"
case .avalanche: return "Avalanche"
case .gnosisChain: return "Gnosis Chain"
case .fantomOpera: return "Fantom Opera"
case .celo: return "Celo"
case .aurora: return "Aurora"
case .neon: return "Neon"
case .scroll: return "Scroll"
case .arbitrumRinkeby: return "Arbitrum Rinkeby"
case .optimisticKovan: return "Optimistic Kovan"
case .ethereumGoerli: return "Ethereum Görli"
case .polygonMumbai: return "Polygon Mumbai"
case .arbitrumKovan: return "Arbitrum Kovan"
case .binanceTestnet: return "BNB Testnet"
case .avalancheFuji: return "Avalanche FUJI"
case .fantomTestnet: return "Fantom Testnet"
case .neonDevnet: return "Neon Devnet"
case .fantomSonicOpen: return "Fantom Sonic Open"
case .scrollSepolia: return "Scroll Sepolia"
}
}
var symbol: String {
switch self {
case .binance, .binanceTestnet:
return "BNB"
case .polygon, .polygonMumbai:
return "MATIC"
case .arbitrum, .arbitrumKovan, .arbitrumRinkeby, .ethereum, .ethereumGoerli, .optimism, .optimisticKovan, .aurora, .zora, .base, .scroll, .scrollSepolia:
return "ETH"
case .avalanche, .avalancheFuji:
return "AVAX"
case .gnosisChain:
return "xDai"
case .fantomOpera, .fantomTestnet, .fantomSonicOpen:
return "FTM"
case .celo:
return "CELO"
case .neonDevnet, .neon:
return "NEON"
case .klaytn:
return "KLAY"
}
}
var symbolIsETH: Bool {
return symbol == "ETH"
}
var hasUSDPrice: Bool {
switch self {
case .ethereum, .arbitrum, .klaytn, .polygon, .optimism, .binance, .avalanche, .gnosisChain, .fantomOpera, .celo, .aurora, .neon, .base, .zora, .scroll:
return symbolIsETH
case .fantomTestnet, .neonDevnet, .avalancheFuji, .binanceTestnet, .polygonMumbai, .ethereumGoerli, .optimisticKovan, .arbitrumKovan, .arbitrumRinkeby, .fantomSonicOpen, .scrollSepolia:
return false
}
}
var nodeURLString: String {
switch self {
case .ethereum: return "https://mainnet.infura.io/v3/" + infuraKey
case .arbitrum: return "https://arbitrum-mainnet.infura.io/v3/" + infuraKey
case .optimism: return "https://optimism-mainnet.infura.io/v3/" + infuraKey
case .polygon: return "https://polygon-mainnet.infura.io/v3/" + infuraKey
case .binance: return "https://bsc-dataseed.binance.org/"
case .avalanche: return "https://api.avax.network/ext/bc/C/rpc"
case .gnosisChain: return "https://rpc.gnosischain.com/"
case .fantomOpera: return "https://rpc.ftm.tools/"
case .celo: return "https://rpc.ankr.com/celo"
case .aurora: return "https://mainnet.aurora.dev"
case .neon: return "https://neon-proxy-mainnet.solana.p2p.org/"
case .zora: return "https://rpc.zora.energy"
case .base: return "https://mainnet.base.org"
case .klaytn: return "https://1rpc.io/klay"
case .scroll: return "https://rpc.scroll.io"
case .arbitrumRinkeby: return "https://rinkeby.arbitrum.io/rpc"
case .arbitrumKovan: return "https://kovan5.arbitrum.io/rpc"
case .optimisticKovan: return "https://kovan.optimism.io"
case .ethereumGoerli: return "https://rpc.ankr.com/eth_goerli"
case .binanceTestnet: return "https://data-seed-prebsc-1-s1.binance.org:8545/"
case .avalancheFuji: return "https://api.avax-test.network/ext/bc/C/rpc"
case .polygonMumbai: return "https://rpc.ankr.com/polygon_mumbai"
case .fantomTestnet: return "https://rpc.testnet.fantom.network/"
case .neonDevnet: return "https://devnet.neonevm.org/"
case .fantomSonicOpen: return "https://rpcapi.sonic.fantom.network/"
case .scrollSepolia: return "https://sepolia-rpc.scroll.io"
}
}
static let ethMainnetChainId = 1
}

View File

@ -0,0 +1,54 @@
// Copyright © 2023 Tokenary. All rights reserved.
import Foundation
struct Networks {
static var ethereum: EthereumNetwork {
return withChainId(EthereumNetwork.ethMainnetChainId)!
}
static func withChainId(_ chainId: Int?) -> EthereumNetwork? {
guard let chainId = chainId else { return nil }
return allBundledDict[chainId]
}
static func withChainIdHex(_ chainIdHex: String?) -> EthereumNetwork? {
guard let chainIdHex = chainIdHex, let id = Int(hexString: chainIdHex) else { return nil }
return allBundledDict[id]
}
static let allMainnets: [EthereumNetwork] = {
return allBundled.filter { !$0.isTestnet }
}()
static let allTestnets: [EthereumNetwork] = {
return allBundled.filter { $0.isTestnet }
}()
private static let allBundled: [EthereumNetwork] = {
return Array(allBundledDict.values.sorted(by: { $0.name < $1.name }))
}()
private static let allBundledDict: [Int: EthereumNetwork] = {
if let url = Bundle.main.url(forResource: "bundled-networks", withExtension: "json"),
let data = try? Data(contentsOf: url),
let bundledNetworks = try? JSONDecoder().decode([Int: BundledNetwork].self, from: data) {
let mapped = bundledNetworks.compactMap { (key, value) -> (Int, EthereumNetwork)? in
guard let node = Nodes.getNode(chainId: key) else { return nil }
let network = EthereumNetwork(chainId: key,
name: value.name,
symbol: value.symbol,
nodeURLString: node,
isTestnet: value.isTest,
mightShowPrice: value.okToShowPriceForSymbol)
return (key, network)
}
let dict = [Int: EthereumNetwork](uniqueKeysWithValues: mapped)
return dict
} else {
return [:]
}
}()
}

View File

@ -0,0 +1,20 @@
// Copyright © 2023 Tokenary. All rights reserved.
import Foundation
struct Nodes {
static func getNode(chainId: Int) -> String? {
if let domain = BundledNodes.dict[chainId] {
let https = "https://" + domain
if domain.hasSuffix(".infura.io/v3/") {
return https + infuraKey
} else {
return https
}
} else {
return nil
}
}
}

View File

@ -21,12 +21,12 @@ struct Transaction {
return value.gweiUInt
}
func description(chain: EthereumNetwork, ethPrice: Double?) -> String {
func description(chain: EthereumNetwork, price: Double?) -> String {
var result = ["🌐 " + chain.name]
if let value = valueWithSymbol(chain: chain, ethPrice: ethPrice, withLabel: false) {
if let value = valueWithSymbol(chain: chain, price: price, withLabel: false) {
result.append(value)
}
result.append(feeWithSymbol(chain: chain, ethPrice: ethPrice))
result.append(feeWithSymbol(chain: chain, price: price))
result.append(dataWithLabel)
return result.joined(separator: "\n\n")
@ -54,13 +54,13 @@ struct Transaction {
return "Gas price: " + gwei
}
func feeWithSymbol(chain: EthereumNetwork, ethPrice: Double?) -> String {
func feeWithSymbol(chain: EthereumNetwork, price: Double?) -> String {
let feeString: String
if let gasPriceString = gasPrice, let gasString = gas,
let gasPrice = BigInt(hexString: gasPriceString),
let gas = BigInt(hexString: gasString) {
let fee = gas * gasPrice
let costString = chain.hasUSDPrice ? cost(value: fee, price: ethPrice) : ""
let costString = chain.mightShowPrice ? cost(value: fee, price: price) : ""
feeString = fee.eth.prefix(8) + " \(chain.symbol)" + costString
} else {
feeString = Strings.calculating
@ -68,9 +68,9 @@ struct Transaction {
return "Fee: " + feeString
}
func valueWithSymbol(chain: EthereumNetwork, ethPrice: Double?, withLabel: Bool) -> String? {
func valueWithSymbol(chain: EthereumNetwork, price: Double?, withLabel: Bool) -> String? {
guard let value = value, let value = BigInt(hexString: value) else { return nil }
let costString = chain.hasUSDPrice ? cost(value: value, price: ethPrice) : ""
let costString = chain.mightShowPrice ? cost(value: value, price: price) : ""
let valueString = "\(value.eth) \(chain.symbol)" + costString
return withLabel ? "Value: " + valueString : valueString
}

View File

@ -27,7 +27,8 @@ struct DappRequestProcessor {
guard let coin = CoinType.correspondingToInpageProvider(configuration.provider) else { return nil }
return walletsManager.getSpecificAccount(coin: coin, address: configuration.address)
}
let network = body.providerConfigurations.compactMap { $0.network }.first
let chainId = body.providerConfigurations.compactMap { $0.chainId }.first
let network = Networks.withChainIdHex(chainId)
let initiallyConnectedProviders = Set(body.providerConfigurations.map { $0.provider })
let action = SelectAccountAction(peer: request.peerMeta,
coinType: nil,
@ -41,7 +42,9 @@ struct DappRequestProcessor {
let account = specificWalletAccount.account
switch account.coin {
case .ethereum:
let responseBody = ResponseToExtension.Ethereum(results: [account.address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString)
let responseBody = ResponseToExtension.Ethereum(results: [account.address],
chainId: chain.chainIdHexString,
rpcURL: chain.nodeURLString)
specificProviderBodies.append(.ethereum(responseBody))
default:
fatalError("Can't select that coin")
@ -82,7 +85,7 @@ struct DappRequestProcessor {
network: nil,
source: .safariExtension) { chain, specificWalletAccounts in
if let chain = chain, let specificWalletAccount = specificWalletAccounts?.first, specificWalletAccount.account.coin == .ethereum {
let responseBody = ResponseToExtension.Ethereum(results: [specificWalletAccount.account.address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString)
let responseBody = ResponseToExtension.Ethereum(results: [specificWalletAccount.account.address], chainId: chain.chainIdHexString, rpcURL: chain.nodeURLString)
respond(to: request, body: .ethereum(responseBody), completion: completion)
} else {
respond(to: request, error: Strings.canceled, completion: completion)
@ -137,7 +140,8 @@ struct DappRequestProcessor {
}
case .signTransaction:
if let transaction = ethereumRequest.transaction,
let chain = ethereumRequest.chain,
let chainId = ethereumRequest.currentChainId,
let chain = Networks.withChainId(chainId),
let account = account,
let privateKey = privateKey {
let action = SendTransactionAction(provider: request.provider,

View File

@ -4,8 +4,22 @@ import Foundation
class PriceService {
private struct PriceResponse: Codable {
let ethereum: Price
private struct Prices: Codable {
let eth: Price?
let bnb: Price?
let matic: Price?
let ftm: Price?
let avax: Price?
enum CodingKeys: String, CodingKey, CaseIterable {
case eth = "ethereum"
case bnb = "binancecoin"
case matic = "matic-network"
case ftm = "fantom"
case avax = "avalanche-2"
}
}
private struct Price: Codable {
@ -15,10 +29,14 @@ class PriceService {
static let shared = PriceService()
private let jsonDecoder = JSONDecoder()
private let urlSession = URLSession(configuration: .ephemeral)
private let idsQuery: String = {
let ids = Prices.CodingKeys.allCases.map { $0.rawValue }
return ids.joined(separator: "%2C")
}()
private init() {}
var currentPrice: Double?
private var currentPrices: Prices?
func start() {
getPrice(scheduleNextRequest: true)
@ -28,13 +46,31 @@ class PriceService {
getPrice(scheduleNextRequest: false)
}
func forNetwork(_ network: EthereumNetwork) -> Double? {
guard network.mightShowPrice else { return nil }
switch network.symbol {
case "ETH":
return currentPrices?.eth?.usd
case "BNB":
return currentPrices?.bnb?.usd
case "FTM":
return currentPrices?.ftm?.usd
case "MATIC":
return currentPrices?.matic?.usd
case "AVAX":
return currentPrices?.avax?.usd
default:
return nil
}
}
private func getPrice(scheduleNextRequest: Bool) {
let url = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd")!
let url = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=\(idsQuery)&vs_currencies=usd")!
let dataTask = urlSession.dataTask(with: url) { [weak self] (data, _, _) in
if let data = data,
let priceResponse = try? self?.jsonDecoder.decode(PriceResponse.self, from: data) {
let pricesResponse = try? self?.jsonDecoder.decode(Prices.self, from: data) {
DispatchQueue.main.async {
self?.currentPrice = priceResponse.ethereum.usd
self?.currentPrices = pricesResponse
}
}
if scheduleNextRequest {

View File

@ -0,0 +1,96 @@
// Copyright © 2023 Tokenary. All rights reserved.
import SwiftUI
struct NetworksListView: View {
@State private var searchText: String = ""
let items: [String] = Networks.all().map { $0.name }
@Environment(\.presentationMode) var presentationMode
var filteredItems: [String] {
items.filter { $0.contains(searchText) || searchText.isEmpty }
}
var body: some View {
VStack {
SearchBar(text: $searchText)
List(filteredItems, id: \.self) { item in
Text(item)
}
Divider() // Separate the list from the buttons
HStack {
Spacer()
Button("Cancel") {
self.presentationMode.wrappedValue.dismiss()
}
.padding()
Button("OK") {
self.presentationMode.wrappedValue.dismiss()
}
.padding()
}
}
}
}
struct SearchBar: View {
@Binding var text: String
var body: some View {
HStack {
TextField("Search ...", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
}.padding()
}
}
#if os(iOS)
import UIKit
extension UIViewController {
func showPopup() {
let contentView = NetworksListView()
let hostingController = UIHostingController(rootView: contentView)
hostingController.modalPresentationStyle = .fullScreen
self.present(hostingController, animated: true, completion: nil)
}
}
#elseif os(macOS)
import Cocoa
var popupWindow: NSWindow? // keep a reference within a NSViewController
extension NSViewController {
func showPopup() {
let contentView = NetworksListView()
popupWindow = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 300, height: 400),
styleMask: [.closable, .fullSizeContentView, .titled],
backing: .buffered, defer: false)
popupWindow?.center()
popupWindow?.titleVisibility = .hidden
popupWindow?.titlebarAppearsTransparent = true
popupWindow?.isMovableByWindowBackground = true
popupWindow?.backgroundColor = NSColor.windowBackgroundColor
popupWindow?.isOpaque = false
popupWindow?.hasShadow = true
popupWindow?.contentView?.wantsLayer = true
popupWindow?.contentView?.layer?.cornerRadius = 10
popupWindow?.contentView?.layer?.masksToBounds = true
popupWindow?.isReleasedWhenClosed = false
popupWindow?.contentView = NSHostingView(rootView: contentView)
popupWindow?.makeKeyAndOrderFront(nil)
}
}
#endif

View File

@ -27,7 +27,7 @@ class AccountsListViewController: UIViewController, DataStateContainer {
private var sections = [Section]()
private let walletsManager = WalletsManager.shared
private var network = EthereumNetwork.ethereum
private var network = Networks.ethereum
var selectAccountAction: SelectAccountAction?
private var wallets: [TokenaryWallet] {
@ -302,7 +302,7 @@ class AccountsListViewController: UIViewController, DataStateContainer {
let actionSheet = UIAlertController(title: Strings.selectNetwork, message: nil, preferredStyle: .actionSheet)
actionSheet.popoverPresentationController?.sourceView = networkButton
for network in EthereumNetwork.allMainnets {
for network in Networks.allMainnets {
let prefix = network == self.network ? "" : ""
let action = UIAlertAction(title: prefix + network.name, style: .default) { [weak self] _ in
self?.selectNetwork(network)
@ -321,7 +321,7 @@ class AccountsListViewController: UIViewController, DataStateContainer {
private func showTestnets() {
let actionSheet = UIAlertController(title: Strings.selectTestnet, message: nil, preferredStyle: .actionSheet)
actionSheet.popoverPresentationController?.sourceView = networkButton
for network in EthereumNetwork.allTestnets {
for network in Networks.allTestnets {
let prefix = network == self.network ? "" : ""
let action = UIAlertAction(title: prefix + network.name, style: .default) { [weak self] _ in
self?.selectNetwork(network)

View File

@ -59,7 +59,7 @@ class ApproveTransactionViewController: UIViewController {
navigationItem.largeTitleDisplayMode = .always
isModalInPresentation = true
if chain == .ethereum {
if chain.isEthMainnet {
sectionModels = [[], [.gasPriceSlider]]
} else {
sectionModels = [[]]
@ -85,10 +85,11 @@ class ApproveTransactionViewController: UIViewController {
.textWithImage(text: chain.name, imageURL: nil, image: Images.network)
]
if let value = transaction.valueWithSymbol(chain: chain, ethPrice: priceService.currentPrice, withLabel: true) {
let price = priceService.forNetwork(chain)
if let value = transaction.valueWithSymbol(chain: chain, price: price, withLabel: true) {
cellModels.append(.text(text: value, oneLine: false))
}
cellModels.append(.text(text: transaction.feeWithSymbol(chain: chain, ethPrice: priceService.currentPrice), oneLine: false))
cellModels.append(.text(text: transaction.feeWithSymbol(chain: chain, price: price), oneLine: false))
cellModels.append(.text(text: transaction.gasPriceWithLabel(chain: chain), oneLine: false))
if let data = transaction.nonEmptyDataWithLabel {
cellModels.append(.text(text: data, oneLine: true))

View File

@ -127,7 +127,7 @@ class AccountsListViewController: NSViewController {
private func callCompletion(specificWalletAccounts: [SpecificWalletAccount]?) {
if !didCallCompletion {
didCallCompletion = true
let network = selectAccountAction?.network ?? .ethereum
let network = selectAccountAction?.network ?? Networks.ethereum
selectAccountAction?.completion(network, specificWalletAccounts)
}
}
@ -147,18 +147,18 @@ class AccountsListViewController: NSViewController {
networkButton.isHidden = true
} else if networkButton.menu == nil {
let menu = NSMenu()
for mainnet in EthereumNetwork.allMainnets {
for mainnet in Networks.allMainnets {
let item = NSMenuItem(title: mainnet.name, action: #selector(didSelectChain(_:)), keyEquivalent: "")
item.tag = mainnet.id
item.tag = mainnet.chainId
menu.addItem(item)
}
let submenuItem = NSMenuItem()
submenuItem.title = Strings.testnets
let submenu = NSMenu()
for testnet in EthereumNetwork.allTestnets {
for testnet in Networks.allTestnets {
let item = NSMenuItem(title: testnet.name, action: #selector(didSelectChain(_:)), keyEquivalent: "")
item.tag = testnet.id
item.tag = testnet.chainId
submenu.addItem(item)
}
@ -171,7 +171,7 @@ class AccountsListViewController: NSViewController {
let titleItem = NSMenuItem(title: Strings.selectNetworkOptionally, action: nil, keyEquivalent: "")
menu.addItem(titleItem)
if let network = selectAccountAction.network, network != .ethereum {
if let network = selectAccountAction.network, !network.isEthMainnet {
selectNetwork(network)
}
}
@ -259,7 +259,7 @@ class AccountsListViewController: NSViewController {
@objc private func didSelectChain(_ sender: AnyObject) {
guard let menuItem = sender as? NSMenuItem,
let selectedNetwork = EthereumNetwork(rawValue: menuItem.tag) else { return }
let selectedNetwork = Networks.withChainId(menuItem.tag) else { return }
selectNetwork(selectedNetwork)
}

View File

@ -85,7 +85,7 @@ class ApproveTransactionViewController: NSViewController {
}
private func updateInterface() {
if chain != .ethereum {
if !chain.isEthMainnet {
speedContainerStackView.isHidden = true
gweiLabel.isHidden = true
infoTextViewBottomConstraint.constant = 30
@ -94,7 +94,7 @@ class ApproveTransactionViewController: NSViewController {
okButton.isEnabled = transaction.hasFee
enableSpeedConfigurationIfNeeded()
let meta = transaction.description(chain: chain, ethPrice: priceService.currentPrice)
let meta = transaction.description(chain: chain, price: priceService.forNetwork(chain))
if metaTextView.string != meta {
metaTextView.string = meta
}

View File

@ -140,6 +140,9 @@
2C96D3A62763CCA000687301 /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96D3A52763CCA000687301 /* Images.swift */; };
2C96D3A92763D13400687301 /* DataStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96D3A72763D13400687301 /* DataStateView.swift */; };
2C96D3AA2763D13400687301 /* DataStateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C96D3A82763D13400687301 /* DataStateView.xib */; };
2C9B55D12AF2AE4B008BE899 /* BundledNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9B55D02AF2AE4B008BE899 /* BundledNetwork.swift */; };
2C9B55D22AF2AE4B008BE899 /* BundledNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9B55D02AF2AE4B008BE899 /* BundledNetwork.swift */; };
2C9B55D32AF2AE4B008BE899 /* BundledNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9B55D02AF2AE4B008BE899 /* BundledNetwork.swift */; };
2C9F0B6826BDCB2E008FA3D6 /* EthereumNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6726BDCB2E008FA3D6 /* EthereumNetwork.swift */; };
2CAA412526C7CD93009F3535 /* ReviewRequester.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAA412426C7CD93009F3535 /* ReviewRequester.swift */; };
2CB3845A27654EA900A189B9 /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = 2CB3845827654E9700A189B9 /* _locales */; };
@ -180,6 +183,21 @@
2CE0594527640EF10042D844 /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; };
2CE0594627640F470042D844 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC89470269A334A00879245 /* UserDefaults.swift */; };
2CE3D012267F73C00032A62E /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE3D011267F73C00032A62E /* Transaction.swift */; };
2CED86A52AF00BC9006F9E26 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86A42AF00BC9006F9E26 /* main.swift */; };
2CED86B02AF0167F006F9E26 /* EIP155ChainData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86AF2AF0167F006F9E26 /* EIP155ChainData.swift */; };
2CED86B32AF01F99006F9E26 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C603D0126B6E13F00956955 /* String.swift */; };
2CED86B62AF17D5A006F9E26 /* BundledNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */; };
2CED86B72AF17D5A006F9E26 /* BundledNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */; };
2CED86BA2AF1820E006F9E26 /* Nodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B92AF1820E006F9E26 /* Nodes.swift */; };
2CED86BB2AF1820E006F9E26 /* Nodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B92AF1820E006F9E26 /* Nodes.swift */; };
2CED86BF2AF25C32006F9E26 /* Networks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86BE2AF25C32006F9E26 /* Networks.swift */; };
2CED86C02AF25C32006F9E26 /* Networks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86BE2AF25C32006F9E26 /* Networks.swift */; };
2CED86C12AF26114006F9E26 /* bundled-networks.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CED86A92AF00F56006F9E26 /* bundled-networks.json */; };
2CED86C22AF2611D006F9E26 /* bundled-networks.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CED86A92AF00F56006F9E26 /* bundled-networks.json */; };
2CED86C32AF262E6006F9E26 /* Nodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B92AF1820E006F9E26 /* Nodes.swift */; };
2CED86C42AF262E7006F9E26 /* Nodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B92AF1820E006F9E26 /* Nodes.swift */; };
2CED86C52AF26327006F9E26 /* BundledNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */; };
2CED86C62AF26328006F9E26 /* BundledNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */; };
2CEFEB16274D5DCA00CE23BD /* inpage.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CEFEB15274D5DC900CE23BD /* inpage.js */; };
2CF25597275A46D300AE54B9 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C528A15267FA8EB00CA3ADD /* Defaults.swift */; };
2CF25598275A46D600AE54B9 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C901C492689F01700D0926A /* Strings.swift */; };
@ -355,6 +373,9 @@
2C96D3A52763CCA000687301 /* Images.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = "<group>"; };
2C96D3A72763D13400687301 /* DataStateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataStateView.swift; sourceTree = "<group>"; };
2C96D3A82763D13400687301 /* DataStateView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DataStateView.xib; sourceTree = "<group>"; };
2C9931DB2AEEC0E200577C8A /* NetworksListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworksListView.swift; sourceTree = "<group>"; };
2C9B55D02AF2AE4B008BE899 /* BundledNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundledNetwork.swift; sourceTree = "<group>"; };
2C9B55D42AF2B004008BE899 /* nodes-to-bundle.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "nodes-to-bundle.json"; sourceTree = "<group>"; };
2C9F0B6726BDCB2E008FA3D6 /* EthereumNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumNetwork.swift; sourceTree = "<group>"; };
2CAA412426C7CD93009F3535 /* ReviewRequester.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewRequester.swift; sourceTree = "<group>"; };
2CB3844327654BF600A189B9 /* error.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = error.js; path = "web3-provider/error.js"; sourceTree = "<group>"; };
@ -389,6 +410,13 @@
2CE059482764169E0042D844 /* Tokenary iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Tokenary iOS.entitlements"; sourceTree = "<group>"; };
2CE0594B2764DF9A0042D844 /* Safari iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Safari iOS.entitlements"; sourceTree = "<group>"; };
2CE3D011267F73C00032A62E /* Transaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transaction.swift; sourceTree = "<group>"; };
2CED86A22AF00BC9006F9E26 /* tools */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tools; sourceTree = BUILT_PRODUCTS_DIR; };
2CED86A42AF00BC9006F9E26 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
2CED86A92AF00F56006F9E26 /* bundled-networks.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "bundled-networks.json"; sourceTree = "<group>"; };
2CED86AF2AF0167F006F9E26 /* EIP155ChainData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EIP155ChainData.swift; sourceTree = "<group>"; };
2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundledNodes.swift; sourceTree = "<group>"; };
2CED86B92AF1820E006F9E26 /* Nodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nodes.swift; sourceTree = "<group>"; };
2CED86BE2AF25C32006F9E26 /* Networks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networks.swift; sourceTree = "<group>"; };
2CEFEB15274D5DC900CE23BD /* inpage.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = inpage.js; sourceTree = "<group>"; };
2CF255B3275A744000AE54B9 /* PasswordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordViewController.swift; sourceTree = "<group>"; };
2CF255B5275A746000AE54B9 /* AccountsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsListViewController.swift; sourceTree = "<group>"; };
@ -435,6 +463,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
2CED869F2AF00BC9006F9E26 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -483,6 +518,7 @@
2CCEB7A227592A3800768473 /* Safari Shared */,
2C09CBA0273979C1009AD39B /* Safari macOS */,
2CCEB82E27594E2A00768473 /* Safari iOS */,
2CED86A32AF00BC9006F9E26 /* tools */,
2C19953D2674C4B900A8E370 /* Products */,
FB5786212D81829B0FADBD25 /* Pods */,
2A7484A18D772B4233D171DA /* Frameworks */,
@ -496,6 +532,7 @@
2C5FF96F26C84F7B00B32ACC /* Tokenary iOS.app */,
2C09CB9F273979C1009AD39B /* Safari macOS.appex */,
2CCEB82D27594E2A00768473 /* Safari iOS.appex */,
2CED86A22AF00BC9006F9E26 /* tools */,
);
name = Products;
sourceTree = "<group>";
@ -627,9 +664,11 @@
isa = PBXGroup;
children = (
2C1995552674D0F300A8E370 /* Ethereum.swift */,
2CE3D011267F73C00032A62E /* Transaction.swift */,
2C8944CA2AEB0C10006A711F /* EthereumRPC.swift */,
2C9F0B6726BDCB2E008FA3D6 /* EthereumNetwork.swift */,
2CE3D011267F73C00032A62E /* Transaction.swift */,
2CED86BE2AF25C32006F9E26 /* Networks.swift */,
2CED86B92AF1820E006F9E26 /* Nodes.swift */,
);
path = Ethereum;
sourceTree = "<group>";
@ -705,6 +744,14 @@
path = Library;
sourceTree = "<group>";
};
2C9B55D52AF2B8D5008BE899 /* helpers */ = {
isa = PBXGroup;
children = (
2C9B55D42AF2B004008BE899 /* nodes-to-bundle.json */,
);
path = helpers;
sourceTree = "<group>";
};
2CB3844027654A0D00A189B9 /* Resources */ = {
isa = PBXGroup;
children = (
@ -755,6 +802,7 @@
2CF255A4275A483600AE54B9 /* Services */,
2CF2559F275A47B600AE54B9 /* Extension */,
2CD0668826B213BB00728C20 /* Wallets */,
2CED86B12AF01DFD006F9E26 /* Views */,
2CF25596275A468B00AE54B9 /* Models */,
2C8944D02AEC34F2006A711F /* Utilities */,
2CF255AF275A490600AE54B9 /* Supporting Files */,
@ -808,6 +856,43 @@
path = Wallets;
sourceTree = "<group>";
};
2CED86A32AF00BC9006F9E26 /* tools */ = {
isa = PBXGroup;
children = (
2CED86A42AF00BC9006F9E26 /* main.swift */,
2CED86B42AF17BF0006F9E26 /* bundled */,
2CED86BD2AF225A4006F9E26 /* models */,
2C9B55D52AF2B8D5008BE899 /* helpers */,
);
path = tools;
sourceTree = "<group>";
};
2CED86B12AF01DFD006F9E26 /* Views */ = {
isa = PBXGroup;
children = (
2C9931DB2AEEC0E200577C8A /* NetworksListView.swift */,
);
path = Views;
sourceTree = "<group>";
};
2CED86B42AF17BF0006F9E26 /* bundled */ = {
isa = PBXGroup;
children = (
2CED86A92AF00F56006F9E26 /* bundled-networks.json */,
2CED86B52AF17D5A006F9E26 /* BundledNodes.swift */,
);
path = bundled;
sourceTree = "<group>";
};
2CED86BD2AF225A4006F9E26 /* models */ = {
isa = PBXGroup;
children = (
2CED86AF2AF0167F006F9E26 /* EIP155ChainData.swift */,
2C9B55D02AF2AE4B008BE899 /* BundledNetwork.swift */,
);
path = models;
sourceTree = "<group>";
};
2CF25596275A468B00AE54B9 /* Models */ = {
isa = PBXGroup;
children = (
@ -962,13 +1047,29 @@
productReference = 2CCEB82D27594E2A00768473 /* Safari iOS.appex */;
productType = "com.apple.product-type.app-extension";
};
2CED86A12AF00BC9006F9E26 /* tools */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2CED86A82AF00BC9006F9E26 /* Build configuration list for PBXNativeTarget "tools" */;
buildPhases = (
2CED869E2AF00BC9006F9E26 /* Sources */,
2CED869F2AF00BC9006F9E26 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = tools;
productName = tools;
productReference = 2CED86A22AF00BC9006F9E26 /* tools */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
2C1995342674C4B900A8E370 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1310;
LastSwiftUpdateCheck = 1500;
LastUpgradeCheck = 1240;
TargetAttributes = {
2C09CB9E273979C1009AD39B = {
@ -983,6 +1084,9 @@
2CCEB82C27594E2A00768473 = {
CreatedOnToolsVersion = 13.1;
};
2CED86A12AF00BC9006F9E26 = {
CreatedOnToolsVersion = 15.0.1;
};
};
};
buildConfigurationList = 2C1995372674C4B900A8E370 /* Build configuration list for PBXProject "Tokenary" */;
@ -1002,6 +1106,7 @@
2C5FF96E26C84F7B00B32ACC /* Tokenary iOS */,
2C09CB9E273979C1009AD39B /* Safari macOS */,
2CCEB82C27594E2A00768473 /* Safari iOS */,
2CED86A12AF00BC9006F9E26 /* tools */,
);
};
/* End PBXProject section */
@ -1025,6 +1130,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2CED86C12AF26114006F9E26 /* bundled-networks.json in Resources */,
2C6B964F26B9D98C00D2C819 /* Colors.xcassets in Resources */,
2C1995442674C4BA00A8E370 /* Assets.xcassets in Resources */,
2C1995472674C4BA00A8E370 /* Main.storyboard in Resources */,
@ -1036,6 +1142,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2CED86C22AF2611D006F9E26 /* bundled-networks.json in Resources */,
2C96D3AA2763D13400687301 /* DataStateView.xib in Resources */,
2C5FF97E26C84F7C00B32ACC /* LaunchScreen.storyboard in Resources */,
2C40709527667A8600AB3D55 /* ImageWithLabelTableViewCell.xib in Resources */,
@ -1202,11 +1309,13 @@
2C2AA1D728AFB1AD00E35DBF /* MultipleResponseToExtension.swift in Sources */,
2C773F5E27450B97007B04E7 /* ExtensionBridge.swift in Sources */,
2C264BDE27B5AC5400234393 /* EthereumResponseToExtension.swift in Sources */,
2CED86BA2AF1820E006F9E26 /* Nodes.swift in Sources */,
2CC8C5AC276A7EF70083FB1B /* EthereumNetwork.swift in Sources */,
2C264BC327B2F2C100234393 /* EthereumSafariRequest.swift in Sources */,
2C264BBE27B2F25E00234393 /* SafariRequest.swift in Sources */,
2C09CBA2273979C1009AD39B /* SafariWebExtensionHandler.swift in Sources */,
2C773F63274523DC007B04E7 /* ResponseToExtension.swift in Sources */,
2CED86B62AF17D5A006F9E26 /* BundledNodes.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1239,8 +1348,10 @@
2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */,
2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */,
2C603D0226B6E13F00956955 /* String.swift in Sources */,
2CED86C32AF262E6006F9E26 /* Nodes.swift in Sources */,
2C264BC127B2F2C100234393 /* EthereumSafariRequest.swift in Sources */,
2C264BD027B2F30C00234393 /* UnknownSafariRequest.swift in Sources */,
2CED86BF2AF25C32006F9E26 /* Networks.swift in Sources */,
2C134BA627553EC500DAFBDB /* Browser.swift in Sources */,
2CC89471269A334A00879245 /* UserDefaults.swift in Sources */,
2C78F8282683BDCC00C10670 /* Alert.swift in Sources */,
@ -1250,6 +1361,7 @@
2C4768A9282598C5005E8D4D /* CoinDerivationCellView.swift in Sources */,
2CB4031D281D745D00BAEBEE /* NSTableView.swift in Sources */,
2CD0B3F726AC619900488D92 /* AddAccountOptionCellView.swift in Sources */,
2CED86C52AF26327006F9E26 /* BundledNodes.swift in Sources */,
2C8944C52AEAFF97006A711F /* FixedWidthInteger.swift in Sources */,
0D059AD226C2796200EE3023 /* ApprovalSubject.swift in Sources */,
2C1995422674C4B900A8E370 /* ImportViewController.swift in Sources */,
@ -1280,6 +1392,7 @@
2C8944CE2AEC34EB006A711F /* Blockies.swift in Sources */,
2C8A09DF267579EA00993638 /* AccountsListViewController.swift in Sources */,
2C917429267D2A6E00049075 /* Keychain.swift in Sources */,
2C9B55D12AF2AE4B008BE899 /* BundledNetwork.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1298,6 +1411,7 @@
2C40709027667A6600AB3D55 /* MultilineLabelTableViewCell.swift in Sources */,
2CF255A6275A48BB00AE54B9 /* GasService.swift in Sources */,
2C96D392276232A300687301 /* UITableView.swift in Sources */,
2CED86C62AF26328006F9E26 /* BundledNodes.swift in Sources */,
2CF255A5275A48BB00AE54B9 /* ReviewRequester.swift in Sources */,
2CF255B6275A746000AE54B9 /* AccountsListViewController.swift in Sources */,
2C96D3A42763C6A800687301 /* UIView.swift in Sources */,
@ -1313,9 +1427,11 @@
2CC6EF0D275E64810040CC62 /* UIViewController.swift in Sources */,
2C264BDD27B5AC5400234393 /* EthereumResponseToExtension.swift in Sources */,
2CF255A9275A48BB00AE54B9 /* Keychain.swift in Sources */,
2CED86C42AF262E7006F9E26 /* Nodes.swift in Sources */,
2CF255A7275A48BB00AE54B9 /* PriceService.swift in Sources */,
2CF25598275A46D600AE54B9 /* Strings.swift in Sources */,
2C4768B52826ED83005E8D4D /* CoinType.swift in Sources */,
2CED86C02AF25C32006F9E26 /* Networks.swift in Sources */,
2CF255AE275A48CF00AE54B9 /* Transaction.swift in Sources */,
2C96D38F2762317300687301 /* AccountTableViewCell.swift in Sources */,
2C264BEC27B6B50700234393 /* DappRequestProcessor.swift in Sources */,
@ -1330,6 +1446,7 @@
2C8ED8DD2AEADDC400818D74 /* BigInt.swift in Sources */,
2C96D3A62763CCA000687301 /* Images.swift in Sources */,
2C264BD127B2F30C00234393 /* UnknownSafariRequest.swift in Sources */,
2C9B55D22AF2AE4B008BE899 /* BundledNetwork.swift in Sources */,
2C96D39827623EC600687301 /* URL.swift in Sources */,
2CF255AD275A48CF00AE54B9 /* EthereumNetwork.swift in Sources */,
2CF2559C275A477F00AE54B9 /* ApprovalSubject.swift in Sources */,
@ -1372,11 +1489,24 @@
2C2AA1D828AFB1AD00E35DBF /* MultipleResponseToExtension.swift in Sources */,
2CE0594327640EAB0042D844 /* ExtensionBridge.swift in Sources */,
2C264BDF27B5AC5400234393 /* EthereumResponseToExtension.swift in Sources */,
2CED86BB2AF1820E006F9E26 /* Nodes.swift in Sources */,
2CC8C5AD276A7EF80083FB1B /* EthereumNetwork.swift in Sources */,
2C264BC427B2F2C100234393 /* EthereumSafariRequest.swift in Sources */,
2C264BBF27B2F25E00234393 /* SafariRequest.swift in Sources */,
2CE0593F27640E300042D844 /* SafariWebExtensionHandler.swift in Sources */,
2CE0594527640EF10042D844 /* ResponseToExtension.swift in Sources */,
2CED86B72AF17D5A006F9E26 /* BundledNodes.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2CED869E2AF00BC9006F9E26 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2C9B55D32AF2AE4B008BE899 /* BundledNetwork.swift in Sources */,
2CED86B02AF0167F006F9E26 /* EIP155ChainData.swift in Sources */,
2CED86A52AF00BC9006F9E26 /* main.swift in Sources */,
2CED86B32AF01F99006F9E26 /* String.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1430,7 +1560,7 @@
CODE_SIGN_ENTITLEMENTS = "Safari macOS/Safari.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@ -1443,7 +1573,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.4;
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@ -1464,7 +1594,7 @@
CODE_SIGN_ENTITLEMENTS = "Safari macOS/Safari.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@ -1477,7 +1607,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.4;
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@ -1617,7 +1747,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/Tokenary macOS/Supporting Files/Info.plist";
@ -1626,7 +1756,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.4;
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
PRODUCT_BUNDLE_IDENTIFIER = mac.tokenary.io;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1645,7 +1775,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/Tokenary macOS/Supporting Files/Info.plist";
@ -1654,7 +1784,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.4;
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
PRODUCT_BUNDLE_IDENTIFIER = mac.tokenary.io;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1671,7 +1801,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "Tokenary iOS/Tokenary iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
INFOPLIST_FILE = "Tokenary iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -1679,7 +1809,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
PRODUCT_BUNDLE_IDENTIFIER = mac.tokenary.io;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@ -1700,7 +1830,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "Tokenary iOS/Tokenary iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
INFOPLIST_FILE = "Tokenary iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -1708,7 +1838,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
PRODUCT_BUNDLE_IDENTIFIER = mac.tokenary.io;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@ -1727,7 +1857,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = "Safari iOS/Safari iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Safari iOS/Info.plist";
@ -1739,7 +1869,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@ -1761,7 +1891,7 @@
CODE_SIGN_ENTITLEMENTS = "Safari iOS/Safari iOS.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 63;
CURRENT_PROJECT_VERSION = 64;
DEVELOPMENT_TEAM = XWNXDSM6BU;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Safari iOS/Info.plist";
@ -1773,7 +1903,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.0.19;
MARKETING_VERSION = 2.0.20;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@ -1790,6 +1920,41 @@
};
name = Release;
};
2CED86A62AF00BC9006F9E26 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
2CED86A72AF00BC9006F9E26 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = XWNXDSM6BU;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -1838,6 +2003,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2CED86A82AF00BC9006F9E26 /* Build configuration list for PBXNativeTarget "tools" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2CED86A62AF00BC9006F9E26 /* Debug */,
2CED86A72AF00BC9006F9E26 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 2C1995342674C4B900A8E370 /* Project object */;

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2CED86A12AF00BC9006F9E26"
BuildableName = "tools"
BlueprintName = "tools"
ReferencedContainer = "container:Tokenary.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "YES"
customWorkingDirectory = "$(SRCROOT)"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
viewDebuggingEnabled = "No">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2CED86A12AF00BC9006F9E26"
BuildableName = "tools"
BlueprintName = "tools"
ReferencedContainer = "container:Tokenary.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2CED86A12AF00BC9006F9E26"
BuildableName = "tools"
BlueprintName = "tools"
ReferencedContainer = "container:Tokenary.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,77 @@
import Foundation
struct BundledNodes {
static let dict: [Int: String] = [
1: "mainnet.infura.io/v3/",
5: "goerli.infura.io/v3/",
10: "optimism-mainnet.infura.io/v3/",
25: "evm.cronos.org",
56: "bsc-dataseed1.bnbchain.org",
66: "exchainrpc.okex.org",
69: "kovan.optimism.io/",
77: "sokol.poa.network",
97: "data-seed-prebsc-1-s1.bnbchain.org:8545",
99: "core.poa.network",
100: "rpc.gnosischain.com",
122: "rpc.fuse.io",
128: "http-mainnet.hecochain.com",
137: "polygon-mainnet.infura.io/v3/",
200: "arbitrum.xdaichain.com/",
204: "opbnb-mainnet-rpc.bnbchain.org",
250: "rpc.ftm.tools",
280: "testnet.era.zksync.dev",
288: "mainnet.boba.network",
314: "api.node.glif.io/",
324: "mainnet.era.zksync.io",
338: "evm-t3.cronos.org",
420: "goerli.optimism.io",
424: "rpc.publicgoods.network",
1001: "api.baobab.klaytn.net:8651",
1088: "andromeda.metis.io/?owner=1088",
1101: "zkevm-rpc.com",
1284: "rpc.api.moonbeam.network",
1285: "rpc.api.moonriver.moonbeam.network",
1442: "rpc.public.zkevm-test.net",
2221: "evm.testnet.kava.io",
2222: "evm.kava.io",
4002: "rpc.testnet.fantom.network",
4337: "subnets.avax.network/beam/mainnet/rpc",
5000: "rpc.mantle.xyz",
5001: "rpc.testnet.mantle.xyz",
5611: "opbnb-testnet-rpc.bnbchain.org",
7700: "canto.slingshot.finance",
8217: "1rpc.io/klay",
8453: "mainnet.base.org/",
10200: "rpc.chiadochain.net",
42161: "arbitrum-mainnet.infura.io/v3/",
42170: "nova.arbitrum.io/rpc",
42220: "forno.celo.org",
43113: "api.avax-test.network/ext/bc/C/rpc",
43114: "api.avax.network/ext/bc/C/rpc",
43288: "avax.boba.network",
44787: "alfajores-forno.celo-testnet.org",
58008: "sepolia.publicgoods.network",
59140: "rpc.goerli.linea.build",
59144: "rpc.linea.build",
64240: "rpcapi.sonic.fantom.network/",
80001: "rpc-mumbai.maticvigil.com",
84531: "goerli.base.org",
84532: "sepolia.base.org",
421613: "goerli-rollup.arbitrum.io/rpc",
421614: "sepolia-rollup.arbitrum.io/rpc",
534351: "sepolia-rpc.scroll.io",
534352: "rpc.scroll.io",
7777777: "rpc.zora.energy/",
11155111: "rpc.sepolia.org",
245022926: "devnet.neonevm.org",
245022934: "neon-proxy-mainnet.solana.p2p.org/",
999999999: "sepolia.rpc.zora.energy",
1313161554: "mainnet.aurora.dev",
1313161555: "testnet.aurora.dev/",
1666600000: "api.harmony.one",
11297108099: "palm-testnet.infura.io/v3/",
11297108109: "palm-mainnet.infura.io/v3/"
]
}

View File

@ -0,0 +1,326 @@
{
"1" : {
"n" : "Ethereum",
"s" : "ETH",
"o" : true
},
"5" : {
"n" : "Goerli",
"s" : "ETH",
"t" : true
},
"10" : {
"n" : "Optimism",
"s" : "ETH",
"o" : true
},
"25" : {
"n" : "Cronos",
"s" : "CRO"
},
"56" : {
"n" : "BNB Chain",
"s" : "BNB",
"o" : true
},
"66" : {
"n" : "OKTC",
"s" : "OKT"
},
"69" : {
"n" : "Optimism Kovan",
"s" : "ETH",
"t" : true
},
"77" : {
"n" : "POA Network Sokol",
"s" : "SPOA",
"t" : true
},
"97" : {
"n" : "BNB Chain Testnet",
"s" : "tBNB",
"t" : true
},
"99" : {
"n" : "POA Network",
"s" : "POA"
},
"100" : {
"n" : "Gnosis",
"s" : "xDai"
},
"122" : {
"n" : "Fuse",
"s" : "FUSE"
},
"128" : {
"n" : "Huobi ECO Chain",
"s" : "HT"
},
"137" : {
"n" : "Polygon",
"s" : "MATIC",
"o" : true
},
"200" : {
"n" : "Arbitrum on xDai",
"s" : "xDai"
},
"204" : {
"n" : "opBNB",
"s" : "BNB",
"o" : true
},
"250" : {
"n" : "Fantom Opera",
"s" : "FTM",
"o" : true
},
"280" : {
"n" : "zkSync Era Testnet",
"s" : "ETH",
"t" : true
},
"288" : {
"n" : "Boba",
"s" : "ETH",
"o" : true
},
"314" : {
"n" : "Filecoin",
"s" : "FIL"
},
"324" : {
"n" : "zkSync Era",
"s" : "ETH",
"o" : true
},
"338" : {
"n" : "Cronos Testnet",
"s" : "TCRO",
"t" : true
},
"420" : {
"n" : "Optimism Goerli",
"s" : "ETH",
"t" : true
},
"424" : {
"n" : "Public Goods Network",
"s" : "ETH",
"o" : true
},
"1001" : {
"n" : "Klaytn Baobab",
"s" : "KLAY",
"t" : true
},
"1088" : {
"n" : "Metis Andromeda",
"s" : "METIS"
},
"1101" : {
"n" : "Polygon zkEVM",
"s" : "ETH",
"o" : true
},
"1284" : {
"n" : "Moonbeam",
"s" : "GLMR"
},
"1285" : {
"n" : "Moonriver",
"s" : "MOVR"
},
"1442" : {
"n" : "Polygon zkEVM Testnet",
"s" : "ETH",
"t" : true
},
"2221" : {
"n" : "Kava Testnet",
"s" : "TKAVA",
"t" : true
},
"2222" : {
"n" : "Kava",
"s" : "KAVA"
},
"4002" : {
"n" : "Fantom Testnet",
"s" : "FTM",
"t" : true
},
"4337" : {
"n" : "Beam",
"s" : "BEAM"
},
"5000" : {
"n" : "Mantle",
"s" : "MNT"
},
"5001" : {
"n" : "Mantle Testnet",
"s" : "MNT",
"t" : true
},
"5611" : {
"n" : "opBNB Testnet",
"s" : "tBNB",
"t" : true
},
"7700" : {
"n" : "Canto",
"s" : "CANTO"
},
"8217" : {
"n" : "Klaytn",
"s" : "KLAY"
},
"8453" : {
"n" : "Base",
"s" : "ETH",
"o" : true
},
"10200" : {
"n" : "Gnosis Chiado",
"s" : "xDai",
"t" : true
},
"42161" : {
"n" : "Arbitrum One",
"s" : "ETH",
"o" : true
},
"42170" : {
"n" : "Arbitrum Nova",
"s" : "ETH",
"o" : true
},
"42220" : {
"n" : "Celo",
"s" : "CELO"
},
"43113" : {
"n" : "Avalanche Fuji",
"s" : "AVAX",
"t" : true
},
"43114" : {
"n" : "Avalanche",
"s" : "AVAX",
"o" : true
},
"43288" : {
"n" : "Boba Avax",
"s" : "BOBA"
},
"44787" : {
"n" : "Celo Alfajores Testnet",
"s" : "CELO",
"t" : true
},
"58008" : {
"n" : "Public Goods Network Sepolia",
"s" : "ETH",
"t" : true
},
"59140" : {
"n" : "Linea Testnet",
"s" : "ETH",
"t" : true
},
"59144" : {
"n" : "Linea",
"s" : "ETH",
"o" : true
},
"64240" : {
"n" : "Fantom Sonic Open",
"s" : "FTM",
"t" : true
},
"80001" : {
"n" : "Polygon Mumbai",
"s" : "MATIC",
"t" : true
},
"84531" : {
"n" : "Base Goerli",
"s" : "ETH",
"t" : true
},
"84532" : {
"n" : "Base Sepolia",
"s" : "ETH",
"t" : true
},
"421613" : {
"n" : "Arbitrum Goerli",
"s" : "AGOR",
"t" : true
},
"421614" : {
"n" : "Arbitrum Sepolia",
"s" : "ETH",
"t" : true
},
"534351" : {
"n" : "Scroll Sepolia",
"s" : "ETH",
"t" : true
},
"534352" : {
"n" : "Scroll",
"s" : "ETH",
"o" : true
},
"7777777" : {
"n" : "Zora",
"s" : "ETH",
"o" : true
},
"11155111" : {
"n" : "Sepolia",
"s" : "ETH",
"t" : true
},
"245022926" : {
"n" : "Neon EVM DevNet",
"s" : "NEON",
"t" : true
},
"245022934" : {
"n" : "Neon EVM",
"s" : "NEON"
},
"999999999" : {
"n" : "Zora Sepolia",
"s" : "ETH",
"t" : true
},
"1313161554" : {
"n" : "Aurora",
"s" : "ETH",
"o" : true
},
"1313161555" : {
"n" : "Aurora Testnet",
"s" : "ETH",
"t" : true
},
"1666600000" : {
"n" : "Harmony",
"s" : "ONE"
},
"11297108099" : {
"n" : "Palm Testnet",
"s" : "PALM",
"t" : true
},
"11297108109" : {
"n" : "Palm",
"s" : "PALM"
}
}

View File

@ -0,0 +1,71 @@
{
"1" : "mainnet.infura.io/v3/",
"5" : "goerli.infura.io/v3/",
"10" : "optimism-mainnet.infura.io/v3/",
"25" : "evm.cronos.org",
"56" : "bsc-dataseed1.bnbchain.org",
"66" : "exchainrpc.okex.org",
"69" : "kovan.optimism.io/",
"77" : "sokol.poa.network",
"97" : "data-seed-prebsc-1-s1.bnbchain.org:8545",
"99" : "core.poa.network",
"100" : "rpc.gnosischain.com",
"122" : "rpc.fuse.io",
"128" : "http-mainnet.hecochain.com",
"137" : "polygon-mainnet.infura.io/v3/",
"200" : "arbitrum.xdaichain.com/",
"204" : "opbnb-mainnet-rpc.bnbchain.org",
"250" : "rpc.ftm.tools",
"280" : "testnet.era.zksync.dev",
"288" : "mainnet.boba.network",
"314" : "api.node.glif.io/",
"324" : "mainnet.era.zksync.io",
"338" : "evm-t3.cronos.org",
"420" : "goerli.optimism.io",
"424" : "rpc.publicgoods.network",
"1001" : "api.baobab.klaytn.net:8651",
"1088" : "andromeda.metis.io/?owner=1088",
"1101" : "zkevm-rpc.com",
"1284" : "rpc.api.moonbeam.network",
"1285" : "rpc.api.moonriver.moonbeam.network",
"1442" : "rpc.public.zkevm-test.net",
"2221" : "evm.testnet.kava.io",
"2222" : "evm.kava.io",
"4002" : "rpc.testnet.fantom.network",
"4337" : "subnets.avax.network/beam/mainnet/rpc",
"5000" : "rpc.mantle.xyz",
"5001" : "rpc.testnet.mantle.xyz",
"5611" : "opbnb-testnet-rpc.bnbchain.org",
"7700" : "canto.slingshot.finance",
"8217" : "1rpc.io/klay",
"8453" : "mainnet.base.org/",
"10200" : "rpc.chiadochain.net",
"42161" : "arbitrum-mainnet.infura.io/v3/",
"42170" : "nova.arbitrum.io/rpc",
"42220" : "forno.celo.org",
"43113" : "api.avax-test.network/ext/bc/C/rpc",
"43114" : "api.avax.network/ext/bc/C/rpc",
"43288" : "avax.boba.network",
"44787" : "alfajores-forno.celo-testnet.org",
"58008" : "sepolia.publicgoods.network",
"59140" : "rpc.goerli.linea.build",
"59144" : "rpc.linea.build",
"64240" : "rpcapi.sonic.fantom.network/",
"80001" : "rpc-mumbai.maticvigil.com",
"84531" : "goerli.base.org",
"84532" : "sepolia.base.org",
"421613" : "goerli-rollup.arbitrum.io/rpc",
"421614" : "sepolia-rollup.arbitrum.io/rpc",
"534351" : "sepolia-rpc.scroll.io",
"534352" : "rpc.scroll.io",
"7777777" : "rpc.zora.energy/",
"11155111" : "rpc.sepolia.org",
"245022926" : "devnet.neonevm.org",
"245022934" : "neon-proxy-mainnet.solana.p2p.org/",
"999999999" : "sepolia.rpc.zora.energy",
"1313161554" : "mainnet.aurora.dev",
"1313161555" : "testnet.aurora.dev/",
"1666600000" : "api.harmony.one",
"11297108099" : "palm-testnet.infura.io/v3/",
"11297108109" : "palm-mainnet.infura.io/v3/"
}

87
tools/main.swift Normal file
View File

@ -0,0 +1,87 @@
// Copyright © 2023 Tokenary. All rights reserved.
import Foundation
let semaphore = DispatchSemaphore(value: 0)
let projectDir = FileManager.default.currentDirectoryPath
let base = "\(projectDir)/tools/"
let bundledNetworksFileURL = URL(fileURLWithPath: base + "bundled/bundled-networks.json")
let bundledNodesFileURL = URL(fileURLWithPath: base + "bundled/BundledNodes.swift")
let nodesToBundleFileURL = URL(fileURLWithPath: base + "helpers/nodes-to-bundle.json")
let https = "https://"
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes, .sortedKeys]
func fetchChains(completion: @escaping ([EIP155ChainData]) -> Void) {
URLSession.shared.dataTask(with: URL(string: "https://chainid.network/chains.json")!) { (data, _, _) in
completion(try! JSONDecoder().decode([EIP155ChainData].self, from: data!))
}.resume()
}
fetchChains { chains in
let currentNetworksData = try! Data(contentsOf: bundledNetworksFileURL)
let currentNodesData = try! Data(contentsOf: nodesToBundleFileURL)
let currentNetworks = try! JSONDecoder().decode([Int: BundledNetwork].self, from: currentNetworksData)
let currentNodes = try! JSONDecoder().decode([String: String].self, from: currentNodesData)
let currentIds = Set(currentNetworks.keys)
let newChainsIds = Set([1284, 1285, 288, 43288, 25, 338])
let newChains = chains.filter { chain in
let isEIP3091 = chain.explorers?.contains(where: { $0.standard == "EIP3091" }) == true
let allowNoEIP3091 = true
if newChainsIds.contains(chain.chainId) &&
!currentIds.contains(chain.chainId) &&
chain.rpc.contains(where: { $0.hasPrefix(https) }) &&
chain.redFlags == nil &&
chain.status != "deprecated" &&
chain.nativeCurrency.decimals == 18 &&
(isEIP3091 || allowNoEIP3091) {
return true
} else {
return false
}
}
var updatedNetworks = currentNetworks
var updatedNodes = currentNodes
newChains.forEach { chain in
updatedNetworks[chain.chainId] = BundledNetwork(name: chain.name, symbol: chain.nativeCurrency.symbol, isTest: true)
updatedNodes[String(chain.chainId)] = String(chain.rpc.first(where: { $0.hasPrefix(https) })!.dropFirst(https.count))
}
let data = (try! encoder.encode(updatedNetworks)) + "\n".data(using: .utf8)!
try! data.write(to: bundledNetworksFileURL)
updateNodesFiles(nodes: updatedNodes)
semaphore.signal()
}
func updateNodesFiles(nodes: [String: String]) {
let dictData = try! JSONSerialization.data(withJSONObject: nodes, options: [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]) + "\n".data(using: .utf8)!
try! dictData.write(to: nodesToBundleFileURL)
let dictString = nodes.sorted(by: { Int($0.key)! < Int($1.key)! }).map { "\($0.key): \"\($0.value)\"" }.joined(separator: ",\n ")
let contents = """
import Foundation
struct BundledNodes {
static let dict: [Int: String] = [
\(dictString)
]
}
"""
try! contents.data(using: .utf8)?.write(to: bundledNodesFileURL)
}
semaphore.wait()
print("🟢 all done")

View File

@ -0,0 +1,46 @@
// Copyright © 2023 Tokenary. All rights reserved.
import Foundation
struct BundledNetwork: Codable {
let name: String
let symbol: String
let isTest: Bool
let okToShowPriceForSymbol: Bool
private enum CodingKeys: String, CodingKey {
case name = "n"
case symbol = "s"
case isTest = "t"
case okToShowPriceForSymbol = "o"
}
init(name: String, symbol: String, isTest: Bool, okToShowPriceForSymbol: Bool) {
self.name = name
self.symbol = symbol
self.isTest = isTest
self.okToShowPriceForSymbol = okToShowPriceForSymbol
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
symbol = try container.decode(String.self, forKey: .symbol)
isTest = try container.decodeIfPresent(Bool.self, forKey: .isTest) ?? false
if isTest {
okToShowPriceForSymbol = false
} else {
okToShowPriceForSymbol = try container.decodeIfPresent(Bool.self, forKey: .okToShowPriceForSymbol) ?? false
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(symbol, forKey: .symbol)
if isTest { try container.encode(isTest, forKey: .isTest) }
if okToShowPriceForSymbol { try container.encode(okToShowPriceForSymbol, forKey: .okToShowPriceForSymbol) }
}
}

View File

@ -0,0 +1,63 @@
// Copyright © 2023 Tokenary. All rights reserved.
import Foundation
// https://github.com/ethereum-lists/chains/blob/master/tools/schema/chainSchema.json
struct EIP155ChainData: Codable {
let name: String // Name of the Network
let shortName: String
let chain: String
let chainId: Int
let networkId: Int
let rpc: [String]
let faucets: [String]
let infoURL: String
let nativeCurrency: NativeCurrency
let title: String?
let icon: String? // Icon type
let features: [Feature]?
let slip44: Int?
let ens: ENS?
let explorers: [Explorer]?
let parent: Parent?
let status: String? // Chain status
let redFlags: [RedFlag]?
struct NativeCurrency: Codable {
let name: String // Name of the Native Currency
let symbol: String // Symbol of the Native Currency
let decimals: Int // Decimal points supported
}
struct Feature: Codable {
let name: String // Feature name - e.g. EIP155
}
struct ENS: Codable {
let registry: String
}
struct Explorer: Codable {
let name: String
let url: String
let standard: String? // EIP3091 or none
}
struct Parent: Codable {
let type: String
let chain: String
let bridges: [Bridge]?
struct Bridge: Codable {
let url: String
}
}
enum RedFlag: String, Codable {
case reusedChainId = "reusedChainId"
}
}