Merge pull request #492 from James-Sangalli/ecrecover-clean-dependencies

Ecrecover without the server
pull/496/head
James Sangalli 6 years ago committed by GitHub
commit 6903e0381c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      AlphaWallet/Info.plist
  2. 196
      AlphaWallet/Market/Coordinators/UniversalLinkCoordinator.swift
  3. 1
      AlphaWallet/Tokens/Coordinators/GetStormBirdBalanceCoordinator.swift
  4. 5
      AlphaWallet/Transfer/ViewControllers/TransferTicketsQuantitySelectionViewController.swift

@ -28,7 +28,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>206</string>
<string>208</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>

@ -5,7 +5,7 @@ import Alamofire
import BigInt
import Realm
import TrustKeystore
//import web3swift
import web3swift
protocol UniversalLinkCoordinatorDelegate: class {
func viewControllerForPresenting(in coordinator: UniversalLinkCoordinator) -> UIViewController?
@ -22,6 +22,7 @@ class UniversalLinkCoordinator: Coordinator {
var ethBalance: Subscribable<BigInt>?
var hasCompleted = false
var addressOfNewWallet: String?
private var getStormbirdBalanceCoordinator: GetStormBirdBalanceCoordinator?
init(config: Config) {
self.config = config
@ -119,8 +120,7 @@ class UniversalLinkCoordinator: Coordinator {
return true
}
//Returns true if handled
//Returns true if handled
func handleUniversalLink(url: URL) -> Bool {
let prefix = UniversalLinkHandler().urlPrefix
let matchedPrefix = url.description.hasPrefix(prefix)
@ -137,113 +137,120 @@ class UniversalLinkCoordinator: Coordinator {
let isStormBirdContract = xmlAddress.eip55String.sameContract(as: signedOrder.order.contractAddress)
importTicketViewController?.url = url
importTicketViewController?.contract = signedOrder.order.contractAddress
//let recoveredSigner = web3.personal.ecrecover(personalMessage: Data(bytes: signedOrder.message), signature: signature)
getTicketDetailsAndEcRecover(signedOrder: signedOrder) { result in
if let goodResult = result {
//user can pay gas for free import links if they are not covered by our server
if signedOrder.order.price > 0 || !isStormBirdContract {
if let balance = self.ethBalance {
balance.subscribeOnce { value in
if value > signedOrder.order.price {
let _ = self.handlePaidUniversalLink(signedOrder: signedOrder, ticketHolder: goodResult)
} else {
if let price = self.ethPrice {
if price.value == nil {
let ethCost = self.convert(ethCost: signedOrder.order.price)
self.showImportError(errorMessage: R.string.localizable.aClaimTicketFailedNotEnoughEthTitle(), ticketHolder: goodResult, ethCost: ethCost.description)
}
price.subscribe { [weak self] value in
if let celf = self {
if let price = price.value {
let (ethCost, dollarCost) = celf.convert(ethCost: signedOrder.order.price, rate: price)
celf.showImportError(errorMessage: R.string.localizable.aClaimTicketFailedNotEnoughEthTitle(), ticketHolder: goodResult, ethCost: ethCost.description, dollarCost: dollarCost.description)
}
}
}
}
}
}
}
//need to hash message here because the web3swift implementation adds prefix
let messageHash = Data(bytes: signedOrder.message).sha3(.keccak256)
//note: web3swift takes the v value as v - 27, so we need to manually convert this
let vValue = signedOrder.signature.drop0x.substring(from: 128)
let vInt = Int(vValue, radix: 16)! - 27
let vString = "0" + String(vInt)
let signature = "0x" + signedOrder.signature.drop0x.substring(to: 128) + vString
let nodeURL = Config().rpcURL
let recoveredSigner = web3(provider: Web3HttpProvider(nodeURL)!).personal.ecrecover(
hash: messageHash,
signature: Data(bytes: signature.hexa2Bytes)
)
switch recoveredSigner {
case .success(let ethereumAddress):
//TODO extract method for the whole .success? Quite long
//TODO return false?
guard let recoverAddress = Address(string: ethereumAddress.address) else { return false }
let contractAsAddress = Address(string: signedOrder.order.contractAddress)!
//gather signer address balance
let web3Swift = Web3Swift()
web3Swift.start()
getStormbirdBalanceCoordinator = GetStormBirdBalanceCoordinator(web3: web3Swift)
getStormbirdBalanceCoordinator?.getStormBirdBalance(for: recoverAddress, contract: contractAsAddress) { result in
//filter null tickets
let filteredTokens = self.checkERC875TokensAreAvailable(
indices: signedOrder.order.indices,
balance: try! result.dematerialize()
)
if filteredTokens.isEmpty {
self.showImportError(errorMessage: R.string.localizable.aClaimTicketInvalidLinkTryAgain())
}
else {
let ticketHolder = self.sortTickets(
filteredTokens,
signedOrder.order.indices,
signedOrder.order.contractAddress
)
if signedOrder.order.price > 0 || !isStormBirdContract {
self.handlePaidImports(signedOrder: signedOrder, ticketHolder: ticketHolder)
} else {
//free transfer
let _ = self.usePaymentServerForFreeTransferLinks(
signedOrder: signedOrder,
ticketHolder: goodResult
ticketHolder: ticketHolder
)
}
} else {
self.showImportError(errorMessage: R.string.localizable.aClaimTicketInvalidLinkTryAgain())
}
}
case .failure(let error):
//TODO handle. Show error maybe?
NSLog("xxx error during ecrecover: \(error.localizedDescription)")
//TODO return true or false?
return false
}
return true
}
func importPaidSignedOrder(signedOrder: SignedOrder, tokenObject: TokenObject) {
updateImportTicketController(with: .processing)
delegate?.importPaidSignedOrder(signedOrder: signedOrder, tokenObject: tokenObject) { successful in
if self.importTicketViewController != nil {
if let vc = self.importTicketViewController, var _ = vc.viewModel {
if successful {
self.showImportSuccessful()
} else {
//TODO Pass in error message
self.showImportError(errorMessage: R.string.localizable.aClaimTicketFailedTitle())
}
private func handlePaidImports(signedOrder: SignedOrder, ticketHolder: TicketHolder) {
if let balance = self.ethBalance {
balance.subscribeOnce { value in
if value > signedOrder.order.price {
let _ = self.handlePaidUniversalLink(signedOrder: signedOrder, ticketHolder: ticketHolder)
} else {
if let price = self.ethPrice {
if price.value == nil {
let ethCost = self.convert(ethCost: signedOrder.order.price)
self.showImportError(
errorMessage: R.string.localizable.aClaimTicketFailedNotEnoughEthTitle(),
ticketHolder: ticketHolder,
ethCost: ethCost.description
)
}
price.subscribe { [weak self] value in
if let celf = self {
if let price = price.value {
let (ethCost, dollarCost) = celf.convert(ethCost: signedOrder.order.price, rate: price)
celf.showImportError(errorMessage: R.string.localizable.aClaimTicketFailedNotEnoughEthTitle(), ticketHolder: ticketHolder, ethCost: ethCost.description, dollarCost: dollarCost.description)
}
}
}
}
}
}
}
}
private func stringEncodeIndices(_ indices: [UInt16]) -> String {
return indices.map(String.init).joined(separator: ",")
}
private func getTicketDetailsAndEcRecover(
signedOrder: SignedOrder,
completion: @escaping( _ response: TicketHolder?) -> Void
) {
let indices = signedOrder.order.indices
let parameters = createHTTPParametersForPaymentServer(
signedOrder: signedOrder,
isForTransfer: false
)
Alamofire.request(Constants.getTicketInfoFromServer, method: .get, parameters: parameters).responseJSON { response in
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
if let statusCode = response.response?.statusCode {
if statusCode > 299 {
completion(nil)
return
}
}
var array = utf8Text.split(separator: ",").map(String.init)
if array.isEmpty || array[0] == "invalid indices" {
completion(nil)
return
}
//start at one to slice off address
let bytes32Tickets = Array(array[1...])
completion(
self.sortTickets(
bytes32Tickets,
indices,
signedOrder.order.contractAddress
)
)
} else {
completion(nil)
func checkERC875TokensAreAvailable(indices: [UInt16], balance: [String]) -> [String] {
var filteredTokens = [String]()
if balance.count < indices.count {
return [String]()
}
for i in 0..<indices.count {
let token: String = balance[Int(indices[i])]
//all of the indices provided should map to a valid non null ticket
if token == Constants.nullTicket {
//if null ticket at any index then the deal cannot happen
return [String]()
}
filteredTokens.append(token)
}
return filteredTokens
}
private func sortTickets(_ bytes32Tickets: [String], _ indices: [UInt16], _ contractAddress: String) -> TicketHolder {
var tickets = [Ticket]()
let xmlHandler = XMLHandler()
for i in 0...bytes32Tickets.count - 1 {
for i in 0..<bytes32Tickets.count {
let ticket = bytes32Tickets[i]
if let tokenId = BigUInt(ticket, radix: 16) {
if let tokenId = BigUInt(ticket.drop0x, radix: 16) {
let ticket = xmlHandler.getFifaInfoForTicket(tokenId: tokenId, index: UInt16(i))
tickets.append(ticket)
}
@ -305,6 +312,23 @@ class UniversalLinkCoordinator: Coordinator {
private func showImportError(errorMessage: String, ticketHolder: TicketHolder? = nil, ethCost: String? = nil, dollarCost: String? = nil) {
updateImportTicketController(with: .failed(errorMessage: errorMessage), ticketHolder: ticketHolder, ethCost: ethCost, dollarCost: dollarCost)
}
func importPaidSignedOrder(signedOrder: SignedOrder, tokenObject: TokenObject) {
updateImportTicketController(with: .processing)
delegate?.importPaidSignedOrder(signedOrder: signedOrder, tokenObject: tokenObject) { successful in
if self.importTicketViewController != nil {
if let vc = self.importTicketViewController, var _ = vc.viewModel {
if successful {
self.showImportSuccessful()
} else {
//TODO Pass in error message
self.showImportError(errorMessage: R.string.localizable.aClaimTicketFailedTitle())
}
}
}
}
}
//handling free transfers, sell links cannot be handled here
private func importUniversalLink(query: String, parameters: Parameters) {

@ -11,7 +11,6 @@ import JavaScriptKit
class GetStormBirdBalanceCoordinator {
private let web3: Web3Swift
init(
web3: Web3Swift
) {

@ -21,7 +21,7 @@ class TransferTicketsQuantitySelectionViewController: UIViewController, Verifiab
var paymentFlow: PaymentFlow
weak var delegate: TransferTicketsQuantitySelectionViewControllerDelegate?
init(config: Config, paymentFlow: PaymentFlow) {
init(config: Config = Config(), paymentFlow: PaymentFlow) {
self.config = config
self.paymentFlow = paymentFlow
super.init(nibName: nil, bundle: nil)
@ -89,9 +89,10 @@ class TransferTicketsQuantitySelectionViewController: UIViewController, Verifiab
footerBar.bottomAnchor.constraint(equalTo: view.bottomAnchor),
] + roundedBackground.createConstraintsWithContainer(view: view))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
}
@objc

Loading…
Cancel
Save