├── lil wallet ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── Frame 14-20@1x.png │ │ ├── Frame 14-20@2x.png │ │ ├── Frame 14-20@3x.png │ │ ├── Frame 14-29@1x.png │ │ ├── Frame 14-29@2x.png │ │ ├── Frame 14-29@3x.png │ │ ├── Frame 14-40@1x.png │ │ ├── Frame 14-40@2x.png │ │ ├── Frame 14-40@3x.png │ │ ├── Frame 14-60@2x.png │ │ ├── Frame 14-60@3x.png │ │ ├── Frame 14-76@1x.png │ │ ├── Frame 14-76@2x.png │ │ ├── Frame 14-1024@1x.png │ │ ├── Frame 14-29@1x-1.png │ │ ├── Frame 14-29@2x-1.png │ │ ├── Frame 14-40@1x-1.png │ │ ├── Frame 14-40@2x-1.png │ │ ├── Frame 14-83.5@2x.png │ │ └── Contents.json │ └── AccentColor.colorset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── lil_wallet.xcdatamodeld │ ├── .xccurrentversion │ └── lil_wallet.xcdatamodel │ │ └── contents ├── lil_walletApp.swift ├── Persistence.swift ├── Components │ ├── AvatarView.swift │ ├── CryptoListItem.swift │ ├── ObjectGridItem.swift │ └── ActivityListItem.swift ├── Views │ ├── ActivityView.swift │ ├── Detail │ │ ├── CryptoDetailView.swift │ │ ├── ObjectDetailView.swift │ │ └── ActivityDetailView.swift │ ├── Settings │ │ ├── WalletsView.swift │ │ ├── SettingsView.swift │ │ └── AddWalletView.swift │ └── Tabs │ │ ├── ObjectsView.swift │ │ └── CoinsView.swift ├── ContentView.swift └── Data │ └── Helpers.swift ├── Pods ├── Target Support Files │ ├── Starscream │ │ ├── Starscream.modulemap │ │ ├── Starscream-dummy.m │ │ ├── Starscream-prefix.pch │ │ ├── Starscream-umbrella.h │ │ ├── Starscream.debug.xcconfig │ │ ├── Starscream.release.xcconfig │ │ └── Starscream-Info.plist │ ├── Pods-lil wallet │ │ ├── Pods-lil wallet.modulemap │ │ ├── Pods-lil wallet-dummy.m │ │ ├── Pods-lil wallet-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-lil wallet-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-lil wallet-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-lil wallet-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-lil wallet-umbrella.h │ │ ├── Pods-lil wallet.debug.xcconfig │ │ ├── Pods-lil wallet.release.xcconfig │ │ └── Pods-lil wallet-Info.plist │ └── Socket.IO-Client-Swift │ │ ├── Socket.IO-Client-Swift.modulemap │ │ ├── Socket.IO-Client-Swift-dummy.m │ │ ├── Socket.IO-Client-Swift-prefix.pch │ │ ├── Socket.IO-Client-Swift-umbrella.h │ │ ├── Socket.IO-Client-Swift.debug.xcconfig │ │ ├── Socket.IO-Client-Swift.release.xcconfig │ │ └── Socket.IO-Client-Swift-Info.plist ├── Manifest.lock ├── Starscream │ └── Sources │ │ ├── Engine │ │ ├── Engine.swift │ │ └── NativeEngine.swift │ │ ├── Compression │ │ └── Compression.swift │ │ ├── Security │ │ ├── Security.swift │ │ └── FoundationSecurity.swift │ │ ├── Server │ │ └── Server.swift │ │ ├── Transport │ │ ├── Transport.swift │ │ └── TCPTransport.swift │ │ ├── DataBytes │ │ └── Data+Extensions.swift │ │ ├── Framer │ │ ├── FoundationHTTPServerHandler.swift │ │ ├── FrameCollector.swift │ │ ├── FoundationHTTPHandler.swift │ │ ├── StringHTTPHandler.swift │ │ └── HTTPHandler.swift │ │ └── Starscream │ │ └── WebSocket.swift ├── Pods.xcodeproj │ └── xcuserdata │ │ └── jordansinger.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ ├── Starscream.xcscheme │ │ ├── Pods-lil wallet.xcscheme │ │ └── Socket.IO-Client-Swift.xcscheme └── Socket.IO-Client-Swift │ ├── Source │ └── SocketIO │ │ ├── Engine │ │ ├── SocketEnginePacketType.swift │ │ ├── SocketEngineClient.swift │ │ └── SocketEngineWebsocket.swift │ │ ├── Client │ │ ├── SocketAnyEvent.swift │ │ ├── SocketEventHandler.swift │ │ ├── SocketIOStatus.swift │ │ ├── SocketIOClientConfiguration.swift │ │ └── SocketRawView.swift │ │ ├── Util │ │ ├── SocketStringReader.swift │ │ ├── SocketLogger.swift │ │ ├── SocketTypes.swift │ │ └── SocketExtensions.swift │ │ ├── Ack │ │ ├── SocketAckManager.swift │ │ └── SocketAckEmitter.swift │ │ ├── Manager │ │ └── SocketManagerSpec.swift │ │ └── Parse │ │ └── SocketParsable.swift │ └── README.md ├── lil wallet.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── jordansinger.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── jordansinger.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── xcshareddata │ └── xcschemes │ └── lil wallet.xcscheme ├── lil wallet.xcworkspace ├── xcuserdata │ └── jordansinger.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Podfile ├── Podfile.lock └── README.md /lil wallet/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lil wallet/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@1x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@2x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-20@3x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@1x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@2x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@3x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@1x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@2x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@3x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-60@2x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-60@3x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-76@1x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-76@2x.png -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream.modulemap: -------------------------------------------------------------------------------- 1 | framework module Starscream { 2 | umbrella header "Starscream-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-1024@1x.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@1x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@1x-1.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-29@2x-1.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@1x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@1x-1.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-40@2x-1.png -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet/Assets.xcassets/AppIcon.appiconset/Frame 14-83.5@2x.png -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Starscream : NSObject 3 | @end 4 | @implementation PodsDummy_Starscream 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_lil_wallet { 2 | umbrella header "Pods-lil wallet-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_lil_wallet : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_lil_wallet 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift.modulemap: -------------------------------------------------------------------------------- 1 | framework module SocketIO { 2 | umbrella header "Socket.IO-Client-Swift-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /lil wallet.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketIO.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketIO.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework -------------------------------------------------------------------------------- /lil wallet.xcworkspace/xcuserdata/jordansinger.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet.xcworkspace/xcuserdata/jordansinger.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Socket_IO_Client_Swift : NSObject 3 | @end 4 | @implementation PodsDummy_Socket_IO_Client_Swift 5 | @end 6 | -------------------------------------------------------------------------------- /lil wallet.xcodeproj/project.xcworkspace/xcuserdata/jordansinger.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jordansinger/lil-wallet/HEAD/lil wallet.xcodeproj/project.xcworkspace/xcuserdata/jordansinger.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Socket.IO-Client-Swift/SocketIO.framework 3 | ${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-lil wallet/Pods-lil wallet-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Socket.IO-Client-Swift/SocketIO.framework 3 | ${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'lil wallet' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for lil wallet 9 | pod 'Socket.IO-Client-Swift' 10 | end 11 | -------------------------------------------------------------------------------- /lil wallet.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lil wallet.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /lil wallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lil wallet/lil_wallet.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | lil_wallet.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double StarscreamVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char StarscreamVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_lil_walletVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_lil_walletVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SocketIOVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SocketIOVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Socket.IO-Client-Swift (16.0.1): 3 | - Starscream (~> 4.0) 4 | - Starscream (4.0.4) 5 | 6 | DEPENDENCIES: 7 | - Socket.IO-Client-Swift 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Socket.IO-Client-Swift 12 | - Starscream 13 | 14 | SPEC CHECKSUMS: 15 | Socket.IO-Client-Swift: c116d6dc9fd6be9c259bacfe143f8725bce7d79e 16 | Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 17 | 18 | PODFILE CHECKSUM: 439f2e2a4e6d42694159d81d272331f984dde688 19 | 20 | COCOAPODS: 1.9.1 21 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Socket.IO-Client-Swift (16.0.1): 3 | - Starscream (~> 4.0) 4 | - Starscream (4.0.4) 5 | 6 | DEPENDENCIES: 7 | - Socket.IO-Client-Swift 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Socket.IO-Client-Swift 12 | - Starscream 13 | 14 | SPEC CHECKSUMS: 15 | Socket.IO-Client-Swift: c116d6dc9fd6be9c259bacfe143f8725bce7d79e 16 | Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 17 | 18 | PODFILE CHECKSUM: 439f2e2a4e6d42694159d81d272331f984dde688 19 | 20 | COCOAPODS: 1.9.1 21 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Starscream 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Starscream 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Starscream 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Starscream 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Engine/Engine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Engine.swift 3 | // Starscream 4 | // 5 | // Created by Dalton Cherry on 6/15/19. 6 | // Copyright © 2019 Vluxe. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol EngineDelegate: class { 12 | func didReceive(event: WebSocketEvent) 13 | } 14 | 15 | public protocol Engine { 16 | func register(delegate: EngineDelegate) 17 | func start(request: URLRequest) 18 | func stop(closeCode: UInt16) 19 | func forceStop() 20 | func write(data: Data, opcode: FrameOpCode, completion: (() -> ())?) 21 | func write(string: String, completion: (() -> ())?) 22 | } 23 | -------------------------------------------------------------------------------- /lil wallet.xcodeproj/xcuserdata/jordansinger.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | lil wallet.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 3 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 862133022753E3E8002BD765 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lil wallet/lil_walletApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // lil_walletApp.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct lil_walletApp: App { 12 | var appearance = Appearance() 13 | var wallet = Wallet() 14 | let persistenceController = PersistenceController.shared 15 | 16 | var body: some Scene { 17 | WindowGroup { 18 | ContentView() 19 | .environmentObject(wallet) 20 | .environmentObject(appearance) 21 | .environment(\.managedObjectContext, persistenceController.container.viewContext) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/jordansinger.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pods-lil wallet.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Socket.IO-Client-Swift.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Starscream.xcscheme 18 | 19 | isShown 20 | 21 | 22 | 23 | SuppressBuildableAutocreation 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Socket.IO-Client-Swift 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | SWIFT_VERSION = 5.0 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Socket.IO-Client-Swift 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | SWIFT_VERSION = 5.0 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /lil wallet/Persistence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Persistence.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import CoreData 9 | 10 | struct PersistenceController { 11 | static let shared = PersistenceController() 12 | 13 | let container: NSPersistentContainer 14 | 15 | init(inMemory: Bool = false) { 16 | container = NSPersistentContainer(name: "lil_wallet") 17 | if inMemory { 18 | container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") 19 | } 20 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 21 | if let error = error as NSError? { 22 | fatalError("Unresolved error \(error), \(error.userInfo)") 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lil wallet 2 | 3 | welcome to lil wallet. it's an open-source Ethereum wallet built with SwiftUI 4 | 5 | there are two main views - coins and objects. coins are your tokens like ETH, etc. objects are your NFTs 6 | 7 | this is an early version. lots of stuff might be broken, including sometimes slow loading times. 8 | 9 | i'm sharing the first version, and hoping the community can take it from here! 10 | 11 | ### todos 12 | - [ ] better data handling (needs lots of optionals cleanup) 13 | - [ ] speed improvements (not great rn) 14 | - [ ] data caching (don't make fresh requests every time) 15 | - [ ] support more NFT types (videos, etc) 16 | - [ ] sorting coins list? 17 | 18 | ### data 19 | - [Zerion](https://docs.zerion.io) (portfolio, transactions, tokens) 20 | - [OpenSea](https://docs.opensea.io) (NFTs) 21 | -------------------------------------------------------------------------------- /lil wallet/lil_wallet.xcdatamodeld/lil_wallet.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Starscream/Starscream-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.0.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/Starscream" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift/SocketIO.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SocketIO" -framework "Starscream" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/Starscream" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Socket.IO-Client-Swift/SocketIO.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SocketIO" -framework "Starscream" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-lil wallet/Pods-lil wallet-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Socket.IO-Client-Swift/Socket.IO-Client-Swift-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 16.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Compression/Compression.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Compression.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 2/4/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public protocol CompressionHandler { 26 | func load(headers: [String: String]) 27 | func decompress(data: Data, isFinal: Bool) -> Data? 28 | func compress(data: Data) -> Data? 29 | } 30 | -------------------------------------------------------------------------------- /lil wallet/Components/AvatarView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AvatarView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/29/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct AvatarView: View { 11 | @EnvironmentObject var appearance: Appearance 12 | @State var text: String 13 | @State var iconURL: String? 14 | 15 | var body: some View { 16 | if let iconURL = iconURL { 17 | ImageView(imageUrl: iconURL) 18 | .frame(width: 40, height: 40) 19 | .cornerRadius(40) 20 | .background( 21 | Ellipse() 22 | .frame(width: 40, height: 40) 23 | .foregroundColor(Color(UIColor.secondarySystemBackground)) 24 | ) 25 | } else { 26 | placeholder 27 | } 28 | } 29 | 30 | var placeholder: some View { 31 | ZStack { 32 | Text(text.prefix(1).uppercased()) 33 | .font(.system(.headline, design: appearance.getAppFont())) 34 | .foregroundColor(Color(UIColor.systemBackground)) 35 | } 36 | .frame(width: 40, height: 40) 37 | .background(appearance.getAppColor()) 38 | .cornerRadius(40) 39 | } 40 | } 41 | 42 | struct AvatarView_Previews: PreviewProvider { 43 | static var previews: some View { 44 | AvatarView(text: "abc") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Security/Security.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Security.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 3/16/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public enum SecurityErrorCode: UInt16 { 26 | case acceptFailed = 1 27 | case pinningFailed = 2 28 | } 29 | 30 | public enum PinningState { 31 | case success 32 | case failed(CFError?) 33 | } 34 | 35 | // CertificatePinning protocol provides an interface for Transports to handle Certificate 36 | // or Public Key Pinning. 37 | public protocol CertificatePinning: class { 38 | func evaluateTrust(trust: SecTrust, domain: String?, completion: ((PinningState) -> ())) 39 | } 40 | 41 | // validates the "Sec-WebSocket-Accept" header as defined 1.3 of the RFC 6455 42 | // https://tools.ietf.org/html/rfc6455#section-1.3 43 | public protocol HeaderValidator: class { 44 | func validate(headers: [String: String], key: String) -> Error? 45 | } 46 | -------------------------------------------------------------------------------- /lil wallet/Components/CryptoListItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoListItem.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CryptoListItem: View { 11 | @EnvironmentObject var wallet: Wallet 12 | @EnvironmentObject var token: Token 13 | @EnvironmentObject var appearance: Appearance 14 | 15 | var body: some View { 16 | let appFont = appearance.getAppFont() 17 | 18 | NavigationLink(destination: CryptoDetailView().environmentObject(token), label: { 19 | HStack(alignment: .center, spacing: 12) { 20 | AvatarView(text: token.name, iconURL: token.iconURL) 21 | 22 | VStack(alignment: .leading, spacing: 2) { 23 | HStack(spacing: 8) { 24 | Text(token.name == "" ? "Untitled" : token.name) 25 | .lineLimit(1) 26 | .font(.system(.headline, design: appFont)) 27 | 28 | Spacer() 29 | 30 | Text(token.percentChange()) 31 | .font(.system(.callout, design: appFont)) 32 | .foregroundColor(.secondary) 33 | } 34 | 35 | Text("\(wallet.formatCurrency(value: token.value()))") 36 | .font(.system(.body, design: appFont)) 37 | .foregroundColor(.secondary) 38 | } 39 | } 40 | .padding(.vertical, 10) 41 | }) 42 | } 43 | } 44 | 45 | struct CurrencyListItem_Previews: PreviewProvider { 46 | static var previews: some View { 47 | CryptoListItem() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Engine/SocketEnginePacketType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketEnginePacketType.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 10/7/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Represents the type of engine.io packet types. 29 | @objc public enum SocketEnginePacketType: Int { 30 | /// Open message. 31 | case open 32 | 33 | /// Close message. 34 | case close 35 | 36 | /// Ping message. 37 | case ping 38 | 39 | /// Pong message. 40 | case pong 41 | 42 | /// Regular message. 43 | case message 44 | 45 | /// Upgrade message. 46 | case upgrade 47 | 48 | /// NOOP. 49 | case noop 50 | } 51 | -------------------------------------------------------------------------------- /lil wallet/Components/ObjectGridItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectGridItem.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ObjectGridItem: View { 11 | @EnvironmentObject var object: OpenSeaAsset 12 | @EnvironmentObject var appearance: Appearance 13 | 14 | var body: some View { 15 | NavigationLink(destination: ObjectDetailView().environmentObject(object), label: { 16 | if object.isSVG() { 17 | ZStack { 18 | RoundedRectangle(cornerRadius: 16, style: .continuous) 19 | .foregroundColor(appearance.getAppColor()) 20 | .aspectRatio(1, contentMode: .fill) 21 | 22 | Text(object.name ?? "Untitled") 23 | .font(.system(.caption, design: appearance.getAppFont())) 24 | .fontWeight(.semibold) 25 | .foregroundColor(Color(UIColor.systemBackground)) 26 | .multilineTextAlignment(.center) 27 | .padding(.horizontal) 28 | .lineLimit(3) 29 | } 30 | } else { 31 | ImageView(imageUrl: object.image_url) 32 | .mask(RoundedRectangle(cornerRadius: 16, style: .continuous)) 33 | .background( 34 | RoundedRectangle(cornerRadius: 16, style: .continuous) 35 | .foregroundColor(Color(UIColor.secondarySystemBackground)) 36 | .aspectRatio(1, contentMode: .fill) 37 | ) 38 | } 39 | 40 | }) 41 | } 42 | } 43 | 44 | struct ObjectGridItem_Previews: PreviewProvider { 45 | static var previews: some View { 46 | ObjectGridItem() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Server/Server.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Server.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 4/2/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public enum ConnectionEvent { 26 | case connected([String: String]) 27 | case disconnected(String, UInt16) 28 | case text(String) 29 | case binary(Data) 30 | case pong(Data?) 31 | case ping(Data?) 32 | case error(Error) 33 | } 34 | 35 | public protocol Connection { 36 | func write(data: Data, opcode: FrameOpCode) 37 | } 38 | 39 | public protocol ConnectionDelegate: class { 40 | func didReceive(event: ServerEvent) 41 | } 42 | 43 | public enum ServerEvent { 44 | case connected(Connection, [String: String]) 45 | case disconnected(Connection, String, UInt16) 46 | case text(Connection, String) 47 | case binary(Connection, Data) 48 | case pong(Connection, Data?) 49 | case ping(Connection, Data?) 50 | } 51 | 52 | public protocol Server { 53 | func start(address: String, port: UInt16) -> Error? 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Client/SocketAnyEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketAnyEvent.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 3/28/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// Represents some event that was received. 28 | public final class SocketAnyEvent : NSObject { 29 | // MARK: Properties 30 | 31 | /// The event name. 32 | @objc 33 | public let event: String 34 | 35 | /// The data items for this event. 36 | @objc 37 | public let items: [Any]? 38 | 39 | /// The description of this event. 40 | override public var description: String { 41 | return "SocketAnyEvent: Event: \(event) items: \(String(describing: items))" 42 | } 43 | 44 | init(event: String, items: [Any]?) { 45 | self.event = event 46 | self.items = items 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lil wallet/Components/ActivityListItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityListItem.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ActivityListItem: View { 11 | @EnvironmentObject var transaction: Transaction 12 | @EnvironmentObject var appearance: Appearance 13 | @EnvironmentObject var wallet: Wallet 14 | 15 | var body: some View { 16 | let appFont = appearance.getAppFont() 17 | 18 | NavigationLink(destination: ActivityDetailView().environmentObject(transaction), label: { 19 | HStack(alignment: .center, spacing: 12) { 20 | AvatarView(text: transaction.token == nil ? transaction.type : transaction.token?.name ?? "", iconURL: transaction.token?.iconURL ?? nil) 21 | 22 | VStack(alignment: .leading, spacing: 2) { 23 | HStack(spacing: 8) { 24 | Text(transaction.title()) 25 | .lineLimit(1) 26 | .font(.system(.headline, design: appFont)) 27 | 28 | Spacer() 29 | 30 | Text("\(wallet.formatCurrency(value: transaction.transactionValue()))") 31 | .font(.system(.callout, design: appFont)) 32 | .foregroundColor(.secondary) 33 | .lineLimit(1) 34 | } 35 | 36 | Text(Date(timeIntervalSince1970: TimeInterval(transaction.mined_at)).formatted(date: .abbreviated, time: .omitted)) 37 | .lineLimit(1) 38 | .font(.system(.body, design: appFont)) 39 | .foregroundColor(.secondary) 40 | } 41 | } 42 | .padding(.vertical, 10) 43 | }) 44 | } 45 | } 46 | 47 | struct ActivityListItem_Previews: PreviewProvider { 48 | static var previews: some View { 49 | ActivityListItem() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Transport/Transport.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | ////////////////////////////////////////////////////////////////////////////////////////////////// 4 | // 5 | // Transport.swift 6 | // Starscream 7 | // 8 | // Created by Dalton Cherry on 1/23/19. 9 | // Copyright © 2019 Vluxe. All rights reserved. 10 | // 11 | // Licensed under the Apache License, Version 2.0 (the "License"); 12 | // you may not use this file except in compliance with the License. 13 | // You may obtain a copy of the License at 14 | // 15 | // http://www.apache.org/licenses/LICENSE-2.0 16 | // 17 | // Unless required by applicable law or agreed to in writing, software 18 | // distributed under the License is distributed on an "AS IS" BASIS, 19 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | // See the License for the specific language governing permissions and 21 | // limitations under the License. 22 | // 23 | ////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | import Foundation 26 | 27 | public enum ConnectionState { 28 | case connected 29 | case waiting 30 | case cancelled 31 | case failed(Error?) 32 | 33 | //the viability (connection status) of the connection has updated 34 | //e.g. connection is down, connection came back up, etc 35 | case viability(Bool) 36 | 37 | //the connection has upgrade to wifi from cellular. 38 | //you should consider reconnecting to take advantage of this 39 | case shouldReconnect(Bool) 40 | 41 | //the connection receive data 42 | case receive(Data) 43 | } 44 | 45 | public protocol TransportEventClient: class { 46 | func connectionChanged(state: ConnectionState) 47 | } 48 | 49 | public protocol Transport: class { 50 | func register(delegate: TransportEventClient) 51 | func connect(url: URL, timeout: Double, certificatePinning: CertificatePinning?) 52 | func disconnect() 53 | func write(data: Data, completion: @escaping ((Error?) -> ())) 54 | var usingTLS: Bool { get } 55 | } 56 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/DataBytes/Data+Extensions.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Data+Extensions.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 3/27/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Fix for deprecation warnings 10 | // 11 | // Licensed under the Apache License, Version 2.0 (the "License"); 12 | // you may not use this file except in compliance with the License. 13 | // You may obtain a copy of the License at 14 | // 15 | // http://www.apache.org/licenses/LICENSE-2.0 16 | // 17 | // Unless required by applicable law or agreed to in writing, software 18 | // distributed under the License is distributed on an "AS IS" BASIS, 19 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | // See the License for the specific language governing permissions and 21 | // limitations under the License. 22 | // 23 | ////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | import Foundation 26 | 27 | internal extension Data { 28 | struct ByteError: Swift.Error {} 29 | 30 | #if swift(>=5.0) 31 | func withUnsafeBytes(_ completion: (UnsafePointer) throws -> ResultType) rethrows -> ResultType { 32 | return try withUnsafeBytes { 33 | if let baseAddress = $0.baseAddress, $0.count > 0 { 34 | return try completion(baseAddress.assumingMemoryBound(to: ContentType.self)) 35 | } else { 36 | throw ByteError() 37 | } 38 | } 39 | } 40 | #endif 41 | 42 | #if swift(>=5.0) 43 | mutating func withUnsafeMutableBytes(_ completion: (UnsafeMutablePointer) throws -> ResultType) rethrows -> ResultType { 44 | return try withUnsafeMutableBytes { 45 | if let baseAddress = $0.baseAddress, $0.count > 0 { 46 | return try completion(baseAddress.assumingMemoryBound(to: ContentType.self)) 47 | } else { 48 | throw ByteError() 49 | } 50 | } 51 | } 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Client/SocketEventHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventHandler.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 1/18/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// A wrapper around a handler. 28 | public struct SocketEventHandler { 29 | // MARK: Properties 30 | 31 | /// The event for this handler. 32 | public let event: String 33 | 34 | /// A unique identifier for this handler. 35 | public let id: UUID 36 | 37 | /// The actual handler function. 38 | public let callback: NormalCallback 39 | 40 | // MARK: Methods 41 | 42 | /// Causes this handler to be executed. 43 | /// 44 | /// - parameter with: The data that this handler should be called with. 45 | /// - parameter withAck: The ack number that this event expects. Pass -1 to say this event doesn't expect an ack. 46 | /// - parameter withSocket: The socket that is calling this event. 47 | public func executeCallback(with items: [Any], withAck ack: Int, withSocket socket: SocketIOClient) { 48 | callback(items, SocketAckEmitter(socket: socket, ackNum: ack)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/jordansinger.xcuserdatad/xcschemes/Starscream.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/jordansinger.xcuserdatad/xcschemes/Pods-lil wallet.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lil wallet/Views/ActivityView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ActivityView: View { 11 | @Environment(\.presentationMode) var presentationMode 12 | @EnvironmentObject var wallet: Wallet 13 | @EnvironmentObject var appearance: Appearance 14 | @State var loading = true 15 | @State var loadingError = false 16 | 17 | var body: some View { 18 | NavigationView { 19 | ZStack { 20 | if wallet.loadingTransactions { 21 | VStack { 22 | Spacer() 23 | ProgressView() 24 | Spacer() 25 | } 26 | } else if wallet.transactions.count == 0 { 27 | VStack { 28 | Spacer() 29 | Text("No activity") 30 | .foregroundColor(.secondary) 31 | .font(.system(.body, design: appearance.getAppFont())) 32 | Spacer() 33 | } 34 | } else { 35 | List { 36 | ForEach(wallet.transactions, id: \.id) { transaction in 37 | ActivityListItem() 38 | .environmentObject(appearance) 39 | .environmentObject(transaction) 40 | .listRowSeparator(.hidden) 41 | } 42 | } 43 | } 44 | } 45 | .listStyle(PlainListStyle()) 46 | .navigationTitle("Activity") 47 | .navigationBarTitleDisplayMode(.inline) 48 | .toolbar { 49 | ToolbarItem(placement: .navigationBarLeading) { 50 | Button { 51 | presentationMode.wrappedValue.dismiss() 52 | } label: { 53 | Text("Done") 54 | } 55 | } 56 | } 57 | } 58 | .accentColor(appearance.getAppColor()) 59 | } 60 | } 61 | 62 | struct ActivityView_Previews: PreviewProvider { 63 | static var previews: some View { 64 | ActivityView() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/jordansinger.xcuserdatad/xcschemes/Socket.IO-Client-Swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Client/SocketIOStatus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOStatus.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 8/14/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// Represents state of a manager or client. 28 | @objc 29 | public enum SocketIOStatus : Int, CustomStringConvertible { 30 | // MARK: Cases 31 | 32 | /// The client/manager has never been connected. Or the client has been reset. 33 | case notConnected 34 | 35 | /// The client/manager was once connected, but not anymore. 36 | case disconnected 37 | 38 | /// The client/manager is in the process of connecting. 39 | case connecting 40 | 41 | /// The client/manager is currently connected. 42 | case connected 43 | 44 | // MARK: Properties 45 | 46 | /// - returns: True if this client/manager is connected/connecting to a server. 47 | public var active: Bool { 48 | return self == .connected || self == .connecting 49 | } 50 | 51 | public var description: String { 52 | switch self { 53 | case .connected: return "connected" 54 | case .connecting: return "connecting" 55 | case .disconnected: return "disconnected" 56 | case .notConnected: return "notConnected" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lil wallet/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | @State var activeTab = 0 12 | @EnvironmentObject var wallet: Wallet 13 | @EnvironmentObject var appearance: Appearance 14 | @Environment(\.managedObjectContext) private var viewContext 15 | @State private var timeRemaining = 3 16 | let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() 17 | 18 | var body: some View { 19 | ZStack { 20 | if showLaunchScreen() { 21 | // loading view 22 | VStack { 23 | Spacer() 24 | Text(Image(systemName: "square.on.circle")) 25 | .font(.system(size: 56, weight: .medium)) 26 | .foregroundColor(appearance.getAppColor()) 27 | Spacer() 28 | } 29 | } else { 30 | TabView(selection: $activeTab) { 31 | CoinsView() 32 | .environmentObject(wallet) 33 | .environment(\.managedObjectContext, viewContext) 34 | .tabItem { 35 | Image(systemName: "circle") 36 | .environment(\.symbolVariants, activeTab == 0 ? .fill : .none) 37 | Text("Coins") 38 | } 39 | .tag(0) 40 | 41 | ObjectsView() 42 | .environment(\.managedObjectContext, viewContext) 43 | .tabItem { 44 | Image(systemName: "app") 45 | .environment(\.symbolVariants, activeTab == 1 ? .fill : .none) 46 | Text("Objects") 47 | } 48 | .tag(1) 49 | } 50 | .accentColor(appearance.getAppColor()) 51 | } 52 | } 53 | .animation(.easeInOut(duration: 0.16), value: showLaunchScreen()) 54 | .onReceive(timer) { time in 55 | if self.timeRemaining > 0 { 56 | self.timeRemaining -= 1 57 | } 58 | } 59 | } 60 | 61 | func showLaunchScreen() -> Bool { 62 | // show launch screen if we're waiting for portfolio/tokens, OR if timer is at 0 63 | return (wallet.loadingPortfolio || wallet.loadingTokens) && self.timeRemaining > 0 64 | } 65 | } 66 | 67 | struct ContentView_Previews: PreviewProvider { 68 | static var previews: some View { 69 | ContentView() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Util/SocketStringReader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketStringReader.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Lukas Schmidt on 07.09.15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | struct SocketStringReader { 26 | let message: String 27 | var currentIndex: String.UTF16View.Index 28 | var hasNext: Bool { 29 | return currentIndex != message.utf16.endIndex 30 | } 31 | 32 | var currentCharacter: String { 33 | return String(UnicodeScalar(message.utf16[currentIndex])!) 34 | } 35 | 36 | init(message: String) { 37 | self.message = message 38 | currentIndex = message.utf16.startIndex 39 | } 40 | 41 | @discardableResult 42 | mutating func advance(by: Int) -> String.UTF16View.Index { 43 | currentIndex = message.utf16.index(currentIndex, offsetBy: by) 44 | 45 | return currentIndex 46 | } 47 | 48 | mutating func read(count: Int) -> String { 49 | let readString = String(message.utf16[currentIndex.. String { 57 | let substring = message.utf16[currentIndex...] 58 | 59 | guard let foundIndex = substring.firstIndex(where: { $0 == string.utf16.first! }) else { 60 | currentIndex = message.utf16.endIndex 61 | 62 | return String(substring)! 63 | } 64 | 65 | advance(by: substring.distance(from: substring.startIndex, to: foundIndex) + 1) 66 | 67 | return String(substring[substring.startIndex.. String { 71 | return read(count: message.utf16.distance(from: currentIndex, to: message.utf16.endIndex)) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lil wallet/Data/Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Helpers.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/29/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | class Appearance: ObservableObject { 11 | @AppStorage("appColor") private var appColor = AppColor.monochrome 12 | @AppStorage("appFont") private var appFont = AppFont.regular 13 | 14 | func getAppColor() -> Color { 15 | appColor.color 16 | } 17 | 18 | func getAppFont() -> Font.Design { 19 | appFont.font 20 | } 21 | } 22 | 23 | enum AppColor: String, Hashable, CaseIterable { 24 | case monochrome 25 | case red 26 | case orange 27 | case yellow 28 | case green 29 | case blue 30 | case indigo 31 | case purple 32 | 33 | var color: Color { 34 | switch self { 35 | case .monochrome: 36 | return Color.primary 37 | case .red: 38 | return Color.red 39 | case .orange: 40 | return Color.orange 41 | case .yellow: 42 | return Color.yellow 43 | case .green: 44 | return Color.green 45 | case .blue: 46 | return Color.blue 47 | case .indigo: 48 | return Color.indigo 49 | case .purple: 50 | return Color.purple 51 | } 52 | } 53 | } 54 | 55 | enum AppFont: String, Hashable, CaseIterable { 56 | case regular 57 | case rounded 58 | case monospaced 59 | case serif 60 | 61 | var font: Font.Design { 62 | switch self { 63 | case .regular: 64 | return Font.Design.default 65 | case .rounded: 66 | return Font.Design.rounded 67 | case .monospaced: 68 | return Font.Design.monospaced 69 | case .serif: 70 | return Font.Design.serif 71 | } 72 | } 73 | } 74 | 75 | struct ImageView: View { 76 | @ObservedObject var remoteImageURL: RemoteImageURL 77 | 78 | init(imageUrl: String) { 79 | remoteImageURL = RemoteImageURL(imageURL: imageUrl) 80 | } 81 | 82 | var body: some View { 83 | Image(uiImage: UIImage(data: self.remoteImageURL.data) ?? UIImage()) 84 | .resizable() 85 | .aspectRatio(1, contentMode: .fill) 86 | } 87 | } 88 | 89 | class RemoteImageURL: ObservableObject { 90 | @Published var data = Data() 91 | 92 | // load our image URL 93 | init(imageURL: String) { 94 | guard let url = URL(string: imageURL) else { 95 | print("Invalid URL") 96 | return 97 | } 98 | 99 | let request = URLRequest(url: url) 100 | URLSession.shared.dataTask(with: request) { data, response, error in 101 | if let data = data, let _ = response { 102 | DispatchQueue.main.async { 103 | self.data = data 104 | } 105 | } 106 | }.resume() 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Engine/SocketEngineClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketEngineClient.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 3/19/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Declares that a type will be a delegate to an engine. 29 | @objc public protocol SocketEngineClient { 30 | // MARK: Methods 31 | 32 | /// Called when the engine errors. 33 | /// 34 | /// - parameter reason: The reason the engine errored. 35 | func engineDidError(reason: String) 36 | 37 | /// Called when the engine closes. 38 | /// 39 | /// - parameter reason: The reason that the engine closed. 40 | func engineDidClose(reason: String) 41 | 42 | /// Called when the engine opens. 43 | /// 44 | /// - parameter reason: The reason the engine opened. 45 | func engineDidOpen(reason: String) 46 | 47 | /// Called when the engine receives a ping message. Only called in socket.io >3. 48 | func engineDidReceivePing() 49 | 50 | /// Called when the engine receives a pong message. Only called in socket.io 2. 51 | func engineDidReceivePong() 52 | 53 | /// Called when the engine sends a ping to the server. Only called in socket.io 2. 54 | func engineDidSendPing() 55 | 56 | /// Called when the engine sends a pong to the server. Only called in socket.io >3. 57 | func engineDidSendPong() 58 | 59 | /// Called when the engine has a message that must be parsed. 60 | /// 61 | /// - parameter msg: The message that needs parsing. 62 | func parseEngineMessage(_ msg: String) 63 | 64 | /// Called when the engine receives binary data. 65 | /// 66 | /// - parameter data: The data the engine received. 67 | func parseEngineBinaryData(_ data: Data) 68 | 69 | /// Called when when upgrading the http connection to a websocket connection. 70 | /// 71 | /// - parameter headers: The http headers. 72 | func engineDidWebsocketUpgrade(headers: [String: String]) 73 | } 74 | -------------------------------------------------------------------------------- /lil wallet/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Frame 14-20@2x.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "Frame 14-20@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "Frame 14-29@1x.png", 17 | "idiom" : "iphone", 18 | "scale" : "1x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "Frame 14-29@2x.png", 23 | "idiom" : "iphone", 24 | "scale" : "2x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "Frame 14-29@3x.png", 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "29x29" 32 | }, 33 | { 34 | "filename" : "Frame 14-40@2x.png", 35 | "idiom" : "iphone", 36 | "scale" : "2x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "Frame 14-40@3x.png", 41 | "idiom" : "iphone", 42 | "scale" : "3x", 43 | "size" : "40x40" 44 | }, 45 | { 46 | "filename" : "Frame 14-60@2x.png", 47 | "idiom" : "iphone", 48 | "scale" : "2x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "Frame 14-60@3x.png", 53 | "idiom" : "iphone", 54 | "scale" : "3x", 55 | "size" : "60x60" 56 | }, 57 | { 58 | "filename" : "Frame 14-20@1x.png", 59 | "idiom" : "ipad", 60 | "scale" : "1x", 61 | "size" : "20x20" 62 | }, 63 | { 64 | "filename" : "Frame 14-40@1x.png", 65 | "idiom" : "ipad", 66 | "scale" : "2x", 67 | "size" : "20x20" 68 | }, 69 | { 70 | "filename" : "Frame 14-29@1x-1.png", 71 | "idiom" : "ipad", 72 | "scale" : "1x", 73 | "size" : "29x29" 74 | }, 75 | { 76 | "filename" : "Frame 14-29@2x-1.png", 77 | "idiom" : "ipad", 78 | "scale" : "2x", 79 | "size" : "29x29" 80 | }, 81 | { 82 | "filename" : "Frame 14-40@1x-1.png", 83 | "idiom" : "ipad", 84 | "scale" : "1x", 85 | "size" : "40x40" 86 | }, 87 | { 88 | "filename" : "Frame 14-40@2x-1.png", 89 | "idiom" : "ipad", 90 | "scale" : "2x", 91 | "size" : "40x40" 92 | }, 93 | { 94 | "filename" : "Frame 14-76@1x.png", 95 | "idiom" : "ipad", 96 | "scale" : "1x", 97 | "size" : "76x76" 98 | }, 99 | { 100 | "filename" : "Frame 14-76@2x.png", 101 | "idiom" : "ipad", 102 | "scale" : "2x", 103 | "size" : "76x76" 104 | }, 105 | { 106 | "filename" : "Frame 14-83.5@2x.png", 107 | "idiom" : "ipad", 108 | "scale" : "2x", 109 | "size" : "83.5x83.5" 110 | }, 111 | { 112 | "filename" : "Frame 14-1024@1x.png", 113 | "idiom" : "ios-marketing", 114 | "scale" : "1x", 115 | "size" : "1024x1024" 116 | } 117 | ], 118 | "info" : { 119 | "author" : "xcode", 120 | "version" : 1 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Util/SocketLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketLogger.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 4/11/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// Represents a class will log client events. 28 | public protocol SocketLogger : AnyObject { 29 | // MARK: Properties 30 | 31 | /// Whether to log or not 32 | var log: Bool { get set } 33 | 34 | // MARK: Methods 35 | 36 | /// Normal log messages 37 | /// 38 | /// - parameter message: The message being logged. Can include `%@` that will be replaced with `args` 39 | /// - parameter type: The type of entity that called for logging. 40 | /// - parameter args: Any args that should be inserted into the message. May be left out. 41 | func log(_ message: @autoclosure () -> String, type: String) 42 | 43 | /// Error Messages 44 | /// 45 | /// - parameter message: The message being logged. Can include `%@` that will be replaced with `args` 46 | /// - parameter type: The type of entity that called for logging. 47 | /// - parameter args: Any args that should be inserted into the message. May be left out. 48 | func error(_ message: @autoclosure () -> String, type: String) 49 | } 50 | 51 | public extension SocketLogger { 52 | /// Default implementation. 53 | func log(_ message: @autoclosure () -> String, type: String) { 54 | guard log else { return } 55 | 56 | abstractLog("LOG", message: message(), type: type) 57 | } 58 | 59 | /// Default implementation. 60 | func error(_ message: @autoclosure () -> String, type: String) { 61 | guard log else { return } 62 | 63 | abstractLog("ERROR", message: message(), type: type) 64 | } 65 | 66 | private func abstractLog(_ logType: String, message: @autoclosure () -> String, type: String) { 67 | NSLog("\(logType) \(type): %@", message()) 68 | } 69 | } 70 | 71 | class DefaultSocketLogger : SocketLogger { 72 | static var Logger: SocketLogger = DefaultSocketLogger() 73 | 74 | var log = false 75 | } 76 | -------------------------------------------------------------------------------- /lil wallet.xcodeproj/xcshareddata/xcschemes/lil wallet.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Ack/SocketAckManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketAckManager.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 4/3/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Dispatch 26 | import Foundation 27 | 28 | /// The status of an ack. 29 | public enum SocketAckStatus : String { 30 | // MARK: Cases 31 | 32 | /// The ack timed out. 33 | case noAck = "NO ACK" 34 | 35 | /// Tests whether a string is equal to a given SocketAckStatus 36 | public static func == (lhs: String, rhs: SocketAckStatus) -> Bool { 37 | return lhs == rhs.rawValue 38 | } 39 | 40 | /// Tests whether a string is equal to a given SocketAckStatus 41 | public static func == (lhs: SocketAckStatus, rhs: String) -> Bool { 42 | return rhs == lhs 43 | } 44 | } 45 | 46 | private struct SocketAck : Hashable { 47 | let ack: Int 48 | var callback: AckCallback! 49 | 50 | init(ack: Int) { 51 | self.ack = ack 52 | } 53 | 54 | init(ack: Int, callback: @escaping AckCallback) { 55 | self.ack = ack 56 | self.callback = callback 57 | } 58 | 59 | func hash(into hasher: inout Hasher) { 60 | ack.hash(into: &hasher) 61 | } 62 | 63 | fileprivate static func <(lhs: SocketAck, rhs: SocketAck) -> Bool { 64 | return lhs.ack < rhs.ack 65 | } 66 | 67 | fileprivate static func ==(lhs: SocketAck, rhs: SocketAck) -> Bool { 68 | return lhs.ack == rhs.ack 69 | } 70 | } 71 | 72 | class SocketAckManager { 73 | private var acks = Set(minimumCapacity: 1) 74 | 75 | func addAck(_ ack: Int, callback: @escaping AckCallback) { 76 | acks.insert(SocketAck(ack: ack, callback: callback)) 77 | } 78 | 79 | /// Should be called on handle queue 80 | func executeAck(_ ack: Int, with items: [Any]) { 81 | acks.remove(SocketAck(ack: ack))?.callback(items) 82 | } 83 | 84 | /// Should be called on handle queue 85 | func timeoutAck(_ ack: Int) { 86 | acks.remove(SocketAck(ack: ack))?.callback?([SocketAckStatus.noAck.rawValue]) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Util/SocketTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketTypes.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 4/8/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// A marking protocol that says a type can be represented in a socket.io packet. 28 | /// 29 | /// Example: 30 | /// 31 | /// ```swift 32 | /// struct CustomData : SocketData { 33 | /// let name: String 34 | /// let age: Int 35 | /// 36 | /// func socketRepresentation() -> SocketData { 37 | /// return ["name": name, "age": age] 38 | /// } 39 | /// } 40 | /// 41 | /// socket.emit("myEvent", CustomData(name: "Erik", age: 24)) 42 | /// ``` 43 | public protocol SocketData { 44 | // MARK: Methods 45 | 46 | /// A representation of self that can sent over socket.io. 47 | func socketRepresentation() throws -> SocketData 48 | } 49 | 50 | public extension SocketData { 51 | /// Default implementation. Only works for native Swift types and a few Foundation types. 52 | func socketRepresentation() -> SocketData { 53 | return self 54 | } 55 | } 56 | 57 | extension Array : SocketData { } 58 | extension Bool : SocketData { } 59 | extension Dictionary : SocketData { } 60 | extension Double : SocketData { } 61 | extension Int : SocketData { } 62 | extension NSArray : SocketData { } 63 | extension Data : SocketData { } 64 | extension NSData : SocketData { } 65 | extension NSDictionary : SocketData { } 66 | extension NSString : SocketData { } 67 | extension NSNull : SocketData { } 68 | extension String : SocketData { } 69 | 70 | /// A typealias for an ack callback. 71 | public typealias AckCallback = ([Any]) -> () 72 | 73 | /// A typealias for a normal callback. 74 | public typealias NormalCallback = ([Any], SocketAckEmitter) -> () 75 | 76 | /// A typealias for a queued POST 77 | public typealias Post = (msg: String, completion: (() -> ())?) 78 | 79 | typealias JSON = [String: Any] 80 | typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data], completion: (() -> ())?) 81 | typealias ProbeWaitQueue = [Probe] 82 | 83 | enum Either { 84 | case left(E) 85 | case right(V) 86 | } 87 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Engine/NativeEngine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NativeEngine.swift 3 | // Starscream 4 | // 5 | // Created by Dalton Cherry on 6/15/19. 6 | // Copyright © 2019 Vluxe. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) 12 | public class NativeEngine: NSObject, Engine, URLSessionDataDelegate, URLSessionWebSocketDelegate { 13 | private var task: URLSessionWebSocketTask? 14 | weak var delegate: EngineDelegate? 15 | 16 | public func register(delegate: EngineDelegate) { 17 | self.delegate = delegate 18 | } 19 | 20 | public func start(request: URLRequest) { 21 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil) 22 | task = session.webSocketTask(with: request) 23 | doRead() 24 | task?.resume() 25 | } 26 | 27 | public func stop(closeCode: UInt16) { 28 | let closeCode = URLSessionWebSocketTask.CloseCode(rawValue: Int(closeCode)) ?? .normalClosure 29 | task?.cancel(with: closeCode, reason: nil) 30 | } 31 | 32 | public func forceStop() { 33 | stop(closeCode: UInt16(URLSessionWebSocketTask.CloseCode.abnormalClosure.rawValue)) 34 | } 35 | 36 | public func write(string: String, completion: (() -> ())?) { 37 | task?.send(.string(string), completionHandler: { (error) in 38 | completion?() 39 | }) 40 | } 41 | 42 | public func write(data: Data, opcode: FrameOpCode, completion: (() -> ())?) { 43 | switch opcode { 44 | case .binaryFrame: 45 | task?.send(.data(data), completionHandler: { (error) in 46 | completion?() 47 | }) 48 | case .textFrame: 49 | let text = String(data: data, encoding: .utf8)! 50 | write(string: text, completion: completion) 51 | case .ping: 52 | task?.sendPing(pongReceiveHandler: { (error) in 53 | completion?() 54 | }) 55 | default: 56 | break //unsupported 57 | } 58 | } 59 | 60 | private func doRead() { 61 | task?.receive { [weak self] (result) in 62 | switch result { 63 | case .success(let message): 64 | switch message { 65 | case .string(let string): 66 | self?.broadcast(event: .text(string)) 67 | case .data(let data): 68 | self?.broadcast(event: .binary(data)) 69 | @unknown default: 70 | break 71 | } 72 | break 73 | case .failure(let error): 74 | self?.broadcast(event: .error(error)) 75 | } 76 | self?.doRead() 77 | } 78 | } 79 | 80 | private func broadcast(event: WebSocketEvent) { 81 | delegate?.didReceive(event: event) 82 | } 83 | 84 | public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) { 85 | let p = `protocol` ?? "" 86 | broadcast(event: .connected([HTTPWSHeader.protocolName: p])) 87 | } 88 | 89 | public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) { 90 | var r = "" 91 | if let d = reason { 92 | r = String(data: d, encoding: .utf8) ?? "" 93 | } 94 | broadcast(event: .disconnected(r, UInt16(closeCode.rawValue))) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Engine/SocketEngineWebsocket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketEngineWebsocket.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 1/15/16. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import Starscream 28 | 29 | /// Protocol that is used to implement socket.io WebSocket support 30 | public protocol SocketEngineWebsocket: SocketEngineSpec { 31 | // MARK: Properties 32 | 33 | /// Whether or not the ws is connected 34 | var wsConnected: Bool { get } 35 | 36 | // MARK: Methods 37 | 38 | /// Sends an engine.io message through the WebSocket transport. 39 | /// 40 | /// You shouldn't call this directly, instead call the `write` method on `SocketEngine`. 41 | /// 42 | /// - parameter message: The message to send. 43 | /// - parameter withType: The type of message to send. 44 | /// - parameter withData: The data associated with this message. 45 | /// - parameter completion: Callback called on transport write completion. 46 | func sendWebSocketMessage(_ str: String, 47 | withType type: SocketEnginePacketType, 48 | withData datas: [Data], 49 | completion: (() -> ())?) 50 | } 51 | 52 | // WebSocket methods 53 | extension SocketEngineWebsocket { 54 | func probeWebSocket() { 55 | if wsConnected { 56 | sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil) 57 | } 58 | } 59 | 60 | /// Sends an engine.io message through the WebSocket transport. 61 | /// 62 | /// You shouldn't call this directly, instead call the `write` method on `SocketEngine`. 63 | /// 64 | /// - parameter message: The message to send. 65 | /// - parameter withType: The type of message to send. 66 | /// - parameter withData: The data associated with this message. 67 | /// - parameter completion: Callback called on transport write completion. 68 | public func sendWebSocketMessage(_ str: String, 69 | withType type: SocketEnginePacketType, 70 | withData data: [Data], 71 | completion: (() -> ())? 72 | ) { 73 | DefaultSocketLogger.Logger.log("Sending ws: \(str) as type: \(type.rawValue)", type: "SocketEngineWebSocket") 74 | 75 | ws?.write(string: "\(type.rawValue)\(str)") 76 | 77 | for item in data { 78 | if case let .left(bin) = createBinaryDataForSend(using: item) { 79 | ws?.write(data: bin, completion: completion) 80 | } 81 | } 82 | 83 | if data.count == 0 { 84 | completion?() 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lil wallet/Views/Detail/CryptoDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoDetailView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CryptoDetailView: View { 11 | @Environment(\.presentationMode) var presentationMode 12 | @Environment(\.colorScheme) var colorScheme 13 | @EnvironmentObject var wallet: Wallet 14 | @EnvironmentObject var token: Token 15 | @EnvironmentObject var appearance: Appearance 16 | 17 | var body: some View { 18 | let appFont = appearance.getAppFont() 19 | 20 | List { 21 | Section(content: { 22 | HStack { 23 | Spacer() 24 | VStack(spacing: 8) { 25 | Text("\(wallet.formatCurrency(value: token.price?.value ?? 0))") 26 | .font(.system(.largeTitle, design: appFont)) 27 | .fontWeight(.bold) 28 | .multilineTextAlignment(.center) 29 | 30 | VStack(spacing: 4) { 31 | Text(token.symbol.uppercased()) 32 | .font(.system(.body, design: appFont)) 33 | .multilineTextAlignment(.center) 34 | } 35 | .foregroundColor(.secondary) 36 | } 37 | .padding(.horizontal) 38 | Spacer() 39 | } 40 | .padding(.vertical, 24) 41 | }) 42 | .listRowBackground( 43 | colorScheme == .light ? 44 | Color(UIColor.secondarySystemBackground) : 45 | Color(UIColor.systemBackground) 46 | ) 47 | 48 | Section(content: { 49 | HStack { 50 | Text("Today") 51 | .font(.system(.body, design: appFont)) 52 | Spacer() 53 | Label(token.percentChange(), systemImage: token.percentChange().contains("-") ? "arrow.down" : "arrow.up") 54 | .font(.system(.headline, design: appFont)) 55 | .foregroundColor(token.percentChange().contains("-") ? .red : .green) 56 | } 57 | }) 58 | 59 | Section(content: { 60 | HStack { 61 | Text("Balance") 62 | .font(.system(.body, design: appFont)) 63 | Spacer() 64 | Text("\(token.tokenQuantity())") 65 | .lineLimit(1) 66 | .font(.system(.headline, design: appFont)) 67 | } 68 | 69 | HStack { 70 | Text("Value") 71 | .font(.system(.body, design: appFont)) 72 | Spacer() 73 | Text("\(wallet.formatCurrency(value: token.value()))") 74 | .font(.system(.headline, design: appFont)) 75 | } 76 | }, header: { 77 | Text("Wallet") 78 | }) 79 | 80 | Section { 81 | Link(destination: URL(string: "https://etherscan.io/token/\(token.id)?a=\(wallet.currentWalletAddress)")!, label: { 82 | Text("View on Etherscan") 83 | .font(.system(.body, design: appFont)) 84 | }) 85 | } 86 | .foregroundColor(appearance.getAppColor()) 87 | } 88 | .navigationTitle(token.name) 89 | .navigationBarTitleDisplayMode(.inline) 90 | } 91 | } 92 | 93 | struct CryptoDetailView_Previews: PreviewProvider { 94 | static var previews: some View { 95 | CryptoDetailView() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/socketio/socket.io-client-swift.svg?branch=master)](https://travis-ci.org/socketio/socket.io-client-swift) 2 | 3 | # Socket.IO-Client-Swift 4 | Socket.IO-client for iOS/OS X. 5 | 6 | ## Example 7 | ```swift 8 | import SocketIO 9 | 10 | let manager = SocketManager(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress]) 11 | let socket = manager.defaultSocket 12 | 13 | socket.on(clientEvent: .connect) {data, ack in 14 | print("socket connected") 15 | } 16 | 17 | socket.on("currentAmount") {data, ack in 18 | guard let cur = data[0] as? Double else { return } 19 | 20 | socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in 21 | if data.first as? String ?? "passed" == SocketAckValue.noAck { 22 | // Handle ack timeout 23 | } 24 | 25 | socket.emit("update", ["amount": cur + 2.50]) 26 | } 27 | 28 | ack.with("Got your currentAmount", "dude") 29 | } 30 | 31 | socket.connect() 32 | ``` 33 | 34 | ## Features 35 | - Supports socket.io 2.0+/3.0+. 36 | - Supports Binary 37 | - Supports Polling and WebSockets 38 | - Supports TLS/SSL 39 | 40 | ## FAQS 41 | Checkout the [FAQs](https://nuclearace.github.io/Socket.IO-Client-Swift/faq.html) for commonly asked questions. 42 | 43 | 44 | Checkout the [12to13](https://nuclearace.github.io/Socket.IO-Client-Swift/12to13.html) guide for migrating to v13+ from v12 below. 45 | 46 | Checkout the [15to16](https://nuclearace.github.io/Socket.IO-Client-Swift/15to16.html) guide for migrating to v16+ from v15. 47 | 48 | ## Installation 49 | Requires Swift 4/5 and Xcode 10.x 50 | 51 | ### Swift Package Manager 52 | Add the project as a dependency to your Package.swift: 53 | ```swift 54 | // swift-tools-version:4.2 55 | 56 | import PackageDescription 57 | 58 | let package = Package( 59 | name: "socket.io-test", 60 | products: [ 61 | .executable(name: "socket.io-test", targets: ["YourTargetName"]) 62 | ], 63 | dependencies: [ 64 | .package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "15.0.0")) 65 | ], 66 | targets: [ 67 | .target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources") 68 | ] 69 | ) 70 | ``` 71 | 72 | Then import `import SocketIO`. 73 | 74 | ### Carthage 75 | Add this line to your `Cartfile`: 76 | ``` 77 | github "socketio/socket.io-client-swift" ~> 15.2.0 78 | ``` 79 | 80 | Run `carthage update --platform ios,macosx`. 81 | 82 | Add the `Starscream` and `SocketIO` frameworks to your projects and follow the usual Carthage process. 83 | 84 | ### CocoaPods 1.0.0 or later 85 | Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`: 86 | 87 | ```ruby 88 | use_frameworks! 89 | 90 | target 'YourApp' do 91 | pod 'Socket.IO-Client-Swift', '~> 15.2.0' 92 | end 93 | ``` 94 | 95 | Install pods: 96 | 97 | ``` 98 | $ pod install 99 | ``` 100 | 101 | Import the module: 102 | 103 | Swift: 104 | ```swift 105 | import SocketIO 106 | ``` 107 | 108 | Objective-C: 109 | 110 | ```Objective-C 111 | @import SocketIO; 112 | ``` 113 | 114 | 115 | # [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html) 116 | 117 | - [Client](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketIOClient.html) 118 | - [Manager](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketManager.html) 119 | - [Engine](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketEngine.html) 120 | - [Options](https://nuclearace.github.io/Socket.IO-Client-Swift/Enums/SocketIOClientOption.html) 121 | 122 | ## Detailed Example 123 | A more detailed example can be found [here](https://github.com/nuclearace/socket.io-client-swift-example) 124 | 125 | An example using the Swift Package Manager can be found [here](https://github.com/nuclearace/socket.io-client-swift-spm-example) 126 | 127 | ## License 128 | MIT 129 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Security/FoundationSecurity.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // FoundationSecurity.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 3/16/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | import CommonCrypto 25 | 26 | public enum FoundationSecurityError: Error { 27 | case invalidRequest 28 | } 29 | 30 | public class FoundationSecurity { 31 | var allowSelfSigned = false 32 | 33 | public init(allowSelfSigned: Bool = false) { 34 | self.allowSelfSigned = allowSelfSigned 35 | } 36 | 37 | 38 | } 39 | 40 | extension FoundationSecurity: CertificatePinning { 41 | public func evaluateTrust(trust: SecTrust, domain: String?, completion: ((PinningState) -> ())) { 42 | if allowSelfSigned { 43 | completion(.success) 44 | return 45 | } 46 | 47 | if let validateDomain = domain { 48 | SecTrustSetPolicies(trust, SecPolicyCreateSSL(true, validateDomain as NSString?)) 49 | } 50 | 51 | handleSecurityTrust(trust: trust, completion: completion) 52 | } 53 | 54 | private func handleSecurityTrust(trust: SecTrust, completion: ((PinningState) -> ())) { 55 | if #available(iOS 12.0, OSX 10.14, watchOS 5.0, tvOS 12.0, *) { 56 | var error: CFError? 57 | if SecTrustEvaluateWithError(trust, &error) { 58 | completion(.success) 59 | } else { 60 | completion(.failed(error)) 61 | } 62 | } else { 63 | handleOldSecurityTrust(trust: trust, completion: completion) 64 | } 65 | } 66 | 67 | private func handleOldSecurityTrust(trust: SecTrust, completion: ((PinningState) -> ())) { 68 | var result: SecTrustResultType = .unspecified 69 | SecTrustEvaluate(trust, &result) 70 | if result == .unspecified || result == .proceed { 71 | completion(.success) 72 | } else { 73 | let e = CFErrorCreate(kCFAllocatorDefault, "FoundationSecurityError" as NSString?, Int(result.rawValue), nil) 74 | completion(.failed(e)) 75 | } 76 | } 77 | } 78 | 79 | extension FoundationSecurity: HeaderValidator { 80 | public func validate(headers: [String: String], key: String) -> Error? { 81 | if let acceptKey = headers[HTTPWSHeader.acceptName] { 82 | let sha = "\(key)258EAFA5-E914-47DA-95CA-C5AB0DC85B11".sha1Base64() 83 | if sha != acceptKey { 84 | return WSError(type: .securityError, message: "accept header doesn't match", code: SecurityErrorCode.acceptFailed.rawValue) 85 | } 86 | } 87 | return nil 88 | } 89 | } 90 | 91 | private extension String { 92 | func sha1Base64() -> String { 93 | let data = self.data(using: .utf8)! 94 | let pointer = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> [UInt8] in 95 | var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH)) 96 | CC_SHA1(bytes.baseAddress, CC_LONG(data.count), &digest) 97 | return digest 98 | } 99 | return Data(pointer).base64EncodedString() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Framer/FoundationHTTPServerHandler.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // FoundationHTTPHandler.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 4/2/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public class FoundationHTTPServerHandler: HTTPServerHandler { 26 | var buffer = Data() 27 | weak var delegate: HTTPServerDelegate? 28 | let getVerb: NSString = "GET" 29 | 30 | public func register(delegate: HTTPServerDelegate) { 31 | self.delegate = delegate 32 | } 33 | 34 | public func createResponse(headers: [String: String]) -> Data { 35 | #if os(watchOS) 36 | //TODO: build response header 37 | return Data() 38 | #else 39 | let response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, HTTPWSHeader.switchProtocolCode, 40 | nil, kCFHTTPVersion1_1).takeRetainedValue() 41 | 42 | //TODO: add other values to make a proper response here... 43 | //TODO: also sec key thing (Sec-WebSocket-Key) 44 | for (key, value) in headers { 45 | CFHTTPMessageSetHeaderFieldValue(response, key as CFString, value as CFString) 46 | } 47 | guard let cfData = CFHTTPMessageCopySerializedMessage(response)?.takeRetainedValue() else { 48 | return Data() 49 | } 50 | return cfData as Data 51 | #endif 52 | } 53 | 54 | public func parse(data: Data) { 55 | buffer.append(data) 56 | if parseContent(data: buffer) { 57 | buffer = Data() 58 | } 59 | } 60 | 61 | //returns true when the buffer should be cleared 62 | func parseContent(data: Data) -> Bool { 63 | var pointer = [UInt8]() 64 | data.withUnsafeBytes { pointer.append(contentsOf: $0) } 65 | #if os(watchOS) 66 | //TODO: parse data 67 | return false 68 | #else 69 | let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, true).takeRetainedValue() 70 | if !CFHTTPMessageAppendBytes(response, pointer, data.count) { 71 | return false //not enough data, wait for more 72 | } 73 | if !CFHTTPMessageIsHeaderComplete(response) { 74 | return false //not enough data, wait for more 75 | } 76 | if let method = CFHTTPMessageCopyRequestMethod(response)?.takeRetainedValue() { 77 | if (method as NSString) != getVerb { 78 | delegate?.didReceive(event: .failure(HTTPUpgradeError.invalidData)) 79 | return true 80 | } 81 | } 82 | 83 | if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) { 84 | let nsHeaders = cfHeaders.takeRetainedValue() as NSDictionary 85 | var headers = [String: String]() 86 | for (key, value) in nsHeaders { 87 | if let key = key as? String, let value = value as? String { 88 | headers[key] = value 89 | } 90 | } 91 | delegate?.didReceive(event: .success(headers)) 92 | return true 93 | } 94 | 95 | delegate?.didReceive(event: .failure(HTTPUpgradeError.invalidData)) 96 | return true 97 | #endif 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lil wallet/Views/Settings/WalletsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EditWalletsView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct WalletsView: View { 11 | @Environment(\.managedObjectContext) private var viewContext 12 | @FetchRequest( 13 | sortDescriptors: [NSSortDescriptor(keyPath: \WalletAddress.name, ascending: true)], 14 | animation: .default) 15 | private var wallets: FetchedResults 16 | @AppStorage("currentWalletAddress") private var currentWalletAddress: String = "" 17 | @EnvironmentObject var wallet: Wallet 18 | @EnvironmentObject var appearance: Appearance 19 | 20 | var body: some View { 21 | let appFont = appearance.getAppFont() 22 | 23 | ZStack { 24 | if wallets.count == 0 { 25 | VStack { 26 | Spacer() 27 | Text("No wallets") 28 | .foregroundColor(.secondary) 29 | .font(.system(.body, design: appearance.getAppFont())) 30 | Spacer() 31 | } 32 | } else { 33 | List { 34 | Section { 35 | ForEach(wallets, id: \.createdAt) { savedWallet in 36 | Button(action: { setCurrentWalletAddress(address: savedWallet.address ?? "") }, label: { 37 | Label { 38 | HStack { 39 | Text(savedWallet.name ?? "Wallet") 40 | .foregroundColor(.primary) 41 | .font(.system(.body, design: appFont)) 42 | .lineLimit(1) 43 | Spacer() 44 | Text(wallet.formatAddress(address: savedWallet.address ?? "")) 45 | .font(.system(.body, design: .monospaced)) 46 | .foregroundColor(.secondary) 47 | .lineLimit(1) 48 | } 49 | } icon: { 50 | Image(systemName: currentWalletAddress == savedWallet.address ? "checkmark" : "") 51 | .font(.headline) 52 | } 53 | }) 54 | } 55 | .onDelete(perform: deleteWallets) 56 | } 57 | } 58 | } 59 | } 60 | .toolbar { 61 | ToolbarItem(placement: .navigationBarTrailing) { 62 | NavigationLink { 63 | AddWalletView() 64 | .environmentObject(wallet) 65 | .environment(\.managedObjectContext, viewContext) 66 | } label: { 67 | Text("Add") 68 | .font(.headline) 69 | } 70 | } 71 | } 72 | .navigationTitle("Wallets") 73 | } 74 | 75 | func setCurrentWalletAddress(address: String) { 76 | let existingCurrentWalletAddress = self.currentWalletAddress 77 | if existingCurrentWalletAddress != address { 78 | self.currentWalletAddress = address 79 | self.wallet.reload(reset: true, refresh: false) 80 | } 81 | } 82 | 83 | private func deleteWallets(offsets: IndexSet) { 84 | withAnimation { 85 | offsets.map { wallets[$0] }.forEach(viewContext.delete) 86 | 87 | do { 88 | try viewContext.save() 89 | } catch { 90 | let nsError = error as NSError 91 | fatalError("Unresolved error \(nsError), \(nsError.userInfo)") 92 | } 93 | } 94 | } 95 | } 96 | 97 | struct EditWalletsView_Previews: PreviewProvider { 98 | static var previews: some View { 99 | WalletsView() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Framer/FrameCollector.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // FrameCollector.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 1/24/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public protocol FrameCollectorDelegate: class { 26 | func didForm(event: FrameCollector.Event) 27 | func decompress(data: Data, isFinal: Bool) -> Data? 28 | } 29 | 30 | public class FrameCollector { 31 | public enum Event { 32 | case text(String) 33 | case binary(Data) 34 | case pong(Data?) 35 | case ping(Data?) 36 | case error(Error) 37 | case closed(String, UInt16) 38 | } 39 | weak var delegate: FrameCollectorDelegate? 40 | var buffer = Data() 41 | var frameCount = 0 42 | var isText = false //was the first frame a text frame or a binary frame? 43 | var needsDecompression = false 44 | 45 | public func add(frame: Frame) { 46 | //check single frame action and out of order frames 47 | if frame.opcode == .connectionClose { 48 | var code = frame.closeCode 49 | var reason = "connection closed by server" 50 | if let customCloseReason = String(data: frame.payload, encoding: .utf8) { 51 | reason = customCloseReason 52 | } else { 53 | code = CloseCode.protocolError.rawValue 54 | } 55 | delegate?.didForm(event: .closed(reason, code)) 56 | return 57 | } else if frame.opcode == .pong { 58 | delegate?.didForm(event: .pong(frame.payload)) 59 | return 60 | } else if frame.opcode == .ping { 61 | delegate?.didForm(event: .ping(frame.payload)) 62 | return 63 | } else if frame.opcode == .continueFrame && frameCount == 0 { 64 | let errCode = CloseCode.protocolError.rawValue 65 | delegate?.didForm(event: .error(WSError(type: .protocolError, message: "first frame can't be a continue frame", code: errCode))) 66 | reset() 67 | return 68 | } else if frameCount > 0 && frame.opcode != .continueFrame { 69 | let errCode = CloseCode.protocolError.rawValue 70 | delegate?.didForm(event: .error(WSError(type: .protocolError, message: "second and beyond of fragment message must be a continue frame", code: errCode))) 71 | reset() 72 | return 73 | } 74 | if frameCount == 0 { 75 | isText = frame.opcode == .textFrame 76 | needsDecompression = frame.needsDecompression 77 | } 78 | 79 | let payload: Data 80 | if needsDecompression { 81 | payload = delegate?.decompress(data: frame.payload, isFinal: frame.isFin) ?? frame.payload 82 | } else { 83 | payload = frame.payload 84 | } 85 | buffer.append(payload) 86 | frameCount += 1 87 | 88 | if frame.isFin { 89 | if isText { 90 | if let string = String(data: buffer, encoding: .utf8) { 91 | delegate?.didForm(event: .text(string)) 92 | } else { 93 | let errCode = CloseCode.protocolError.rawValue 94 | delegate?.didForm(event: .error(WSError(type: .protocolError, message: "not valid UTF-8 data", code: errCode))) 95 | } 96 | } else { 97 | delegate?.didForm(event: .binary(buffer)) 98 | } 99 | reset() 100 | } 101 | } 102 | 103 | func reset() { 104 | buffer = Data() 105 | frameCount = 0 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lil wallet/Views/Tabs/ObjectsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectsView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ObjectsView: View { 11 | @State private var showActivityView = false 12 | @State private var showSettingsView = false 13 | @State private var showAddWalletView = false 14 | @EnvironmentObject var wallet: Wallet 15 | @EnvironmentObject var appearance: Appearance 16 | @Environment(\.managedObjectContext) private var viewContext 17 | @FetchRequest( 18 | sortDescriptors: [NSSortDescriptor(keyPath: \WalletAddress.name, ascending: true)], 19 | animation: .default) 20 | private var wallets: FetchedResults 21 | 22 | var body: some View { 23 | NavigationView { 24 | ZStack { 25 | if wallet.loadingObjects { 26 | VStack { 27 | Spacer() 28 | ProgressView() 29 | Spacer() 30 | } 31 | } else if wallets.count == 0 { 32 | VStack { 33 | Spacer() 34 | Text("No wallets") 35 | .foregroundColor(.secondary) 36 | .font(.system(.body, design: appearance.getAppFont())) 37 | Button(action: { showAddWalletView = true }, label: { 38 | Text("Add wallet") 39 | .font(.headline) 40 | }) 41 | .buttonStyle(BorderedButtonStyle()) 42 | .sheet(isPresented: $showAddWalletView) { 43 | NavigationView { AddWalletView() } 44 | .environmentObject(wallet) 45 | .environmentObject(appearance) 46 | .accentColor(appearance.getAppColor()) 47 | } 48 | Spacer() 49 | } 50 | } else if wallet.objects.count == 0 && !wallet.loadingObjects { 51 | VStack { 52 | Spacer() 53 | Text("No objects") 54 | .foregroundColor(.secondary) 55 | .font(.system(.body, design: appearance.getAppFont())) 56 | Spacer() 57 | } 58 | } else { 59 | ScrollView { 60 | LazyVGrid(columns: [ 61 | GridItem(.flexible(minimum: 40)), 62 | GridItem(.flexible(minimum: 40)) 63 | ]) { 64 | ForEach(wallet.objects, id: \.id) { object in 65 | ObjectGridItem() 66 | .environmentObject(object) 67 | } 68 | } 69 | .padding() 70 | } 71 | } 72 | } 73 | .listStyle(PlainListStyle()) 74 | .navigationTitle("Objects") 75 | .navigationBarTitleDisplayMode(.inline) 76 | .toolbar { 77 | ToolbarItem(placement: .navigationBarTrailing) { 78 | Button(action: { showActivityView.toggle() }, label: { Image(systemName: "clock").font(.headline) }) 79 | .sheet(isPresented: $showActivityView) { 80 | ActivityView() 81 | .environmentObject(wallet) 82 | .environmentObject(appearance) 83 | } 84 | } 85 | 86 | ToolbarItem(placement: .navigationBarTrailing) { 87 | Button(action: { showSettingsView.toggle() }, label: { Image(systemName: "gear").font(.headline) }) 88 | .sheet(isPresented: $showSettingsView) { 89 | SettingsView(showSettingsView: $showSettingsView) 90 | .environmentObject(wallet) 91 | .environmentObject(appearance) 92 | .environment(\.managedObjectContext, viewContext) 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | 100 | struct ObjectsView_Previews: PreviewProvider { 101 | static var previews: some View { 102 | ObjectsView() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lil wallet/Views/Tabs/CoinsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoinsView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CoinsView: View { 11 | @State private var showActivityView = false 12 | @State private var showSettingsView = false 13 | @State private var showAddWalletView = false 14 | @State var loading = true 15 | @State var loadingError = false 16 | @EnvironmentObject var wallet: Wallet 17 | @EnvironmentObject var appearance: Appearance 18 | @Environment(\.managedObjectContext) private var viewContext 19 | @FetchRequest( 20 | sortDescriptors: [NSSortDescriptor(keyPath: \WalletAddress.name, ascending: true)], 21 | animation: .default) 22 | private var wallets: FetchedResults 23 | 24 | var body: some View { 25 | NavigationView { 26 | ZStack { 27 | if wallet.loadingTokens { 28 | VStack { 29 | Spacer() 30 | ProgressView() 31 | Spacer() 32 | } 33 | } else if wallets.count == 0 { 34 | VStack { 35 | Spacer() 36 | Text("No wallets") 37 | .foregroundColor(.secondary) 38 | .font(.system(.body, design: appearance.getAppFont())) 39 | Button(action: { showAddWalletView = true }, label: { 40 | Text("Add wallet") 41 | .font(.headline) 42 | }) 43 | .buttonStyle(BorderedButtonStyle()) 44 | .sheet(isPresented: $showAddWalletView) { 45 | NavigationView { AddWalletView() } 46 | .environmentObject(wallet) 47 | .environmentObject(appearance) 48 | .accentColor(appearance.getAppColor()) 49 | } 50 | Spacer() 51 | } 52 | } else if wallet.tokens.count == 0 && !wallet.loadingTokens { 53 | VStack { 54 | Spacer() 55 | Text("No crypto") 56 | .foregroundColor(.secondary) 57 | .font(.system(.body, design: appearance.getAppFont())) 58 | Spacer() 59 | } 60 | } else { 61 | List { 62 | ForEach(sortedTokens(), id: \.id) { token in 63 | CryptoListItem() 64 | .environmentObject(token) 65 | .environmentObject(appearance) 66 | .listRowSeparator(.hidden) 67 | } 68 | } 69 | .listStyle(PlainListStyle()) 70 | .refreshable { 71 | self.wallet.reload(reset: false, refresh: true) 72 | } 73 | } 74 | } 75 | .navigationTitle(wallet.formatCurrency(value: wallet.value)) 76 | .toolbar { 77 | ToolbarItem(placement: .navigationBarTrailing) { 78 | Button(action: { showActivityView.toggle() }, label: { Image(systemName: "clock").font(.headline) }) 79 | .sheet(isPresented: $showActivityView) { 80 | ActivityView() 81 | .environmentObject(wallet) 82 | .environmentObject(appearance) 83 | } 84 | } 85 | 86 | ToolbarItem(placement: .navigationBarTrailing) { 87 | Button(action: { showSettingsView.toggle() }, label: { Image(systemName: "gear").font(.headline) }) 88 | .sheet(isPresented: $showSettingsView) { 89 | SettingsView(showSettingsView: $showSettingsView) 90 | .environmentObject(wallet) 91 | .environmentObject(appearance) 92 | .environment(\.managedObjectContext, viewContext) 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | func sortedTokens() -> [Token] { 100 | return wallet.tokens.sorted(by: { 101 | $0.name.lowercased() < $1.name.lowercased() 102 | }) 103 | } 104 | } 105 | 106 | struct CryptoView_Previews: PreviewProvider { 107 | static var previews: some View { 108 | CoinsView() 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lil wallet/Views/Detail/ObjectDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectDetailView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | import WebKit 10 | 11 | struct ObjectDetailView: View { 12 | @Environment(\.presentationMode) var presentationMode 13 | @Environment(\.colorScheme) var colorScheme 14 | @EnvironmentObject var object: OpenSeaAsset 15 | @EnvironmentObject var appearance: Appearance 16 | 17 | var body: some View { 18 | let appFont = appearance.getAppFont() 19 | 20 | List { 21 | Group { 22 | if object.isSVG() { 23 | WebView(loadURL: object.image_url) 24 | .aspectRatio(1, contentMode: .fit) 25 | } else { 26 | AsyncImage(url: URL(string: object.image_url)) { image in 27 | image.resizable() 28 | .aspectRatio(contentMode: .fit) 29 | } placeholder: { 30 | Rectangle() 31 | .foregroundColor(Color(UIColor.secondarySystemBackground)) 32 | .aspectRatio(1, contentMode: .fit) 33 | } 34 | } 35 | } 36 | .listRowInsets(EdgeInsets()) 37 | .listRowSeparator(.hidden) 38 | 39 | Section(content: { 40 | VStack(alignment: .leading, spacing: 4) { 41 | Text(object.name ?? "Untitled") 42 | .font(.system(.headline, design: appFont)) 43 | 44 | if let description = object.description { 45 | Text(description) 46 | .font(.system(.body, design: appFont)) 47 | } 48 | } 49 | .listRowSeparator(.hidden) 50 | }, header: { 51 | Text("About") 52 | }) 53 | 54 | if object.traits.count > 0 { 55 | Section(content: { 56 | ForEach(object.traits, id: \.trait_type) { trait in 57 | HStack { 58 | Text(trait.trait_type.capitalized) 59 | .font(.system(.body, design: appFont)) 60 | .lineLimit(1) 61 | Spacer() 62 | Text(trait.value.capitalized) 63 | .font(.system(.headline, design: appFont)) 64 | .lineLimit(1) 65 | } 66 | } 67 | .listRowSeparator(.hidden) 68 | }, header: { 69 | Text("Properties") 70 | }) 71 | } 72 | 73 | Section(content: { 74 | Group { 75 | Link(destination: URL(string: object.permalink)!, label: { 76 | Text("View on OpenSea") 77 | .font(.system(.body, design: appFont)) 78 | }) 79 | } 80 | .font(.system(.body, design: appFont)) 81 | .foregroundColor(appearance.getAppColor()) 82 | .listRowSeparator(.hidden) 83 | }, header: { 84 | Text("Options") 85 | }) 86 | } 87 | .listStyle(InsetListStyle()) 88 | .navigationBarTitle(object.name ?? "Untitled") 89 | .navigationBarTitleDisplayMode(.inline) 90 | } 91 | } 92 | 93 | struct WebView: UIViewRepresentable { 94 | let loadURL: String 95 | 96 | func makeUIView(context: Context) -> WKWebView { 97 | let webView = WKWebView() 98 | webView.scrollView.isScrollEnabled = false 99 | webView.isUserInteractionEnabled = false 100 | return webView 101 | } 102 | 103 | func updateUIView(_ uiView: WKWebView, context: Context) { 104 | if let url = URL(string: loadURL) { 105 | do { 106 | let contents = try String(contentsOf: url) 107 | let html = contents + "" 108 | uiView.loadHTMLString(html, baseURL: nil) 109 | } catch { 110 | // contents could not be loaded 111 | } 112 | } else { 113 | // the URL was bad 114 | } 115 | } 116 | } 117 | 118 | struct ObjectDetailView_Previews: PreviewProvider { 119 | static var previews: some View { 120 | ObjectDetailView() 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Framer/FoundationHTTPHandler.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // FoundationHTTPHandler.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 1/25/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | #if os(watchOS) 25 | public typealias FoundationHTTPHandler = StringHTTPHandler 26 | #else 27 | public class FoundationHTTPHandler: HTTPHandler { 28 | 29 | var buffer = Data() 30 | weak var delegate: HTTPHandlerDelegate? 31 | 32 | public init() { 33 | 34 | } 35 | 36 | public func convert(request: URLRequest) -> Data { 37 | let msg = CFHTTPMessageCreateRequest(kCFAllocatorDefault, request.httpMethod! as CFString, 38 | request.url! as CFURL, kCFHTTPVersion1_1).takeRetainedValue() 39 | if let headers = request.allHTTPHeaderFields { 40 | for (aKey, aValue) in headers { 41 | CFHTTPMessageSetHeaderFieldValue(msg, aKey as CFString, aValue as CFString) 42 | } 43 | } 44 | if let body = request.httpBody { 45 | CFHTTPMessageSetBody(msg, body as CFData) 46 | } 47 | guard let data = CFHTTPMessageCopySerializedMessage(msg) else { 48 | return Data() 49 | } 50 | return data.takeRetainedValue() as Data 51 | } 52 | 53 | public func parse(data: Data) -> Int { 54 | let offset = findEndOfHTTP(data: data) 55 | if offset > 0 { 56 | buffer.append(data.subdata(in: 0.. Bool { 68 | var pointer = [UInt8]() 69 | data.withUnsafeBytes { pointer.append(contentsOf: $0) } 70 | 71 | let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue() 72 | if !CFHTTPMessageAppendBytes(response, pointer, data.count) { 73 | return false //not enough data, wait for more 74 | } 75 | if !CFHTTPMessageIsHeaderComplete(response) { 76 | return false //not enough data, wait for more 77 | } 78 | 79 | let code = CFHTTPMessageGetResponseStatusCode(response) 80 | if code != HTTPWSHeader.switchProtocolCode { 81 | delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code))) 82 | return true 83 | } 84 | 85 | if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) { 86 | let nsHeaders = cfHeaders.takeRetainedValue() as NSDictionary 87 | var headers = [String: String]() 88 | for (key, value) in nsHeaders { 89 | if let key = key as? String, let value = value as? String { 90 | headers[key] = value 91 | } 92 | } 93 | delegate?.didReceiveHTTP(event: .success(headers)) 94 | return true 95 | } 96 | 97 | delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.invalidData)) 98 | return true 99 | } 100 | 101 | public func register(delegate: HTTPHandlerDelegate) { 102 | self.delegate = delegate 103 | } 104 | 105 | private func findEndOfHTTP(data: Data) -> Int { 106 | let endBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")] 107 | var pointer = [UInt8]() 108 | data.withUnsafeBytes { pointer.append(contentsOf: $0) } 109 | var k = 0 110 | for i in 0...Index 34 | 35 | /// Iterator type. 36 | public typealias Iterator = Array.Iterator 37 | 38 | /// SubSequence type. 39 | public typealias SubSequence = Array.SubSequence 40 | 41 | // MARK: Properties 42 | 43 | private var backingArray = [SocketIOClientOption]() 44 | 45 | /// The start index of this collection. 46 | public var startIndex: Index { 47 | return backingArray.startIndex 48 | } 49 | 50 | /// The end index of this collection. 51 | public var endIndex: Index { 52 | return backingArray.endIndex 53 | } 54 | 55 | /// Whether this collection is empty. 56 | public var isEmpty: Bool { 57 | return backingArray.isEmpty 58 | } 59 | 60 | /// The number of elements stored in this collection. 61 | public var count: Index.Stride { 62 | return backingArray.count 63 | } 64 | 65 | /// The first element in this collection. 66 | public var first: Element? { 67 | return backingArray.first 68 | } 69 | 70 | public subscript(position: Index) -> Element { 71 | get { 72 | return backingArray[position] 73 | } 74 | 75 | set { 76 | backingArray[position] = newValue 77 | } 78 | } 79 | 80 | public subscript(bounds: Range) -> SubSequence { 81 | get { 82 | return backingArray[bounds] 83 | } 84 | 85 | set { 86 | backingArray[bounds] = newValue 87 | } 88 | } 89 | 90 | // MARK: Initializers 91 | 92 | /// Creates a new `SocketIOClientConfiguration` from an array literal. 93 | /// 94 | /// - parameter arrayLiteral: The elements. 95 | public init(arrayLiteral elements: Element...) { 96 | backingArray = elements 97 | } 98 | 99 | // MARK: Methods 100 | 101 | /// Creates an iterator for this collection. 102 | /// 103 | /// - returns: An iterator over this collection. 104 | public func makeIterator() -> Iterator { 105 | return backingArray.makeIterator() 106 | } 107 | 108 | /// - returns: The index after index. 109 | public func index(after i: Index) -> Index { 110 | return backingArray.index(after: i) 111 | } 112 | 113 | /// Special method that inserts `element` into the collection, replacing any other instances of `element`. 114 | /// 115 | /// - parameter element: The element to insert. 116 | /// - parameter replacing: Whether to replace any occurrences of element to the new item. Default is `true`. 117 | public mutating func insert(_ element: Element, replacing replace: Bool = true) { 118 | for i in 0.. Data { 35 | guard let url = request.url else { 36 | return Data() 37 | } 38 | 39 | var path = url.absoluteString 40 | let offset = (url.scheme?.count ?? 2) + 3 41 | path = String(path[path.index(path.startIndex, offsetBy: offset).. Int { 71 | let offset = findEndOfHTTP(data: data) 72 | if offset > 0 { 73 | buffer.append(data.subdata(in: 0.. Bool { 85 | guard let str = String(data: data, encoding: .utf8) else { 86 | delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.invalidData)) 87 | return true 88 | } 89 | let splitArr = str.components(separatedBy: "\r\n") 90 | var code = -1 91 | var i = 0 92 | var headers = [String: String]() 93 | for str in splitArr { 94 | if i == 0 { 95 | let responseSplit = str.components(separatedBy: .whitespaces) 96 | guard responseSplit.count > 1 else { 97 | delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.invalidData)) 98 | return true 99 | } 100 | if let c = Int(responseSplit[1]) { 101 | code = c 102 | } 103 | } else { 104 | guard let separatorIndex = str.firstIndex(of: ":") else { break } 105 | let key = str.prefix(upTo: separatorIndex).trimmingCharacters(in: .whitespaces) 106 | let val = str.suffix(from: str.index(after: separatorIndex)).trimmingCharacters(in: .whitespaces) 107 | headers[key.lowercased()] = val 108 | } 109 | i += 1 110 | } 111 | 112 | if code != HTTPWSHeader.switchProtocolCode { 113 | delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code))) 114 | return true 115 | } 116 | 117 | delegate?.didReceiveHTTP(event: .success(headers)) 118 | return true 119 | } 120 | 121 | public func register(delegate: HTTPHandlerDelegate) { 122 | self.delegate = delegate 123 | } 124 | 125 | private func findEndOfHTTP(data: Data) -> Int { 126 | let endBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")] 127 | var pointer = [UInt8]() 128 | data.withUnsafeBytes { pointer.append(contentsOf: $0) } 129 | var k = 0 130 | for i in 0.. 25 | @EnvironmentObject var wallet: Wallet 26 | @EnvironmentObject var appearance: Appearance 27 | @State var loading = false 28 | @State var showAlert = false 29 | 30 | var body: some View { 31 | Form { 32 | Section(content: { 33 | TextField("Name", text: $name) 34 | .focused($focusedField, equals: .name) 35 | .textInputAutocapitalization(.never) 36 | .disableAutocorrection(true) 37 | .submitLabel(.next) 38 | 39 | TextField("Address", text: $address) 40 | .focused($focusedField, equals: .address) 41 | .textInputAutocapitalization(.never) 42 | .disableAutocorrection(true) 43 | .submitLabel(.done) 44 | }, footer: { 45 | Text("Ethereum address or ENS name") 46 | }) 47 | } 48 | .font(.system(.body, design: appearance.getAppFont())) 49 | .toolbar(content: { 50 | ToolbarItem { 51 | Button(action: saveWallet, label: { 52 | if self.loading { 53 | ProgressView() 54 | } else { 55 | Text("Save") 56 | .font(.headline) 57 | } 58 | }) 59 | .disabled(!isValid() || self.loading) 60 | .alert("Failed to load wallet", isPresented: $showAlert) { 61 | Button("OK", role: .cancel) { } 62 | } 63 | } 64 | }) 65 | .navigationTitle("Add Wallet") 66 | .navigationBarTitleDisplayMode(.inline) 67 | .onAppear(perform: { autofocus() }) 68 | } 69 | 70 | func autofocus() { 71 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.75) { 72 | self.focusedField = .name 73 | } 74 | } 75 | 76 | func isValid() -> Bool { 77 | return self.address != "" && (self.address.hasPrefix("0x") || self.address.hasSuffix(".eth")) 78 | } 79 | 80 | private func saveWallet() { 81 | if self.address.hasSuffix(".eth") { 82 | // address contains .eth, do reverse lookup 83 | reverseENSLookup(ensName: self.address) 84 | } else { 85 | addWallet(address: self.address) 86 | } 87 | } 88 | 89 | private func addWallet(address: String) { 90 | let newWallet = WalletAddress(context: viewContext) 91 | newWallet.createdAt = Date() 92 | newWallet.name = self.name == "" ? nil : self.name 93 | newWallet.address = address 94 | 95 | if wallets.count == 0 { 96 | // set to active wallet if it's the first one 97 | self.currentWalletAddress = address 98 | wallet.reload(reset: true, refresh: false) 99 | } 100 | 101 | do { 102 | try viewContext.save() 103 | presentationMode.wrappedValue.dismiss() 104 | } catch { 105 | let nsError = error as NSError 106 | fatalError("Unresolved error \(nsError), \(nsError.userInfo)") 107 | } 108 | } 109 | 110 | func reverseENSLookup(ensName: String) { 111 | self.loading = true 112 | 113 | guard let url = URL(string: "https://0xmade-ens.vercel.app/api/ens/resolve?name=\(ensName)") else { 114 | print("Invalid URL") 115 | return 116 | } 117 | 118 | let request = URLRequest(url: url) 119 | 120 | URLSession.shared.dataTask(with: request) { data, response, error in 121 | if let data = data { 122 | if let decodedResponse = try? JSONDecoder().decode(ReverseENSLookupResponse.self, from: data) { 123 | DispatchQueue.main.async { 124 | self.loading = false 125 | addWallet(address: decodedResponse.address) 126 | } 127 | 128 | return 129 | } 130 | } 131 | 132 | self.loading = false 133 | self.showAlert = true 134 | 135 | // if we're still here it means there was a problem 136 | print("failed: \(error?.localizedDescription ?? "Unknown error")") 137 | }.resume() 138 | } 139 | } 140 | 141 | struct AddWalletView_Previews: PreviewProvider { 142 | static var previews: some View { 143 | AddWalletView() 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Util/SocketExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketExtensions.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 7/1/2016. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import Starscream 27 | 28 | enum JSONError : Error { 29 | case notArray 30 | case notNSDictionary 31 | } 32 | 33 | extension Array { 34 | func toJSON() throws -> Data { 35 | return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions(rawValue: 0)) 36 | } 37 | } 38 | 39 | extension CharacterSet { 40 | static var allowedURLCharacterSet: CharacterSet { 41 | return CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]\" {}^|").inverted 42 | } 43 | } 44 | 45 | extension Dictionary where Key == String, Value == Any { 46 | private static func keyValueToSocketIOClientOption(key: String, value: Any) -> SocketIOClientOption? { 47 | switch (key, value) { 48 | case let ("connectParams", params as [String: Any]): 49 | return .connectParams(params) 50 | case let ("cookies", cookies as [HTTPCookie]): 51 | return .cookies(cookies) 52 | case let ("extraHeaders", headers as [String: String]): 53 | return .extraHeaders(headers) 54 | case let ("forceNew", force as Bool): 55 | return .forceNew(force) 56 | case let ("forcePolling", force as Bool): 57 | return .forcePolling(force) 58 | case let ("forceWebsockets", force as Bool): 59 | return .forceWebsockets(force) 60 | case let ("handleQueue", queue as DispatchQueue): 61 | return .handleQueue(queue) 62 | case let ("log", log as Bool): 63 | return .log(log) 64 | case let ("logger", logger as SocketLogger): 65 | return .logger(logger) 66 | case let ("path", path as String): 67 | return .path(path) 68 | case let ("reconnects", reconnects as Bool): 69 | return .reconnects(reconnects) 70 | case let ("reconnectAttempts", attempts as Int): 71 | return .reconnectAttempts(attempts) 72 | case let ("reconnectWait", wait as Int): 73 | return .reconnectWait(wait) 74 | case let ("reconnectWaitMax", wait as Int): 75 | return .reconnectWaitMax(wait) 76 | case let ("randomizationFactor", factor as Double): 77 | return .randomizationFactor(factor) 78 | case let ("secure", secure as Bool): 79 | return .secure(secure) 80 | case let ("security", security as CertificatePinning): 81 | return .security(security) 82 | case let ("selfSigned", selfSigned as Bool): 83 | return .selfSigned(selfSigned) 84 | case let ("sessionDelegate", delegate as URLSessionDelegate): 85 | return .sessionDelegate(delegate) 86 | case let ("compress", compress as Bool): 87 | return compress ? .compress : nil 88 | case let ("enableSOCKSProxy", enable as Bool): 89 | return .enableSOCKSProxy(enable) 90 | case let ("version", version as Int): 91 | return .version(SocketIOVersion(rawValue: version) ?? .three) 92 | case _: 93 | return nil 94 | } 95 | } 96 | 97 | func toSocketConfiguration() -> SocketIOClientConfiguration { 98 | var options = [] as SocketIOClientConfiguration 99 | 100 | for (rawKey, value) in self { 101 | if let opt = Dictionary.keyValueToSocketIOClientOption(key: rawKey, value: value) { 102 | options.insert(opt) 103 | } 104 | } 105 | 106 | return options 107 | } 108 | } 109 | 110 | extension String { 111 | func toArray() throws -> [Any] { 112 | guard let stringData = data(using: .utf16, allowLossyConversion: false) else { return [] } 113 | guard let array = try JSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? [Any] else { 114 | throw JSONError.notArray 115 | } 116 | 117 | return array 118 | } 119 | 120 | func toDictionary() throws -> [String: Any] { 121 | guard let binData = data(using: .utf16, allowLossyConversion: false) else { return [:] } 122 | guard let json = try JSONSerialization.jsonObject(with: binData, options: .allowFragments) as? [String: Any] else { 123 | throw JSONError.notNSDictionary 124 | } 125 | 126 | return json 127 | } 128 | 129 | func urlEncode() -> String? { 130 | return addingPercentEncoding(withAllowedCharacters: .allowedURLCharacterSet) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Ack/SocketAckEmitter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketAckEmitter.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 9/16/15. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Dispatch 26 | import Foundation 27 | 28 | /// A class that represents a waiting ack call. 29 | /// 30 | /// **NOTE**: You should not store this beyond the life of the event handler. 31 | public final class SocketAckEmitter : NSObject { 32 | private unowned let socket: SocketIOClient 33 | private let ackNum: Int 34 | 35 | /// A view into this emitter where emits do not check for binary data. 36 | /// 37 | /// Usage: 38 | /// 39 | /// ```swift 40 | /// ack.rawEmitView.with(myObject) 41 | /// ``` 42 | /// 43 | /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. 44 | @objc 45 | public private(set) lazy var rawEmitView = SocketRawAckView(socket: socket, ackNum: ackNum) 46 | 47 | // MARK: Properties 48 | 49 | /// If true, this handler is expecting to be acked. Call `with(_: SocketData...)` to ack. 50 | public var expected: Bool { 51 | return ackNum != -1 52 | } 53 | 54 | // MARK: Initializers 55 | 56 | /// Creates a new `SocketAckEmitter`. 57 | /// 58 | /// - parameter socket: The socket for this emitter. 59 | /// - parameter ackNum: The ack number for this emitter. 60 | public init(socket: SocketIOClient, ackNum: Int) { 61 | self.socket = socket 62 | self.ackNum = ackNum 63 | } 64 | 65 | // MARK: Methods 66 | 67 | /// Call to ack receiving this event. 68 | /// 69 | /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` 70 | /// will be emitted. The structure of the error data is `[ackNum, items, theError]` 71 | /// 72 | /// - parameter items: A variable number of items to send when acking. 73 | public func with(_ items: SocketData...) { 74 | guard ackNum != -1 else { return } 75 | 76 | do { 77 | socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() })) 78 | } catch { 79 | socket.handleClientEvent(.error, data: [ackNum, items, error]) 80 | } 81 | } 82 | 83 | /// Call to ack receiving this event. 84 | /// 85 | /// - parameter items: An array of items to send when acking. Use `[]` to send nothing. 86 | @objc 87 | public func with(_ items: [Any]) { 88 | guard ackNum != -1 else { return } 89 | 90 | socket.emitAck(ackNum, with: items) 91 | } 92 | 93 | } 94 | 95 | /// A class that represents an emit that will request an ack that has not yet been sent. 96 | /// Call `timingOut(after:callback:)` to complete the emit 97 | /// Example: 98 | /// 99 | /// ```swift 100 | /// socket.emitWithAck("myEvent").timingOut(after: 1) {data in 101 | /// ... 102 | /// } 103 | /// ``` 104 | public final class OnAckCallback : NSObject { 105 | private let ackNumber: Int 106 | private let binary: Bool 107 | private let items: [Any] 108 | 109 | private weak var socket: SocketIOClient? 110 | 111 | init(ackNumber: Int, items: [Any], socket: SocketIOClient, binary: Bool = true) { 112 | self.ackNumber = ackNumber 113 | self.items = items 114 | self.socket = socket 115 | self.binary = binary 116 | } 117 | 118 | /// :nodoc: 119 | deinit { 120 | DefaultSocketLogger.Logger.log("OnAckCallback for \(ackNumber) being released", type: "OnAckCallback") 121 | } 122 | 123 | // MARK: Methods 124 | 125 | /// Completes an emitWithAck. If this isn't called, the emit never happens. 126 | /// 127 | /// - parameter seconds: The number of seconds before this emit times out if an ack hasn't been received. 128 | /// - parameter callback: The callback called when an ack is received, or when a timeout happens. 129 | /// To check for timeout, use `SocketAckStatus`'s `noAck` case. 130 | @objc 131 | public func timingOut(after seconds: Double, callback: @escaping AckCallback) { 132 | guard let socket = self.socket, ackNumber != -1 else { return } 133 | 134 | socket.ackHandlers.addAck(ackNumber, callback: callback) 135 | socket.emit(items, ack: ackNumber, binary: binary) 136 | 137 | guard seconds != 0 else { return } 138 | 139 | socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in 140 | guard let socket = socket else { return } 141 | 142 | socket.ackHandlers.timeoutAck(self.ackNumber) 143 | } 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Framer/HTTPHandler.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // HTTPHandler.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 1/24/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public enum HTTPUpgradeError: Error { 26 | case notAnUpgrade(Int) 27 | case invalidData 28 | } 29 | 30 | public struct HTTPWSHeader { 31 | static let upgradeName = "Upgrade" 32 | static let upgradeValue = "websocket" 33 | static let hostName = "Host" 34 | static let connectionName = "Connection" 35 | static let connectionValue = "Upgrade" 36 | static let protocolName = "Sec-WebSocket-Protocol" 37 | static let versionName = "Sec-WebSocket-Version" 38 | static let versionValue = "13" 39 | static let extensionName = "Sec-WebSocket-Extensions" 40 | static let keyName = "Sec-WebSocket-Key" 41 | static let originName = "Origin" 42 | static let acceptName = "Sec-WebSocket-Accept" 43 | static let switchProtocolCode = 101 44 | static let defaultSSLSchemes = ["wss", "https"] 45 | 46 | /// Creates a new URLRequest based off the source URLRequest. 47 | /// - Parameter request: the request to "upgrade" the WebSocket request by adding headers. 48 | /// - Parameter supportsCompression: set if the client support text compression. 49 | /// - Parameter secKeyName: the security key to use in the WebSocket request. https://tools.ietf.org/html/rfc6455#section-1.3 50 | /// - returns: A URLRequest request to be converted to data and sent to the server. 51 | public static func createUpgrade(request: URLRequest, supportsCompression: Bool, secKeyValue: String) -> URLRequest { 52 | guard let url = request.url, let parts = url.getParts() else { 53 | return request 54 | } 55 | 56 | var req = request 57 | if request.value(forHTTPHeaderField: HTTPWSHeader.originName) == nil { 58 | var origin = url.absoluteString 59 | if let hostUrl = URL (string: "/", relativeTo: url) { 60 | origin = hostUrl.absoluteString 61 | origin.remove(at: origin.index(before: origin.endIndex)) 62 | } 63 | req.setValue(origin, forHTTPHeaderField: HTTPWSHeader.originName) 64 | } 65 | req.setValue(HTTPWSHeader.upgradeValue, forHTTPHeaderField: HTTPWSHeader.upgradeName) 66 | req.setValue(HTTPWSHeader.connectionValue, forHTTPHeaderField: HTTPWSHeader.connectionName) 67 | req.setValue(HTTPWSHeader.versionValue, forHTTPHeaderField: HTTPWSHeader.versionName) 68 | req.setValue(secKeyValue, forHTTPHeaderField: HTTPWSHeader.keyName) 69 | 70 | if let cookies = HTTPCookieStorage.shared.cookies(for: url), !cookies.isEmpty { 71 | let headers = HTTPCookie.requestHeaderFields(with: cookies) 72 | for (key, val) in headers { 73 | req.setValue(val, forHTTPHeaderField: key) 74 | } 75 | } 76 | 77 | if supportsCompression { 78 | let val = "permessage-deflate; client_max_window_bits; server_max_window_bits=15" 79 | req.setValue(val, forHTTPHeaderField: HTTPWSHeader.extensionName) 80 | } 81 | let hostValue = req.allHTTPHeaderFields?[HTTPWSHeader.hostName] ?? "\(parts.host):\(parts.port)" 82 | req.setValue(hostValue, forHTTPHeaderField: HTTPWSHeader.hostName) 83 | return req 84 | } 85 | 86 | // generateWebSocketKey 16 random characters between a-z and return them as a base64 string 87 | public static func generateWebSocketKey() -> String { 88 | return Data((0..<16).map{ _ in UInt8.random(in: 97...122) }).base64EncodedString() 89 | } 90 | } 91 | 92 | public enum HTTPEvent { 93 | case success([String: String]) 94 | case failure(Error) 95 | } 96 | 97 | public protocol HTTPHandlerDelegate: class { 98 | func didReceiveHTTP(event: HTTPEvent) 99 | } 100 | 101 | public protocol HTTPHandler { 102 | func register(delegate: HTTPHandlerDelegate) 103 | func convert(request: URLRequest) -> Data 104 | func parse(data: Data) -> Int 105 | } 106 | 107 | public protocol HTTPServerDelegate: class { 108 | func didReceive(event: HTTPEvent) 109 | } 110 | 111 | public protocol HTTPServerHandler { 112 | func register(delegate: HTTPServerDelegate) 113 | func parse(data: Data) 114 | func createResponse(headers: [String: String]) -> Data 115 | } 116 | 117 | public struct URLParts { 118 | let port: Int 119 | let host: String 120 | let isTLS: Bool 121 | } 122 | 123 | public extension URL { 124 | /// isTLSScheme returns true if the scheme is https or wss 125 | var isTLSScheme: Bool { 126 | guard let scheme = self.scheme else { 127 | return false 128 | } 129 | return HTTPWSHeader.defaultSSLSchemes.contains(scheme) 130 | } 131 | 132 | /// getParts pulls host and port from the url. 133 | func getParts() -> URLParts? { 134 | guard let host = self.host else { 135 | return nil // no host, this isn't a valid url 136 | } 137 | let isTLS = isTLSScheme 138 | var port = self.port ?? 0 139 | if self.port == nil { 140 | if isTLS { 141 | port = 443 142 | } else { 143 | port = 80 144 | } 145 | } 146 | return URLParts(port: port, host: host, isTLS: isTLS) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Transport/TCPTransport.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // HTTPTransport.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 1/23/19. 7 | // Copyright © 2019 Vluxe. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | #if canImport(Network) 24 | import Foundation 25 | import Network 26 | 27 | public enum TCPTransportError: Error { 28 | case invalidRequest 29 | } 30 | 31 | @available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *) 32 | public class TCPTransport: Transport { 33 | private var connection: NWConnection? 34 | private let queue = DispatchQueue(label: "com.vluxe.starscream.networkstream", attributes: []) 35 | private weak var delegate: TransportEventClient? 36 | private var isRunning = false 37 | private var isTLS = false 38 | 39 | public var usingTLS: Bool { 40 | return self.isTLS 41 | } 42 | 43 | public init(connection: NWConnection) { 44 | self.connection = connection 45 | start() 46 | } 47 | 48 | public init() { 49 | //normal connection, will use the "connect" method below 50 | } 51 | 52 | public func connect(url: URL, timeout: Double = 10, certificatePinning: CertificatePinning? = nil) { 53 | guard let parts = url.getParts() else { 54 | delegate?.connectionChanged(state: .failed(TCPTransportError.invalidRequest)) 55 | return 56 | } 57 | self.isTLS = parts.isTLS 58 | let options = NWProtocolTCP.Options() 59 | options.connectionTimeout = Int(timeout.rounded(.up)) 60 | 61 | let tlsOptions = isTLS ? NWProtocolTLS.Options() : nil 62 | if let tlsOpts = tlsOptions { 63 | sec_protocol_options_set_verify_block(tlsOpts.securityProtocolOptions, { (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in 64 | let trust = sec_trust_copy_ref(sec_trust).takeRetainedValue() 65 | guard let pinner = certificatePinning else { 66 | sec_protocol_verify_complete(true) 67 | return 68 | } 69 | pinner.evaluateTrust(trust: trust, domain: parts.host, completion: { (state) in 70 | switch state { 71 | case .success: 72 | sec_protocol_verify_complete(true) 73 | case .failed(_): 74 | sec_protocol_verify_complete(false) 75 | } 76 | }) 77 | }, queue) 78 | } 79 | let parameters = NWParameters(tls: tlsOptions, tcp: options) 80 | let conn = NWConnection(host: NWEndpoint.Host.name(parts.host, nil), port: NWEndpoint.Port(rawValue: UInt16(parts.port))!, using: parameters) 81 | connection = conn 82 | start() 83 | } 84 | 85 | public func disconnect() { 86 | isRunning = false 87 | connection?.cancel() 88 | } 89 | 90 | public func register(delegate: TransportEventClient) { 91 | self.delegate = delegate 92 | } 93 | 94 | public func write(data: Data, completion: @escaping ((Error?) -> ())) { 95 | connection?.send(content: data, completion: .contentProcessed { (error) in 96 | completion(error) 97 | }) 98 | } 99 | 100 | private func start() { 101 | guard let conn = connection else { 102 | return 103 | } 104 | conn.stateUpdateHandler = { [weak self] (newState) in 105 | switch newState { 106 | case .ready: 107 | self?.delegate?.connectionChanged(state: .connected) 108 | case .waiting: 109 | self?.delegate?.connectionChanged(state: .waiting) 110 | case .cancelled: 111 | self?.delegate?.connectionChanged(state: .cancelled) 112 | case .failed(let error): 113 | self?.delegate?.connectionChanged(state: .failed(error)) 114 | case .setup, .preparing: 115 | break 116 | @unknown default: 117 | break 118 | } 119 | } 120 | 121 | conn.viabilityUpdateHandler = { [weak self] (isViable) in 122 | self?.delegate?.connectionChanged(state: .viability(isViable)) 123 | } 124 | 125 | conn.betterPathUpdateHandler = { [weak self] (isBetter) in 126 | self?.delegate?.connectionChanged(state: .shouldReconnect(isBetter)) 127 | } 128 | 129 | conn.start(queue: queue) 130 | isRunning = true 131 | readLoop() 132 | } 133 | 134 | //readLoop keeps reading from the connection to get the latest content 135 | private func readLoop() { 136 | if !isRunning { 137 | return 138 | } 139 | connection?.receive(minimumIncompleteLength: 2, maximumLength: 4096, completion: {[weak self] (data, context, isComplete, error) in 140 | guard let s = self else {return} 141 | if let data = data { 142 | s.delegate?.connectionChanged(state: .receive(data)) 143 | } 144 | 145 | // Refer to https://developer.apple.com/documentation/network/implementing_netcat_with_network_framework 146 | if let context = context, context.isFinal, isComplete { 147 | return 148 | } 149 | 150 | if error == nil { 151 | s.readLoop() 152 | } 153 | 154 | }) 155 | } 156 | } 157 | #else 158 | typealias TCPTransport = FoundationTransport 159 | #endif 160 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Manager/SocketManagerSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Erik Little on 10/18/17. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | import Dispatch 23 | import Foundation 24 | 25 | // TODO Fix the types so that we aren't using concrete types 26 | 27 | /// 28 | /// A manager for a socket.io connection. 29 | /// 30 | /// A `SocketManagerSpec` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`. 31 | /// 32 | /// Example with `SocketManager`: 33 | /// 34 | /// ```swift 35 | /// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!) 36 | /// let defaultNamespaceSocket = manager.defaultSocket 37 | /// let swiftSocket = manager.socket(forNamespace: "/swift") 38 | /// 39 | /// // defaultNamespaceSocket and swiftSocket both share a single connection to the server 40 | /// ``` 41 | /// 42 | /// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference 43 | /// to the manager must be maintained to keep sockets alive. 44 | /// 45 | /// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket, 46 | /// or call one of the `disconnectSocket` methods on this class. 47 | /// 48 | public protocol SocketManagerSpec : AnyObject, SocketEngineClient { 49 | // MARK: Properties 50 | 51 | /// Returns the socket associated with the default namespace ("/"). 52 | var defaultSocket: SocketIOClient { get } 53 | 54 | /// The engine for this manager. 55 | var engine: SocketEngineSpec? { get set } 56 | 57 | /// If `true` then every time `connect` is called, a new engine will be created. 58 | var forceNew: Bool { get set } 59 | 60 | // TODO Per socket queues? 61 | /// The queue that all interaction with the client should occur on. This is the queue that event handlers are 62 | /// called on. 63 | var handleQueue: DispatchQueue { get set } 64 | 65 | /// The sockets in this manager indexed by namespace. 66 | var nsps: [String: SocketIOClient] { get set } 67 | 68 | /// If `true`, this manager will try and reconnect on any disconnects. 69 | var reconnects: Bool { get set } 70 | 71 | /// The minimum number of seconds to wait before attempting to reconnect. 72 | var reconnectWait: Int { get set } 73 | 74 | /// The maximum number of seconds to wait before attempting to reconnect. 75 | var reconnectWaitMax: Int { get set } 76 | 77 | /// The randomization factor for calculating reconnect jitter. 78 | var randomizationFactor: Double { get set } 79 | 80 | /// The URL of the socket.io server. 81 | var socketURL: URL { get } 82 | 83 | /// The status of this manager. 84 | var status: SocketIOStatus { get } 85 | 86 | /// The version of socket.io in use. 87 | var version: SocketIOVersion { get } 88 | 89 | // MARK: Methods 90 | 91 | /// Connects the underlying transport. 92 | func connect() 93 | 94 | /// Connects a socket through this manager's engine. 95 | /// 96 | /// - parameter socket: The socket who we should connect through this manager. 97 | /// - parameter withPayload: Optional payload to send on connect 98 | func connectSocket(_ socket: SocketIOClient, withPayload: [String: Any]?) 99 | 100 | /// Called when the manager has disconnected from socket.io. 101 | /// 102 | /// - parameter reason: The reason for the disconnection. 103 | func didDisconnect(reason: String) 104 | 105 | /// Disconnects the manager and all associated sockets. 106 | func disconnect() 107 | 108 | /// Disconnects the given socket. 109 | /// 110 | /// - parameter socket: The socket to disconnect. 111 | func disconnectSocket(_ socket: SocketIOClient) 112 | 113 | /// Disconnects the socket associated with `forNamespace`. 114 | /// 115 | /// - parameter nsp: The namespace to disconnect from. 116 | func disconnectSocket(forNamespace nsp: String) 117 | 118 | /// Sends an event to the server on all namespaces in this manager. 119 | /// 120 | /// - parameter event: The event to send. 121 | /// - parameter items: The data to send with this event. 122 | func emitAll(_ event: String, _ items: SocketData...) 123 | 124 | /// Tries to reconnect to the server. 125 | /// 126 | /// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event. 127 | func reconnect() 128 | 129 | /// Removes the socket from the manager's control. 130 | /// After calling this method the socket should no longer be considered usable. 131 | /// 132 | /// - parameter socket: The socket to remove. 133 | /// - returns: The socket removed, if it was owned by the manager. 134 | @discardableResult 135 | func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? 136 | 137 | /// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager. 138 | /// 139 | /// Calling multiple times returns the same socket. 140 | /// 141 | /// Sockets created from this method are retained by the manager. 142 | /// Call one of the `disconnectSocket` methods on the implementing class to remove the socket from manager control. 143 | /// Or call `SocketIOClient.disconnect()` on the client. 144 | /// 145 | /// - parameter nsp: The namespace for the socket. 146 | /// - returns: A `SocketIOClient` for the given namespace. 147 | func socket(forNamespace nsp: String) -> SocketIOClient 148 | } 149 | -------------------------------------------------------------------------------- /Pods/Starscream/Sources/Starscream/WebSocket.swift: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Websocket.swift 4 | // Starscream 5 | // 6 | // Created by Dalton Cherry on 7/16/14. 7 | // Copyright (c) 2014-2019 Dalton Cherry. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | import Foundation 24 | 25 | public enum ErrorType: Error { 26 | case compressionError 27 | case securityError 28 | case protocolError //There was an error parsing the WebSocket frames 29 | case serverError 30 | } 31 | 32 | public struct WSError: Error { 33 | public let type: ErrorType 34 | public let message: String 35 | public let code: UInt16 36 | 37 | public init(type: ErrorType, message: String, code: UInt16) { 38 | self.type = type 39 | self.message = message 40 | self.code = code 41 | } 42 | } 43 | 44 | public protocol WebSocketClient: class { 45 | func connect() 46 | func disconnect(closeCode: UInt16) 47 | func write(string: String, completion: (() -> ())?) 48 | func write(stringData: Data, completion: (() -> ())?) 49 | func write(data: Data, completion: (() -> ())?) 50 | func write(ping: Data, completion: (() -> ())?) 51 | func write(pong: Data, completion: (() -> ())?) 52 | } 53 | 54 | //implements some of the base behaviors 55 | extension WebSocketClient { 56 | public func write(string: String) { 57 | write(string: string, completion: nil) 58 | } 59 | 60 | public func write(data: Data) { 61 | write(data: data, completion: nil) 62 | } 63 | 64 | public func write(ping: Data) { 65 | write(ping: ping, completion: nil) 66 | } 67 | 68 | public func write(pong: Data) { 69 | write(pong: pong, completion: nil) 70 | } 71 | 72 | public func disconnect() { 73 | disconnect(closeCode: CloseCode.normal.rawValue) 74 | } 75 | } 76 | 77 | public enum WebSocketEvent { 78 | case connected([String: String]) 79 | case disconnected(String, UInt16) 80 | case text(String) 81 | case binary(Data) 82 | case pong(Data?) 83 | case ping(Data?) 84 | case error(Error?) 85 | case viabilityChanged(Bool) 86 | case reconnectSuggested(Bool) 87 | case cancelled 88 | } 89 | 90 | public protocol WebSocketDelegate: class { 91 | func didReceive(event: WebSocketEvent, client: WebSocket) 92 | } 93 | 94 | open class WebSocket: WebSocketClient, EngineDelegate { 95 | private let engine: Engine 96 | public weak var delegate: WebSocketDelegate? 97 | public var onEvent: ((WebSocketEvent) -> Void)? 98 | 99 | public var request: URLRequest 100 | // Where the callback is executed. It defaults to the main UI thread queue. 101 | public var callbackQueue = DispatchQueue.main 102 | public var respondToPingWithPong: Bool { 103 | set { 104 | guard let e = engine as? WSEngine else { return } 105 | e.respondToPingWithPong = newValue 106 | } 107 | get { 108 | guard let e = engine as? WSEngine else { return true } 109 | return e.respondToPingWithPong 110 | } 111 | } 112 | 113 | // serial write queue to ensure writes happen in order 114 | private let writeQueue = DispatchQueue(label: "com.vluxe.starscream.writequeue") 115 | private var canSend = false 116 | private let mutex = DispatchSemaphore(value: 1) 117 | 118 | public init(request: URLRequest, engine: Engine) { 119 | self.request = request 120 | self.engine = engine 121 | } 122 | 123 | public convenience init(request: URLRequest, certPinner: CertificatePinning? = FoundationSecurity(), compressionHandler: CompressionHandler? = nil, useCustomEngine: Bool = true) { 124 | if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *), !useCustomEngine { 125 | self.init(request: request, engine: NativeEngine()) 126 | } else if #available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *) { 127 | self.init(request: request, engine: WSEngine(transport: TCPTransport(), certPinner: certPinner, compressionHandler: compressionHandler)) 128 | } else { 129 | self.init(request: request, engine: WSEngine(transport: FoundationTransport(), certPinner: certPinner, compressionHandler: compressionHandler)) 130 | } 131 | } 132 | 133 | public func connect() { 134 | engine.register(delegate: self) 135 | engine.start(request: request) 136 | } 137 | 138 | public func disconnect(closeCode: UInt16 = CloseCode.normal.rawValue) { 139 | engine.stop(closeCode: closeCode) 140 | } 141 | 142 | public func forceDisconnect() { 143 | engine.forceStop() 144 | } 145 | 146 | public func write(data: Data, completion: (() -> ())?) { 147 | write(data: data, opcode: .binaryFrame, completion: completion) 148 | } 149 | 150 | public func write(string: String, completion: (() -> ())?) { 151 | engine.write(string: string, completion: completion) 152 | } 153 | 154 | public func write(stringData: Data, completion: (() -> ())?) { 155 | write(data: stringData, opcode: .textFrame, completion: completion) 156 | } 157 | 158 | public func write(ping: Data, completion: (() -> ())?) { 159 | write(data: ping, opcode: .ping, completion: completion) 160 | } 161 | 162 | public func write(pong: Data, completion: (() -> ())?) { 163 | write(data: pong, opcode: .pong, completion: completion) 164 | } 165 | 166 | private func write(data: Data, opcode: FrameOpCode, completion: (() -> ())?) { 167 | engine.write(data: data, opcode: opcode, completion: completion) 168 | } 169 | 170 | // MARK: - EngineDelegate 171 | public func didReceive(event: WebSocketEvent) { 172 | callbackQueue.async { [weak self] in 173 | guard let s = self else { return } 174 | s.delegate?.didReceive(event: event, client: s) 175 | s.onEvent?(event) 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /lil wallet/Views/Detail/ActivityDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityDetailView.swift 3 | // lil wallet 4 | // 5 | // Created by Jordan Singer on 11/28/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ActivityDetailView: View { 11 | @Environment(\.presentationMode) var presentationMode 12 | @Environment(\.colorScheme) var colorScheme 13 | @EnvironmentObject var transaction: Transaction 14 | @EnvironmentObject var appearance: Appearance 15 | @EnvironmentObject var wallet: Wallet 16 | 17 | var body: some View { 18 | let appFont = appearance.getAppFont() 19 | 20 | List { 21 | Section(content: { 22 | HStack { 23 | Spacer() 24 | VStack(spacing: 8) { 25 | Text("\(wallet.formatCurrency(value: transaction.transactionValue()))") 26 | .font(.system(.largeTitle, design: appFont)) 27 | .fontWeight(.bold) 28 | .multilineTextAlignment(.center) 29 | 30 | Text(Date(timeIntervalSince1970: TimeInterval(transaction.mined_at)).formatted(date: .abbreviated, time: .shortened)) 31 | .font(.system(.body, design: appFont)) 32 | .foregroundColor(.secondary) 33 | .multilineTextAlignment(.center) 34 | } 35 | .padding(.horizontal) 36 | Spacer() 37 | } 38 | .padding(.vertical, 24) 39 | }) 40 | .listRowBackground( 41 | colorScheme == .light ? 42 | Color(UIColor.secondarySystemBackground) : 43 | Color(UIColor.systemBackground) 44 | ) 45 | 46 | Section(content: { 47 | HStack { 48 | Text("Type") 49 | .font(.system(.body, design: appFont)) 50 | Spacer() 51 | Text(transaction.type.capitalized) 52 | .font(.system(.headline, design: appFont)) 53 | } 54 | 55 | HStack { 56 | Text("Status") 57 | .font(.system(.body, design: appFont)) 58 | Spacer() 59 | Text(transaction.status.capitalized) 60 | .font(.system(.headline, design: appFont)) 61 | } 62 | 63 | HStack { 64 | Text("Amount") 65 | .font(.system(.body, design: appFont)) 66 | Spacer() 67 | Text("\(transaction.transactionQuantity())") 68 | .font(.system(.headline, design: appFont)) 69 | } 70 | }) 71 | 72 | Section(content: { 73 | if let address_from = transaction.address_from { 74 | Link(destination: URL(string: "https://etherscan.io/address/\(address_from)")!, label: { 75 | HStack { 76 | Text("From") 77 | .font(.system(.body, design: appFont)) 78 | Spacer() 79 | Text(wallet.formatAddress(address: address_from)) 80 | .font(.system(.headline, design: appFont)) 81 | } 82 | }) 83 | } 84 | 85 | if let address_to = transaction.address_to { 86 | Link(destination: URL(string: "https://etherscan.io/address/\(address_to)")!, label: { 87 | HStack { 88 | Text("To") 89 | .font(.system(.body, design: appFont)) 90 | Spacer() 91 | Text(wallet.formatAddress(address: address_to)) 92 | .font(.system(.headline, design: appFont)) 93 | } 94 | }) 95 | } 96 | }) 97 | .foregroundColor(.primary) 98 | 99 | if let token = transaction.token { 100 | Section(content: { 101 | HStack { 102 | Text(token.name) 103 | .font(.system(.body, design: appFont)) 104 | .lineLimit(1) 105 | Spacer() 106 | Text(token.symbol.uppercased()) 107 | .font(.system(.headline, design: appFont)) 108 | } 109 | 110 | if let transactionPrice = transaction.price { 111 | HStack { 112 | Text("Price") 113 | .font(.system(.body, design: appFont)) 114 | Spacer() 115 | Text(wallet.formatCurrency(value: transactionPrice)) 116 | .font(.system(.headline, design: appFont)) 117 | } 118 | } 119 | }, header: { Text("Token") }) 120 | } 121 | 122 | if let fee = transaction.fee { 123 | Section(content: { 124 | HStack { 125 | Text("Value") 126 | .font(.system(.body, design: appFont)) 127 | .lineLimit(1) 128 | Spacer() 129 | Text("\(fee.feeValue())") 130 | .font(.system(.headline, design: appFont)) 131 | } 132 | 133 | HStack { 134 | Text("Price") 135 | .font(.system(.body, design: appFont)) 136 | Spacer() 137 | Text(wallet.formatCurrency(value: fee.feePrice())) 138 | .font(.system(.headline, design: appFont)) 139 | } 140 | }, header: { Text("Fee") }) 141 | } 142 | 143 | Section { 144 | Link(destination: URL(string: "https://etherscan.io/tx/\(transaction.hash)")!, label: { 145 | Text("View on Etherscan") 146 | .font(.system(.body, design: appFont)) 147 | }) 148 | } 149 | .foregroundColor(appearance.getAppColor()) 150 | } 151 | .navigationBarTitle(transaction.title()) 152 | .navigationBarTitleDisplayMode(.inline) 153 | } 154 | } 155 | 156 | struct ActivityDetailView_Previews: PreviewProvider { 157 | static var previews: some View { 158 | ActivityDetailView() 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Client/SocketRawView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketRawView.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Created by Erik Little on 3/30/18. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. 28 | /// 29 | /// Usage: 30 | /// 31 | /// ```swift 32 | /// socket.rawEmitView.emit("myEvent", myObject) 33 | /// ``` 34 | public final class SocketRawView : NSObject { 35 | private unowned let socket: SocketIOClient 36 | 37 | init(socket: SocketIOClient) { 38 | self.socket = socket 39 | } 40 | 41 | /// Send an event to the server, with optional data items. 42 | /// 43 | /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` 44 | /// will be emitted. The structure of the error data is `[eventName, items, theError]` 45 | /// 46 | /// - parameter event: The event to send. 47 | /// - parameter items: The items to send with this event. May be left out. 48 | public func emit(_ event: String, _ items: SocketData...) { 49 | do { 50 | try emit(event, with: items.map({ try $0.socketRepresentation() })) 51 | } catch { 52 | DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", 53 | type: "SocketIOClient") 54 | 55 | socket.handleClientEvent(.error, data: [event, items, error]) 56 | } 57 | } 58 | 59 | /// Same as emit, but meant for Objective-C 60 | /// 61 | /// - parameter event: The event to send. 62 | /// - parameter items: The items to send with this event. Send an empty array to send no data. 63 | @objc 64 | public func emit(_ event: String, with items: [Any]) { 65 | socket.emit([event] + items, binary: false) 66 | } 67 | 68 | /// Sends a message to the server, requesting an ack. 69 | /// 70 | /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. 71 | /// Check that your server's api will ack the event being sent. 72 | /// 73 | /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` 74 | /// will be emitted. The structure of the error data is `[eventName, items, theError]` 75 | /// 76 | /// Example: 77 | /// 78 | /// ```swift 79 | /// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in 80 | /// ... 81 | /// } 82 | /// ``` 83 | /// 84 | /// - parameter event: The event to send. 85 | /// - parameter items: The items to send with this event. May be left out. 86 | /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. 87 | public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback { 88 | do { 89 | return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() })) 90 | } catch { 91 | DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", 92 | type: "SocketIOClient") 93 | 94 | socket.handleClientEvent(.error, data: [event, items, error]) 95 | 96 | return OnAckCallback(ackNumber: -1, items: [], socket: socket) 97 | } 98 | } 99 | 100 | /// Same as emitWithAck, but for Objective-C 101 | /// 102 | /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. 103 | /// Check that your server's api will ack the event being sent. 104 | /// 105 | /// Example: 106 | /// 107 | /// ```swift 108 | /// socket.emitWithAck("myEvent", with: [1]).timingOut(after: 1) {data in 109 | /// ... 110 | /// } 111 | /// ``` 112 | /// 113 | /// - parameter event: The event to send. 114 | /// - parameter items: The items to send with this event. Use `[]` to send nothing. 115 | /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. 116 | @objc 117 | public func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { 118 | return socket.createOnAck([event] + items, binary: false) 119 | } 120 | } 121 | 122 | /// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. 123 | /// 124 | /// Usage: 125 | /// 126 | /// ```swift 127 | /// ack.rawEmitView.with(myObject) 128 | /// ``` 129 | public final class SocketRawAckView : NSObject { 130 | private unowned let socket: SocketIOClient 131 | private let ackNum: Int 132 | 133 | init(socket: SocketIOClient, ackNum: Int) { 134 | self.socket = socket 135 | self.ackNum = ackNum 136 | } 137 | 138 | /// Call to ack receiving this event. 139 | /// 140 | /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` 141 | /// will be emitted. The structure of the error data is `[ackNum, items, theError]` 142 | /// 143 | /// - parameter items: A variable number of items to send when acking. 144 | public func with(_ items: SocketData...) { 145 | guard ackNum != -1 else { return } 146 | 147 | do { 148 | socket.emit(try items.map({ try $0.socketRepresentation() }), ack: ackNum, binary: false, isAck: true) 149 | } catch { 150 | socket.handleClientEvent(.error, data: [ackNum, items, error]) 151 | } 152 | } 153 | 154 | /// Call to ack receiving this event. 155 | /// 156 | /// - parameter items: An array of items to send when acking. Use `[]` to send nothing. 157 | @objc 158 | public func with(_ items: [Any]) { 159 | guard ackNum != -1 else { return } 160 | 161 | socket.emit(items, ack: ackNum, binary: false, isAck: true) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Pods/Socket.IO-Client-Swift/Source/SocketIO/Parse/SocketParsable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketParsable.swift 3 | // Socket.IO-Client-Swift 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | /// Defines that a type will be able to parse socket.io-protocol messages. 26 | public protocol SocketParsable : AnyObject { 27 | // MARK: Methods 28 | 29 | /// Called when the engine has received some binary data that should be attached to a packet. 30 | /// 31 | /// Packets binary data should be sent directly after the packet that expects it, so there's confusion over 32 | /// where the data should go. Data should be received in the order it is sent, so that the correct data is put 33 | /// into the correct placeholder. 34 | /// 35 | /// - parameter data: The data that should be attached to a packet. 36 | func parseBinaryData(_ data: Data) -> SocketPacket? 37 | 38 | /// Called when the engine has received a string that should be parsed into a socket.io packet. 39 | /// 40 | /// - parameter message: The string that needs parsing. 41 | /// - returns: A completed socket packet if there is no more data left to collect. 42 | func parseSocketMessage(_ message: String) -> SocketPacket? 43 | } 44 | 45 | /// Errors that can be thrown during parsing. 46 | public enum SocketParsableError : Error { 47 | // MARK: Cases 48 | 49 | /// Thrown when a packet received has an invalid data array, or is missing the data array. 50 | case invalidDataArray 51 | 52 | /// Thrown when an malformed packet is received. 53 | case invalidPacket 54 | 55 | /// Thrown when the parser receives an unknown packet type. 56 | case invalidPacketType 57 | } 58 | 59 | /// Says that a type will be able to buffer binary data before all data for an event has come in. 60 | public protocol SocketDataBufferable : AnyObject { 61 | // MARK: Properties 62 | 63 | /// A list of packets that are waiting for binary data. 64 | /// 65 | /// The way that socket.io works all data should be sent directly after each packet. 66 | /// So this should ideally be an array of one packet waiting for data. 67 | /// 68 | /// **This should not be modified directly.** 69 | var waitingPackets: [SocketPacket] { get set } 70 | } 71 | 72 | public extension SocketParsable where Self: SocketManagerSpec & SocketDataBufferable { 73 | /// Parses a message from the engine, returning a complete SocketPacket or throwing. 74 | /// 75 | /// - parameter message: The message to parse. 76 | /// - returns: A completed packet, or throwing. 77 | internal func parseString(_ message: String) throws -> SocketPacket { 78 | var reader = SocketStringReader(message: message) 79 | 80 | guard let type = Int(reader.read(count: 1)).flatMap({ SocketPacket.PacketType(rawValue: $0) }) else { 81 | throw SocketParsableError.invalidPacketType 82 | } 83 | 84 | if !reader.hasNext { 85 | return SocketPacket(type: type, nsp: "/") 86 | } 87 | 88 | var namespace = "/" 89 | var placeholders = -1 90 | 91 | if type.isBinary { 92 | if let holders = Int(reader.readUntilOccurence(of: "-")) { 93 | placeholders = holders 94 | } else { 95 | throw SocketParsableError.invalidPacket 96 | } 97 | } 98 | 99 | if reader.currentCharacter == "/" { 100 | namespace = reader.readUntilOccurence(of: ",") 101 | } 102 | 103 | if !reader.hasNext { 104 | return SocketPacket(type: type, nsp: namespace, placeholders: placeholders) 105 | } 106 | 107 | var idString = "" 108 | 109 | if type == .error { 110 | reader.advance(by: -1) 111 | } else { 112 | while let int = Int(reader.read(count: 1)) { 113 | idString += String(int) 114 | } 115 | 116 | reader.advance(by: -2) 117 | } 118 | 119 | var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)...])! 120 | 121 | if (type == .error || type == .connect) && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") { 122 | dataArray = "[" + dataArray + "]" 123 | } 124 | 125 | let data = try parseData(dataArray) 126 | 127 | return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, nsp: namespace, placeholders: placeholders) 128 | } 129 | 130 | // Parses data for events 131 | private func parseData(_ data: String) throws -> [Any] { 132 | do { 133 | return try data.toArray() 134 | } catch { 135 | throw SocketParsableError.invalidDataArray 136 | } 137 | } 138 | 139 | /// Called when the engine has received a string that should be parsed into a socket.io packet. 140 | /// 141 | /// - parameter message: The string that needs parsing. 142 | /// - returns: A completed socket packet or nil if the packet is invalid. 143 | func parseSocketMessage(_ message: String) -> SocketPacket? { 144 | guard !message.isEmpty else { return nil } 145 | 146 | DefaultSocketLogger.Logger.log("Parsing \(message)", type: "SocketParser") 147 | 148 | do { 149 | let packet = try parseString(message) 150 | 151 | DefaultSocketLogger.Logger.log("Decoded packet as: \(packet.description)", type: "SocketParser") 152 | 153 | return packet 154 | } catch { 155 | DefaultSocketLogger.Logger.error("\(error): \(message)", type: "SocketParser") 156 | 157 | return nil 158 | } 159 | } 160 | 161 | /// Called when the engine has received some binary data that should be attached to a packet. 162 | /// 163 | /// Packets binary data should be sent directly after the packet that expects it, so there's confusion over 164 | /// where the data should go. Data should be received in the order it is sent, so that the correct data is put 165 | /// into the correct placeholder. 166 | /// 167 | /// - parameter data: The data that should be attached to a packet. 168 | /// - returns: A completed socket packet if there is no more data left to collect. 169 | func parseBinaryData(_ data: Data) -> SocketPacket? { 170 | guard !waitingPackets.isEmpty else { 171 | DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser") 172 | 173 | return nil 174 | } 175 | 176 | // Should execute event? 177 | guard waitingPackets[waitingPackets.count - 1].addData(data) else { return nil } 178 | 179 | return waitingPackets.removeLast() 180 | } 181 | } 182 | --------------------------------------------------------------------------------