-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 66ae311
Showing
79 changed files
with
4,258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
TestCredentials.swift |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# | ||
# Be sure to run `pod lib lint ChangellyAPI.podspec' to ensure this is a | ||
# valid spec before submitting. | ||
# | ||
# Any lines starting with a # are optional, but their use is encouraged | ||
# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html | ||
# | ||
|
||
Pod::Spec.new do |s| | ||
s.name = 'ChangellyAPI' | ||
s.version = '0.1.0' | ||
s.summary = 'A short description of ChangellyAPI.' | ||
|
||
# This description is used to generate tags and improve search results. | ||
# * Think: What does it do? Why did you write it? What is the focus? | ||
# * Try to keep it short, snappy and to the point. | ||
# * Write the description between the DESC delimiters below. | ||
# * Finally, don't worry about the indent, CocoaPods strips it! | ||
|
||
s.description = <<-DESC | ||
TODO: Add long description of the pod here. | ||
DESC | ||
|
||
s.homepage = 'https://github.com/coinpaprika/changelly-api-swift-client' | ||
s.license = { :type => 'MIT', :file => 'LICENSE' } | ||
s.author = { 'Dominique Stranz' => '[email protected]' } | ||
s.source = { :git => 'https://github.com/coinpaprika/changelly-api-swift-client.git', :tag => s.version.to_s } | ||
s.source = { :git => 'https://github.com/Dominique Stranz/ChangellyAPI.git', :tag => s.version.to_s } | ||
s.social_media_url = 'https://twitter.com/coinpaprika' | ||
|
||
s.ios.deployment_target = '10.0' | ||
|
||
s.source_files = 'ChangellyAPI/Classes/**/*' | ||
|
||
# s.resource_bundles = { | ||
# 'ChangellyAPI' => ['ChangellyAPI/Assets/*.png'] | ||
# } | ||
|
||
# s.public_header_files = 'Pod/Classes/**/*.h' | ||
# s.frameworks = 'UIKit', 'MapKit' | ||
s.dependency 'CoinpaprikaAPI/Networking' | ||
end |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// | ||
// ChangellyAPI.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
|
||
public struct ChangellyAPI { | ||
private let credentials: Credentials | ||
private let baseUrl: URL = URL(string: "https://api.changelly.com")! | ||
|
||
public init(key: String, secret: String) { | ||
self.credentials = Credentials(key: key, secret: secret) | ||
} | ||
|
||
public func getCurrencies() -> JsonRpcRequest<[String]> { | ||
return JsonRpcRequest<[String]>(baseUrl: baseUrl, method: "getCurrencies", params: [:], credentials: credentials) | ||
} | ||
|
||
public func getCurrenciesFull() -> JsonRpcRequest<[Currency]> { | ||
return JsonRpcRequest<[Currency]>(baseUrl: baseUrl, method: "getCurrenciesFull", params: [:], credentials: credentials) | ||
} | ||
|
||
public func getMinAmount(from: String, to: String) -> JsonRpcRequest<Decimal> { | ||
return JsonRpcRequest<Decimal>(baseUrl: baseUrl, method: "getMinAmount", params: ["from": from, "to": to], credentials: credentials) | ||
} | ||
|
||
public func getExchangeAmount(from: String, to: String, amount: Decimal) -> JsonRpcRequest<String> { | ||
return JsonRpcRequest<String>(baseUrl: baseUrl, method: "getExchangeAmount", params: ["from": from, "to": to, "amount": amount], credentials: credentials) | ||
} | ||
|
||
public func createTransaction(from: String, to: String, amount: Decimal, address: String, extraId: String? = nil, refundAddress: String? = nil, refundExtraId: String? = nil) -> JsonRpcRequest<Transaction> { | ||
var params: [String : Any] = ["from": from, "to": to, "amount": amount, "address": address] | ||
params["extraId"] = extraId | ||
params["refundAddress"] = refundAddress | ||
params["refundExtraId"] = refundExtraId | ||
return JsonRpcRequest<Transaction>(baseUrl: baseUrl, method: "createTransaction", params: params, credentials: credentials) | ||
} | ||
|
||
public func getTransactions(currency: String? = nil, address: String? = nil, extraId: String? = nil, limit: Int? = nil, offset: Int? = nil) -> JsonRpcRequest<[TransactionLog]> { | ||
var params = [String : Any]() | ||
params["currency"] = currency | ||
params["address"] = address | ||
params["extraId"] = extraId | ||
params["limit"] = limit | ||
params["offset"] = offset | ||
return JsonRpcRequest<[TransactionLog]>(baseUrl: baseUrl, method: "getTransactions", params: params, credentials: credentials) | ||
} | ||
|
||
public func getStatus(id: String) -> JsonRpcRequest<Transaction.Status> { | ||
return JsonRpcRequest<Transaction.Status>(baseUrl: baseUrl, method: "getStatus", params: ["id": id], credentials: credentials) | ||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// Currency.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
|
||
public struct Currency: Codable { | ||
public let name: String | ||
public let fullName: String | ||
public let enabled: Bool | ||
public let fixRateEnabled: Bool | ||
public let payinConfirmations: Int | ||
public let extraIdName: String? | ||
public let addressUrl: String? | ||
public let transactionUrl: String? | ||
public let image: URL | ||
public let fixedTime: Int | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// Transaction.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
import CoinpaprikaAPI | ||
|
||
public struct Transaction: Codable, CodableModel { | ||
public let id: String | ||
public let apiExtraFee: String | ||
public let changellyFee: String | ||
public let payinExtraId: String? | ||
public let payoutExtraId: String? | ||
public let amountExpectedFrom: Decimal | ||
public let amountExpectedTo: String | ||
public let status: Status | ||
public let currencyFrom: String | ||
public let currencyTo: String | ||
public let payinAddress: String | ||
public let payoutAddress: String | ||
public let createdAt: Date | ||
public let kycRequired: Bool | ||
|
||
public enum Status: String, Codable { | ||
case new | ||
case waiting | ||
case confirming | ||
case exchanging | ||
case sending | ||
case finished | ||
case failed | ||
case refunded | ||
case overdue | ||
case hold | ||
|
||
var localizedDescription: String { | ||
switch self { | ||
case .new: | ||
return "Freshly created transaction." | ||
case .waiting: | ||
return "Transaction is waiting for an incoming payment." | ||
case .confirming: | ||
return "We have received payin and are waiting for certain amount of confirmations depending of incoming currency." | ||
case .exchanging: | ||
return "Payment was confirmed and is being exchanged." | ||
case .sending: | ||
return "Coins are being sent to the recipient address." | ||
case .finished: | ||
return "Coins were successfully sent to the recipient address." | ||
case .failed: | ||
return "Transaction has failed. In most cases, the amount was less than the minimum. Please contact support and provide a transaction id." | ||
case .refunded: | ||
return "Exchange failed and coins were refunded to user's wallet. The wallet address should be provided by user." | ||
case .overdue: | ||
return "We did not receive any payment since 36 hours from transaction creation." | ||
case .hold: | ||
return "Due to AML/KYC procedure, exchange may be delayed" | ||
} | ||
} | ||
|
||
static var dateFormatter: DateFormatter { | ||
let formatter = DateFormatter() | ||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" | ||
return formatter | ||
} | ||
|
||
static var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? { | ||
return .formatted(dateFormatter) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// TransactionLog.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
import CoinpaprikaAPI | ||
|
||
public struct TransactionLog: Codable, CodableModel { | ||
public let id: String | ||
public let createdAt: Date | ||
public let moneyReceived: Decimal | ||
public let moneySent: Decimal | ||
public let payinConfirmations: String | ||
public let status: Transaction.Status | ||
public let currencyFrom: String | ||
public let currencyTo: String | ||
public let payinAddress: String | ||
public let payinExtraId: String? | ||
public let payinHash: String? | ||
public let amountExpectedFrom: String | ||
public let payoutAddress: String | ||
public let payoutExtraId: String? | ||
public let payoutHash: String? | ||
public let refundHash: String? | ||
public let amountFrom: String | ||
public let amountTo: String | ||
public let networkFee: String? | ||
public let changellyFee: String | ||
public let apiExtraFee: String | ||
|
||
static var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? { | ||
return .secondsSince1970 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// Credentials.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
|
||
public struct Credentials { | ||
public let key: String | ||
public let secret: String | ||
|
||
internal func signature(for data: Data) -> String? { | ||
guard let jsonString = String(data: data, encoding: .utf8) else { | ||
return nil | ||
} | ||
|
||
return jsonString.hmac(key: secret) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// | ||
// Request+JSON-RPC.swift | ||
// Coinpaprika | ||
// | ||
// Created by Dominique Stranz on 06.09.2018. | ||
// Copyright © 2018 Grey Wizard sp. z o.o. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import CoinpaprikaAPI | ||
|
||
public struct JsonRpcRequest<Model: Codable> { | ||
|
||
let request: Request<JsonRpcResponseEvelope<Model>> | ||
|
||
init(baseUrl: URL, method: String, params: [String: Any], credentials: Credentials) { | ||
let requestId = JsonRpcIdentifier.next() | ||
let rpcBody = ["jsonrpc": "2.0", "method": method, "id": requestId, "params": params] as [String: Any] | ||
request = Request<JsonRpcResponseEvelope<Model>>(baseUrl: baseUrl, method: .post, path: "", params: rpcBody, userAgent: "Changelly API Client - Swift", authorisation: .dynamic(signer: { (request) in | ||
guard let jsonData = request.httpBody, let signature = credentials.signature(for: jsonData) else { | ||
return | ||
} | ||
|
||
request.addValue(credentials.key, forHTTPHeaderField: "api-key") | ||
request.addValue(signature, forHTTPHeaderField: "sign") | ||
})) | ||
} | ||
|
||
public func perform(responseQueue: DispatchQueue? = nil, cachePolicy: URLRequest.CachePolicy? = nil, _ callback: @escaping (Result<Model, Error>) -> Void) { | ||
request.perform(responseQueue: responseQueue, cachePolicy: cachePolicy) { (response) in | ||
switch response { | ||
case .success(let envelope): | ||
if let result = envelope.result { | ||
callback(Result.success(result)) | ||
} else if let error = envelope.error { | ||
callback(Result.failure(JsonRpcError.serviceError(code: error.code, message: error.message))) | ||
} else { | ||
callback(Result.failure(JsonRpcError.unableToDecodeEnvelope)) | ||
} | ||
case .failure(let error): | ||
callback(Result.failure(error)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
struct JsonRpcIdentifier { | ||
private static var currentId: Int = 1 | ||
|
||
static func next() -> Int { | ||
defer { currentId += 1 } | ||
return currentId | ||
} | ||
} | ||
|
||
enum JsonRpcError: Error { | ||
case unableToDecodeEnvelope | ||
case serviceError(code: Int, message: String) | ||
} | ||
|
||
extension JsonRpcError: LocalizedError { | ||
public var errorDescription: String? { | ||
switch self { | ||
case .unableToDecodeEnvelope: | ||
return "Unable to decode response" | ||
case .serviceError(_, let message): | ||
return "\(message)" | ||
} | ||
} | ||
} | ||
|
||
struct JsonRpcResponseEvelope<Model: Codable>: Codable, CodableModel { | ||
let id: Int | ||
let result: Model? | ||
let error: JsonRpcErrorEnvelope? | ||
|
||
static var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? { | ||
if codableModel = model as? CodableModel { | ||
return Model.dateDecodingStrategy | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
struct JsonRpcErrorEnvelope: Codable { | ||
let code: Int | ||
let message: String | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// String+HMAC.swift | ||
// ChangellyAPI | ||
// | ||
// Created by Dominique Stranz on 10/04/2019. | ||
// | ||
|
||
import Foundation | ||
import CommonCrypto | ||
|
||
extension String { | ||
func hmac(key: String) -> String { | ||
var digest = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH)) | ||
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA512), key, key.count, self, self.count, &digest) | ||
let data = Data(bytes: digest) | ||
return data.map { String(format: "%02hhx", $0) }.joined() | ||
} | ||
} |
Oops, something went wrong.