├── .gitignore ├── Kraken.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── CommonCryptoModuleMap.xcscheme │ │ └── Kraken.xcscheme └── xcuserdata │ └── antoniocaseropalmero.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Kraken ├── Crypto.swift ├── Info.plist ├── Kraken.h ├── Kraken.swift ├── Network.swift └── Utils.swift ├── KrakenTests ├── Info.plist └── KrakenTests.swift ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output -------------------------------------------------------------------------------- /Kraken.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 0AE0B90D1F2E1FE400678F96 /* CommonCryptoModuleMap */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 0AE0B90E1F2E1FE400678F96 /* Build configuration list for PBXAggregateTarget "CommonCryptoModuleMap" */; 13 | buildPhases = ( 14 | 0AE0B9111F2E1FFE00678F96 /* ShellScript */, 15 | 0AC741911F386827000CC663 /* ShellScript */, 16 | ); 17 | dependencies = ( 18 | ); 19 | name = CommonCryptoModuleMap; 20 | productName = CommonCryptoModuleMap; 21 | }; 22 | /* End PBXAggregateTarget section */ 23 | 24 | /* Begin PBXBuildFile section */ 25 | 0A6177BE1F2934F7000554B1 /* Kraken.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A6177B01F2934F7000554B1 /* Kraken.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | 0A6177D91F2935DD000554B1 /* Kraken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6177C71F29350C000554B1 /* Kraken.swift */; }; 27 | 0A6177DA1F2935DF000554B1 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6177C81F29350C000554B1 /* Network.swift */; }; 28 | 0A6177DB1F2935EA000554B1 /* Kraken.swift in Headers */ = {isa = PBXBuildFile; fileRef = 0A6177C71F29350C000554B1 /* Kraken.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | 0A6177DC1F2935F2000554B1 /* Network.swift in Headers */ = {isa = PBXBuildFile; fileRef = 0A6177C81F29350C000554B1 /* Network.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 30 | 0AC741901F385DB0000CC663 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC7418F1F385DB0000CC663 /* Utils.swift */; }; 31 | 0AE0B9031F2E1C0600678F96 /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE0B9021F2E1C0600678F96 /* Crypto.swift */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | 0AC741931F3A470E000CC663 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 0A6177A41F2934F7000554B1 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 0AE0B90D1F2E1FE400678F96; 40 | remoteInfo = CommonCryptoModuleMap; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 0A6177AD1F2934F7000554B1 /* Kraken.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kraken.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 0A6177B01F2934F7000554B1 /* Kraken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Kraken.h; sourceTree = ""; }; 47 | 0A6177B11F2934F7000554B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 0A6177BB1F2934F7000554B1 /* KrakenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KrakenTests.swift; sourceTree = ""; }; 49 | 0A6177BD1F2934F7000554B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 0A6177C71F29350C000554B1 /* Kraken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Kraken.swift; sourceTree = ""; }; 51 | 0A6177C81F29350C000554B1 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 52 | 0AC7418F1F385DB0000CC663 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 53 | 0AE0B9021F2E1C0600678F96 /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = ""; }; 54 | 0AE0B9051F2E1C8C00678F96 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 0A6177A91F2934F7000554B1 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 0A6177A31F2934F7000554B1 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 0A6177AF1F2934F7000554B1 /* Kraken */, 72 | 0A6177BA1F2934F7000554B1 /* KrakenTests */, 73 | 0A6177AE1F2934F7000554B1 /* Products */, 74 | 0AE0B9041F2E1C8C00678F96 /* Frameworks */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 0A6177AE1F2934F7000554B1 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 0A6177AD1F2934F7000554B1 /* Kraken.framework */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 0A6177AF1F2934F7000554B1 /* Kraken */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 0A6177C71F29350C000554B1 /* Kraken.swift */, 90 | 0A6177C81F29350C000554B1 /* Network.swift */, 91 | 0A6177B01F2934F7000554B1 /* Kraken.h */, 92 | 0A6177B11F2934F7000554B1 /* Info.plist */, 93 | 0AE0B9021F2E1C0600678F96 /* Crypto.swift */, 94 | 0AC7418F1F385DB0000CC663 /* Utils.swift */, 95 | ); 96 | path = Kraken; 97 | sourceTree = ""; 98 | }; 99 | 0A6177BA1F2934F7000554B1 /* KrakenTests */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 0A6177BB1F2934F7000554B1 /* KrakenTests.swift */, 103 | 0A6177BD1F2934F7000554B1 /* Info.plist */, 104 | ); 105 | path = KrakenTests; 106 | sourceTree = ""; 107 | }; 108 | 0AE0B9041F2E1C8C00678F96 /* Frameworks */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 0AE0B9051F2E1C8C00678F96 /* Security.framework */, 112 | ); 113 | name = Frameworks; 114 | sourceTree = ""; 115 | }; 116 | /* End PBXGroup section */ 117 | 118 | /* Begin PBXHeadersBuildPhase section */ 119 | 0A6177AA1F2934F7000554B1 /* Headers */ = { 120 | isa = PBXHeadersBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | 0A6177BE1F2934F7000554B1 /* Kraken.h in Headers */, 124 | 0A6177DB1F2935EA000554B1 /* Kraken.swift in Headers */, 125 | 0A6177DC1F2935F2000554B1 /* Network.swift in Headers */, 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXHeadersBuildPhase section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | 0A6177AC1F2934F7000554B1 /* Kraken */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = 0A6177C11F2934F7000554B1 /* Build configuration list for PBXNativeTarget "Kraken" */; 135 | buildPhases = ( 136 | 0A6177A81F2934F7000554B1 /* Sources */, 137 | 0A6177A91F2934F7000554B1 /* Frameworks */, 138 | 0A6177AA1F2934F7000554B1 /* Headers */, 139 | 0A6177AB1F2934F7000554B1 /* Resources */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | 0AC741941F3A470E000CC663 /* PBXTargetDependency */, 145 | ); 146 | name = Kraken; 147 | productName = Kraken; 148 | productReference = 0A6177AD1F2934F7000554B1 /* Kraken.framework */; 149 | productType = "com.apple.product-type.framework"; 150 | }; 151 | /* End PBXNativeTarget section */ 152 | 153 | /* Begin PBXProject section */ 154 | 0A6177A41F2934F7000554B1 /* Project object */ = { 155 | isa = PBXProject; 156 | attributes = { 157 | LastSwiftUpdateCheck = 0900; 158 | LastUpgradeCheck = 0900; 159 | ORGANIZATIONNAME = "Antonio Casero Palmero"; 160 | TargetAttributes = { 161 | 0A6177AC1F2934F7000554B1 = { 162 | CreatedOnToolsVersion = 9.0; 163 | LastSwiftMigration = 0900; 164 | }; 165 | 0AE0B90D1F2E1FE400678F96 = { 166 | CreatedOnToolsVersion = 9.0; 167 | }; 168 | }; 169 | }; 170 | buildConfigurationList = 0A6177A71F2934F7000554B1 /* Build configuration list for PBXProject "Kraken" */; 171 | compatibilityVersion = "Xcode 8.0"; 172 | developmentRegion = en; 173 | hasScannedForEncodings = 0; 174 | knownRegions = ( 175 | en, 176 | ); 177 | mainGroup = 0A6177A31F2934F7000554B1; 178 | productRefGroup = 0A6177AE1F2934F7000554B1 /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | 0A6177AC1F2934F7000554B1 /* Kraken */, 183 | 0AE0B90D1F2E1FE400678F96 /* CommonCryptoModuleMap */, 184 | ); 185 | }; 186 | /* End PBXProject section */ 187 | 188 | /* Begin PBXResourcesBuildPhase section */ 189 | 0A6177AB1F2934F7000554B1 /* Resources */ = { 190 | isa = PBXResourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXResourcesBuildPhase section */ 197 | 198 | /* Begin PBXShellScriptBuildPhase section */ 199 | 0AC741911F386827000CC663 /* ShellScript */ = { 200 | isa = PBXShellScriptBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | inputPaths = ( 205 | ); 206 | outputPaths = ( 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | shellPath = /bin/sh; 210 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 211 | }; 212 | 0AE0B9111F2E1FFE00678F96 /* ShellScript */ = { 213 | isa = PBXShellScriptBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | ); 217 | inputPaths = ( 218 | ); 219 | outputPaths = ( 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | shellPath = /bin/sh; 223 | shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap\"\ncat < \"${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap/module.modulemap\"\nmodule CommonCrypto [system] {\n header \"${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h\"\n export *\n}\nEOF"; 224 | }; 225 | /* End PBXShellScriptBuildPhase section */ 226 | 227 | /* Begin PBXSourcesBuildPhase section */ 228 | 0A6177A81F2934F7000554B1 /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | 0AE0B9031F2E1C0600678F96 /* Crypto.swift in Sources */, 233 | 0A6177DA1F2935DF000554B1 /* Network.swift in Sources */, 234 | 0A6177D91F2935DD000554B1 /* Kraken.swift in Sources */, 235 | 0AC741901F385DB0000CC663 /* Utils.swift in Sources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXSourcesBuildPhase section */ 240 | 241 | /* Begin PBXTargetDependency section */ 242 | 0AC741941F3A470E000CC663 /* PBXTargetDependency */ = { 243 | isa = PBXTargetDependency; 244 | target = 0AE0B90D1F2E1FE400678F96 /* CommonCryptoModuleMap */; 245 | targetProxy = 0AC741931F3A470E000CC663 /* PBXContainerItemProxy */; 246 | }; 247 | /* End PBXTargetDependency section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | 0A6177BF1F2934F7000554B1 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_COMMA = YES; 263 | CLANG_WARN_CONSTANT_CONVERSION = YES; 264 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 265 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INFINITE_RECURSION = YES; 269 | CLANG_WARN_INT_CONVERSION = YES; 270 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 271 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 273 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 274 | CLANG_WARN_STRICT_PROTOTYPES = YES; 275 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 276 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 277 | CLANG_WARN_UNREACHABLE_CODE = YES; 278 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 279 | CODE_SIGN_IDENTITY = "iPhone Developer"; 280 | COPY_PHASE_STRIP = NO; 281 | CURRENT_PROJECT_VERSION = 1; 282 | DEBUG_INFORMATION_FORMAT = dwarf; 283 | ENABLE_STRICT_OBJC_MSGSEND = YES; 284 | ENABLE_TESTABILITY = YES; 285 | GCC_C_LANGUAGE_STANDARD = gnu11; 286 | GCC_DYNAMIC_NO_PIC = NO; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_OPTIMIZATION_LEVEL = 0; 289 | GCC_PREPROCESSOR_DEFINITIONS = ( 290 | "DEBUG=1", 291 | "$(inherited)", 292 | ); 293 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 294 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 295 | GCC_WARN_UNDECLARED_SELECTOR = YES; 296 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 297 | GCC_WARN_UNUSED_FUNCTION = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 300 | MTL_ENABLE_DEBUG_INFO = YES; 301 | ONLY_ACTIVE_ARCH = YES; 302 | SDKROOT = iphoneos; 303 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 305 | VERSIONING_SYSTEM = "apple-generic"; 306 | VERSION_INFO_PREFIX = ""; 307 | }; 308 | name = Debug; 309 | }; 310 | 0A6177C01F2934F7000554B1 /* Release */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_ANALYZER_NONNULL = YES; 315 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 316 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 317 | CLANG_CXX_LIBRARY = "libc++"; 318 | CLANG_ENABLE_MODULES = YES; 319 | CLANG_ENABLE_OBJC_ARC = YES; 320 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_COMMA = YES; 323 | CLANG_WARN_CONSTANT_CONVERSION = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INFINITE_RECURSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 334 | CLANG_WARN_STRICT_PROTOTYPES = YES; 335 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 336 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 337 | CLANG_WARN_UNREACHABLE_CODE = YES; 338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 339 | CODE_SIGN_IDENTITY = "iPhone Developer"; 340 | COPY_PHASE_STRIP = NO; 341 | CURRENT_PROJECT_VERSION = 1; 342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 343 | ENABLE_NS_ASSERTIONS = NO; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | GCC_C_LANGUAGE_STANDARD = gnu11; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 354 | MTL_ENABLE_DEBUG_INFO = NO; 355 | SDKROOT = iphoneos; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 357 | VALIDATE_PRODUCT = YES; 358 | VERSIONING_SYSTEM = "apple-generic"; 359 | VERSION_INFO_PREFIX = ""; 360 | }; 361 | name = Release; 362 | }; 363 | 0A6177C21F2934F7000554B1 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | CLANG_ENABLE_MODULES = YES; 367 | CODE_SIGN_IDENTITY = ""; 368 | DEFINES_MODULE = YES; 369 | DEVELOPMENT_TEAM = 9HX8L3BY3M; 370 | DYLIB_COMPATIBILITY_VERSION = 1; 371 | DYLIB_CURRENT_VERSION = 1; 372 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 373 | HEADER_SEARCH_PATHS = ( 374 | "$(inherited)", 375 | "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap", 376 | ); 377 | INFOPLIST_FILE = Kraken/Info.plist; 378 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 379 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 381 | PRODUCT_BUNDLE_IDENTIFIER = com.uttopia.Kraken; 382 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 383 | SKIP_INSTALL = YES; 384 | SWIFT_OBJC_BRIDGING_HEADER = ""; 385 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 386 | SWIFT_VERSION = 3.0; 387 | TARGETED_DEVICE_FAMILY = "1,2"; 388 | }; 389 | name = Debug; 390 | }; 391 | 0A6177C31F2934F7000554B1 /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | CLANG_ENABLE_MODULES = YES; 395 | CODE_SIGN_IDENTITY = ""; 396 | DEFINES_MODULE = YES; 397 | DEVELOPMENT_TEAM = 9HX8L3BY3M; 398 | DYLIB_COMPATIBILITY_VERSION = 1; 399 | DYLIB_CURRENT_VERSION = 1; 400 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 401 | HEADER_SEARCH_PATHS = ( 402 | "$(inherited)", 403 | "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap", 404 | ); 405 | INFOPLIST_FILE = Kraken/Info.plist; 406 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 407 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 408 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 409 | PRODUCT_BUNDLE_IDENTIFIER = com.uttopia.Kraken; 410 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 411 | SKIP_INSTALL = YES; 412 | SWIFT_OBJC_BRIDGING_HEADER = ""; 413 | SWIFT_VERSION = 3.0; 414 | TARGETED_DEVICE_FAMILY = "1,2"; 415 | }; 416 | name = Release; 417 | }; 418 | 0AE0B90F1F2E1FE400678F96 /* Debug */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | DEVELOPMENT_TEAM = 9HX8L3BY3M; 422 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 423 | PRODUCT_NAME = "$(TARGET_NAME)"; 424 | }; 425 | name = Debug; 426 | }; 427 | 0AE0B9101F2E1FE400678F96 /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | DEVELOPMENT_TEAM = 9HX8L3BY3M; 431 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 432 | PRODUCT_NAME = "$(TARGET_NAME)"; 433 | }; 434 | name = Release; 435 | }; 436 | /* End XCBuildConfiguration section */ 437 | 438 | /* Begin XCConfigurationList section */ 439 | 0A6177A71F2934F7000554B1 /* Build configuration list for PBXProject "Kraken" */ = { 440 | isa = XCConfigurationList; 441 | buildConfigurations = ( 442 | 0A6177BF1F2934F7000554B1 /* Debug */, 443 | 0A6177C01F2934F7000554B1 /* Release */, 444 | ); 445 | defaultConfigurationIsVisible = 0; 446 | defaultConfigurationName = Release; 447 | }; 448 | 0A6177C11F2934F7000554B1 /* Build configuration list for PBXNativeTarget "Kraken" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 0A6177C21F2934F7000554B1 /* Debug */, 452 | 0A6177C31F2934F7000554B1 /* Release */, 453 | ); 454 | defaultConfigurationIsVisible = 0; 455 | defaultConfigurationName = Release; 456 | }; 457 | 0AE0B90E1F2E1FE400678F96 /* Build configuration list for PBXAggregateTarget "CommonCryptoModuleMap" */ = { 458 | isa = XCConfigurationList; 459 | buildConfigurations = ( 460 | 0AE0B90F1F2E1FE400678F96 /* Debug */, 461 | 0AE0B9101F2E1FE400678F96 /* Release */, 462 | ); 463 | defaultConfigurationIsVisible = 0; 464 | defaultConfigurationName = Release; 465 | }; 466 | /* End XCConfigurationList section */ 467 | }; 468 | rootObject = 0A6177A41F2934F7000554B1 /* Project object */; 469 | } 470 | -------------------------------------------------------------------------------- /Kraken.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Kraken.xcodeproj/xcshareddata/xcschemes/CommonCryptoModuleMap.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Kraken.xcodeproj/xcshareddata/xcschemes/Kraken.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Kraken.xcodeproj/xcuserdata/antoniocaseropalmero.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CommonCryptoModuleMap.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | Kraken.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 0A6177AC1F2934F7000554B1 21 | 22 | primary 23 | 24 | 25 | 0A6177B51F2934F7000554B1 26 | 27 | primary 28 | 29 | 30 | 0AE0B90D1F2E1FE400678F96 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Kraken/Crypto.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Crypto.swift 3 | // Kraken 4 | // 5 | // Created by Antonio Casero Palmero on 30.07.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | public struct HMAC { 13 | 14 | // MARK: - Types 15 | public enum Algorithm { 16 | case sha1 17 | case md5 18 | case sha256 19 | case sha384 20 | case sha512 21 | case sha224 22 | 23 | public var algorithm: CCHmacAlgorithm { 24 | switch self { 25 | case .md5: return CCHmacAlgorithm(kCCHmacAlgMD5) 26 | case .sha1: return CCHmacAlgorithm(kCCHmacAlgSHA1) 27 | case .sha224: return CCHmacAlgorithm(kCCHmacAlgSHA224) 28 | case .sha256: return CCHmacAlgorithm(kCCHmacAlgSHA256) 29 | case .sha384: return CCHmacAlgorithm(kCCHmacAlgSHA384) 30 | case .sha512: return CCHmacAlgorithm(kCCHmacAlgSHA512) 31 | } 32 | } 33 | 34 | public var digestLength: Int { 35 | switch self { 36 | case .md5: return Int(CC_MD5_DIGEST_LENGTH) 37 | case .sha1: return Int(CC_SHA1_DIGEST_LENGTH) 38 | case .sha224: return Int(CC_SHA224_DIGEST_LENGTH) 39 | case .sha256: return Int(CC_SHA256_DIGEST_LENGTH) 40 | case .sha384: return Int(CC_SHA384_DIGEST_LENGTH) 41 | case .sha512: return Int(CC_SHA512_DIGEST_LENGTH) 42 | } 43 | } 44 | } 45 | 46 | // MARK: - Signing 47 | public static func sign(data: Data, algorithm: Algorithm, key: Data) -> Data { 48 | let signature = UnsafeMutablePointer.allocate(capacity: algorithm.digestLength) 49 | defer { signature.deallocate(capacity: algorithm.digestLength) } 50 | 51 | data.withUnsafeBytes { dataBytes in 52 | key.withUnsafeBytes { keyBytes in 53 | CCHmac(algorithm.algorithm, keyBytes, key.count, dataBytes, data.count, signature) 54 | } 55 | } 56 | 57 | return Data(bytes: signature, count: algorithm.digestLength) 58 | } 59 | } 60 | 61 | extension String { 62 | 63 | func base64Decoded() -> String? { 64 | guard let data = Data(base64Encoded: self) else { 65 | return nil 66 | } 67 | return String(data: data, encoding: .utf8) 68 | } 69 | 70 | func base64Encoded() -> String { 71 | return Data(self.utf8).base64EncodedString() 72 | } 73 | } 74 | 75 | extension Data { 76 | 77 | func MD5() -> Data { 78 | var result = Data(count: Int(CC_MD5_DIGEST_LENGTH)) 79 | _ = result.withUnsafeMutableBytes {resultPtr in 80 | self.withUnsafeBytes {(bytes: UnsafePointer) in 81 | CC_MD5(bytes, CC_LONG(count), resultPtr) 82 | } 83 | } 84 | return result 85 | } 86 | func SHA1() -> Data { 87 | var result = Data(count: Int(CC_SHA1_DIGEST_LENGTH)) 88 | _ = result.withUnsafeMutableBytes {resultPtr in 89 | self.withUnsafeBytes {(bytes: UnsafePointer) in 90 | CC_SHA1(bytes, CC_LONG(count), resultPtr) 91 | } 92 | } 93 | return result 94 | } 95 | func SHA256() -> Data { 96 | var result = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) 97 | _ = result.withUnsafeMutableBytes {resultPtr in 98 | self.withUnsafeBytes {(bytes: UnsafePointer) in 99 | CC_SHA256(bytes, CC_LONG(count), resultPtr) 100 | } 101 | } 102 | return result 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Kraken/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Kraken/Kraken.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kraken.h 3 | // Kraken 4 | // 5 | // Created by Antonio Casero Palmero on 26.07.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Kraken. 12 | FOUNDATION_EXPORT double KrakenVersionNumber; 13 | 14 | //! Project version string for Kraken. 15 | FOUNDATION_EXPORT const unsigned char KrakenVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Kraken/Kraken.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Kraken.swift 3 | // KrakenClient 4 | // 5 | // Created by Antonio Casero Palmero on 23.07.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Kraken { 12 | 13 | public struct Credentials { 14 | var apiKey: String 15 | var apiSecret: String 16 | 17 | public init(key: String, secret: String) { 18 | apiKey = key 19 | apiSecret = secret 20 | } 21 | } 22 | 23 | private let request: Network 24 | 25 | // MARK: Public methods 26 | 27 | public init(credentials: Credentials) { 28 | request = Network(credentials: credentials) 29 | } 30 | 31 | public func serverTime(completion: @escaping Network.AsyncOperation) { 32 | request.getRequest(with: "Time", completion:completion) 33 | } 34 | 35 | public func assets(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 36 | request.getRequest(with: "Assets", params: options, completion:completion) 37 | } 38 | 39 | public func assetPairs(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 40 | request.getRequest(with: "AssetPairs", params: options, completion:completion) 41 | } 42 | 43 | public func ticker(pairs: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 44 | var optionsCopy = options ?? [:] 45 | optionsCopy["pair"] = pairs.joined(separator: ",") 46 | request.getRequest(with: "Ticker", params:optionsCopy, completion:completion) 47 | } 48 | 49 | public func orderBook(pairs: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 50 | var optionsCopy = options ?? [:] 51 | optionsCopy["pair"] = pairs.joined(separator: ",") 52 | request.getRequest(with: "Depth", params:optionsCopy, completion:completion) 53 | } 54 | 55 | public func trades(pairs: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 56 | var optionsCopy = options ?? [:] 57 | optionsCopy["pair"] = pairs.joined(separator: ",") 58 | request.getRequest(with: "Trades", params:optionsCopy, completion:completion) 59 | } 60 | 61 | public func spread(pairs: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 62 | var optionsCopy = options ?? [:] 63 | optionsCopy["pair"] = pairs.joined(separator: ",") 64 | request.getRequest(with: "Spread", params:optionsCopy, completion:completion) 65 | } 66 | 67 | // MARK: Private methods 68 | 69 | public func balance(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 70 | request.postRequest(with: "Balance", params: options, completion: completion) 71 | } 72 | 73 | public func tradeBalance(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 74 | request.postRequest(with: "TradeBalance", params: options, completion: completion) 75 | } 76 | 77 | public func openOrders(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 78 | request.postRequest(with: "OpenOrders", params: options, completion: completion) 79 | } 80 | 81 | public func queryOrders(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 82 | request.postRequest(with: "QueryOrders", params: options, completion: completion) 83 | } 84 | 85 | public func tradesHistory(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 86 | request.postRequest(with: "TradesHistory", params: options, completion: completion) 87 | } 88 | 89 | public func queryTrades(ids: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 90 | var optionsCopy = options ?? [:] 91 | optionsCopy["txid"] = ids.joined(separator: ",") 92 | request.postRequest(with: "QueryTrades", params: optionsCopy, completion: completion) 93 | } 94 | 95 | public func openPositions(ids: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 96 | var optionsCopy = options ?? [:] 97 | optionsCopy["txid"] = ids.joined(separator: ",") 98 | request.postRequest(with: "OpenPositions", params: optionsCopy, completion: completion) 99 | } 100 | 101 | public func ledgersInfo(options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 102 | request.postRequest(with: "Ledgers", params: options, completion: completion) 103 | } 104 | 105 | public func queryLedgers(ledgerIds: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 106 | var optionsCopy = options ?? [:] 107 | optionsCopy["id"] = ledgerIds.joined(separator: ",") 108 | request.postRequest(with: "QueryLedgers", params: optionsCopy, completion: completion) 109 | } 110 | 111 | public func tradeVolume(pairs: [String], options: [String:String]? = nil, completion: @escaping Network.AsyncOperation) { 112 | var optionsCopy = options ?? [:] 113 | optionsCopy["pair"] = pairs.joined(separator: ",") 114 | request.postRequest(with: "TradeVolume", params: optionsCopy, completion: completion) 115 | } 116 | 117 | public func addOrder(options: [String:String], completion: @escaping Network.AsyncOperation) { 118 | let valuesNeeded = ["pair", "type", "orderType", "volume"] 119 | guard options.keys.contains(array: valuesNeeded) else { 120 | fatalError("Required options, not given. Input must include \(valuesNeeded)") 121 | } 122 | request.postRequest(with: "AddOrder", params: options, completion: completion) 123 | } 124 | 125 | public func cancelOrder(ids: [String], completion: @escaping Network.AsyncOperation) { 126 | var optionsCopy: [String:String] = [:] 127 | optionsCopy["txid"] = ids.joined(separator: ",") 128 | request.postRequest(with: "CancelOrder", params: optionsCopy, completion: completion) 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /Kraken/Network.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operations.swift 3 | // KrakenClient 4 | // 5 | // Created by Antonio Casero Palmero on 24.07.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Network { 12 | 13 | enum RequestType: String { 14 | case publicRequest = "public" 15 | case privateRequest = "private" 16 | } 17 | 18 | public typealias AsyncOperation = (Result<[String : Any]>) -> Void 19 | private let credentials: Kraken.Credentials 20 | let version = "0" 21 | let krakenUrl = "api.kraken.com" 22 | let scheme = "https" 23 | 24 | init(credentials: Kraken.Credentials) { 25 | self.credentials = credentials 26 | 27 | } 28 | 29 | private func createURL(with method: String, params: [String:String], type: RequestType) -> URL? { 30 | var urlComponents = URLComponents() 31 | urlComponents.scheme = scheme 32 | urlComponents.host = krakenUrl 33 | urlComponents.path = "/" + version + "/" + type.rawValue + "/" + method 34 | 35 | if type == RequestType.publicRequest { 36 | urlComponents.query = encode(params: params) 37 | } 38 | 39 | return urlComponents.url 40 | } 41 | 42 | private func encode(params: [String : String]) -> String { 43 | var urlComponents = URLComponents() 44 | var parameters: [URLQueryItem] = [] 45 | let parametersDictionary = params 46 | 47 | for (key, value) in parametersDictionary { 48 | let newParameter = URLQueryItem(name: key, value: value) 49 | parameters.append(newParameter) 50 | } 51 | 52 | urlComponents.queryItems = parameters 53 | return urlComponents.url?.query ?? "" 54 | } 55 | 56 | func getRequest(with method: String, params: [String : String]? = [:], type: RequestType = .publicRequest, 57 | completion: @escaping AsyncOperation) { 58 | let params = params ?? [:] 59 | guard let url = createURL(with: method, params:params, type: type) else { 60 | fatalError() 61 | } 62 | 63 | let request = URLRequest(url: url) 64 | 65 | rawRequest(request, completion: completion) 66 | } 67 | 68 | func postRequest(with path: String, params: [String : String]?, type: RequestType = .privateRequest, 69 | completion: @escaping AsyncOperation) { 70 | 71 | let params = addNonce(to:params) 72 | let urlParams = encode(params: params) 73 | 74 | guard let url = createURL(with: path, params: params, type: type), 75 | let signature = try? generateSignature(url, params:params) else { 76 | fatalError() 77 | } 78 | var request = URLRequest(url: url) 79 | request.httpMethod = "POST" 80 | request.httpBody = urlParams.data(using: .utf8) 81 | request.setValue(credentials.apiKey, forHTTPHeaderField: "API-Key") 82 | request.setValue(signature, forHTTPHeaderField: "API-Sign") 83 | request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 84 | for (key, value) in params { 85 | request.setValue(value, forHTTPHeaderField: key) 86 | } 87 | rawRequest(request, completion: completion) 88 | } 89 | 90 | private func rawRequest(_ request: URLRequest, completion: @escaping AsyncOperation) { 91 | 92 | let session = URLSession.shared 93 | session.dataTask(with: request) { (data, response, error) in 94 | guard let data = data, let _ = response else { 95 | return completion(.failure(error!)) 96 | } 97 | do { 98 | guard let json = try JSONSerialization.jsonObject(with: data, options:.allowFragments) as? [String : AnyObject] else { 99 | return completion(.failure(KrakenError.errorNetworking(reason: "Wrong JSON structure"))) 100 | } 101 | if let errorArray = json["error"] as? [String] { 102 | if !errorArray.isEmpty { 103 | return completion(.failure(KrakenError.errorAPI(reason: errorArray.first!))) 104 | } 105 | } 106 | return completion(.success(json)) 107 | 108 | } catch let error as NSError { 109 | return completion(.failure(KrakenError.errorNetworking(reason: "Error JSON parsing: \(error.localizedDescription)"))) 110 | } 111 | 112 | }.resume() 113 | } 114 | 115 | private func generateSignature(_ url: URL, params: [String:String]) throws -> String { 116 | 117 | let path = url.path 118 | let encodedParams = encode(params: params) 119 | guard let decodedSecret = Data(base64Encoded: credentials.apiSecret), 120 | let nonce = params["nonce"], 121 | let digest = (nonce + encodedParams).data(using: .utf8), 122 | let encodedPath = path.data(using: .utf8) else { 123 | throw KrakenError.errorAPI(reason: "Error encoding signature") 124 | } 125 | 126 | let message = digest.SHA256() 127 | let messagePath = encodedPath + message 128 | 129 | let signature = HMAC.sign(data: messagePath, algorithm: HMAC.Algorithm.sha512, key: decodedSecret) 130 | return signature.base64EncodedString() 131 | } 132 | 133 | private func addNonce(to params: [String : String]?) -> [String: String] { 134 | var paramsWithNonce = params ?? [:] 135 | let nonce = String(Int(Date().timeIntervalSinceReferenceDate.rounded()*1000)) 136 | paramsWithNonce["nonce"] = nonce 137 | return paramsWithNonce 138 | 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Kraken/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.swift 3 | // Kraken 4 | // 5 | // Created by Antonio Casero Palmero on 07.08.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum KrakenError: Error { 12 | case errorAPI(reason: String) 13 | case errorNetworking(reason: String) 14 | } 15 | 16 | public enum Result { 17 | case success(Value) 18 | case failure(Error) 19 | 20 | public func dematerialize() throws -> Value { 21 | switch self { 22 | case let .success(value): 23 | return value 24 | case let .failure(error): 25 | throw error 26 | } 27 | } 28 | 29 | public func map(_ transform: (Value) -> U) -> Result { 30 | return flatMap { .success(transform($0)) } 31 | } 32 | 33 | public func flatMap(_ transform: (Value) -> Result) -> Result { 34 | return analysis( 35 | ifSuccess: transform, 36 | ifFailure: Result.failure) 37 | } 38 | 39 | public func analysis(ifSuccess: (Value) -> Result, ifFailure: (Error) -> Result) -> Result { 40 | switch self { 41 | case let .success(value): 42 | return ifSuccess(value) 43 | case let .failure(value): 44 | return ifFailure(value) 45 | } 46 | } 47 | 48 | } 49 | 50 | extension Sequence where Iterator.Element: Equatable { 51 | func contains(array: [Iterator.Element]) -> Bool { 52 | for item in array { 53 | if !self.contains(item) { 54 | return false 55 | } 56 | } 57 | return true 58 | } 59 | } 60 | 61 | public protocol DataConvertible { 62 | static func + (lhs: Data, rhs: Self) -> Data 63 | static func += (lhs: inout Data, rhs: Self) 64 | } 65 | 66 | extension DataConvertible { 67 | public static func + (lhs: Data, rhs: Self) -> Data { 68 | var value = rhs 69 | let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1)) 70 | return lhs + data 71 | } 72 | 73 | public static func += (lhs: inout Data, rhs: Self) { 74 | lhs += rhs 75 | } 76 | } 77 | 78 | extension UInt8 : DataConvertible { } 79 | extension UInt16 : DataConvertible { } 80 | extension UInt32 : DataConvertible { } 81 | 82 | extension Int : DataConvertible { } 83 | extension Float : DataConvertible { } 84 | extension Double : DataConvertible { } 85 | 86 | extension String : DataConvertible { 87 | public static func + (lhs: Data, rhs: String) -> Data { 88 | guard let data = rhs.data(using: .utf8) else { return lhs} 89 | return lhs + data 90 | } 91 | } 92 | 93 | extension Data : DataConvertible { 94 | public static func + (lhs: Data, rhs: Data) -> Data { 95 | var data = Data() 96 | data.append(lhs) 97 | data.append(rhs) 98 | 99 | return data 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /KrakenTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /KrakenTests/KrakenTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KrakenTests.swift 3 | // KrakenTests 4 | // 5 | // Created by Antonio Casero Palmero on 26.07.17. 6 | // Copyright © 2017 Antonio Casero Palmero. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Kraken 11 | 12 | class KrakenTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Antonio Casero 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kraken Swift 2 | 3 | 4 | ### IMPORTANT 5 | 6 | Please thoroughly vet everything in the code for yourself before using this lib to buy, sell, or move any of your assets. 7 | 8 | PLEASE submit an issue or pull request if you notice any bugs, security holes, or potential improvements. Any help is appreciated! 9 | 10 | 11 | ### Description 12 | 13 | This library is a wrapper for the [Kraken Digital Asset Trading Platform](https://www.kraken.com) API. Official documentation from Kraken can be found [here](https://www.kraken.com/help/api). 14 | 15 | The current version can be used to query public/private data and make trades. Private data queries and trading functionality require use of your Kraken account API keys. 16 | 17 | Kraken Swift was built by [Antonio Casero](@acaserop) 18 | 19 | 20 | ## Installation 21 | 22 | 23 | ### Carthage 24 | 25 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 26 | 27 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 28 | 29 | ```bash 30 | $ brew update 31 | $ brew install carthage 32 | ``` 33 | 34 | To integrate Kraken into your Xcode project using Carthage, specify it in your `Cartfile`: 35 | 36 | ```ogdl 37 | github "antoniocasero/Kraken" ~> 1.0 38 | ``` 39 | 40 | Run `carthage update` to build the framework and drag the built `Kraken.framework` into your Xcode project. 41 | 42 | ### Manually 43 | 44 | If you prefer not to use any of the aforementioned dependency managers, you can integrate Kraken into your project manually. 45 | 46 | #### Embedded Framework 47 | 48 | - Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository: 49 | 50 | ```bash 51 | $ git init 52 | ``` 53 | 54 | - Add Kraken as a git [submodule](http://git-scm.com/docs/git-submodule) by running the following command: 55 | 56 | ```bash 57 | $ git submodule add https://github.com/antoniocasero/Kraken.git 58 | ``` 59 | 60 | - Open the new `Kraken` folder, and drag the `Kraken.xcodeproj` into the Project Navigator of your application's Xcode project. 61 | 62 | > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter. 63 | 64 | - Select the `Kraken.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target. 65 | - Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar. 66 | - In the tab bar at the top of that window, open the "General" panel. 67 | - Click on the `+` button under the "Embedded Binaries" section. 68 | - Select the top `Kraken.framework` 69 | - And that's it! 70 | 71 | > The `Kraken.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device. 72 | 73 | --- 74 | 75 | ## Usage 76 | 77 | Create a Kraken client using your credentials 78 | 79 | ```swift 80 | 81 | let credentials = Kraken.Credentials(key: "0Q/eOVRtyfg+WbIuLjKJ.....", 82 | secret: "EVFTYSinNiC89V.....") 83 | 84 | let kraken = Kraken(credentials: credentials) 85 | 86 | kraken.serverTime(completion: { let _ = $0.map{ print($0) } } // 1393056191 87 | 88 | ``` 89 | 90 | ### Public Data Methods 91 | 92 | #### Server Time 93 | 94 | This functionality is provided by Kraken to to aid in approximating the skew time between the server and client. 95 | 96 | ```swift 97 | 98 | kraken.serverTime { result in 99 | switch result { 100 | case .success(let serverTime): 101 | serverTime["unixtime"] // 1393056191 102 | serverTime["rfc1123"] // "Sat, 22 Feb 2014 08:28:04 GMT" 103 | case .failure(let error): print(error) 104 | } 105 | } 106 | 107 | ``` 108 | 109 | #### Asset Info 110 | 111 | Returns the assets that can be traded on the exchange. This method can be passed ```info```, ```aclass``` (asset class), and ```asset``` options. An example below is given for each: 112 | 113 | ```swift 114 | kraken.assets(completion: { let _ = $0.map{ print($0) } }) 115 | 116 | ``` 117 | 118 | #### Asset Pairs 119 | 120 | ```swift 121 | kraken.assetsPairs(completion: { let _ = $0.map{ print($0) } }) 122 | ``` 123 | 124 | #### Ticker Information 125 | 126 | ```swift 127 | kraken.ticker(pairs: ["BCHEUR", "BCHUSD"], completion: { let _ = $0.map{ print($0) } }) 128 | ``` 129 | 130 | #### Order Book 131 | 132 | Get market depth information for given asset pairs 133 | 134 | ```swift 135 | 136 | depth_data = kraken.order_book('LTCXRP', completion: { ... }) 137 | ``` 138 | 139 | #### Trades 140 | 141 | Get recent trades 142 | 143 | ```swift 144 | trades = kraken.trades('LTCXRP', completion: { ... }) 145 | ``` 146 | 147 | #### Spread 148 | 149 | Get spread data for a given asset pair 150 | 151 | ```swift 152 | spread = kraken.spread('LTCXRP', completion: { ... }) 153 | ``` 154 | 155 | ### Private Data Methods 156 | 157 | #### Balance 158 | 159 | Get account balance for each asset 160 | Note: Rates used for the floating valuation is the midpoint of the best bid and ask prices 161 | 162 | ```swift 163 | kraken.balance(completion: { ... }) 164 | ``` 165 | 166 | #### Trade Balance 167 | 168 | Get account trade balance 169 | 170 | ```swift 171 | kraken.tradeBalance(completion: { ... }) 172 | ``` 173 | 174 | #### Open Orders 175 | 176 | ```swift 177 | kraken.openOrders(completion: { ... }) 178 | ``` 179 | 180 | #### Closed Orders 181 | 182 | ```swift 183 | kraken.closedOrders(completion: { ... }) 184 | ``` 185 | 186 | #### Query Orders 187 | 188 | See all orders 189 | 190 | ```swift 191 | kraken.queryOrders(completion: { ... }) 192 | ``` 193 | 194 | #### Trades History 195 | 196 | Get array of all trades 197 | 198 | ```swift 199 | kraken.tradeHistory(completion: { ... }) 200 | ``` 201 | 202 | #### Query Trades 203 | 204 | **Input:** Array of transaction (tx) ids 205 | 206 | ```swift 207 | kraken.queryTrades(txids:arrayIds completion: { ... }) 208 | ``` 209 | 210 | #### Open Positions 211 | 212 | **Input:** Array of transaction (tx) ids 213 | 214 | ```swift 215 | kraken.openPositions(txids:arrayIds completion: { ... }) 216 | ``` 217 | 218 | #### Ledgers Info 219 | 220 | ```swift 221 | kraken.ledgersInfo(completion: { ... }) 222 | ``` 223 | 224 | #### Ledgers Info 225 | 226 | **Input:** Array of ledger ids 227 | 228 | ```swift 229 | kraken.queryTrades(ids: ledgerIds completion: { ... }) 230 | ``` 231 | 232 | #### Trade Volume 233 | 234 | ```swift 235 | let assetPairs = ["XLTCXXDG", "ZEURXXDG"] 236 | kraken.queryTrades(ids: assetPairs completion: { ... }) 237 | ``` 238 | 239 | ### Adding and Cancelling Orders 240 | 241 | #### Add Order 242 | 243 | There are 4 required parameters for buying an order. The example below illustrates the most basic order. Please see the [Kraken documentation](https://www.kraken.com/help/api#add-standard-order) for the parameters required for more advanced order types. 244 | ```swift 245 | // buying 0.01 XBT (bitcoin) for XRP (ripple) at market price 246 | let opts = [ 247 | "pair": "XBTXRP", 248 | "type": "buy", 249 | "ordertype": "market", 250 | "volume": "0.01" 251 | ] 252 | 253 | kraken.addOrder(options:opts completion: { ... }) 254 | 255 | ``` 256 | 257 | #### Cancel Order 258 | 259 | ```swift 260 | kraken.cancelOrder(ids:["UKIYSP-9VN27-AJWWYC"] completion: { ... }) 261 | ``` 262 | 263 | --------------------------------------------------------------------------------