Merge pull request #893 from AlphaWallet/update-xml-parsing-for-latest-asset-definition-schema

Update XML parsing to handle latest asset definition schema
pull/894/head
James Sangalli 6 years ago committed by GitHub
commit 896ff006cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      AlphaWallet/AssetDefinition/AssetAttribute.swift
  2. 2
      AlphaWallet/AssetDefinition/XMLHandler.swift
  3. 16
      AlphaWallet/RPC/Commands/web3swift-pod/CallForAssetAttribute.swift
  4. 2
      AlphaWallet/Tokens/Coordinators/CallForAssetAttributeCoordinator.swift
  5. 11
      AlphaWallet/UI/ViewModels/TokenCardRowViewModel.swift
  6. 5
      AlphaWallet/UI/Views/TokenCardRowView.swift

@ -83,27 +83,16 @@ enum AssetAttribute {
let attributeAccessor = XML.Accessor(attribute)
let functionElement = attributeAccessor["\(rootNamespacePrefix)origin"]["\(rootNamespacePrefix)function"]
if let attributeName = attributeAccessor.attributes["id"], case .singleElement(let origin) = attributeAccessor["\(rootNamespacePrefix)origin"], let rawSyntax = attributeAccessor.attributes["syntax"], let syntax = AssetAttributeSyntax(rawValue: rawSyntax), let functionName = functionElement.text?.dropParenthesis, !functionName.isEmpty {
if let attributeName = attributeAccessor.attributes["id"], case .singleElement(let origin) = attributeAccessor["\(rootNamespacePrefix)origin"], let rawSyntax = attributeAccessor.attributes["syntax"], let syntax = AssetAttributeSyntax(rawValue: rawSyntax), let functionName = functionElement.attributes["name"], !functionName.isEmpty {
let inputs: [CallForAssetAttribute.Argument]
let returnType = syntax.solidityReturnType
let output = CallForAssetAttribute.ReturnType(type: returnType)
switch functionElement["\(rootNamespacePrefix)value"] {
case .singleElement(let inputElement):
if let inputTypeString = inputElement.text, !inputTypeString.isEmpty, let inputName = inputElement.attributes["ref"], !inputName.isEmpty, let inputType = CallForAssetAttribute.SolidityType(rawValue: inputTypeString) {
inputs = [.init(name: inputName, type: inputType)]
} else {
inputs = []
}
case .sequence(let inputElements):
inputs = inputElements.compactMap {
if let inputTypeString = $0.text, !inputTypeString.isEmpty, let inputName = $0.attributes["ref"], !inputName.isEmpty, let inputType = CallForAssetAttribute.SolidityType(rawValue: inputTypeString) {
return .init(name: inputName, type: inputType)
} else {
return nil
}
}
switch functionElement["\(rootNamespacePrefix)inputs"] {
case .singleElement(let inputsElement):
inputs = AssetAttribute.extractInputs(fromInputsElements: [inputsElement])
case .sequence(let inputsElements):
inputs = AssetAttribute.extractInputs(fromInputsElements: inputsElements)
case .failure:
inputs = []
}
@ -116,7 +105,18 @@ enum AssetAttribute {
}()
}
func extract(from tokenValue: BigUInt, ofContract contract: String, config: Config, callForAssetAttributeCoordinator: CallForAssetAttributeCoordinator?) -> AssetAttributeValue {
private static func extractInputs(fromInputsElements inputsElements: [XML.Element]) -> [CallForAssetAttribute.Argument]{
return inputsElements.flatMap { $0.childElements }.compactMap {
let inputTypeString = $0.name.withoutXMLNamespacePrefix
if !inputTypeString.isEmpty, let inputName = $0.attributes["ref"], !inputName.isEmpty, let inputType = CallForAssetAttribute.SolidityType(rawValue: inputTypeString) {
return .init(name: inputName, type: inputType)
} else {
return nil
}
}
}
func extract(from tokenValue: BigUInt, ofContract contract: String, config: Config, callForAssetAttributeCoordinator: CallForAssetAttributeCoordinator?) -> AssetAttributeValue {
switch self {
case .mapping(_, _, let syntax, _, _, _), .direct(_, _, let syntax, _, _):
switch syntax {
@ -155,7 +155,7 @@ enum AssetAttribute {
switch self {
case .mapping(let attribute, let rootNamespacePrefix, let syntax, let lang, _, _):
guard let key = parseValue(tokenValue: tokenValue) else { return nil }
guard let value = attribute["\(rootNamespacePrefix)origin"]["\(rootNamespacePrefix)option"].getElementWithKeyAttribute(equals: String(key))?["\(rootNamespacePrefix)value"].getElementWithLangAttribute(equals: lang)?.text else { return nil }
guard let value = attribute["\(rootNamespacePrefix)origin"]["\(rootNamespacePrefix)mapping"]["\(rootNamespacePrefix)option"].getElementWithKeyAttribute(equals: String(key))?["\(rootNamespacePrefix)value"].getElementWithLangAttribute(equals: lang)?.text else { return nil }
return syntax.extract(from: value, isMapping: true) as? T
case .direct(_, _, let syntax, _, _):
guard let value = parseValue(tokenValue: tokenValue) else { return nil }
@ -222,3 +222,14 @@ enum AssetAttribute {
return callForAssetAttributeCoordinator.getValue(forAttributeName: attributeName, tokenId: tokenId, functionCall: functionCall)
}
}
extension String {
fileprivate var withoutXMLNamespacePrefix: String {
let components = split(separator: ":")
if components.count > 1 {
return String(components[1])
} else {
return String(components[0])
}
}
}

@ -89,7 +89,7 @@ private class PrivateXMLHandler {
let lang = getLang()
var fields = [String: AssetAttribute]()
for e in xml["\(rootNamespacePrefix)token"]["\(rootNamespacePrefix)attribute-types"]["\(rootNamespacePrefix)attribute-type"] {
if let id = e.attributes["id"], case let .singleElement(element) = e, XML.Accessor(element)["\(rootNamespacePrefix)origin"].attributes["as"] != nil {
if let id = e.attributes["id"], case let .singleElement(element) = e, XML.Accessor(element)["\(rootNamespacePrefix)origin"].attributes["bitmask"] != nil {
fields[id] = AssetAttribute(attribute: element, rootNamespacePrefix: rootNamespacePrefix, lang: lang)
} else if let id = e.attributes["id"], case let .singleElement(element) = e, XML.Accessor(element)["\(rootNamespacePrefix)origin"].attributes["contract"] == "holding-contract" {
fields[id] = AssetAttribute(attribute: element, rootNamespacePrefix: rootNamespacePrefix)

@ -4,10 +4,24 @@ import Foundation
struct CallForAssetAttribute {
enum SolidityType: String {
//TODO do we need to support the "odd" ones like uint24 in all steps of 8?
//TODO support address, enums, etc?
case bool
case int
case string
case int8
case int16
case int32
case int64
case int128
case int256
case uint
case uint8
case uint16
case uint32
case uint64
case uint128
case uint256
case string
}
struct Argument: Equatable {

@ -101,7 +101,7 @@ class CallForAssetAttributeCoordinator {
let result = value as? String ?? ""
seal.fulfill(result)
self.updateDataStore(forContract: functionCall.contract, tokenId: tokenId, attributeName: attributeName, value: result)
case .int, .uint256:
case .int, .int8, .int16, .int32, .int64, .int128, .int256, .uint, .uint8, .uint16, .uint32, .uint64, .uint128, .uint256:
let result = value as? Int ?? 0
seal.fulfill(result)
self.updateDataStore(forContract: functionCall.contract, tokenId: tokenId, attributeName: attributeName, value: result)

@ -75,6 +75,17 @@ struct TokenCardRowViewModel: TokenCardRowViewModelProtocol {
}
}
func subscribeLocality(withBlock block: @escaping (String) -> ()) {
guard isMeetupContract else { return }
if let subscribableAssetAttributeValue = tokenHolder.values["locality"] as? SubscribableAssetAttributeValue {
subscribableAssetAttributeValue.subscribable.subscribe { value in
if let value = value as? String {
block(value)
}
}
}
}
func subscribeBuilding(withBlock block: @escaping (String) -> ()) {
if let subscribableAssetAttributeValue = tokenHolder.values["building"] as? SubscribableAssetAttributeValue {
subscribableAssetAttributeValue.subscribable.subscribe { value in

@ -190,6 +190,11 @@ class TokenCardRowView: UIView {
strongSelf.categoryLabel.text = building
}
vm.subscribeLocality { [weak self] locality in
guard let strongSelf = self else { return }
strongSelf.cityLabel.text = ", \(locality)"
}
vm.subscribeExpired { [weak self] expired in
guard let strongSelf = self else { return }
strongSelf.teamsLabel.text = expired

Loading…
Cancel
Save