Skip to content

Commit

Permalink
fix(swift): sign typed data (#28)
Browse files Browse the repository at this point in the history
* chore(swift): fix sign typed data

* chore: remove debug logs

* chore: fix knowncodable constructor
  • Loading branch information
cbrzn authored Aug 10, 2023
1 parent 96d9a38 commit f63f1ad
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 74 deletions.
2 changes: 1 addition & 1 deletion MetamaskProviderPlugin.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'MetamaskProviderPlugin'
s.version = '0.0.3'
s.version = '0.0.4'
s.summary = 'Metamask ethereum wallet plugin'
s.homepage = 'https://github.com/polywrap/ethereum-wallet'
s.license = 'MIT'
Expand Down
45 changes: 24 additions & 21 deletions implementations/swift/metamask/Source/MetamaskProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class MetamaskProvider: Plugin {
public var methodsMap: [String: PluginMethod] = [:]
var provider: Ethereum?
var cancellables: Set<AnyCancellable> = []
var address: String?

public init() {}

Expand All @@ -23,9 +24,11 @@ public class MetamaskProvider: Plugin {
print("Error connecting to address: \(error)")
default: break
}
}, receiveValue: { value in
print("Wallet connected! \(value)")
}).store(in: &cancellables)
}, receiveValue: { address in
if let stringAddress = address as? String {
self.address = stringAddress
}
}).store(in: &cancellables)
}

func executeRequest(publisher: EthereumPublisher?, completion: @escaping (Result<String, Error>) -> Void) {
Expand Down Expand Up @@ -93,13 +96,21 @@ public class MetamaskProvider: Plugin {
handleGetBlockByNumber(block: "latest", includeTx: false, completion: completion)
} else if args.method == "eth_signTypedData_v4" {
if let params = args.params {
let json = params.data(using: .utf8)!
let jsonDecoder = JSONDecoder()
let mixedArray = try! jsonDecoder.decode([AddressOrTypedData].self, from: json)
let params = [mixedArray[0].toString(), mixedArray[1].toString()]
let request = EthereumRequest(method: args.method, params: params)
let publisher = provider.request(request)
executeRequest(publisher: publisher, completion: completion)
if let jsonData = params.data(using: .utf8),
let mixedArray = try? JSONSerialization.jsonObject(with: jsonData) as? [Any],
mixedArray.count >= 2 {
// Convert the first element to string
let address = String(describing: mixedArray[0])

// Convert the second element back to JSON string
if let signMessage = try? JSONSerialization.data(withJSONObject: mixedArray[1]),
let messageAsString = String(data: signMessage, encoding: .utf8) {
let params = [address, messageAsString]
let request = EthereumRequest(method: args.method, params: params)
let publisher = provider.request(request)
executeRequest(publisher: publisher, completion: completion)
}
}
}
} else if args.method == "eth_feeHistory" {
handleFeeHistory(blockCount: "0xa", newestBlock: "latest", rewardPercentiles: [5.0], completion: completion)
Expand Down Expand Up @@ -186,15 +197,7 @@ public class MetamaskProvider: Plugin {
}

public func signerAddress(_ args: ArgsSignerAddress, _ env: VoidCodable?, _ invoker: Invoker) throws -> String? {
guard let provider = self.provider else {
return nil
}

if !provider.connected {
return nil
}

return provider.selectedAddress
self.address
}

private func isTransactionMethod(_ method: String) -> Bool {
Expand Down Expand Up @@ -287,12 +290,12 @@ extension Data {
}


public func getMetamaskProviderPlugin() -> Plugin {
public func getMetamaskProviderPlugin() -> MetamaskProvider {
var plugin = MetamaskProvider()
plugin.addMethod(name: "request", closure: plugin.request)
plugin.addMethod(name: "waitForTransaction", closure: plugin.waitForTransaction)
plugin.addMethod(name: "signerAddress", closure: plugin.signerAddress)
plugin.addMethod(name: "signMessage", closure: plugin.signMessage)
plugin.addMethod(name: "signTransaction", closure: plugin.signTransaction)
return plugin
}
}
66 changes: 14 additions & 52 deletions implementations/swift/metamask/Source/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,23 @@ public enum ProviderError: Error {
case dataCorruptedError
}

public enum StringOrInt: Codable {
public enum KnownCodable: Codable {
case string(String)
case int(Int)
case dict([String: KnownCodable])

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

if let typedDataValue = try? container.decode(Int.self) {
self = .int(typedDataValue)
} else if let stringValue = try? container.decode(String.self) {
self = .string(stringValue)
} else if let dictValue = try? container.decode([String: KnownCodable].self) {
self = .dict(dictValue)
} else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Unable to decode StringOrInt"
debugDescription: "Unable to decode KnownCodable"
)
}
}
Expand All @@ -110,11 +112,12 @@ public enum StringOrInt: Codable {
switch self {
case .string(let stringValue):
try container.encode(stringValue)
case .int(let int):
try container.encode(int)
case .int(let intValue):
try container.encode(intValue)
case .dict(let dictionaryValue):
try container.encode(dictionaryValue)
}
}

}

public enum TxOrString: Codable {
Expand Down Expand Up @@ -199,56 +202,15 @@ public struct CustomBoolOrStringArray: CodableData {
}

public struct Domain: Codable {
var chainId: Int
var verifyingContract: String
public var name: String
public var version: String
public var chainId: Int
public var verifyingContract: String
}

public struct TypedData: Codable {
var domain: Domain
var message: [String: StringOrInt]
var message: [String: KnownCodable]
var primaryType: String
var types: [String: [String: String]]
}

enum AddressOrTypedData: Codable {
case string(String)
case typedData(TypedData)

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

if let typedDataValue = try? container.decode(TypedData.self) {
self = .typedData(typedDataValue)
} else if let stringValue = try? container.decode(String.self) {
self = .string(stringValue)
} else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Unable to decode AddressOrTypedData"
)
}
}

func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()

switch self {
case .string(let stringValue):
try container.encode(stringValue)
case .typedData(let typedDatavalue):
try container.encode(typedDatavalue)
}
}

func toString() -> String {
switch self {
case .typedData(let v):
let encoder = JSONEncoder()
let jsonData = try! encoder.encode(v)
let string = String(data: jsonData, encoding: .utf8)!
return string
case.string(let v):
return v
}
}
}

0 comments on commit f63f1ad

Please sign in to comment.