From f4806d40dc471d52aae37a894c8c3509be5c3b2e Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Tue, 22 Aug 2023 19:49:20 +0900 Subject: [PATCH 01/33] initial commit --- Package.resolved | 113 ++++++++++++++++ Package.swift | 33 +++++ README 2.md | 3 + Sources/MpcProvider/EthereumTssAccount.swift | 123 ++++++++++++++++++ Sources/MpcProvider/MpcProvider.swift | 19 +++ Sources/MpcProvider/TssClientHelper.swift | 35 +++++ Tests/MpcProviderTests/MpcProviderTests.swift | 11 ++ 7 files changed, 337 insertions(+) create mode 100644 Package.resolved create mode 100644 Package.swift create mode 100644 README 2.md create mode 100644 Sources/MpcProvider/EthereumTssAccount.swift create mode 100644 Sources/MpcProvider/MpcProvider.swift create mode 100644 Sources/MpcProvider/TssClientHelper.swift create mode 100644 Tests/MpcProviderTests/MpcProviderTests.swift diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..ebca1f9 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,113 @@ +{ + "pins" : [ + { + "identity" : "anycodable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Flight-School/AnyCodable", + "state" : { + "revision" : "862808b2070cd908cb04f9aafe7de83d35f81b05", + "version" : "0.6.7" + } + }, + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt.git", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "32f641cf24fc7abc1c591a2025e9f2f572648b0f", + "version" : "1.7.2" + } + }, + { + "identity" : "fetch-node-details-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/fetch-node-details-swift.git", + "state" : { + "branch" : "alpha", + "revision" : "46603072d1796e9adc5afe2af33aaceb2294db67" + } + }, + { + "identity" : "generic-json-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zoul/generic-json-swift", + "state" : { + "revision" : "0a06575f4038b504e78ac330913d920f1630f510", + "version" : "2.0.2" + } + }, + { + "identity" : "secp256k1.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/GigaBitcoin/secp256k1.swift", + "state" : { + "revision" : "1a14e189def5eaa92f839afdd2faad8e43b61a6e", + "version" : "0.12.2" + } + }, + { + "identity" : "socket.io-client-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/socketio/socket.io-client-swift", + "state" : { + "revision" : "af5ce97b755d964235348d96f6db5cbdcbe334a5", + "version" : "16.0.1" + } + }, + { + "identity" : "starscream", + "kind" : "remoteSourceControl", + "location" : "https://github.com/daltoniam/Starscream", + "state" : { + "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", + "version" : "4.0.6" + } + }, + { + "identity" : "tkey-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tkey/tkey-ios", + "state" : { + "branch" : "alpha", + "revision" : "f52ffcedfd18e9ae4899b9f23e8905be43e9344d" + } + }, + { + "identity" : "torus-utils-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/torus-utils-swift", + "state" : { + "branch" : "alpha", + "revision" : "82956b84fc60dbb3983f1663a315cfe798e29f06" + } + }, + { + "identity" : "tss-client-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/tss-client-swift.git", + "state" : { + "branch" : "fix/hash_only", + "revision" : "0cd7a44dce2811ca02db24ad7dcd54dc5cc5c81a" + } + }, + { + "identity" : "web3.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/argentlabs/web3.swift", + "state" : { + "revision" : "0474eb5e883bc4800b3909833207a1d35e72b808", + "version" : "0.9.3" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..67465e9 --- /dev/null +++ b/Package.swift @@ -0,0 +1,33 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "MpcProvider", + platforms: [.iOS(.v13), .macOS(.v10_15)], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "MpcProvider", + targets: ["MpcProvider"]), + ], + dependencies: [ + .package(url: "https://github.com/argentlabs/web3.swift", from:"0.8.1"), + .package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"), + .package(url: "https://github.com/torusresearch/tss-client-swift.git", branch: "fix/hash_only"), + .package(url: "https://github.com/tkey/tkey-ios.git", branch: "alpha"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "MpcProvider", + dependencies: ["web3.swift", "BigInt", "tss-client-swift", "tkey_pkg"], + path: "Sources/MpcProvider"), + + .testTarget( + name: "MpcProviderTests", + dependencies: ["MpcProvider"]), + ] +) diff --git a/README 2.md b/README 2.md new file mode 100644 index 0000000..9f122bb --- /dev/null +++ b/README 2.md @@ -0,0 +1,3 @@ +# MpcProvider + +A description of this package. diff --git a/Sources/MpcProvider/EthereumTssAccount.swift b/Sources/MpcProvider/EthereumTssAccount.swift new file mode 100644 index 0000000..4615124 --- /dev/null +++ b/Sources/MpcProvider/EthereumTssAccount.swift @@ -0,0 +1,123 @@ +// +// EthereumTssAccount.swift +// tkey_ios +// +// Created by himanshu on 09/08/23. +// + +import Foundation +import web3 +import secp256k1 +import tss_client_swift +import CryptoKit +import BigInt +public enum CustomError: Error { + case unknownError + case methodUnavailable + + public var errorDescription: String { + switch self { + case .unknownError: + return "unknownError" + case .methodUnavailable: + return "method unavailable/unimplemented" + } + } +} + +enum EthereumSignerError: Error { + case emptyRawTransaction + case unknownError +} + +public class EthereumTssAccount: EthereumAccountProtocol { + public let selectedTag: String + public let verifier: String + public let factorKey: String + public let verifierID: String + public let publicKey: String + public let authSigs: [String] + public let tssNonce: Int32 + public let tssShare: String + public let tssIndex: String + public let nodeIndexes: [Int] + public let tssEndpoints: [String] + public let address: EthereumAddress + + required public init(evmAddress: String, pubkey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) throws { + self.factorKey = factorKey + self.selectedTag = selectedTag + self.verifier = verifier + self.verifierID = verifierID + self.publicKey = pubkey + self.nodeIndexes = nodeIndexes + self.tssEndpoints = tssEndpoints + self.tssNonce = tssNonce + self.tssIndex = tssIndex + self.tssShare = tssShare + self.address = EthereumAddress(evmAddress) + self.authSigs = authSigs + } + + public func sign(data: Data) throws -> Data { + throw CustomError.methodUnavailable + } + + public func sign(hex: String) throws -> Data { + throw CustomError.methodUnavailable + } + + public func sign(hash: String) throws -> Data { + throw CustomError.methodUnavailable + } + + public func sign(message: Data) throws -> Data { + throw CustomError.methodUnavailable + } + + public func sign(message: String) throws -> Data { + throw CustomError.methodUnavailable + } + + public func signMessage(message: Data) throws -> String { + throw CustomError.methodUnavailable + } + + public func signMessage(message: TypedData) throws -> String { + throw CustomError.methodUnavailable + } + + + public func signtx(transaction: EthereumTransaction) throws -> SignedTransaction { + // Create tss Client using helper + let (client, coeffs) = try helperTssClient(selected_tag: self.selectedTag, tssNonce: self.tssNonce, publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) + + // Wait for sockets to be connected + let connected = try client.checkConnected() + if !(connected) { + throw EthereumSignerError.unknownError + } + + let precompute = try client.precompute(serverCoeffs: coeffs, signatures: self.authSigs) + + let ready = try client.isReady() + if !(ready) { + throw EthereumSignerError.unknownError + } + + guard let raw = transaction.raw else { + throw EthereumSignerError.emptyRawTransaction + } + + let msgData = raw.web3.keccak256 + let signingMessage = Data(msgData).base64EncodedString() + let (s, r, v) = try! client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.authSigs) + + try! client.cleanup(signatures: self.authSigs) + + guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } + + return SignedTransaction(transaction: transaction, signature: signature) + } +} + diff --git a/Sources/MpcProvider/MpcProvider.swift b/Sources/MpcProvider/MpcProvider.swift new file mode 100644 index 0000000..641e36e --- /dev/null +++ b/Sources/MpcProvider/MpcProvider.swift @@ -0,0 +1,19 @@ +import Foundation +import web3 +import secp256k1 +import CryptoKit +import BigInt + + +public struct MpcProvider { + public private(set) var text = "Hello, World!" + + public init() { + + } + + public func sign(transaction: EthereumTransaction) -> SignedTransaction { + return signtx(transaction: transaction) + } + +} diff --git a/Sources/MpcProvider/TssClientHelper.swift b/Sources/MpcProvider/TssClientHelper.swift new file mode 100644 index 0000000..6df1d47 --- /dev/null +++ b/Sources/MpcProvider/TssClientHelper.swift @@ -0,0 +1,35 @@ +import BigInt +import Foundation +import SwiftUI +import tss_client_swift +import web3 +import tkey_pkg + +public func helperTssClient (selected_tag: String, tssNonce: Int32, publicKey: String, tssShare: String, tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { + + // generate a random nonce for sessionID + let randomKey = BigUInt(SECP256K1.generatePrivateKey()!) + let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) + let sessionNonce = TSSHelpers.hashMessage(message: String(random)) + // create the full session string + let session = TSSHelpers.assembleFullSession(verifier: verifier, verifierId: verifierId, tssTag: selected_tag, tssNonce: String(tssNonce), sessionNonce: sessionNonce) + + let userTssIndex = BigInt(tssIndex, radix: 16)! + // total parties, including the client + let parties = 4 + // index of the client, last index of partiesIndexes + let clientIndex = Int32(parties - 1) + + let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: nodeIndexes, urls: tssEndpoints) + + let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) + + let shareUnsigned = BigUInt(tssShare, radix: 16)! + let share = BigInt(sign: .plus, magnitude: shareUnsigned) + + let address = try KeyPoint(address: publicKey).getAsCompressedPublicKey(format: "") + + let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: address))) + + return (client, coeffs) + } diff --git a/Tests/MpcProviderTests/MpcProviderTests.swift b/Tests/MpcProviderTests/MpcProviderTests.swift new file mode 100644 index 0000000..366c706 --- /dev/null +++ b/Tests/MpcProviderTests/MpcProviderTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import MpcProvider + +final class MpcProviderTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(MpcProvider().text, "Hello, World!") + } +} From 461c8476d2ad7bcc8565df97afb06edbef5e933a Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Tue, 22 Aug 2023 19:49:59 +0900 Subject: [PATCH 02/33] remove readme --- README 2.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 README 2.md diff --git a/README 2.md b/README 2.md deleted file mode 100644 index 9f122bb..0000000 --- a/README 2.md +++ /dev/null @@ -1,3 +0,0 @@ -# MpcProvider - -A description of this package. From 867b10ab747868788f41df4f7b632538d21b8eae Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Tue, 22 Aug 2023 20:39:39 +0900 Subject: [PATCH 03/33] update package --- .DS_Store | Bin 0 -> 6148 bytes Package.resolved | 6 ++--- Package.swift | 21 +++++++++--------- README.md | 2 +- Sources/.DS_Store | Bin 0 -> 6148 bytes .../EthereumTssAccount.swift | 0 .../TssClientHelper.swift | 0 .../Web3SwiftMpcProvider.swift} | 7 ++---- .../MpcProviderTests.swift | 6 ++--- 9 files changed, 20 insertions(+), 22 deletions(-) create mode 100644 .DS_Store create mode 100644 Sources/.DS_Store rename Sources/{MpcProvider => Web3SwiftMpcProvider}/EthereumTssAccount.swift (100%) rename Sources/{MpcProvider => Web3SwiftMpcProvider}/TssClientHelper.swift (100%) rename Sources/{MpcProvider/MpcProvider.swift => Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift} (51%) rename Tests/{MpcProviderTests => Web3SwiftMpcProviderTests}/MpcProviderTests.swift (58%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e3ebfbe7f82d6047d95fc747c3d017015a251af3 GIT binary patch literal 6148 zcmeHK&ubGw6n>MYW@9MipkNQefY(sdM1<1I8qXHEg9!2hm*S^Tdkq$!;t{#w5oDN5)PD|z-JQPU_<5t8AJ;tPE5 zhc=zw4%PV?6%^A)%BxKAu*U4rF&)t}8q-UlqyhGh^ZI;^(;BN?Vco(IS2ae90%Wtq zzBENXS?yPS|MTdm$S!R5U!#j8&hmc$n`mq`x9_yPme=v#2cJ|CqgbtCMaP4EM8|5l5sgW1)KtZRRP`~B%IN=SQ^w@2ZFu=0GnvmhBAL5 zFh^SSEtUq+0~3Y{G*n@)7{bueF6}tqVrkION!ZJWurmvLLlJs*JYVYJBz%J|It82p zRRy+8wae%K(eLm7Rg$YY1)KsKrGRLTgYgI{*|YUVa(vcG_y;%}k1Gvo3W7b3b%BrK c2XJlZlUxA$7E6O@fw>O>ErSbAfq$yNPe!$zhX4Qo literal 0 HcmV?d00001 diff --git a/Package.resolved b/Package.resolved index ebca1f9..42a65c5 100644 --- a/Package.resolved +++ b/Package.resolved @@ -73,12 +73,12 @@ } }, { - "identity" : "tkey-ios", + "identity" : "tkey-mpc-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/tkey/tkey-ios", + "location" : "https://github.com/tkey/tkey-mpc-swift.git", "state" : { "branch" : "alpha", - "revision" : "f52ffcedfd18e9ae4899b9f23e8905be43e9344d" + "revision" : "9f2930b6c24703dca52c7fb19fd56a4755a954a0" } }, { diff --git a/Package.swift b/Package.swift index 67465e9..f329263 100644 --- a/Package.swift +++ b/Package.swift @@ -4,30 +4,31 @@ import PackageDescription let package = Package( - name: "MpcProvider", + name: "Web3SwiftMpcProvider", platforms: [.iOS(.v13), .macOS(.v10_15)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( - name: "MpcProvider", - targets: ["MpcProvider"]), + name: "Web3SwiftMpcProvider", + targets: ["Web3SwiftMpcProvider"]), ], dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"0.8.1"), .package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", branch: "fix/hash_only"), - .package(url: "https://github.com/tkey/tkey-ios.git", branch: "alpha"), + .package(url: "https://github.com/tkey/tkey-mpc-swift.git", branch: "alpha"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( - name: "MpcProvider", - dependencies: ["web3.swift", "BigInt", "tss-client-swift", "tkey_pkg"], - path: "Sources/MpcProvider"), + name: "Web3SwiftMpcProvider", + dependencies: ["web3.swift", "BigInt", "tss-client-swift"], + path: "Sources/Web3SwiftMpcProvider"), .testTarget( - name: "MpcProviderTests", - dependencies: ["MpcProvider"]), - ] + name: "Web3SwiftMpcProviderTests", + dependencies: ["Web3SwiftMpcProvider"]), + ], + swiftLanguageVersions: [.v5] ) diff --git a/README.md b/README.md index ff5ddb3..9f122bb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# mpc-signing-provider-swift +# MpcProvider A description of this package. diff --git a/Sources/.DS_Store b/Sources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8da41ee7011714ccbf5779d33dd9cfbff325d220 GIT binary patch literal 6148 zcmeHKJxc>Y5PhR50yZfuEcY*ne_#o*6oeGElAMANI7$3yukv^K(|j|t2**XRv5_}0 z^LA(F?QyTTxdC9y*X|Nn0GQJq@!?@=e(pZ8la?_eop-G9jwd|g1viuG;|b@U;|>ql z;A+Hw#um5OqsJTX>{zky4%^+P?{~+qQdSB`0VyB_q<|Fog#zAtY4fv0MJXT!q`J$Z|F7vk%>QGOc2YnJ{3``)wpy>2e5KY~Coku{ yw$ShCUh_$J<2on|(T<7Hj=Ax6d=W)iSA5O$+Hgn=I`cs%>Sw@pkx7BSR^SV?dKni0 literal 0 HcmV?d00001 diff --git a/Sources/MpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift similarity index 100% rename from Sources/MpcProvider/EthereumTssAccount.swift rename to Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift diff --git a/Sources/MpcProvider/TssClientHelper.swift b/Sources/Web3SwiftMpcProvider/TssClientHelper.swift similarity index 100% rename from Sources/MpcProvider/TssClientHelper.swift rename to Sources/Web3SwiftMpcProvider/TssClientHelper.swift diff --git a/Sources/MpcProvider/MpcProvider.swift b/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift similarity index 51% rename from Sources/MpcProvider/MpcProvider.swift rename to Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift index 641e36e..a3cdba7 100644 --- a/Sources/MpcProvider/MpcProvider.swift +++ b/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift @@ -5,15 +5,12 @@ import CryptoKit import BigInt -public struct MpcProvider { +public struct Web3SwiftMpcProvider { public private(set) var text = "Hello, World!" public init() { } - public func sign(transaction: EthereumTransaction) -> SignedTransaction { - return signtx(transaction: transaction) - } - + } diff --git a/Tests/MpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift similarity index 58% rename from Tests/MpcProviderTests/MpcProviderTests.swift rename to Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 366c706..e2278cf 100644 --- a/Tests/MpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -1,11 +1,11 @@ import XCTest -@testable import MpcProvider +@testable import Web3SwiftMpcProvider -final class MpcProviderTests: XCTestCase { +final class Web3SwiftMpcProviderTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. - XCTAssertEqual(MpcProvider().text, "Hello, World!") + XCTAssertEqual(Web3SwiftMpcProvider().text, "Hello, World!") } } From 21e64d47277d4d5899f3b6a460abe5c66f74409e Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Wed, 23 Aug 2023 11:10:02 +0900 Subject: [PATCH 04/33] update pkg version --- Package.resolved | 88 +++++++++++++++++-- Package.swift | 9 +- .../EthereumTssAccount.swift | 1 + .../TssClientHelper.swift | 1 + 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/Package.resolved b/Package.resolved index 42a65c5..68ed46e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -39,7 +39,7 @@ { "identity" : "generic-json-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/zoul/generic-json-swift", + "location" : "https://github.com/iwill/generic-json-swift", "state" : { "revision" : "0a06575f4038b504e78ac330913d920f1630f510", "version" : "2.0.2" @@ -68,8 +68,71 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/daltoniam/Starscream", "state" : { - "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", - "version" : "4.0.6" + "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", + "version" : "4.0.4" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", + "version" : "1.0.4" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", + "version" : "1.5.3" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "cf281631ff10ec6111f2761052aa81896a83a007", + "version" : "2.58.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", + "version" : "1.19.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "320bd978cceb8e88c125dcbb774943a92f6286e9", + "version" : "2.25.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "e7403c35ca6bb539a7ca353b91cc2d8ec0362d58", + "version" : "1.19.0" } }, { @@ -84,7 +147,7 @@ { "identity" : "torus-utils-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/torus-utils-swift", + "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { "branch" : "alpha", "revision" : "82956b84fc60dbb3983f1663a315cfe798e29f06" @@ -95,8 +158,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/tss-client-swift.git", "state" : { - "branch" : "fix/hash_only", - "revision" : "0cd7a44dce2811ca02db24ad7dcd54dc5cc5c81a" + "revision" : "ab123d96c36d07aa73bf6118ca9602ab2d2846d0", + "version" : "1.0.10" } }, { @@ -104,8 +167,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/argentlabs/web3.swift", "state" : { - "revision" : "0474eb5e883bc4800b3909833207a1d35e72b808", - "version" : "0.9.3" + "revision" : "8ca33e700ed8de6137a0e1471017aa3b3c8de0db", + "version" : "1.6.0" + } + }, + { + "identity" : "websocket-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/websocket-kit.git", + "state" : { + "revision" : "53fe0639a98903858d0196b699720decb42aee7b", + "version" : "2.14.0" } } ], diff --git a/Package.swift b/Package.swift index f329263..ee68d38 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "Web3SwiftMpcProvider", - platforms: [.iOS(.v13), .macOS(.v10_15)], + platforms: [.iOS(.v14), .macOS(.v10_15)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( @@ -13,9 +13,8 @@ let package = Package( targets: ["Web3SwiftMpcProvider"]), ], dependencies: [ - .package(url: "https://github.com/argentlabs/web3.swift", from:"0.8.1"), - .package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"), - .package(url: "https://github.com/torusresearch/tss-client-swift.git", branch: "fix/hash_only"), + .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), + .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), .package(url: "https://github.com/tkey/tkey-mpc-swift.git", branch: "alpha"), ], targets: [ @@ -23,7 +22,7 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Web3SwiftMpcProvider", - dependencies: ["web3.swift", "BigInt", "tss-client-swift"], + dependencies: ["web3.swift", "tss-client-swift", .product(name: "ThresholdKey", package: "tkey-mpc-swift")], path: "Sources/Web3SwiftMpcProvider"), .testTarget( diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 4615124..ecc60e1 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -11,6 +11,7 @@ import secp256k1 import tss_client_swift import CryptoKit import BigInt + public enum CustomError: Error { case unknownError case methodUnavailable diff --git a/Sources/Web3SwiftMpcProvider/TssClientHelper.swift b/Sources/Web3SwiftMpcProvider/TssClientHelper.swift index 6df1d47..69faead 100644 --- a/Sources/Web3SwiftMpcProvider/TssClientHelper.swift +++ b/Sources/Web3SwiftMpcProvider/TssClientHelper.swift @@ -5,6 +5,7 @@ import tss_client_swift import web3 import tkey_pkg + public func helperTssClient (selected_tag: String, tssNonce: Int32, publicKey: String, tssShare: String, tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { // generate a random nonce for sessionID From 9217692070d4a29d337ce20fc367a1b764be41e0 Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 23 Aug 2023 19:52:45 +0800 Subject: [PATCH 05/33] fix: package.swift restructure and rename signing code add Error type --- .gitignore | 96 +++++ Package.resolved | 332 ++++++++---------- Package.swift | 13 +- Sources/Web3SwiftMpcProvider/Error.swift | 24 ++ .../EthereumTssAccount.swift | 176 +++++++--- .../{TssClientHelper.swift => Helper.swift} | 28 +- .../MpcProviderTests.swift | 8 +- 7 files changed, 423 insertions(+), 254 deletions(-) create mode 100644 .gitignore create mode 100644 Sources/Web3SwiftMpcProvider/Error.swift rename Sources/Web3SwiftMpcProvider/{TssClientHelper.swift => Helper.swift} (66%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5d2630 --- /dev/null +++ b/.gitignore @@ -0,0 +1,96 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +.swiftpm/ + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ +.idea diff --git a/Package.resolved b/Package.resolved index 68ed46e..9a23ba0 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,185 +1,151 @@ { - "pins" : [ - { - "identity" : "anycodable", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Flight-School/AnyCodable", - "state" : { - "revision" : "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version" : "0.6.7" - } - }, - { - "identity" : "bigint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/attaswift/BigInt.git", - "state" : { - "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version" : "5.3.0" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", - "state" : { - "revision" : "32f641cf24fc7abc1c591a2025e9f2f572648b0f", - "version" : "1.7.2" - } - }, - { - "identity" : "fetch-node-details-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/fetch-node-details-swift.git", - "state" : { - "branch" : "alpha", - "revision" : "46603072d1796e9adc5afe2af33aaceb2294db67" - } - }, - { - "identity" : "generic-json-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/iwill/generic-json-swift", - "state" : { - "revision" : "0a06575f4038b504e78ac330913d920f1630f510", - "version" : "2.0.2" - } - }, - { - "identity" : "secp256k1.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/GigaBitcoin/secp256k1.swift", - "state" : { - "revision" : "1a14e189def5eaa92f839afdd2faad8e43b61a6e", - "version" : "0.12.2" - } - }, - { - "identity" : "socket.io-client-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/socketio/socket.io-client-swift", - "state" : { - "revision" : "af5ce97b755d964235348d96f6db5cbdcbe334a5", - "version" : "16.0.1" - } - }, - { - "identity" : "starscream", - "kind" : "remoteSourceControl", - "location" : "https://github.com/daltoniam/Starscream", - "state" : { - "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version" : "4.0.4" - } - }, - { - "identity" : "swift-atomics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-atomics.git", - "state" : { - "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", - "version" : "1.1.0" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", - "version" : "1.5.3" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "cf281631ff10ec6111f2761052aa81896a83a007", - "version" : "2.58.0" - } - }, - { - "identity" : "swift-nio-extras", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-extras.git", - "state" : { - "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", - "version" : "1.19.0" - } - }, - { - "identity" : "swift-nio-ssl", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-ssl.git", - "state" : { - "revision" : "320bd978cceb8e88c125dcbb774943a92f6286e9", - "version" : "2.25.0" - } - }, - { - "identity" : "swift-nio-transport-services", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-transport-services.git", - "state" : { - "revision" : "e7403c35ca6bb539a7ca353b91cc2d8ec0362d58", - "version" : "1.19.0" - } - }, - { - "identity" : "tkey-mpc-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tkey/tkey-mpc-swift.git", - "state" : { - "branch" : "alpha", - "revision" : "9f2930b6c24703dca52c7fb19fd56a4755a954a0" - } - }, - { - "identity" : "torus-utils-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/torus-utils-swift.git", - "state" : { - "branch" : "alpha", - "revision" : "82956b84fc60dbb3983f1663a315cfe798e29f06" - } - }, - { - "identity" : "tss-client-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/tss-client-swift.git", - "state" : { - "revision" : "ab123d96c36d07aa73bf6118ca9602ab2d2846d0", - "version" : "1.0.10" - } - }, - { - "identity" : "web3.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/argentlabs/web3.swift", - "state" : { - "revision" : "8ca33e700ed8de6137a0e1471017aa3b3c8de0db", - "version" : "1.6.0" - } - }, - { - "identity" : "websocket-kit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/websocket-kit.git", - "state" : { - "revision" : "53fe0639a98903858d0196b699720decb42aee7b", - "version" : "2.14.0" - } - } - ], - "version" : 2 + "object": { + "pins": [ + { + "package": "BigInt", + "repositoryURL": "https://github.com/attaswift/BigInt.git", + "state": { + "branch": null, + "revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version": "5.3.0" + } + }, + { + "package": "CryptoSwift", + "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", + "state": { + "branch": null, + "revision": "32f641cf24fc7abc1c591a2025e9f2f572648b0f", + "version": "1.7.2" + } + }, + { + "package": "GenericJSON", + "repositoryURL": "https://github.com/iwill/generic-json-swift", + "state": { + "branch": null, + "revision": "0a06575f4038b504e78ac330913d920f1630f510", + "version": "2.0.2" + } + }, + { + "package": "secp256k1", + "repositoryURL": "https://github.com/GigaBitcoin/secp256k1.swift.git", + "state": { + "branch": null, + "revision": "1a14e189def5eaa92f839afdd2faad8e43b61a6e", + "version": "0.12.2" + } + }, + { + "package": "SocketIO", + "repositoryURL": "https://github.com/socketio/socket.io-client-swift", + "state": { + "branch": null, + "revision": "af5ce97b755d964235348d96f6db5cbdcbe334a5", + "version": "16.0.1" + } + }, + { + "package": "Starscream", + "repositoryURL": "https://github.com/daltoniam/Starscream", + "state": { + "branch": null, + "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", + "version": "4.0.4" + } + }, + { + "package": "swift-atomics", + "repositoryURL": "https://github.com/apple/swift-atomics.git", + "state": { + "branch": null, + "revision": "6c89474e62719ddcc1e9614989fff2f68208fe10", + "version": "1.1.0" + } + }, + { + "package": "swift-collections", + "repositoryURL": "https://github.com/apple/swift-collections.git", + "state": { + "branch": null, + "revision": "937e904258d22af6e447a0b72c0bc67583ef64a2", + "version": "1.0.4" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "532d8b529501fb73a2455b179e0bbb6d49b652ed", + "version": "1.5.3" + } + }, + { + "package": "swift-nio", + "repositoryURL": "https://github.com/apple/swift-nio.git", + "state": { + "branch": null, + "revision": "cf281631ff10ec6111f2761052aa81896a83a007", + "version": "2.58.0" + } + }, + { + "package": "swift-nio-extras", + "repositoryURL": "https://github.com/apple/swift-nio-extras.git", + "state": { + "branch": null, + "revision": "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", + "version": "1.19.0" + } + }, + { + "package": "swift-nio-ssl", + "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", + "state": { + "branch": null, + "revision": "320bd978cceb8e88c125dcbb774943a92f6286e9", + "version": "2.25.0" + } + }, + { + "package": "swift-nio-transport-services", + "repositoryURL": "https://github.com/apple/swift-nio-transport-services.git", + "state": { + "branch": null, + "revision": "e7403c35ca6bb539a7ca353b91cc2d8ec0362d58", + "version": "1.19.0" + } + }, + { + "package": "tss-client-swift", + "repositoryURL": "https://github.com/torusresearch/tss-client-swift.git", + "state": { + "branch": null, + "revision": "ab123d96c36d07aa73bf6118ca9602ab2d2846d0", + "version": "1.0.10" + } + }, + { + "package": "web3.swift", + "repositoryURL": "https://github.com/argentlabs/web3.swift", + "state": { + "branch": null, + "revision": "8ca33e700ed8de6137a0e1471017aa3b3c8de0db", + "version": "1.6.0" + } + }, + { + "package": "websocket-kit", + "repositoryURL": "https://github.com/vapor/websocket-kit.git", + "state": { + "branch": null, + "revision": "53fe0639a98903858d0196b699720decb42aee7b", + "version": "2.14.0" + } + } + ] + }, + "version": 1 } diff --git a/Package.swift b/Package.swift index ee68d38..01178fe 100644 --- a/Package.swift +++ b/Package.swift @@ -1,33 +1,34 @@ -// swift-tools-version: 5.8 +// swift-tools-version: 5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Web3SwiftMpcProvider", - platforms: [.iOS(.v14), .macOS(.v10_15)], + platforms: [.iOS(.v13), .macOS(.v11)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Web3SwiftMpcProvider", targets: ["Web3SwiftMpcProvider"]), + ], dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), - .package(url: "https://github.com/tkey/tkey-mpc-swift.git", branch: "alpha"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Web3SwiftMpcProvider", - dependencies: ["web3.swift", "tss-client-swift", .product(name: "ThresholdKey", package: "tkey-mpc-swift")], + dependencies: ["web3.swift", "tss-client-swift"], path: "Sources/Web3SwiftMpcProvider"), - + .testTarget( name: "Web3SwiftMpcProviderTests", - dependencies: ["Web3SwiftMpcProvider"]), + dependencies: ["Web3SwiftMpcProvider" ], + path: "Tests"), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/Web3SwiftMpcProvider/Error.swift b/Sources/Web3SwiftMpcProvider/Error.swift new file mode 100644 index 0000000..75e9bc2 --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/Error.swift @@ -0,0 +1,24 @@ +// +// File.swift +// +// +// Created by CW Lee on 23/08/2023. +// + +import Foundation + + +public enum CustomSigningError: Error { + case generalError(error: String = "") + case unknownError(error: String = "") + + public var errorDescription: String { + switch self { + case .generalError ( let err): + return err + + case .unknownError ( let err): + return err + } + } +} diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index ecc60e1..0ab84e0 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -46,52 +46,49 @@ public class EthereumTssAccount: EthereumAccountProtocol { public let address: EthereumAddress required public init(evmAddress: String, pubkey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) throws { - self.factorKey = factorKey - self.selectedTag = selectedTag - self.verifier = verifier - self.verifierID = verifierID - self.publicKey = pubkey - self.nodeIndexes = nodeIndexes - self.tssEndpoints = tssEndpoints - self.tssNonce = tssNonce - self.tssIndex = tssIndex - self.tssShare = tssShare - self.address = EthereumAddress(evmAddress) - self.authSigs = authSigs - } - - public func sign(data: Data) throws -> Data { - throw CustomError.methodUnavailable - } - - public func sign(hex: String) throws -> Data { - throw CustomError.methodUnavailable - } - - public func sign(hash: String) throws -> Data { - throw CustomError.methodUnavailable - } - - public func sign(message: Data) throws -> Data { - throw CustomError.methodUnavailable - } - - public func sign(message: String) throws -> Data { - throw CustomError.methodUnavailable - } - - public func signMessage(message: Data) throws -> String { - throw CustomError.methodUnavailable - } - - public func signMessage(message: TypedData) throws -> String { - throw CustomError.methodUnavailable - } + self.factorKey = factorKey + self.selectedTag = selectedTag + self.verifier = verifier + self.verifierID = verifierID + self.publicKey = pubkey + self.nodeIndexes = nodeIndexes + self.tssEndpoints = tssEndpoints + self.tssNonce = tssNonce + self.tssIndex = tssIndex + self.tssShare = tssShare + self.address = EthereumAddress(evmAddress) + self.authSigs = authSigs + } - - public func signtx(transaction: EthereumTransaction) throws -> SignedTransaction { - // Create tss Client using helper - let (client, coeffs) = try helperTssClient(selected_tag: self.selectedTag, tssNonce: self.tssNonce, publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) + /// hash and sign data + public func sign(data: Data) throws -> Data { + let hash = data.sha3(.keccak256) + let signature = try self.sign(message: hash) + return signature + } + + /// hash and sign hex string + public func sign(hex: String) throws -> Data { + if let data = Data(hex: hex) { + return try self.sign(data: data) + } else { + throw EthereumAccountError.signError + } + } + + /// Signing hashed string + public func sign(hash: String) throws -> Data { + if let data = hash.web3.hexData { + return try self.sign(message: data) + } else { + throw EthereumAccountError.signError + } + } + + /// Signing Data without hashing + public func sign(message: Data) throws -> Data { + // Create tss Client using helper + let (client, coeffs) = try bootstrapTssClient(selected_tag: self.selectedTag, tssNonce: self.tssNonce, publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) // Wait for sockets to be connected let connected = try client.checkConnected() @@ -105,20 +102,91 @@ public class EthereumTssAccount: EthereumAccountProtocol { if !(ready) { throw EthereumSignerError.unknownError } - - guard let raw = transaction.raw else { - throw EthereumSignerError.emptyRawTransaction - } - - let msgData = raw.web3.keccak256 - let signingMessage = Data(msgData).base64EncodedString() + + let signingMessage = message.base64EncodedString() let (s, r, v) = try! client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.authSigs) try! client.cleanup(signatures: self.authSigs) guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } + return signature + } + + /// Signing utf8 encoded message String without hashing + public func sign(message: String) throws -> Data { + if let data = message.data(using: .utf8) { + return try self.sign(data: data) + } else { + throw EthereumAccountError.signError + } + } - return SignedTransaction(transaction: transaction, signature: signature) - } + /// prefix message and hash it before signing + public func signMessage(message: Data) throws -> String { + let prefix = "\u{19}Ethereum Signed Message:\n\(String(message.count))" + guard var data = prefix.data(using: .ascii) else { + throw EthereumAccountError.signError + } + data.append(message) + let hash = data.web3.keccak256 + + guard var signed = try? self.sign(message: hash) else { + throw EthereumAccountError.signError + } + + // Check last char (v) + guard var last = signed.popLast() else { + throw EthereumAccountError.signError + } + + if last < 27 { + last += 27 + } + + signed.append(last) + return signed.web3.hexString + } + + /// signing TypedData + public func signMessage(message: TypedData) throws -> String { + let hash = try message.signableHash() + + guard var signed = try? self.sign(message: hash) else { + throw EthereumAccountError.signError + } + + // Check last char (v) + guard var last = signed.popLast() else { + throw EthereumAccountError.signError + } + + if last < 27 { + last += 27 + } + + signed.append(last) + return signed.web3.hexString + } + + /// Signing EthereumTransaction + public func signtx(transaction: EthereumTransaction) throws -> SignedTransaction { + guard let raw = transaction.raw else { + throw EthereumSignerError.emptyRawTransaction + } + + // hash and sign data + var signed = try self.sign(data: raw) + // Check last char (v) + guard var last = signed.popLast() else { + throw EthereumAccountError.signError + } + + if last < 27 { + last += 27 + } + + signed.append(last) + return SignedTransaction(transaction: transaction, signature: signed) + } } diff --git a/Sources/Web3SwiftMpcProvider/TssClientHelper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift similarity index 66% rename from Sources/Web3SwiftMpcProvider/TssClientHelper.swift rename to Sources/Web3SwiftMpcProvider/Helper.swift index 69faead..c1c8722 100644 --- a/Sources/Web3SwiftMpcProvider/TssClientHelper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -3,11 +3,14 @@ import Foundation import SwiftUI import tss_client_swift import web3 -import tkey_pkg +import secp256k1 -public func helperTssClient (selected_tag: String, tssNonce: Int32, publicKey: String, tssShare: String, tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { - +public func bootstrapTssClient (selected_tag: String, tssNonce: Int32, publicKey: String, tssShare: String, tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { + if ( publicKey.count < 128 || publicKey.count > 130 ) { + throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") + } + // generate a random nonce for sessionID let randomKey = BigUInt(SECP256K1.generatePrivateKey()!) let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) @@ -17,7 +20,8 @@ public func helperTssClient (selected_tag: String, tssNonce: Int32, publicKey: S let userTssIndex = BigInt(tssIndex, radix: 16)! // total parties, including the client - let parties = 4 + let parties = nodeIndexes.count > 0 ? nodeIndexes.count + 1 : 4 + // index of the client, last index of partiesIndexes let clientIndex = Int32(parties - 1) @@ -28,9 +32,19 @@ public func helperTssClient (selected_tag: String, tssNonce: Int32, publicKey: S let shareUnsigned = BigUInt(tssShare, radix: 16)! let share = BigInt(sign: .plus, magnitude: shareUnsigned) - let address = try KeyPoint(address: publicKey).getAsCompressedPublicKey(format: "") - - let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: address))) + let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) return (client, coeffs) } + + + +public func hashMessage(message: Data) -> String { + let hash = message.sha3(.keccak256) + return hash.base64EncodedString() +} + +public func hashMessage(message: String) -> String { + return hashMessage(message: Data(message.utf8)) +} + diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index e2278cf..b2ab9e7 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -1,11 +1,11 @@ import XCTest @testable import Web3SwiftMpcProvider +import secp256k1 final class Web3SwiftMpcProviderTests: XCTestCase { func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - XCTAssertEqual(Web3SwiftMpcProvider().text, "Hello, World!") + // get example share signature + +// XCTAssertEqual(Web3SwiftMpcProvider().text, "Hello, World!") } } From 77509610db669598c18d710563426e84ef8d933b Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 11:38:13 +0800 Subject: [PATCH 06/33] feat: add ci with swiftlint --- workflows/ci.yaml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 workflows/ci.yaml diff --git a/workflows/ci.yaml b/workflows/ci.yaml new file mode 100644 index 0000000..f030017 --- /dev/null +++ b/workflows/ci.yaml @@ -0,0 +1,31 @@ +on: + push: + branches: + - master + - v2 + pull_request: + types: + - opened + - reopened + - synchronize + +jobs: + test: + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Lint code using SwiftLint + run: swiftlint lint ./Sources --reporter github-actions-logging + + - name: Build + run: swift build -v + + - name: xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: "14.2.0" + + - name: run tests + run: xcodebuild test -scheme tkey_pkg -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO \ No newline at end of file From 2c3acc399dc4d231be3daaccf4d4e97406bd4499 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 12:04:44 +0800 Subject: [PATCH 07/33] fix: swiftlint --- Package.swift | 5 ++++- .../EthereumTssAccount.swift | 17 ++++++++++++----- Sources/Web3SwiftMpcProvider/Helper.swift | 14 +++++++++----- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Package.swift b/Package.swift index 01178fe..5a7afdf 100644 --- a/Package.swift +++ b/Package.swift @@ -16,6 +16,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), + .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -23,7 +24,9 @@ let package = Package( .target( name: "Web3SwiftMpcProvider", dependencies: ["web3.swift", "tss-client-swift"], - path: "Sources/Web3SwiftMpcProvider"), + path: "Sources/Web3SwiftMpcProvider", + plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] + ), .testTarget( name: "Web3SwiftMpcProviderTests", diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 0ab84e0..1d22fcd 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -45,7 +45,9 @@ public class EthereumTssAccount: EthereumAccountProtocol { public let tssEndpoints: [String] public let address: EthereumAddress - required public init(evmAddress: String, pubkey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) throws { + required public init(evmAddress: String, pubkey: String, factorKey: String, tssNonce: Int32, tssShare: String, + tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], + tssEndpoints: [String], authSigs: [String]) throws { self.factorKey = factorKey self.selectedTag = selectedTag self.verifier = verifier @@ -88,7 +90,10 @@ public class EthereumTssAccount: EthereumAccountProtocol { /// Signing Data without hashing public func sign(message: Data) throws -> Data { // Create tss Client using helper - let (client, coeffs) = try bootstrapTssClient(selected_tag: self.selectedTag, tssNonce: self.tssNonce, publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) + let (client, coeffs) = try bootstrapTssClient(selectedTag: self.selectedTag, tssNonce: self.tssNonce, + publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, + nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, + verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) // Wait for sockets to be connected let connected = try client.checkConnected() @@ -102,11 +107,13 @@ public class EthereumTssAccount: EthereumAccountProtocol { if !(ready) { throw EthereumSignerError.unknownError } - + let signingMessage = message.base64EncodedString() - let (s, r, v) = try! client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.authSigs) - try! client.cleanup(signatures: self.authSigs) + // swiftlint:disable:next identifier_name + let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.authSigs) + + try client.cleanup(signatures: self.authSigs) guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } return signature diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift index c1c8722..d934077 100644 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -5,9 +5,11 @@ import tss_client_swift import web3 import secp256k1 - -public func bootstrapTssClient (selected_tag: String, tssNonce: Int32, publicKey: String, tssShare: String, tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { - if ( publicKey.count < 128 || publicKey.count > 130 ) { +// swiftlint:disable:next function_parameter_count +public func bootstrapTssClient (selectedTag: String, tssNonce: Int32, publicKey: String, tssShare: String, + tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, + tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { + if publicKey.count < 128 || publicKey.count > 130 { throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") } @@ -16,7 +18,7 @@ public func bootstrapTssClient (selected_tag: String, tssNonce: Int32, publicKey let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) let sessionNonce = TSSHelpers.hashMessage(message: String(random)) // create the full session string - let session = TSSHelpers.assembleFullSession(verifier: verifier, verifierId: verifierId, tssTag: selected_tag, tssNonce: String(tssNonce), sessionNonce: sessionNonce) + let session = TSSHelpers.assembleFullSession(verifier: verifier, verifierId: verifierId, tssTag: selectedTag, tssNonce: String(tssNonce), sessionNonce: sessionNonce) let userTssIndex = BigInt(tssIndex, radix: 16)! // total parties, including the client @@ -32,7 +34,9 @@ public func bootstrapTssClient (selected_tag: String, tssNonce: Int32, publicKey let shareUnsigned = BigUInt(tssShare, radix: 16)! let share = BigInt(sign: .plus, magnitude: shareUnsigned) - let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) + let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), + endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), + share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) return (client, coeffs) } From 6564fda855ff5f4cc6b0a6c45e859efcfbc0469e Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 12:09:39 +0800 Subject: [PATCH 08/33] fix: ci fix comment, update resolved package --- {workflows => .github/workflows}/ci.yaml | 0 Package.resolved | 72 +++++++++++++++++++ .../EthereumTssAccount.swift | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) rename {workflows => .github/workflows}/ci.yaml (100%) diff --git a/workflows/ci.yaml b/.github/workflows/ci.yaml similarity index 100% rename from workflows/ci.yaml rename to .github/workflows/ci.yaml diff --git a/Package.resolved b/Package.resolved index 9a23ba0..290e6cb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -10,6 +10,15 @@ "version": "5.3.0" } }, + { + "package": "CollectionConcurrencyKit", + "repositoryURL": "https://github.com/JohnSundell/CollectionConcurrencyKit.git", + "state": { + "branch": null, + "revision": "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version": "0.2.0" + } + }, { "package": "CryptoSwift", "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", @@ -46,6 +55,15 @@ "version": "16.0.1" } }, + { + "package": "SourceKitten", + "repositoryURL": "https://github.com/jpsim/SourceKitten.git", + "state": { + "branch": null, + "revision": "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", + "version": "0.34.1" + } + }, { "package": "Starscream", "repositoryURL": "https://github.com/daltoniam/Starscream", @@ -55,6 +73,15 @@ "version": "4.0.4" } }, + { + "package": "swift-argument-parser", + "repositoryURL": "https://github.com/apple/swift-argument-parser.git", + "state": { + "branch": null, + "revision": "8f4d2753f0e4778c76d5f05ad16c74f707390531", + "version": "1.2.3" + } + }, { "package": "swift-atomics", "repositoryURL": "https://github.com/apple/swift-atomics.git", @@ -118,6 +145,42 @@ "version": "1.19.0" } }, + { + "package": "swift-syntax", + "repositoryURL": "https://github.com/apple/swift-syntax.git", + "state": { + "branch": null, + "revision": "59ed009d2c4a5a6b78f75a25679b6417ac040dcf", + "version": "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-07-04-a" + } + }, + { + "package": "SwiftLint", + "repositoryURL": "https://github.com/realm/SwiftLint", + "state": { + "branch": null, + "revision": "9eaecbedce469a51bd8487effbd4ab46ec8384ae", + "version": "0.52.4" + } + }, + { + "package": "SwiftyTextTable", + "repositoryURL": "https://github.com/scottrhoyt/SwiftyTextTable.git", + "state": { + "branch": null, + "revision": "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", + "version": "0.9.0" + } + }, + { + "package": "SWXMLHash", + "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", + "state": { + "branch": null, + "revision": "a853604c9e9a83ad9954c7e3d2a565273982471f", + "version": "7.0.2" + } + }, { "package": "tss-client-swift", "repositoryURL": "https://github.com/torusresearch/tss-client-swift.git", @@ -144,6 +207,15 @@ "revision": "53fe0639a98903858d0196b699720decb42aee7b", "version": "2.14.0" } + }, + { + "package": "Yams", + "repositoryURL": "https://github.com/jpsim/Yams.git", + "state": { + "branch": null, + "revision": "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", + "version": "5.0.6" + } } ] }, diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 1d22fcd..2050c58 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -119,7 +119,7 @@ public class EthereumTssAccount: EthereumAccountProtocol { return signature } - /// Signing utf8 encoded message String without hashing + /// Signing utf8 encoded message String public func sign(message: String) throws -> Data { if let data = message.data(using: .utf8) { return try self.sign(data: data) From fbc8b45607fd519133576fa5cdd84752be2c98dd Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 13:06:49 +0800 Subject: [PATCH 09/33] fix: denormalize share --- Sources/Web3SwiftMpcProvider/Helper.swift | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift index d934077..df280dc 100644 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -12,7 +12,7 @@ public func bootstrapTssClient (selectedTag: String, tssNonce: Int32, publicKey: if publicKey.count < 128 || publicKey.count > 130 { throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") } - + // generate a random nonce for sessionID let randomKey = BigUInt(SECP256K1.generatePrivateKey()!) let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) @@ -33,22 +33,11 @@ public func bootstrapTssClient (selectedTag: String, tssNonce: Int32, publicKey: let shareUnsigned = BigUInt(tssShare, radix: 16)! let share = BigInt(sign: .plus, magnitude: shareUnsigned) + let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), - share: TSSHelpers.base64Share(share: share), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) + share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) return (client, coeffs) } - - - -public func hashMessage(message: Data) -> String { - let hash = message.sha3(.keccak256) - return hash.base64EncodedString() -} - -public func hashMessage(message: String) -> String { - return hashMessage(message: Data(message.utf8)) -} - From 3bc8c9735a99129ab4c1ea9f03f3180323c19cd8 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 13:07:24 +0800 Subject: [PATCH 10/33] lint: swiftLinting --- .DS_Store | Bin 6148 -> 6148 bytes Sources/.DS_Store | Bin 6148 -> 6148 bytes Sources/Web3SwiftMpcProvider/Error.swift | 7 +++---- .../EthereumTssAccount.swift | 5 ++--- .../Web3SwiftMpcProvider.swift | 4 +--- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.DS_Store b/.DS_Store index e3ebfbe7f82d6047d95fc747c3d017015a251af3..4f1e21027b244a8fda57001abb508afe88037dca 100644 GIT binary patch delta 105 zcmZoMXfc=|#>B)qu~2NHo-uPVL;1$S<&2CRlYLlhH}7Y0W8_RJPR>cn&(C3;{F&8T zgq0zLA(f$+p@g9rF0omVLx5#7I|n}p&>$e^JM(0I5l0RNAYf!*VA&iYvW6J|8~_^9 delta 179 zcmZoMXfc=|#>B!ku~2NHo-uO~L+WNmmgUTj91IK$0t^8Ri44gM*+4R#A(cUo0VvH- z%#hEJ!%zlfrFiD#Cnx3PCxO*6FsujCdjG+IfnhQaldU>8LlA>2gCm0rgD;R)U@!uj zk&CX6DSfjQQz+x)Rm_%~*;r08Zf57;=Kwkh=#cNslles)IT#rjn1E(8Y>p6F!wdkI CAt+}6 diff --git a/Sources/.DS_Store b/Sources/.DS_Store index 8da41ee7011714ccbf5779d33dd9cfbff325d220..ca8ef6227f403274561108f2ac8b9b4672cbe6e8 100644 GIT binary patch delta 295 zcmZoMXfc=|#>B)qu~2NHo+2aj!~pA!7aACWj2@l(r1Ii|q@4UD1_p*5Nd-BX#U%y? z*BF_YSyuu5=%;pof3{WY=Zw0cijk(g2~s=4}oU*}y!pfdv4yT~18^ delta 79 zcmZoMXfc=|#>CJzu~2NHo+2aT!~pBb2F$t~DaFY-N%{FXn+utzv21Q&-pI6>or9kP gs1hjhoq009h%P510|UbWAZD0s!y~;pMq~*y0Gx6alK=n! diff --git a/Sources/Web3SwiftMpcProvider/Error.swift b/Sources/Web3SwiftMpcProvider/Error.swift index 75e9bc2..1f3d2f4 100644 --- a/Sources/Web3SwiftMpcProvider/Error.swift +++ b/Sources/Web3SwiftMpcProvider/Error.swift @@ -7,17 +7,16 @@ import Foundation - public enum CustomSigningError: Error { case generalError(error: String = "") case unknownError(error: String = "") public var errorDescription: String { switch self { - case .generalError ( let err): + case .generalError( let err): return err - - case .unknownError ( let err): + + case .unknownError( let err): return err } } diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 2050c58..2a5f084 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -174,13 +174,13 @@ public class EthereumTssAccount: EthereumAccountProtocol { signed.append(last) return signed.web3.hexString } - + /// Signing EthereumTransaction public func signtx(transaction: EthereumTransaction) throws -> SignedTransaction { guard let raw = transaction.raw else { throw EthereumSignerError.emptyRawTransaction } - + // hash and sign data var signed = try self.sign(data: raw) // Check last char (v) @@ -196,4 +196,3 @@ public class EthereumTssAccount: EthereumAccountProtocol { return SignedTransaction(transaction: transaction, signature: signed) } } - diff --git a/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift b/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift index a3cdba7..6b88bb5 100644 --- a/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift +++ b/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift @@ -4,13 +4,11 @@ import secp256k1 import CryptoKit import BigInt - public struct Web3SwiftMpcProvider { public private(set) var text = "Hello, World!" public init() { - + } - } From d902660d8ede02aab62872b2fff7a982ce37d69c Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 24 Aug 2023 13:57:17 +0800 Subject: [PATCH 11/33] fix: ci --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f030017..b56897a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,8 +19,8 @@ jobs: - name: Lint code using SwiftLint run: swiftlint lint ./Sources --reporter github-actions-logging - - name: Build - run: swift build -v + # - name: Build + # run: swift build -v - name: xcode uses: maxim-lobanov/setup-xcode@v1 @@ -28,4 +28,4 @@ jobs: xcode-version: "14.2.0" - name: run tests - run: xcodebuild test -scheme tkey_pkg -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO \ No newline at end of file + run: xcodebuild test -scheme Web3SwiftMpcProvider -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO \ No newline at end of file From 0b1cdd55c447a4ebe07b25eda854be7c170fdcd4 Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Fri, 25 Aug 2023 13:16:10 +0900 Subject: [PATCH 12/33] make EthTssAccountParams interface --- .../EthTssAccountParams.swift | 33 ++++++++++++++ .../EthereumTssAccount.swift | 45 +++++-------------- Sources/Web3SwiftMpcProvider/Helper.swift | 18 ++++---- 3 files changed, 51 insertions(+), 45 deletions(-) create mode 100644 Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift new file mode 100644 index 0000000..e80e9b8 --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -0,0 +1,33 @@ +public class EthTssAccountParams { + public let evmAddress: String + public let publicKey: String + public let factorKey: String + public let tssNonce: Int32 + public let tssShare: String + public let tssIndex: String + public let selectedTag: String + public let verifier: String + + ///verifierID for + public let verifierID: String + public let nodeIndexes: [Int] + public let tssEndpoints: [String] + public let authSigs: [String] + + // Initializer + public init(evmAddress: String, publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { + self.evmAddress = evmAddress + self.publicKey = publicKey + self.factorKey = factorKey + self.tssNonce = tssNonce + self.tssShare = tssShare + self.tssIndex = tssIndex + self.selectedTag = selectedTag + self.verifier = verifier + self.verifierID = verifierID + self.nodeIndexes = nodeIndexes + self.tssEndpoints = tssEndpoints + self.authSigs = authSigs + } +} + diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 2a5f084..200e57b 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -32,34 +32,12 @@ enum EthereumSignerError: Error { } public class EthereumTssAccount: EthereumAccountProtocol { - public let selectedTag: String - public let verifier: String - public let factorKey: String - public let verifierID: String - public let publicKey: String - public let authSigs: [String] - public let tssNonce: Int32 - public let tssShare: String - public let tssIndex: String - public let nodeIndexes: [Int] - public let tssEndpoints: [String] - public let address: EthereumAddress - - required public init(evmAddress: String, pubkey: String, factorKey: String, tssNonce: Int32, tssShare: String, - tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], - tssEndpoints: [String], authSigs: [String]) throws { - self.factorKey = factorKey - self.selectedTag = selectedTag - self.verifier = verifier - self.verifierID = verifierID - self.publicKey = pubkey - self.nodeIndexes = nodeIndexes - self.tssEndpoints = tssEndpoints - self.tssNonce = tssNonce - self.tssIndex = tssIndex - self.tssShare = tssShare - self.address = EthereumAddress(evmAddress) - self.authSigs = authSigs + public var address: web3.EthereumAddress + public let ethAccountParams: EthTssAccountParams + + required public init(params: EthTssAccountParams) throws { + self.ethAccountParams = params + self.address = EthereumAddress(params.evmAddress) } /// hash and sign data @@ -90,10 +68,7 @@ public class EthereumTssAccount: EthereumAccountProtocol { /// Signing Data without hashing public func sign(message: Data) throws -> Data { // Create tss Client using helper - let (client, coeffs) = try bootstrapTssClient(selectedTag: self.selectedTag, tssNonce: self.tssNonce, - publicKey: self.publicKey, tssShare: self.tssShare, tssIndex: self.tssIndex, - nodeIndexes: self.nodeIndexes, factorKey: self.factorKey, verifier: self.verifier, - verifierId: self.verifierID, tssEndpoints: self.tssEndpoints) + let (client, coeffs) = try bootstrapTssClient(params: self.ethAccountParams) // Wait for sockets to be connected let connected = try client.checkConnected() @@ -101,7 +76,7 @@ public class EthereumTssAccount: EthereumAccountProtocol { throw EthereumSignerError.unknownError } - let precompute = try client.precompute(serverCoeffs: coeffs, signatures: self.authSigs) + let precompute = try client.precompute(serverCoeffs: coeffs, signatures: self.ethAccountParams.authSigs) let ready = try client.isReady() if !(ready) { @@ -111,9 +86,9 @@ public class EthereumTssAccount: EthereumAccountProtocol { let signingMessage = message.base64EncodedString() // swiftlint:disable:next identifier_name - let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.authSigs) + let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.ethAccountParams.authSigs) - try client.cleanup(signatures: self.authSigs) + try client.cleanup(signatures: self.ethAccountParams.authSigs) guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } return signature diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift index df280dc..de829ab 100644 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -6,10 +6,8 @@ import web3 import secp256k1 // swiftlint:disable:next function_parameter_count -public func bootstrapTssClient (selectedTag: String, tssNonce: Int32, publicKey: String, tssShare: String, - tssIndex: String, nodeIndexes: [Int], factorKey: String, verifier: String, verifierId: String, - tssEndpoints: [String] ) throws -> (TSSClient, [String: String]) { - if publicKey.count < 128 || publicKey.count > 130 { +public func bootstrapTssClient (params: EthTssAccountParams) throws -> (TSSClient, [String: String]) { + if params.publicKey.count < 128 || params.publicKey.count > 130 { throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") } @@ -18,26 +16,26 @@ public func bootstrapTssClient (selectedTag: String, tssNonce: Int32, publicKey: let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) let sessionNonce = TSSHelpers.hashMessage(message: String(random)) // create the full session string - let session = TSSHelpers.assembleFullSession(verifier: verifier, verifierId: verifierId, tssTag: selectedTag, tssNonce: String(tssNonce), sessionNonce: sessionNonce) + let session = TSSHelpers.assembleFullSession(verifier: params.verifier, verifierId: params.verifierID, tssTag: params.selectedTag, tssNonce: String(params.tssNonce), sessionNonce: sessionNonce) - let userTssIndex = BigInt(tssIndex, radix: 16)! + let userTssIndex = BigInt(params.tssIndex, radix: 16)! // total parties, including the client - let parties = nodeIndexes.count > 0 ? nodeIndexes.count + 1 : 4 + let parties = params.nodeIndexes.count > 0 ? params.nodeIndexes.count + 1 : 4 // index of the client, last index of partiesIndexes let clientIndex = Int32(parties - 1) - let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: nodeIndexes, urls: tssEndpoints) + let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: params.nodeIndexes, urls: params.tssEndpoints) let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) - let shareUnsigned = BigUInt(tssShare, radix: 16)! + let shareUnsigned = BigUInt(params.tssShare, radix: 16)! let share = BigInt(sign: .plus, magnitude: shareUnsigned) let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), - share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: publicKey))) + share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: params.publicKey))) return (client, coeffs) } From f3474075201805ff75cfa67746e37dd09812d3ad Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Fri, 25 Aug 2023 13:28:37 +0900 Subject: [PATCH 13/33] remove ethAddress from struct --- Package.resolved | 36 +++++++++++++++++++ Package.swift | 7 ++-- .../EthTssAccountParams.swift | 8 +---- .../EthereumTssAccount.swift | 4 ++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Package.resolved b/Package.resolved index 290e6cb..8655714 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,6 +1,15 @@ { "object": { "pins": [ + { + "package": "AnyCodable", + "repositoryURL": "https://github.com/Flight-School/AnyCodable", + "state": { + "branch": null, + "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", + "version": "0.6.7" + } + }, { "package": "BigInt", "repositoryURL": "https://github.com/attaswift/BigInt.git", @@ -28,6 +37,15 @@ "version": "1.7.2" } }, + { + "package": "FetchNodeDetails", + "repositoryURL": "https://github.com/torusresearch/fetch-node-details-swift.git", + "state": { + "branch": "alpha", + "revision": "46603072d1796e9adc5afe2af33aaceb2294db67", + "version": null + } + }, { "package": "GenericJSON", "repositoryURL": "https://github.com/iwill/generic-json-swift", @@ -181,6 +199,24 @@ "version": "7.0.2" } }, + { + "package": "tkey_pkg", + "repositoryURL": "https://github.com/tkey/tkey-mpc-swift.git", + "state": { + "branch": "alpha", + "revision": "cf6fae63427cab2f8637fce371992eaa3353258c", + "version": null + } + }, + { + "package": "TorusUtils", + "repositoryURL": "https://github.com/torusresearch/torus-utils-swift", + "state": { + "branch": "alpha", + "revision": "cc2b7a28beb633c2c534ec0a5ed45a165be221b6", + "version": null + } + }, { "package": "tss-client-swift", "repositoryURL": "https://github.com/torusresearch/tss-client-swift.git", diff --git a/Package.swift b/Package.swift index 5a7afdf..88559d0 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "Web3SwiftMpcProvider", - platforms: [.iOS(.v13), .macOS(.v11)], + platforms: [.iOS(.v14), .macOS(.v11)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( @@ -16,14 +16,15 @@ let package = Package( dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), - .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4") + .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4"), + .package(url: "https://github.com/tkey/tkey-mpc-swift.git", branch: "alpha"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Web3SwiftMpcProvider", - dependencies: ["web3.swift", "tss-client-swift"], + dependencies: ["web3.swift", "tss-client-swift",.product(name: "ThresholdKey", package: "tkey-mpc-swift")], path: "Sources/Web3SwiftMpcProvider", plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] ), diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index e80e9b8..6ddcfbc 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -1,5 +1,4 @@ public class EthTssAccountParams { - public let evmAddress: String public let publicKey: String public let factorKey: String public let tssNonce: Int32 @@ -7,16 +6,12 @@ public class EthTssAccountParams { public let tssIndex: String public let selectedTag: String public let verifier: String - - ///verifierID for public let verifierID: String public let nodeIndexes: [Int] public let tssEndpoints: [String] public let authSigs: [String] - // Initializer - public init(evmAddress: String, publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { - self.evmAddress = evmAddress + public init(publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { self.publicKey = publicKey self.factorKey = factorKey self.tssNonce = tssNonce @@ -30,4 +25,3 @@ public class EthTssAccountParams { self.authSigs = authSigs } } - diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 200e57b..92bb9e8 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -11,6 +11,7 @@ import secp256k1 import tss_client_swift import CryptoKit import BigInt +import tkey_pkg public enum CustomError: Error { case unknownError @@ -37,7 +38,8 @@ public class EthereumTssAccount: EthereumAccountProtocol { required public init(params: EthTssAccountParams) throws { self.ethAccountParams = params - self.address = EthereumAddress(params.evmAddress) + + self.address = EthereumAddress(try KeyPoint(address: self.ethAccountParams.publicKey).getPublicKey(format: .FullAddress)) } /// hash and sign data From 3d056c0de2c3c422477110688e7c0551a7778943 Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Fri, 25 Aug 2023 20:03:29 +0900 Subject: [PATCH 14/33] change logic getting evmaddress --- Package.resolved | 36 ------------------- Package.swift | 3 +- .../EthTssAccountParams.swift | 3 ++ .../EthereumTssAccount.swift | 7 ++-- 4 files changed, 7 insertions(+), 42 deletions(-) diff --git a/Package.resolved b/Package.resolved index 8655714..290e6cb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,15 +1,6 @@ { "object": { "pins": [ - { - "package": "AnyCodable", - "repositoryURL": "https://github.com/Flight-School/AnyCodable", - "state": { - "branch": null, - "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version": "0.6.7" - } - }, { "package": "BigInt", "repositoryURL": "https://github.com/attaswift/BigInt.git", @@ -37,15 +28,6 @@ "version": "1.7.2" } }, - { - "package": "FetchNodeDetails", - "repositoryURL": "https://github.com/torusresearch/fetch-node-details-swift.git", - "state": { - "branch": "alpha", - "revision": "46603072d1796e9adc5afe2af33aaceb2294db67", - "version": null - } - }, { "package": "GenericJSON", "repositoryURL": "https://github.com/iwill/generic-json-swift", @@ -199,24 +181,6 @@ "version": "7.0.2" } }, - { - "package": "tkey_pkg", - "repositoryURL": "https://github.com/tkey/tkey-mpc-swift.git", - "state": { - "branch": "alpha", - "revision": "cf6fae63427cab2f8637fce371992eaa3353258c", - "version": null - } - }, - { - "package": "TorusUtils", - "repositoryURL": "https://github.com/torusresearch/torus-utils-swift", - "state": { - "branch": "alpha", - "revision": "cc2b7a28beb633c2c534ec0a5ed45a165be221b6", - "version": null - } - }, { "package": "tss-client-swift", "repositoryURL": "https://github.com/torusresearch/tss-client-swift.git", diff --git a/Package.swift b/Package.swift index 88559d0..ef4d436 100644 --- a/Package.swift +++ b/Package.swift @@ -17,14 +17,13 @@ let package = Package( .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4"), - .package(url: "https://github.com/tkey/tkey-mpc-swift.git", branch: "alpha"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Web3SwiftMpcProvider", - dependencies: ["web3.swift", "tss-client-swift",.product(name: "ThresholdKey", package: "tkey-mpc-swift")], + dependencies: ["web3.swift", "tss-client-swift"], path: "Sources/Web3SwiftMpcProvider", plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] ), diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index 6ddcfbc..de80f25 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -1,6 +1,9 @@ public class EthTssAccountParams { + /// Ethereum publicKey public let publicKey: String + /// tss factorKey public let factorKey: String + /// public let tssNonce: Int32 public let tssShare: String public let tssIndex: String diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 92bb9e8..7f5b3fe 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -11,7 +11,6 @@ import secp256k1 import tss_client_swift import CryptoKit import BigInt -import tkey_pkg public enum CustomError: Error { case unknownError @@ -37,9 +36,9 @@ public class EthereumTssAccount: EthereumAccountProtocol { public let ethAccountParams: EthTssAccountParams required public init(params: EthTssAccountParams) throws { - self.ethAccountParams = params - - self.address = EthereumAddress(try KeyPoint(address: self.ethAccountParams.publicKey).getPublicKey(format: .FullAddress)) + self.ethAccountParams = params + let address = KeyUtil.generateAddress(from: Data(hex: self.ethAccountParams.publicKey).suffix(64)).toChecksumAddress() + self.address = EthereumAddress(address) } /// hash and sign data From 9eed0ad534809c04b36617df47fa8b4d8a7f83ad Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Fri, 25 Aug 2023 20:46:46 +0900 Subject: [PATCH 15/33] ci run --- Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index de80f25..3abb07c 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -1,9 +1,6 @@ public class EthTssAccountParams { - /// Ethereum publicKey public let publicKey: String - /// tss factorKey public let factorKey: String - /// public let tssNonce: Int32 public let tssShare: String public let tssIndex: String @@ -13,7 +10,7 @@ public class EthTssAccountParams { public let nodeIndexes: [Int] public let tssEndpoints: [String] public let authSigs: [String] - // Initializer + // swiftlint:disable:next line_length public init(publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { self.publicKey = publicKey self.factorKey = factorKey From ba4f5c05e9da701dcd57d798a44ae5f24f7a30a1 Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Mon, 28 Aug 2023 12:59:47 +0900 Subject: [PATCH 16/33] add extensions --- .../Extensions/Array+Extension.swift | 16 ++ .../NSRegularExpressionExtension.swift | 80 ++++++++++ .../Extensions/String+Extension.swift | 149 ++++++++++++++++++ .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 81 ++++++++++ .../MpcProviderTests.swift | 9 ++ 5 files changed, 335 insertions(+) create mode 100644 Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift create mode 100644 Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift create mode 100644 Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift create mode 100644 Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift diff --git a/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift new file mode 100644 index 0000000..b7323d9 --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift @@ -0,0 +1,16 @@ +// web3swift +// +// Created by Alex Vlasov. +// Copyright © 2018 Alex Vlasov. All rights reserved. +// + +import Foundation + +extension Array { + public func split(intoChunksOf chunkSize: Int) -> [[Element]] { + return stride(from: 0, to: count, by: chunkSize).map { + let endIndex = ($0.advanced(by: chunkSize) > self.count) ? self.count - $0 : chunkSize + return Array(self[$0 ..< $0.advanced(by: endIndex)]) + } + } +} diff --git a/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift b/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift new file mode 100644 index 0000000..ff50f23 --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift @@ -0,0 +1,80 @@ +// web3swift +// +// Created by Alex Vlasov. +// Copyright © 2018 Alex Vlasov. All rights reserved. +// + +import Foundation + +extension NSRegularExpression { + typealias GroupNamesSearchResult = (NSTextCheckingResult, NSTextCheckingResult, Int) + + private func textCheckingResultsOfNamedCaptureGroups() -> [String: GroupNamesSearchResult] { + var groupnames = [String: GroupNamesSearchResult]() + + guard let greg = try? NSRegularExpression(pattern: "^\\(\\?<([\\w\\a_-]*)>$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { + // This never happens but the alternative is to make this method throwing + return groupnames + } + guard let reg = try? NSRegularExpression(pattern: "\\(.*?>", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { + // This never happens but the alternative is to make this method throwing + return groupnames + } + let m = reg.matches(in: pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: pattern.utf16.count)) + for (n, g) in m.enumerated() { + let r = pattern.range(from: g.range(at: 0)) + let gstring = String(pattern[r!]) + let gmatch = greg.matches(in: gstring, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: gstring.utf16.count)) + if gmatch.count > 0 { + let r2 = gstring.range(from: gmatch[0].range(at: 1))! + groupnames[String(gstring[r2])] = (g, gmatch[0], n) + } + } + return groupnames + } + + func indexOfNamedCaptureGroups() throws -> [String: Int] { + var groupnames = [String: Int]() + for (name, (_, _, n)) in textCheckingResultsOfNamedCaptureGroups() { + groupnames[name] = n + 1 + } + return groupnames + } + + func rangesOfNamedCaptureGroups(match: NSTextCheckingResult) throws -> [String: Range] { + var ranges = [String: Range]() + for (name, (_, _, n)) in textCheckingResultsOfNamedCaptureGroups() { + ranges[name] = Range(match.range(at: n + 1)) + } + return ranges + } + + private func nameForIndex(_ index: Int, from: [String: GroupNamesSearchResult]) -> String? { + for (name, (_, _, n)) in from { + if (n + 1) == index { + return name + } + } + return nil + } + + func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = []) -> [String: String] { + return captureGroups(string: string, options: options, range: NSRange(location: 0, length: string.utf16.count)) + } + + func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [String: String] { + var dict = [String: String]() + let matchResult = matches(in: string, options: options, range: range) + let names = textCheckingResultsOfNamedCaptureGroups() + for (_, m) in matchResult.enumerated() { + for i in 0 ..< m.numberOfRanges { + guard let r2 = string.range(from: m.range(at: i)) else { continue } + let g = String(string[r2]) + if let name = nameForIndex(i, from: names) { + dict[name] = g + } + } + } + return dict + } +} diff --git a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift new file mode 100644 index 0000000..54005bf --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift @@ -0,0 +1,149 @@ +// web3swift +// +// Created by Alex Vlasov. +// Copyright © 2018 Alex Vlasov. All rights reserved. +// + +import Foundation + +extension String { + var fullRange: Range { + return startIndex ..< endIndex + } + + var fullNSRange: NSRange { + return NSRange(fullRange, in: self) + } + + func index(of char: Character) -> Index? { + guard let range = range(of: String(char)) else { + return nil + } + return range.lowerBound + } + + func split(intoChunksOf chunkSize: Int) -> [String] { + var output = [String]() + let splittedString = map { $0 } + .split(intoChunksOf: chunkSize) + splittedString.forEach { + output.append($0.map { String($0) }.joined(separator: "")) + } + return output + } + + subscript(bounds: CountableClosedRange) -> String { + let start = index(startIndex, offsetBy: bounds.lowerBound) + let end = index(startIndex, offsetBy: bounds.upperBound) + return String(self[start ... end]) + } + + subscript(bounds: CountableRange) -> String { + let start = index(startIndex, offsetBy: bounds.lowerBound) + let end = index(startIndex, offsetBy: bounds.upperBound) + return String(self[start ..< end]) + } + + subscript(bounds: CountablePartialRangeFrom) -> String { + let start = index(startIndex, offsetBy: bounds.lowerBound) + let end = endIndex + return String(self[start ..< end]) + } + + func leftPadding(toLength: Int, withPad character: Character) -> String { + let stringLength = count + if stringLength < toLength { + return String(repeatElement(character, count: toLength - stringLength)) + self + } else { + return String(suffix(toLength)) + } + } + + func interpretAsBinaryData() -> Data? { + let padded = padding(toLength: ((count + 7) / 8) * 8, withPad: "0", startingAt: 0) + let byteArray = padded.split(intoChunksOf: 8).map { UInt8(strtoul($0, nil, 2)) } + return Data(byteArray) + } + + func hasHexPrefix() -> Bool { + return hasPrefix("0x") + } + + func stripHexPrefix() -> String { + if hasPrefix("0x") { + let indexStart = index(startIndex, offsetBy: 2) + return String(self[indexStart...]) + } + return self + } + + func addHexPrefix() -> String { + if !hasPrefix("0x") { + return "0x" + self + } + return self + } + + func stripLeadingZeroes() -> String? { + let hex = addHexPrefix() + guard let matcher = try? NSRegularExpression(pattern: "^(?0x)0*(?[0-9a-fA-F]*)$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { return nil } + let match = matcher.captureGroups(string: hex, options: NSRegularExpression.MatchingOptions.anchored) + guard let prefix = match["prefix"] else { return nil } + guard let end = match["end"] else { return nil } + if end != "" { + return prefix + end + } + return "0x0" + } + + func matchingStrings(regex: String) -> [[String]] { + guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] } + let nsString = self as NSString + let results = regex.matches(in: self, options: [], range: NSRange(location: 0, length: nsString.length)) + return results.map { result in + (0 ..< result.numberOfRanges).map { result.range(at: $0).location != NSNotFound + ? nsString.substring(with: result.range(at: $0)) + : "" + } + } + } + + func range(from nsRange: NSRange) -> Range? { + guard + let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex), + let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex), + let from = from16.samePosition(in: self), + let to = to16.samePosition(in: self) + else { return nil } + return from ..< to + } + + var asciiValue: Int { + let s = unicodeScalars + return Int(s[s.startIndex].value) + } +} + +extension Character { + var asciiValue: Int { + let s = String(self).unicodeScalars + return Int(s[s.startIndex].value) + } +} + +extension String { + func toChecksumAddress() -> String { + let lowerCaseAddress = stripHexPrefix().lowercased() + let arr = Array(lowerCaseAddress) + let hash = Array(lowerCaseAddress.sha3(.keccak256)) + var result = "0x" + for i in 0 ... lowerCaseAddress.count - 1 { + if let val = Int(String(hash[i]), radix: 16), val >= 8 { + result.append(arr[i].uppercased()) + } else { + result.append(arr[i]) + } + } + return result + } +} diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift new file mode 100644 index 0000000..5700d40 --- /dev/null +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -0,0 +1,81 @@ +// +// TorusWeb3Utils.swift +// tkey_ios +// +// Created by himanshu on 09/08/23. +// + +import BigInt +import Foundation +import web3 +import CryptoKit + +public typealias Ether = Double +public typealias Wei = BigUInt + +public func keccak256Data(_ data: Data) -> String { + let hash = data.sha3(.keccak256) + return "0x" + hash.map { String(format: "%02x", $0) }.joined() +} + +public final class TorusWeb3Utils { + + public static func timeMinToSec(val: Double) -> Double { + return val * 60 + } + + // NOTE: calculate wei by 10^18 + private static let etherInWei = pow(Double(10), 18) + private static let etherInGwei = pow(Double(10), 9) + + /// Convert Wei(BInt) unit to Ether(Decimal) unit + public static func toEther(wei: Wei) -> Ether { + guard let decimalWei = Double(wei.description) else { + return 0 + } + return decimalWei / etherInWei + } + + public static func toEther(Gwie: BigUInt) -> Ether { + guard let decimalWei = Double(Gwie.description) else { + return 0 + } + return decimalWei / etherInGwei + } + + /// Convert Ether(Decimal) unit to Wei(BInt) unit + public static func toWei(ether: Ether) -> Wei { + let wei = Wei(ether * etherInWei) + return wei + } + + /// Convert Ether(String) unit to Wei(BInt) unit + public static func toWei(ether: String) -> Wei { + guard let decimalEther = Double(ether) else { + return 0 + } + return toWei(ether: decimalEther) + } + + // Only used for calcurating gas price and gas limit. + public static func toWei(GWei: Double) -> Wei { + return Wei(GWei * 1000000000) + } + + public static func generateAddressFromPubKey(publicKeyX: String, publicKeyY: String) -> String { + let publicKeyHex = "04" + publicKeyX.addLeading0sForLength64() + publicKeyY.addLeading0sForLength64() + let publicKeyData = Data(hexString: publicKeyHex)! + + do { + let publicKey = try P256.KeyAgreement.PublicKey(x963Representation: publicKeyData) + let publicKeyBytes = publicKey.rawRepresentation// .dropFirst().dropLast() // Remove the first byte (0x04) + let ethAddressLower = "0x" + keccak256Data(publicKeyBytes).suffix(40) + return ethAddressLower.toChecksumAddress() + } catch { + // Handle the error if necessary + print("Failed to derive public key: \(error)") + return "" + } + } + +} diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index b2ab9e7..700fc28 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -8,4 +8,13 @@ final class Web3SwiftMpcProviderTests: XCTestCase { // XCTAssertEqual(Web3SwiftMpcProvider().text, "Hello, World!") } + + func testSigningMessage() { + + + } + + func testSigningTx() { + + } } From dd97c789c9384a7184dab3b87ff7c9bb89ea5f3a Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Mon, 28 Aug 2023 13:13:30 +0900 Subject: [PATCH 17/33] fix lint --- .../NSRegularExpressionExtension.swift | 34 +++++++++---------- .../Extensions/String+Extension.swift | 16 ++++----- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 8 ++--- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift b/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift index ff50f23..671d421 100644 --- a/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift +++ b/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift @@ -20,14 +20,14 @@ extension NSRegularExpression { // This never happens but the alternative is to make this method throwing return groupnames } - let m = reg.matches(in: pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: pattern.utf16.count)) - for (n, g) in m.enumerated() { - let r = pattern.range(from: g.range(at: 0)) - let gstring = String(pattern[r!]) + let pat = reg.matches(in: pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: pattern.utf16.count)) + for (num, grg) in pat.enumerated() { + let range = pattern.range(from: grg.range(at: 0)) + let gstring = String(pattern[range!]) let gmatch = greg.matches(in: gstring, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: gstring.utf16.count)) if gmatch.count > 0 { let r2 = gstring.range(from: gmatch[0].range(at: 1))! - groupnames[String(gstring[r2])] = (g, gmatch[0], n) + groupnames[String(gstring[r2])] = (grg, gmatch[0], num) } } return groupnames @@ -35,23 +35,23 @@ extension NSRegularExpression { func indexOfNamedCaptureGroups() throws -> [String: Int] { var groupnames = [String: Int]() - for (name, (_, _, n)) in textCheckingResultsOfNamedCaptureGroups() { - groupnames[name] = n + 1 + for (name, (_, _, num)) in textCheckingResultsOfNamedCaptureGroups() { + groupnames[name] = num + 1 } return groupnames } func rangesOfNamedCaptureGroups(match: NSTextCheckingResult) throws -> [String: Range] { var ranges = [String: Range]() - for (name, (_, _, n)) in textCheckingResultsOfNamedCaptureGroups() { - ranges[name] = Range(match.range(at: n + 1)) + for (name, (_, _, num)) in textCheckingResultsOfNamedCaptureGroups() { + ranges[name] = Range(match.range(at: num + 1)) } return ranges } private func nameForIndex(_ index: Int, from: [String: GroupNamesSearchResult]) -> String? { - for (name, (_, _, n)) in from { - if (n + 1) == index { + for (name, (_, _, num)) in from { + if (num + 1) == index { return name } } @@ -66,12 +66,12 @@ extension NSRegularExpression { var dict = [String: String]() let matchResult = matches(in: string, options: options, range: range) let names = textCheckingResultsOfNamedCaptureGroups() - for (_, m) in matchResult.enumerated() { - for i in 0 ..< m.numberOfRanges { - guard let r2 = string.range(from: m.range(at: i)) else { continue } - let g = String(string[r2]) - if let name = nameForIndex(i, from: names) { - dict[name] = g + for (_, mmm) in matchResult.enumerated() { + for idx in 0 ..< mmm.numberOfRanges { + guard let r2 = string.range(from: mmm.range(at: idx)) else { continue } + let str = String(string[r2]) + if let name = nameForIndex(idx, from: names) { + dict[name] = str } } } diff --git a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift index 54005bf..7afa35c 100644 --- a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift +++ b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift @@ -119,15 +119,15 @@ extension String { } var asciiValue: Int { - let s = unicodeScalars - return Int(s[s.startIndex].value) + let str = unicodeScalars + return Int(str[str.startIndex].value) } } extension Character { var asciiValue: Int { - let s = String(self).unicodeScalars - return Int(s[s.startIndex].value) + let str = String(self).unicodeScalars + return Int(str[str.startIndex].value) } } @@ -137,11 +137,11 @@ extension String { let arr = Array(lowerCaseAddress) let hash = Array(lowerCaseAddress.sha3(.keccak256)) var result = "0x" - for i in 0 ... lowerCaseAddress.count - 1 { - if let val = Int(String(hash[i]), radix: 16), val >= 8 { - result.append(arr[i].uppercased()) + for idx in 0 ... lowerCaseAddress.count - 1 { + if let val = Int(String(hash[idx]), radix: 16), val >= 8 { + result.append(arr[idx].uppercased()) } else { - result.append(arr[i]) + result.append(arr[idx]) } } return result diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index 5700d40..be395b2 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -36,8 +36,8 @@ public final class TorusWeb3Utils { return decimalWei / etherInWei } - public static func toEther(Gwie: BigUInt) -> Ether { - guard let decimalWei = Double(Gwie.description) else { + public static func toEther(gwei: BigUInt) -> Ether { + guard let decimalWei = Double(gwei.description) else { return 0 } return decimalWei / etherInGwei @@ -58,8 +58,8 @@ public final class TorusWeb3Utils { } // Only used for calcurating gas price and gas limit. - public static func toWei(GWei: Double) -> Wei { - return Wei(GWei * 1000000000) + public static func toWei(gwei: Double) -> Wei { + return Wei(gwei * 1000000000) } public static func generateAddressFromPubKey(publicKeyX: String, publicKeyY: String) -> String { From 78a51fbe8d1146acb2f1ab6ec2b6ddb3310d68cb Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Mon, 28 Aug 2023 15:17:04 +0900 Subject: [PATCH 18/33] add testcode for sign message and tx signing --- .../MpcProviderTests.swift | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 700fc28..3ed1c94 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -1,6 +1,8 @@ import XCTest @testable import Web3SwiftMpcProvider import secp256k1 +import BigInt +import web3 final class Web3SwiftMpcProviderTests: XCTestCase { func testExample() throws { @@ -10,11 +12,70 @@ final class Web3SwiftMpcProviderTests: XCTestCase { } func testSigningMessage() { + let fullAddress = "04e9c133d21e56435a3f410dbdfc2330704ecd98718fdb06f607415aa18b3d981e32f022656a771f9488bb4ae94e50a1f269b1d8d1df7052bd44d43d892c941f1f" + let factorKey = "b8a2281666923af982a72c6ee2f050242a8aa81a6ed33f81c24f1d98377b9406" + let tssNonce = 0 + let tssShare = "2852d4132ff0b296aed2cb1d5cc732a737b26fee99ae60bfc35f639d25a5cf59" + let tssIndex = "2" + let selected_tag = "" + let verifier = "google-lrc" + let verifierId = "hqjang95@gmail.com" + let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] + let sigs = ["{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"188ecc2fc2dd477566bbe3c0c7b85560f8f64cc317713dd1b3a0f7a2f3d5f8136e8fbb68a30076f4c0f7f186f7091567cbd9487907c311598316c5686cb79a611c\"}", "{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"e3d3920cc952418c064333be2f614542abdcac529764c82329569bd5ce894c9368d201cb43e2f49ebbc34507c858ba631ba64261ae3c05de8e6ab1c73de14b3a1b\"}", "{\"sig\":\"4b0ce34422c1b737dd1a26bfc4679ede79c8851c284cac26e35e65ab9206b46276e3cdd8b219591a8740253368cf102b12bb285edbb23dacb68007bc0273eff31c\",\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + + let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) + + do { + let account = try EthereumTssAccount(params: params) + + let msg = "hello world" + let signature = try account.sign(message: msg) + let str = String(bytes: signature) + + } catch let err{ + XCTFail(err.localizedDescription) + } } - func testSigningTx() { + func testSigningTx() async { + do { + let fullAddress = "04e9c133d21e56435a3f410dbdfc2330704ecd98718fdb06f607415aa18b3d981e32f022656a771f9488bb4ae94e50a1f269b1d8d1df7052bd44d43d892c941f1f" + let factorKey = "b8a2281666923af982a72c6ee2f050242a8aa81a6ed33f81c24f1d98377b9406" + let tssNonce = 0 + let tssShare = "2852d4132ff0b296aed2cb1d5cc732a737b26fee99ae60bfc35f639d25a5cf59" + let tssIndex = "2" + let selected_tag = "" + let verifier = "google-lrc" + let verifierId = "hqjang95@gmail.com" + let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] + let sigs = ["{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"188ecc2fc2dd477566bbe3c0c7b85560f8f64cc317713dd1b3a0f7a2f3d5f8136e8fbb68a30076f4c0f7f186f7091567cbd9487907c311598316c5686cb79a611c\"}", "{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"e3d3920cc952418c064333be2f614542abdcac529764c82329569bd5ce894c9368d201cb43e2f49ebbc34507c858ba631ba64261ae3c05de8e6ab1c73de14b3a1b\"}", "{\"sig\":\"4b0ce34422c1b737dd1a26bfc4679ede79c8851c284cac26e35e65ab9206b46276e3cdd8b219591a8740253368cf102b12bb285edbb23dacb68007bc0273eff31c\",\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + + let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) + + let tssAccount = try EthereumTssAccount(params: params) + + // let RPC_URL = "https://api.avax-test.network/ext/bc/C/rpc" + // let chainID = 43113 + let RPC_URL = "https://rpc.ankr.com/eth_goerli" + let chainID = 5 + let web3Client = EthereumHttpClient(url: URL(string: RPC_URL)!) + + let amount = 0.001 + let toAddress = tssAccount.address + let fromAddress = tssAccount.address + let gasPrice = try await web3Client.eth_gasPrice() + let maxTipInGwie = BigUInt(TorusWeb3Utils.toEther(gwei: BigUInt(amount))) + let totalGas = gasPrice + maxTipInGwie + let gasLimit = BigUInt(21000) + + let amtInGwie = TorusWeb3Utils.toWei(ether: amount) + let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) + let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) + } catch let err { + XCTFail(err.localizedDescription) + } } } From 879a66d99fc6c2427c242a98953563ead6decda7 Mon Sep 17 00:00:00 2001 From: hqjang-pepper Date: Wed, 30 Aug 2023 17:01:34 +0900 Subject: [PATCH 19/33] add verification logic at signing --- .../EthereumTssAccount.swift | 7 ++++- .../MpcProviderTests.swift | 31 ++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 7f5b3fe..a4975ed 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -92,7 +92,12 @@ public class EthereumTssAccount: EthereumAccountProtocol { try client.cleanup(signatures: self.ethAccountParams.authSigs) guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } - return signature + + let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: self.ethAccountParams.publicKey)) + if verified { + return signature + } + throw EthereumSignerError.unknownError } /// Signing utf8 encoded message String diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 3ed1c94..72ff2fa 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -12,16 +12,16 @@ final class Web3SwiftMpcProviderTests: XCTestCase { } func testSigningMessage() { - let fullAddress = "04e9c133d21e56435a3f410dbdfc2330704ecd98718fdb06f607415aa18b3d981e32f022656a771f9488bb4ae94e50a1f269b1d8d1df7052bd44d43d892c941f1f" - let factorKey = "b8a2281666923af982a72c6ee2f050242a8aa81a6ed33f81c24f1d98377b9406" + let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" + let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" let tssNonce = 0 - let tssShare = "2852d4132ff0b296aed2cb1d5cc732a737b26fee99ae60bfc35f639d25a5cf59" + let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" let tssIndex = "2" - let selected_tag = "" + let selected_tag = "default" let verifier = "google-lrc" let verifierId = "hqjang95@gmail.com" let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] - let sigs = ["{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"188ecc2fc2dd477566bbe3c0c7b85560f8f64cc317713dd1b3a0f7a2f3d5f8136e8fbb68a30076f4c0f7f186f7091567cbd9487907c311598316c5686cb79a611c\"}", "{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"e3d3920cc952418c064333be2f614542abdcac529764c82329569bd5ce894c9368d201cb43e2f49ebbc34507c858ba631ba64261ae3c05de8e6ab1c73de14b3a1b\"}", "{\"sig\":\"4b0ce34422c1b737dd1a26bfc4679ede79c8851c284cac26e35e65ab9206b46276e3cdd8b219591a8740253368cf102b12bb285edbb23dacb68007bc0273eff31c\",\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) @@ -29,8 +29,14 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let account = try EthereumTssAccount(params: params) let msg = "hello world" + // verifying logic is already included in sign function, so if verify fails then it will throw error +// let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: self.ethAccountParams.publicKey)) +// if verified { +// return signature +// } +// throw EthereumSignerError.unknownError let signature = try account.sign(message: msg) - let str = String(bytes: signature) + let _ = String(bytes: signature) } catch let err{ XCTFail(err.localizedDescription) @@ -41,16 +47,16 @@ final class Web3SwiftMpcProviderTests: XCTestCase { func testSigningTx() async { do { - let fullAddress = "04e9c133d21e56435a3f410dbdfc2330704ecd98718fdb06f607415aa18b3d981e32f022656a771f9488bb4ae94e50a1f269b1d8d1df7052bd44d43d892c941f1f" - let factorKey = "b8a2281666923af982a72c6ee2f050242a8aa81a6ed33f81c24f1d98377b9406" + let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" + let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" let tssNonce = 0 - let tssShare = "2852d4132ff0b296aed2cb1d5cc732a737b26fee99ae60bfc35f639d25a5cf59" + let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" let tssIndex = "2" - let selected_tag = "" + let selected_tag = "default" let verifier = "google-lrc" let verifierId = "hqjang95@gmail.com" let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] - let sigs = ["{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"188ecc2fc2dd477566bbe3c0c7b85560f8f64cc317713dd1b3a0f7a2f3d5f8136e8fbb68a30076f4c0f7f186f7091567cbd9487907c311598316c5686cb79a611c\"}", "{\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\",\"sig\":\"e3d3920cc952418c064333be2f614542abdcac529764c82329569bd5ce894c9368d201cb43e2f49ebbc34507c858ba631ba64261ae3c05de8e6ab1c73de14b3a1b\"}", "{\"sig\":\"4b0ce34422c1b737dd1a26bfc4679ede79c8851c284cac26e35e65ab9206b46276e3cdd8b219591a8740253368cf102b12bb285edbb23dacb68007bc0273eff31c\",\"data\":\"eyJleHAiOjE2OTMyODgxMDUsInRlbXBfa2V5X3giOiJkMjgxYWFjNmUyOWIyZmU2NGQyYWFiNDJjMDBjOGJhZWRmNWVjODhjYjk2YjBiMGYzNWUzOGM1ZjFjYjA0Nzc5IiwidGVtcF9rZXlfeSI6ImE4Yzc3YmM2YzE3NzhkMjQ3YmRlMzZmYmM5MWZiNDQ4NGQ3MDQ3Mjc2ZDljYjg0ZDdlMjY5YjNjMzAwYjZiYzUiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) @@ -73,6 +79,9 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let amtInGwie = TorusWeb3Utils.toWei(ether: amount) let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) + + // also sign function includes verify logic, so if verification fails then test will fail + let signed = try tssAccount.sign(transaction: transaction) } catch let err { XCTFail(err.localizedDescription) } From ea463dc025579fe146b0de03edceb1d8d2eba6a5 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 4 Sep 2023 10:51:30 +0200 Subject: [PATCH 20/33] fix: CI --- .github/workflows/ci.yaml | 13 +--- .gitignore | 1 + Package.resolved | 76 +------------------ Package.swift | 13 ++-- .../MpcProviderTests.swift | 5 +- 5 files changed, 14 insertions(+), 94 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b56897a..07c1871 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,8 +1,7 @@ on: push: branches: - - master - - v2 + - main pull_request: types: - opened @@ -15,17 +14,11 @@ jobs: steps: - name: checkout uses: actions/checkout@v3 - - - name: Lint code using SwiftLint + - name: SwiftLint run: swiftlint lint ./Sources --reporter github-actions-logging - - # - name: Build - # run: swift build -v - - name: xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: "14.2.0" - - - name: run tests + - name: package run: xcodebuild test -scheme Web3SwiftMpcProvider -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO \ No newline at end of file diff --git a/.gitignore b/.gitignore index b5d2630..c1de6b6 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,4 @@ fastlane/test_output iOSInjectionProject/ .idea +.DS_Store diff --git a/Package.resolved b/Package.resolved index 290e6cb..c811411 100644 --- a/Package.resolved +++ b/Package.resolved @@ -10,15 +10,6 @@ "version": "5.3.0" } }, - { - "package": "CollectionConcurrencyKit", - "repositoryURL": "https://github.com/JohnSundell/CollectionConcurrencyKit.git", - "state": { - "branch": null, - "revision": "b4f23e24b5a1bff301efc5e70871083ca029ff95", - "version": "0.2.0" - } - }, { "package": "CryptoSwift", "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", @@ -55,15 +46,6 @@ "version": "16.0.1" } }, - { - "package": "SourceKitten", - "repositoryURL": "https://github.com/jpsim/SourceKitten.git", - "state": { - "branch": null, - "revision": "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version": "0.34.1" - } - }, { "package": "Starscream", "repositoryURL": "https://github.com/daltoniam/Starscream", @@ -73,15 +55,6 @@ "version": "4.0.4" } }, - { - "package": "swift-argument-parser", - "repositoryURL": "https://github.com/apple/swift-argument-parser.git", - "state": { - "branch": null, - "revision": "8f4d2753f0e4778c76d5f05ad16c74f707390531", - "version": "1.2.3" - } - }, { "package": "swift-atomics", "repositoryURL": "https://github.com/apple/swift-atomics.git", @@ -145,49 +118,13 @@ "version": "1.19.0" } }, - { - "package": "swift-syntax", - "repositoryURL": "https://github.com/apple/swift-syntax.git", - "state": { - "branch": null, - "revision": "59ed009d2c4a5a6b78f75a25679b6417ac040dcf", - "version": "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-07-04-a" - } - }, - { - "package": "SwiftLint", - "repositoryURL": "https://github.com/realm/SwiftLint", - "state": { - "branch": null, - "revision": "9eaecbedce469a51bd8487effbd4ab46ec8384ae", - "version": "0.52.4" - } - }, - { - "package": "SwiftyTextTable", - "repositoryURL": "https://github.com/scottrhoyt/SwiftyTextTable.git", - "state": { - "branch": null, - "revision": "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", - "version": "0.9.0" - } - }, - { - "package": "SWXMLHash", - "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", - "state": { - "branch": null, - "revision": "a853604c9e9a83ad9954c7e3d2a565273982471f", - "version": "7.0.2" - } - }, { "package": "tss-client-swift", "repositoryURL": "https://github.com/torusresearch/tss-client-swift.git", "state": { "branch": null, - "revision": "ab123d96c36d07aa73bf6118ca9602ab2d2846d0", - "version": "1.0.10" + "revision": "a5f54880550d7c0f2979e06290a1ac0941626b3f", + "version": "1.0.12" } }, { @@ -207,15 +144,6 @@ "revision": "53fe0639a98903858d0196b699720decb42aee7b", "version": "2.14.0" } - }, - { - "package": "Yams", - "repositoryURL": "https://github.com/jpsim/Yams.git", - "state": { - "branch": null, - "revision": "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", - "version": "5.0.6" - } } ] }, diff --git a/Package.swift b/Package.swift index ef4d436..781712f 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "Web3SwiftMpcProvider", - platforms: [.iOS(.v14), .macOS(.v11)], + platforms: [.iOS(.v14)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( @@ -15,8 +15,8 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), - .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.10"), - .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4"), + .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.12"), + // .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -24,13 +24,12 @@ let package = Package( .target( name: "Web3SwiftMpcProvider", dependencies: ["web3.swift", "tss-client-swift"], - path: "Sources/Web3SwiftMpcProvider", - plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] + path: "Sources/Web3SwiftMpcProvider" + // plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] ), - .testTarget( name: "Web3SwiftMpcProviderTests", - dependencies: ["Web3SwiftMpcProvider" ], + dependencies: ["Web3SwiftMpcProvider"], path: "Tests"), ], swiftLanguageVersions: [.v5] diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 72ff2fa..6e041f9 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -1,7 +1,6 @@ import XCTest -@testable import Web3SwiftMpcProvider -import secp256k1 import BigInt +import Web3SwiftMpcProvider import web3 final class Web3SwiftMpcProviderTests: XCTestCase { @@ -81,7 +80,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) // also sign function includes verify logic, so if verification fails then test will fail - let signed = try tssAccount.sign(transaction: transaction) + let _ = try tssAccount.sign(transaction: transaction) } catch let err { XCTFail(err.localizedDescription) } From 6c561c23a28a59d3f271f3c08fa1812164c75ecc Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 4 Sep 2023 12:57:59 +0200 Subject: [PATCH 21/33] Update MpcProviderTests.swift --- .../MpcProviderTests.swift | 110 +++++++----------- 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 6e041f9..5afb0fa 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -1,16 +1,10 @@ -import XCTest import BigInt -import Web3SwiftMpcProvider import web3 +import Web3SwiftMpcProvider +import XCTest final class Web3SwiftMpcProviderTests: XCTestCase { - func testExample() throws { - // get example share signature - -// XCTAssertEqual(Web3SwiftMpcProvider().text, "Hello, World!") - } - - func testSigningMessage() { + func testSigningMessage() throws { let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" let tssNonce = 0 @@ -21,69 +15,51 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let verifierId = "hqjang95@gmail.com" let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] - + let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - - do { - let account = try EthereumTssAccount(params: params) - let msg = "hello world" - // verifying logic is already included in sign function, so if verify fails then it will throw error -// let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: self.ethAccountParams.publicKey)) -// if verified { -// return signature -// } -// throw EthereumSignerError.unknownError - let signature = try account.sign(message: msg) - let _ = String(bytes: signature) - - } catch let err{ - XCTFail(err.localizedDescription) - } - - + let account = try EthereumTssAccount(params: params) + + let msg = "hello world" + let signature = try account.sign(message: msg) + let _ = String(bytes: signature) } - - func testSigningTx() async { - do { - let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" - let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" - let tssNonce = 0 - let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" - let tssIndex = "2" - let selected_tag = "default" - let verifier = "google-lrc" - let verifierId = "hqjang95@gmail.com" - let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] - let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] - - let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - - let tssAccount = try EthereumTssAccount(params: params) - // let RPC_URL = "https://api.avax-test.network/ext/bc/C/rpc" - // let chainID = 43113 - let RPC_URL = "https://rpc.ankr.com/eth_goerli" - let chainID = 5 - let web3Client = EthereumHttpClient(url: URL(string: RPC_URL)!) + func testSigningTx() async throws { + let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" + let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" + let tssNonce = 0 + let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" + let tssIndex = "2" + let selected_tag = "default" + let verifier = "google-lrc" + let verifierId = "hqjang95@gmail.com" + let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] + let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + + let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) + + let tssAccount = try EthereumTssAccount(params: params) + + // let RPC_URL = "https://api.avax-test.network/ext/bc/C/rpc" + // let chainID = 43113 + let RPC_URL = "https://rpc.ankr.com/eth_goerli" + let chainID = 5 + let web3Client = EthereumHttpClient(url: URL(string: RPC_URL)!) + + let amount = 0.001 + let toAddress = tssAccount.address + let fromAddress = tssAccount.address + let gasPrice = try await web3Client.eth_gasPrice() + let maxTipInGwie = BigUInt(TorusWeb3Utils.toEther(gwei: BigUInt(amount))) + let totalGas = gasPrice + maxTipInGwie + let gasLimit = BigUInt(21000) - let amount = 0.001 - let toAddress = tssAccount.address - let fromAddress = tssAccount.address - let gasPrice = try await web3Client.eth_gasPrice() - let maxTipInGwie = BigUInt(TorusWeb3Utils.toEther(gwei: BigUInt(amount))) - let totalGas = gasPrice + maxTipInGwie - let gasLimit = BigUInt(21000) + let amtInGwie = TorusWeb3Utils.toWei(ether: amount) + let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) + let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) - let amtInGwie = TorusWeb3Utils.toWei(ether: amount) - let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) - let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) - - // also sign function includes verify logic, so if verification fails then test will fail - let _ = try tssAccount.sign(transaction: transaction) - } catch let err { - XCTFail(err.localizedDescription) - } - + // also sign function includes verify logic, so if verification fails then test will fail + let _ = try tssAccount.sign(transaction: transaction) } } From 6b27c614679390359d04b633443377df82b16268 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 4 Sep 2023 20:12:39 +0200 Subject: [PATCH 22/33] refactor: remove unused extension code --- Package.swift | 5 - .../Extensions/Array+Extension.swift | 16 --- .../NSRegularExpressionExtension.swift | 80 ------------ .../Extensions/String+Extension.swift | 115 ------------------ Sources/Web3SwiftMpcProvider/Helper.swift | 1 - .../Web3SwiftMpcProvider.swift | 14 --- 6 files changed, 231 deletions(-) delete mode 100644 Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift delete mode 100644 Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift delete mode 100644 Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift diff --git a/Package.swift b/Package.swift index 781712f..4fb4a51 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,6 @@ let package = Package( name: "Web3SwiftMpcProvider", platforms: [.iOS(.v14)], products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Web3SwiftMpcProvider", targets: ["Web3SwiftMpcProvider"]), @@ -16,16 +15,12 @@ let package = Package( dependencies: [ .package(url: "https://github.com/argentlabs/web3.swift", from:"1.6.0"), .package(url: "https://github.com/torusresearch/tss-client-swift.git", from: "1.0.12"), - // .package(url: "https://github.com/realm/SwiftLint", from: "0.52.4"), ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Web3SwiftMpcProvider", dependencies: ["web3.swift", "tss-client-swift"], path: "Sources/Web3SwiftMpcProvider" - // plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] ), .testTarget( name: "Web3SwiftMpcProviderTests", diff --git a/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift deleted file mode 100644 index b7323d9..0000000 --- a/Sources/Web3SwiftMpcProvider/Extensions/Array+Extension.swift +++ /dev/null @@ -1,16 +0,0 @@ -// web3swift -// -// Created by Alex Vlasov. -// Copyright © 2018 Alex Vlasov. All rights reserved. -// - -import Foundation - -extension Array { - public func split(intoChunksOf chunkSize: Int) -> [[Element]] { - return stride(from: 0, to: count, by: chunkSize).map { - let endIndex = ($0.advanced(by: chunkSize) > self.count) ? self.count - $0 : chunkSize - return Array(self[$0 ..< $0.advanced(by: endIndex)]) - } - } -} diff --git a/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift b/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift deleted file mode 100644 index 671d421..0000000 --- a/Sources/Web3SwiftMpcProvider/Extensions/NSRegularExpressionExtension.swift +++ /dev/null @@ -1,80 +0,0 @@ -// web3swift -// -// Created by Alex Vlasov. -// Copyright © 2018 Alex Vlasov. All rights reserved. -// - -import Foundation - -extension NSRegularExpression { - typealias GroupNamesSearchResult = (NSTextCheckingResult, NSTextCheckingResult, Int) - - private func textCheckingResultsOfNamedCaptureGroups() -> [String: GroupNamesSearchResult] { - var groupnames = [String: GroupNamesSearchResult]() - - guard let greg = try? NSRegularExpression(pattern: "^\\(\\?<([\\w\\a_-]*)>$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { - // This never happens but the alternative is to make this method throwing - return groupnames - } - guard let reg = try? NSRegularExpression(pattern: "\\(.*?>", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { - // This never happens but the alternative is to make this method throwing - return groupnames - } - let pat = reg.matches(in: pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: pattern.utf16.count)) - for (num, grg) in pat.enumerated() { - let range = pattern.range(from: grg.range(at: 0)) - let gstring = String(pattern[range!]) - let gmatch = greg.matches(in: gstring, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: gstring.utf16.count)) - if gmatch.count > 0 { - let r2 = gstring.range(from: gmatch[0].range(at: 1))! - groupnames[String(gstring[r2])] = (grg, gmatch[0], num) - } - } - return groupnames - } - - func indexOfNamedCaptureGroups() throws -> [String: Int] { - var groupnames = [String: Int]() - for (name, (_, _, num)) in textCheckingResultsOfNamedCaptureGroups() { - groupnames[name] = num + 1 - } - return groupnames - } - - func rangesOfNamedCaptureGroups(match: NSTextCheckingResult) throws -> [String: Range] { - var ranges = [String: Range]() - for (name, (_, _, num)) in textCheckingResultsOfNamedCaptureGroups() { - ranges[name] = Range(match.range(at: num + 1)) - } - return ranges - } - - private func nameForIndex(_ index: Int, from: [String: GroupNamesSearchResult]) -> String? { - for (name, (_, _, num)) in from { - if (num + 1) == index { - return name - } - } - return nil - } - - func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = []) -> [String: String] { - return captureGroups(string: string, options: options, range: NSRange(location: 0, length: string.utf16.count)) - } - - func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [String: String] { - var dict = [String: String]() - let matchResult = matches(in: string, options: options, range: range) - let names = textCheckingResultsOfNamedCaptureGroups() - for (_, mmm) in matchResult.enumerated() { - for idx in 0 ..< mmm.numberOfRanges { - guard let r2 = string.range(from: mmm.range(at: idx)) else { continue } - let str = String(string[r2]) - if let name = nameForIndex(idx, from: names) { - dict[name] = str - } - } - } - return dict - } -} diff --git a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift index 7afa35c..a3dab9d 100644 --- a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift +++ b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift @@ -7,68 +7,6 @@ import Foundation extension String { - var fullRange: Range { - return startIndex ..< endIndex - } - - var fullNSRange: NSRange { - return NSRange(fullRange, in: self) - } - - func index(of char: Character) -> Index? { - guard let range = range(of: String(char)) else { - return nil - } - return range.lowerBound - } - - func split(intoChunksOf chunkSize: Int) -> [String] { - var output = [String]() - let splittedString = map { $0 } - .split(intoChunksOf: chunkSize) - splittedString.forEach { - output.append($0.map { String($0) }.joined(separator: "")) - } - return output - } - - subscript(bounds: CountableClosedRange) -> String { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return String(self[start ... end]) - } - - subscript(bounds: CountableRange) -> String { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return String(self[start ..< end]) - } - - subscript(bounds: CountablePartialRangeFrom) -> String { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = endIndex - return String(self[start ..< end]) - } - - func leftPadding(toLength: Int, withPad character: Character) -> String { - let stringLength = count - if stringLength < toLength { - return String(repeatElement(character, count: toLength - stringLength)) + self - } else { - return String(suffix(toLength)) - } - } - - func interpretAsBinaryData() -> Data? { - let padded = padding(toLength: ((count + 7) / 8) * 8, withPad: "0", startingAt: 0) - let byteArray = padded.split(intoChunksOf: 8).map { UInt8(strtoul($0, nil, 2)) } - return Data(byteArray) - } - - func hasHexPrefix() -> Bool { - return hasPrefix("0x") - } - func stripHexPrefix() -> String { if hasPrefix("0x") { let indexStart = index(startIndex, offsetBy: 2) @@ -76,59 +14,6 @@ extension String { } return self } - - func addHexPrefix() -> String { - if !hasPrefix("0x") { - return "0x" + self - } - return self - } - - func stripLeadingZeroes() -> String? { - let hex = addHexPrefix() - guard let matcher = try? NSRegularExpression(pattern: "^(?0x)0*(?[0-9a-fA-F]*)$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else { return nil } - let match = matcher.captureGroups(string: hex, options: NSRegularExpression.MatchingOptions.anchored) - guard let prefix = match["prefix"] else { return nil } - guard let end = match["end"] else { return nil } - if end != "" { - return prefix + end - } - return "0x0" - } - - func matchingStrings(regex: String) -> [[String]] { - guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] } - let nsString = self as NSString - let results = regex.matches(in: self, options: [], range: NSRange(location: 0, length: nsString.length)) - return results.map { result in - (0 ..< result.numberOfRanges).map { result.range(at: $0).location != NSNotFound - ? nsString.substring(with: result.range(at: $0)) - : "" - } - } - } - - func range(from nsRange: NSRange) -> Range? { - guard - let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex), - let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex), - let from = from16.samePosition(in: self), - let to = to16.samePosition(in: self) - else { return nil } - return from ..< to - } - - var asciiValue: Int { - let str = unicodeScalars - return Int(str[str.startIndex].value) - } -} - -extension Character { - var asciiValue: Int { - let str = String(self).unicodeScalars - return Int(str[str.startIndex].value) - } } extension String { diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift index de829ab..e1d5677 100644 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -5,7 +5,6 @@ import tss_client_swift import web3 import secp256k1 -// swiftlint:disable:next function_parameter_count public func bootstrapTssClient (params: EthTssAccountParams) throws -> (TSSClient, [String: String]) { if params.publicKey.count < 128 || params.publicKey.count > 130 { throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") diff --git a/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift b/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift deleted file mode 100644 index 6b88bb5..0000000 --- a/Sources/Web3SwiftMpcProvider/Web3SwiftMpcProvider.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation -import web3 -import secp256k1 -import CryptoKit -import BigInt - -public struct Web3SwiftMpcProvider { - public private(set) var text = "Hello, World!" - - public init() { - - } - -} From e4acd3b4dc3b07b3d670055c75eeefc2a733fadd Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 05:10:12 +0200 Subject: [PATCH 23/33] refactor: remove force unwraps and further cleanup --- .../{Error.swift => CustomSigningError.swift} | 0 .../Extensions/String+Extension.swift | 4 +--- Sources/Web3SwiftMpcProvider/Helper.swift | 13 ++++++++----- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 17 ----------------- 4 files changed, 9 insertions(+), 25 deletions(-) rename Sources/Web3SwiftMpcProvider/{Error.swift => CustomSigningError.swift} (100%) diff --git a/Sources/Web3SwiftMpcProvider/Error.swift b/Sources/Web3SwiftMpcProvider/CustomSigningError.swift similarity index 100% rename from Sources/Web3SwiftMpcProvider/Error.swift rename to Sources/Web3SwiftMpcProvider/CustomSigningError.swift diff --git a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift index a3dab9d..66bc325 100644 --- a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift +++ b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift @@ -14,9 +14,7 @@ extension String { } return self } -} - -extension String { + func toChecksumAddress() -> String { let lowerCaseAddress = stripHexPrefix().lowercased() let arr = Array(lowerCaseAddress) diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift index e1d5677..a643c9d 100644 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ b/Sources/Web3SwiftMpcProvider/Helper.swift @@ -11,13 +11,16 @@ public func bootstrapTssClient (params: EthTssAccountParams) throws -> (TSSClien } // generate a random nonce for sessionID - let randomKey = BigUInt(SECP256K1.generatePrivateKey()!) - let random = BigInt(sign: .plus, magnitude: randomKey) + BigInt(Date().timeIntervalSince1970) - let sessionNonce = TSSHelpers.hashMessage(message: String(random)) + guard let randomKey = SECP256K1.generatePrivateKey() else { + throw CustomSigningError.generalError(error: "Could not generate random key for sessionID nonce") + } + let randomKeyBigUint = BigUInt(randomKey) + let random = BigInt(sign: .plus, magnitude: randomKeyBigUint) + BigInt(Date().timeIntervalSince1970) + let sessionNonce = TSSHelpers.base64ToBase64url(base64: TSSHelpers.hashMessage(message: String(random))) // create the full session string let session = TSSHelpers.assembleFullSession(verifier: params.verifier, verifierId: params.verifierID, tssTag: params.selectedTag, tssNonce: String(params.tssNonce), sessionNonce: sessionNonce) - let userTssIndex = BigInt(params.tssIndex, radix: 16)! + let userTssIndex = BigInt(params.tssIndex, radix: 16) ?? BigInt.zero // total parties, including the client let parties = params.nodeIndexes.count > 0 ? params.nodeIndexes.count + 1 : 4 @@ -28,7 +31,7 @@ public func bootstrapTssClient (params: EthTssAccountParams) throws -> (TSSClien let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) - let shareUnsigned = BigUInt(params.tssShare, radix: 16)! + let shareUnsigned = BigUInt(params.tssShare, radix: 16) ?? BigUInt.zero let share = BigInt(sign: .plus, magnitude: shareUnsigned) let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index be395b2..0cfb8d3 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -61,21 +61,4 @@ public final class TorusWeb3Utils { public static func toWei(gwei: Double) -> Wei { return Wei(gwei * 1000000000) } - - public static func generateAddressFromPubKey(publicKeyX: String, publicKeyY: String) -> String { - let publicKeyHex = "04" + publicKeyX.addLeading0sForLength64() + publicKeyY.addLeading0sForLength64() - let publicKeyData = Data(hexString: publicKeyHex)! - - do { - let publicKey = try P256.KeyAgreement.PublicKey(x963Representation: publicKeyData) - let publicKeyBytes = publicKey.rawRepresentation// .dropFirst().dropLast() // Remove the first byte (0x04) - let ethAddressLower = "0x" + keccak256Data(publicKeyBytes).suffix(40) - return ethAddressLower.toChecksumAddress() - } catch { - // Handle the error if necessary - print("Failed to derive public key: \(error)") - return "" - } - } - } From 13eb9485c2cdb4c24cd88cc57fc5c0ff16ecbc24 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 06:39:14 +0200 Subject: [PATCH 24/33] refactor: more cleanup --- .../CustomSigningError.swift | 23 -- .../EthTssAccountParams.swift | 25 +- .../EthereumTssAccount.swift | 258 +++++++++--------- .../Extensions/String+Extension.swift | 32 --- Sources/Web3SwiftMpcProvider/Helper.swift | 43 --- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 17 -- 6 files changed, 137 insertions(+), 261 deletions(-) delete mode 100644 Sources/Web3SwiftMpcProvider/CustomSigningError.swift delete mode 100644 Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift delete mode 100644 Sources/Web3SwiftMpcProvider/Helper.swift diff --git a/Sources/Web3SwiftMpcProvider/CustomSigningError.swift b/Sources/Web3SwiftMpcProvider/CustomSigningError.swift deleted file mode 100644 index 1f3d2f4..0000000 --- a/Sources/Web3SwiftMpcProvider/CustomSigningError.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// File.swift -// -// -// Created by CW Lee on 23/08/2023. -// - -import Foundation - -public enum CustomSigningError: Error { - case generalError(error: String = "") - case unknownError(error: String = "") - - public var errorDescription: String { - switch self { - case .generalError( let err): - return err - - case .unknownError( let err): - return err - } - } -} diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index 3abb07c..cecaa6e 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -1,16 +1,15 @@ -public class EthTssAccountParams { - public let publicKey: String - public let factorKey: String - public let tssNonce: Int32 - public let tssShare: String - public let tssIndex: String - public let selectedTag: String - public let verifier: String - public let verifierID: String - public let nodeIndexes: [Int] - public let tssEndpoints: [String] - public let authSigs: [String] - // swiftlint:disable:next line_length +public final class EthTssAccountParams { + private(set) var publicKey: String + private(set) var factorKey: String + private(set) var tssNonce: Int32 + private(set) var tssShare: String + private(set) var tssIndex: String + private(set) var selectedTag: String + private(set) var verifier: String + private(set) var verifierID: String + private(set) var nodeIndexes: [Int] + private(set) var tssEndpoints: [String] + private(set) var authSigs: [String] public init(publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { self.publicKey = publicKey self.factorKey = factorKey diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index a4975ed..40e9cc0 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -1,27 +1,17 @@ -// -// EthereumTssAccount.swift -// tkey_ios -// -// Created by himanshu on 09/08/23. -// - +import BigInt +import CryptoKit import Foundation -import web3 import secp256k1 import tss_client_swift -import CryptoKit -import BigInt +import web3 -public enum CustomError: Error { - case unknownError - case methodUnavailable +public enum CustomSigningError: Error { + case generalError(error: String = "") public var errorDescription: String { switch self { - case .unknownError: - return "unknownError" - case .methodUnavailable: - return "method unavailable/unimplemented" + case let .generalError(err): + return err } } } @@ -31,149 +21,151 @@ enum EthereumSignerError: Error { case unknownError } -public class EthereumTssAccount: EthereumAccountProtocol { +public final class EthereumTssAccount: EthereumAccountProtocol { public var address: web3.EthereumAddress - public let ethAccountParams: EthTssAccountParams + public var ethAccountParams: EthTssAccountParams - required public init(params: EthTssAccountParams) throws { - self.ethAccountParams = params - let address = KeyUtil.generateAddress(from: Data(hex: self.ethAccountParams.publicKey).suffix(64)).toChecksumAddress() - self.address = EthereumAddress(address) - } + public required init(params: EthTssAccountParams) throws { + ethAccountParams = params + address = EthereumAddress(KeyUtil.generateAddress(from: Data(hex: ethAccountParams.publicKey).suffix(64)).toChecksumAddress()) + } - /// hash and sign data - public func sign(data: Data) throws -> Data { - let hash = data.sha3(.keccak256) - let signature = try self.sign(message: hash) - return signature - } + /// hash and sign data + public func sign(data: Data) throws -> Data { + let hash = data.sha3(.keccak256) + let signature = try sign(message: hash) + return signature + } - /// hash and sign hex string - public func sign(hex: String) throws -> Data { - if let data = Data(hex: hex) { - return try self.sign(data: data) - } else { - throw EthereumAccountError.signError - } + /// hash and sign hex string + public func sign(hex: String) throws -> Data { + if let data = Data(hex: hex) { + return try sign(data: data) + } else { + throw EthereumAccountError.signError } + } - /// Signing hashed string - public func sign(hash: String) throws -> Data { - if let data = hash.web3.hexData { - return try self.sign(message: data) - } else { - throw EthereumAccountError.signError - } + /// Signing hashed string + public func sign(hash: String) throws -> Data { + if let data = hash.web3.hexData { + return try sign(message: data) + } else { + throw EthereumAccountError.signError } + } - /// Signing Data without hashing - public func sign(message: Data) throws -> Data { - // Create tss Client using helper - let (client, coeffs) = try bootstrapTssClient(params: self.ethAccountParams) - - // Wait for sockets to be connected - let connected = try client.checkConnected() - if !(connected) { - throw EthereumSignerError.unknownError - } + /// Signing Data without hashing + public func sign(message: Data) throws -> Data { + // Create tss Client using helper + let (client, coeffs) = try bootstrapTssClient(params: ethAccountParams) - let precompute = try client.precompute(serverCoeffs: coeffs, signatures: self.ethAccountParams.authSigs) + // Wait for sockets to be connected + let connected = try client.checkConnected() + if !connected { + throw EthereumSignerError.unknownError + } - let ready = try client.isReady() - if !(ready) { - throw EthereumSignerError.unknownError - } + let precompute = try client.precompute(serverCoeffs: coeffs, signatures: ethAccountParams.authSigs) - let signingMessage = message.base64EncodedString() + let ready = try client.isReady() + if !ready { + throw EthereumSignerError.unknownError + } - // swiftlint:disable:next identifier_name - let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: self.ethAccountParams.authSigs) + let signingMessage = message.base64EncodedString() - try client.cleanup(signatures: self.ethAccountParams.authSigs) + let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: ethAccountParams.authSigs) - guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } + try client.cleanup(signatures: ethAccountParams.authSigs) - let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: self.ethAccountParams.publicKey)) - if verified { - return signature - } + let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: ethAccountParams.publicKey)) + if !verified { throw EthereumSignerError.unknownError } + guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } - /// Signing utf8 encoded message String - public func sign(message: String) throws -> Data { - if let data = message.data(using: .utf8) { - return try self.sign(data: data) - } else { - throw EthereumAccountError.signError - } + return signature + } + + /// Signing utf8 encoded message String + public func sign(message: String) throws -> Data { + if let data = message.data(using: .utf8) { + return try sign(data: data) + } else { + throw EthereumAccountError.signError } + } - /// prefix message and hash it before signing - public func signMessage(message: Data) throws -> String { - let prefix = "\u{19}Ethereum Signed Message:\n\(String(message.count))" - guard var data = prefix.data(using: .ascii) else { - throw EthereumAccountError.signError - } - data.append(message) - let hash = data.web3.keccak256 - - guard var signed = try? self.sign(message: hash) else { - throw EthereumAccountError.signError - } - - // Check last char (v) - guard var last = signed.popLast() else { - throw EthereumAccountError.signError - } - - if last < 27 { - last += 27 - } - - signed.append(last) - return signed.web3.hexString + /// prefix message and hash it before signing + public func signMessage(message: Data) throws -> String { + let prefix = "\u{19}Ethereum Signed Message:\n\(String(message.count))" + guard var data = prefix.data(using: .ascii) else { + throw EthereumAccountError.signError } + data.append(message) + let hash = data.web3.keccak256 - /// signing TypedData - public func signMessage(message: TypedData) throws -> String { - let hash = try message.signableHash() + let signed = try sign(message: hash) + + return signed.web3.hexString + } - guard var signed = try? self.sign(message: hash) else { - throw EthereumAccountError.signError - } + /// signing TypedData + public func signMessage(message: TypedData) throws -> String { + let hash = try message.signableHash() - // Check last char (v) - guard var last = signed.popLast() else { - throw EthereumAccountError.signError - } + let signed = try sign(message: hash) - if last < 27 { - last += 27 - } + return signed.web3.hexString + } - signed.append(last) - return signed.web3.hexString + /// Signing EthereumTransaction + public func sign(transaction: EthereumTransaction) throws -> SignedTransaction { + guard let raw = transaction.raw else { + throw EthereumSignerError.emptyRawTransaction } - /// Signing EthereumTransaction - public func signtx(transaction: EthereumTransaction) throws -> SignedTransaction { - guard let raw = transaction.raw else { - throw EthereumSignerError.emptyRawTransaction - } - - // hash and sign data - var signed = try self.sign(data: raw) - // Check last char (v) - guard var last = signed.popLast() else { - throw EthereumAccountError.signError - } - - if last < 27 { - last += 27 - } - - signed.append(last) - return SignedTransaction(transaction: transaction, signature: signed) + // hash and sign data + let signed = try sign(data: raw) + + return SignedTransaction(transaction: transaction, signature: signed) + } + + private func bootstrapTssClient(params: EthTssAccountParams) throws -> (TSSClient, [String: String]) { + if params.publicKey.count < 128 || params.publicKey.count > 130 { + throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") } + + // generate a random nonce for sessionID + guard let randomKey = SECP256K1.generatePrivateKey() else { + throw CustomSigningError.generalError(error: "Could not generate random key for sessionID nonce") + } + let randomKeyBigUint = BigUInt(randomKey) + let random = BigInt(sign: .plus, magnitude: randomKeyBigUint) + BigInt(Date().timeIntervalSince1970) + let sessionNonce = TSSHelpers.base64ToBase64url(base64: TSSHelpers.hashMessage(message: String(random))) + // create the full session string + let session = TSSHelpers.assembleFullSession(verifier: params.verifier, verifierId: params.verifierID, tssTag: params.selectedTag, tssNonce: String(params.tssNonce), sessionNonce: sessionNonce) + + let userTssIndex = BigInt(params.tssIndex, radix: 16) ?? BigInt.zero + // total parties, including the client + let parties = params.nodeIndexes.count > 0 ? params.nodeIndexes.count + 1 : 4 + + // index of the client, last index of partiesIndexes + let clientIndex = Int32(parties - 1) + + let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: params.nodeIndexes, urls: params.tssEndpoints) + + let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) + + let shareUnsigned = BigUInt(params.tssShare, radix: 16) ?? BigUInt.zero + let share = BigInt(sign: .plus, magnitude: shareUnsigned) + let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) + + let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({ Int32($0) }), + endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), + share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: params.publicKey))) + + return (client, coeffs) + } } diff --git a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift b/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift deleted file mode 100644 index 66bc325..0000000 --- a/Sources/Web3SwiftMpcProvider/Extensions/String+Extension.swift +++ /dev/null @@ -1,32 +0,0 @@ -// web3swift -// -// Created by Alex Vlasov. -// Copyright © 2018 Alex Vlasov. All rights reserved. -// - -import Foundation - -extension String { - func stripHexPrefix() -> String { - if hasPrefix("0x") { - let indexStart = index(startIndex, offsetBy: 2) - return String(self[indexStart...]) - } - return self - } - - func toChecksumAddress() -> String { - let lowerCaseAddress = stripHexPrefix().lowercased() - let arr = Array(lowerCaseAddress) - let hash = Array(lowerCaseAddress.sha3(.keccak256)) - var result = "0x" - for idx in 0 ... lowerCaseAddress.count - 1 { - if let val = Int(String(hash[idx]), radix: 16), val >= 8 { - result.append(arr[idx].uppercased()) - } else { - result.append(arr[idx]) - } - } - return result - } -} diff --git a/Sources/Web3SwiftMpcProvider/Helper.swift b/Sources/Web3SwiftMpcProvider/Helper.swift deleted file mode 100644 index a643c9d..0000000 --- a/Sources/Web3SwiftMpcProvider/Helper.swift +++ /dev/null @@ -1,43 +0,0 @@ -import BigInt -import Foundation -import SwiftUI -import tss_client_swift -import web3 -import secp256k1 - -public func bootstrapTssClient (params: EthTssAccountParams) throws -> (TSSClient, [String: String]) { - if params.publicKey.count < 128 || params.publicKey.count > 130 { - throw CustomSigningError.generalError(error: "Public Key should be in uncompressed format") - } - - // generate a random nonce for sessionID - guard let randomKey = SECP256K1.generatePrivateKey() else { - throw CustomSigningError.generalError(error: "Could not generate random key for sessionID nonce") - } - let randomKeyBigUint = BigUInt(randomKey) - let random = BigInt(sign: .plus, magnitude: randomKeyBigUint) + BigInt(Date().timeIntervalSince1970) - let sessionNonce = TSSHelpers.base64ToBase64url(base64: TSSHelpers.hashMessage(message: String(random))) - // create the full session string - let session = TSSHelpers.assembleFullSession(verifier: params.verifier, verifierId: params.verifierID, tssTag: params.selectedTag, tssNonce: String(params.tssNonce), sessionNonce: sessionNonce) - - let userTssIndex = BigInt(params.tssIndex, radix: 16) ?? BigInt.zero - // total parties, including the client - let parties = params.nodeIndexes.count > 0 ? params.nodeIndexes.count + 1 : 4 - - // index of the client, last index of partiesIndexes - let clientIndex = Int32(parties - 1) - - let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: params.nodeIndexes, urls: params.tssEndpoints) - - let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) - - let shareUnsigned = BigUInt(params.tssShare, radix: 16) ?? BigUInt.zero - let share = BigInt(sign: .plus, magnitude: shareUnsigned) - let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) - - let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({Int32($0)}), - endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), - share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: params.publicKey))) - - return (client, coeffs) - } diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index 0cfb8d3..73fa44b 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -1,10 +1,3 @@ -// -// TorusWeb3Utils.swift -// tkey_ios -// -// Created by himanshu on 09/08/23. -// - import BigInt import Foundation import web3 @@ -13,17 +6,7 @@ import CryptoKit public typealias Ether = Double public typealias Wei = BigUInt -public func keccak256Data(_ data: Data) -> String { - let hash = data.sha3(.keccak256) - return "0x" + hash.map { String(format: "%02x", $0) }.joined() -} - public final class TorusWeb3Utils { - - public static func timeMinToSec(val: Double) -> Double { - return val * 60 - } - // NOTE: calculate wei by 10^18 private static let etherInWei = pow(Double(10), 18) private static let etherInGwei = pow(Double(10), 9) From 0ce0618616634795635299c36bf912790c10baf0 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 06:58:11 +0200 Subject: [PATCH 25/33] refactor: further cleanup --- .../EthereumTssAccount.swift | 25 ++++++++++++++++--- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 1 - .../MpcProviderTests.swift | 8 +----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 40e9cc0..1b5824c 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -1,5 +1,4 @@ import BigInt -import CryptoKit import Foundation import secp256k1 import tss_client_swift @@ -106,8 +105,18 @@ public final class EthereumTssAccount: EthereumAccountProtocol { data.append(message) let hash = data.web3.keccak256 - let signed = try sign(message: hash) + var signed = try sign(message: hash) + // Check last char (v) + guard var last = signed.popLast() else { + throw EthereumAccountError.signError + } + + if last < 27 { + last += 27 + } + + signed.append(last) return signed.web3.hexString } @@ -115,8 +124,18 @@ public final class EthereumTssAccount: EthereumAccountProtocol { public func signMessage(message: TypedData) throws -> String { let hash = try message.signableHash() - let signed = try sign(message: hash) + var signed = try sign(message: hash) + + // Check last char (v) + guard var last = signed.popLast() else { + throw EthereumAccountError.signError + } + + if last < 27 { + last += 27 + } + signed.append(last) return signed.web3.hexString } diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index 73fa44b..a3b940f 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -1,7 +1,6 @@ import BigInt import Foundation import web3 -import CryptoKit public typealias Ether = Double public typealias Wei = BigUInt diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 5afb0fa..1b01d35 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -21,8 +21,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let account = try EthereumTssAccount(params: params) let msg = "hello world" - let signature = try account.sign(message: msg) - let _ = String(bytes: signature) + let _ = try account.sign(message: msg) } func testSigningTx() async throws { @@ -40,9 +39,6 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) let tssAccount = try EthereumTssAccount(params: params) - - // let RPC_URL = "https://api.avax-test.network/ext/bc/C/rpc" - // let chainID = 43113 let RPC_URL = "https://rpc.ankr.com/eth_goerli" let chainID = 5 let web3Client = EthereumHttpClient(url: URL(string: RPC_URL)!) @@ -58,8 +54,6 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let amtInGwie = TorusWeb3Utils.toWei(ether: amount) let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) - - // also sign function includes verify logic, so if verification fails then test will fail let _ = try tssAccount.sign(transaction: transaction) } } From 00790cb981bcb6058344b510ac883baa0f8015ea Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 07:07:11 +0200 Subject: [PATCH 26/33] Update EthereumTssAccount.swift --- Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 1b5824c..fc4a931 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -4,7 +4,7 @@ import secp256k1 import tss_client_swift import web3 -public enum CustomSigningError: Error { +enum CustomSigningError: Error { case generalError(error: String = "") public var errorDescription: String { From 45c2e314683cf9ad82d32e97855f58209dee6ef1 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 07:21:21 +0200 Subject: [PATCH 27/33] fix: disable lints for specific lines --- .../EthTssAccountParams.swift | 1 + .../EthereumTssAccount.swift | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index cecaa6e..48aae39 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -10,6 +10,7 @@ public final class EthTssAccountParams { private(set) var nodeIndexes: [Int] private(set) var tssEndpoints: [String] private(set) var authSigs: [String] + // swiftlint:disable:next line_length public init(publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { self.publicKey = publicKey self.factorKey = factorKey diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index fc4a931..2e19012 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -26,6 +26,7 @@ public final class EthereumTssAccount: EthereumAccountProtocol { public required init(params: EthTssAccountParams) throws { ethAccountParams = params + // swiftlint:disable:next line_length address = EthereumAddress(KeyUtil.generateAddress(from: Data(hex: ethAccountParams.publicKey).suffix(64)).toChecksumAddress()) } @@ -74,14 +75,18 @@ public final class EthereumTssAccount: EthereumAccountProtocol { let signingMessage = message.base64EncodedString() + // swiftlint:disable:next identifier_name line_length let (s, r, v) = try client.sign(message: signingMessage, hashOnly: true, original_message: nil, precompute: precompute, signatures: ethAccountParams.authSigs) try client.cleanup(signatures: ethAccountParams.authSigs) + // swiftlint:disable:next line_length let verified = TSSHelpers.verifySignature(msgHash: signingMessage, s: s, r: r, v: v, pubKey: Data(hex: ethAccountParams.publicKey)) if !verified { throw EthereumSignerError.unknownError } + + // swiftlint:disable:next line_length guard let signature = Data(hexString: try TSSHelpers.hexSignature(s: s, r: r, v: v)) else { throw EthereumSignerError.unknownError } return signature @@ -125,7 +130,7 @@ public final class EthereumTssAccount: EthereumAccountProtocol { let hash = try message.signableHash() var signed = try sign(message: hash) - + // Check last char (v) guard var last = signed.popLast() else { throw EthereumAccountError.signError @@ -164,6 +169,7 @@ public final class EthereumTssAccount: EthereumAccountProtocol { let random = BigInt(sign: .plus, magnitude: randomKeyBigUint) + BigInt(Date().timeIntervalSince1970) let sessionNonce = TSSHelpers.base64ToBase64url(base64: TSSHelpers.hashMessage(message: String(random))) // create the full session string + // swiftlint:disable:next line_length let session = TSSHelpers.assembleFullSession(verifier: params.verifier, verifierId: params.verifierID, tssTag: params.selectedTag, tssNonce: String(params.tssNonce), sessionNonce: sessionNonce) let userTssIndex = BigInt(params.tssIndex, radix: 16) ?? BigInt.zero @@ -172,17 +178,20 @@ public final class EthereumTssAccount: EthereumAccountProtocol { // index of the client, last index of partiesIndexes let clientIndex = Int32(parties - 1) - + // swiftlint:disable:next line_length let (urls, socketUrls, partyIndexes, nodeInd) = try TSSHelpers.generateEndpoints(parties: parties, clientIndex: Int(clientIndex), nodeIndexes: params.nodeIndexes, urls: params.tssEndpoints) - + // swiftlint:disable:next line_length let coeffs = try TSSHelpers.getServerCoefficients(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex) let shareUnsigned = BigUInt(params.tssShare, radix: 16) ?? BigUInt.zero let share = BigInt(sign: .plus, magnitude: shareUnsigned) + // swiftlint:disable:next line_length let denormalizeShare = try TSSHelpers.denormalizeShare(participatingServerDKGIndexes: nodeInd.map({ BigInt($0) }), userTssIndex: userTssIndex, userTssShare: share) - + // swiftlint:disable:next line_length let client = try TSSClient(session: session, index: Int32(clientIndex), parties: partyIndexes.map({ Int32($0) }), + // swiftlint:disable:next line_length endpoints: urls.map({ URL(string: $0 ?? "") }), tssSocketEndpoints: socketUrls.map({ URL(string: $0 ?? "") }), + // swiftlint:disable:next line_length share: TSSHelpers.base64Share(share: denormalizeShare), pubKey: try TSSHelpers.base64PublicKey(pubKey: Data(hex: params.publicKey))) return (client, coeffs) From ceb925b3a2724e9bca6661244769384db4cc91a1 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:07:07 +0200 Subject: [PATCH 28/33] fix: throw conversion error instead of returning zero --- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 16 ++++++++++------ .../MpcProviderTests.swift | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index a3b940f..7b8868d 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -5,22 +5,26 @@ import web3 public typealias Ether = Double public typealias Wei = BigUInt +enum TorusWeb3UtilsError: Error { + case conversionError +} + public final class TorusWeb3Utils { // NOTE: calculate wei by 10^18 private static let etherInWei = pow(Double(10), 18) private static let etherInGwei = pow(Double(10), 9) /// Convert Wei(BInt) unit to Ether(Decimal) unit - public static func toEther(wei: Wei) -> Ether { + public static func toEther(wei: Wei) throws -> Ether { guard let decimalWei = Double(wei.description) else { - return 0 + throw TorusWeb3UtilsError.conversionError } return decimalWei / etherInWei } - public static func toEther(gwei: BigUInt) -> Ether { + public static func toEther(gwei: BigUInt) throws -> Ether { guard let decimalWei = Double(gwei.description) else { - return 0 + throw TorusWeb3UtilsError.conversionError } return decimalWei / etherInGwei } @@ -32,9 +36,9 @@ public final class TorusWeb3Utils { } /// Convert Ether(String) unit to Wei(BInt) unit - public static func toWei(ether: String) -> Wei { + public static func toWei(ether: String) throws -> Wei { guard let decimalEther = Double(ether) else { - return 0 + throw TorusWeb3UtilsError.conversionError } return toWei(ether: decimalEther) } diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 1b01d35..0d32cd4 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -47,7 +47,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let toAddress = tssAccount.address let fromAddress = tssAccount.address let gasPrice = try await web3Client.eth_gasPrice() - let maxTipInGwie = BigUInt(TorusWeb3Utils.toEther(gwei: BigUInt(amount))) + let maxTipInGwie = BigUInt(try TorusWeb3Utils.toEther(gwei: BigUInt(amount))) let totalGas = gasPrice + maxTipInGwie let gasLimit = BigUInt(21000) From 47e7705f9b29469e4430349cb338cc048c71c9bd Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:26:00 +0200 Subject: [PATCH 29/33] refactor: test cleanup and typedData test --- .../MpcProviderTests.swift | 112 ++++++++++++++---- 1 file changed, 88 insertions(+), 24 deletions(-) diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 0d32cd4..ba02155 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -4,18 +4,87 @@ import Web3SwiftMpcProvider import XCTest final class Web3SwiftMpcProviderTests: XCTestCase { + let example1 = """ + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Account", + "wallet": "0x048975d4997d7578a3419851639c10318db430b6" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } + """.data(using: .utf8)! + + let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" + let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" + let tssNonce = 0 + let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" + let tssIndex = "2" + let selected_tag = "default" + let verifier = "google-lrc" + let verifierId = "hqjang95@gmail.com" + let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] + let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] + + let decoder = JSONDecoder() + func testSigningMessage() throws { - let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" - let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" - let tssNonce = 0 - let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" - let tssIndex = "2" - let selected_tag = "default" - let verifier = "google-lrc" - let verifierId = "hqjang95@gmail.com" - let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] - let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] - let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) let account = try EthereumTssAccount(params: params) @@ -24,20 +93,8 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let _ = try account.sign(message: msg) } - func testSigningTx() async throws { - let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" - let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" - let tssNonce = 0 - let tssShare = "4f62ddd962fab8b0777bd18a2e6f3992c7e15ff929df79a15a7046da46af5a05" - let tssIndex = "2" - let selected_tag = "default" - let verifier = "google-lrc" - let verifierId = "hqjang95@gmail.com" - let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] - let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] - + func testSigningTransaction() async throws { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - let tssAccount = try EthereumTssAccount(params: params) let RPC_URL = "https://rpc.ankr.com/eth_goerli" let chainID = 5 @@ -56,4 +113,11 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) let _ = try tssAccount.sign(transaction: transaction) } + + func testSignTyped() async throws { + let typedData = try! decoder.decode(TypedData.self, from: example1) + let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) + let tssAccount = try EthereumTssAccount(params: params) + let signed = try tssAccount.signMessage(message: typedData) + } } From 289ceb2a62d69f3f2df6df3a06d45ad774f3034e Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:28:27 +0200 Subject: [PATCH 30/33] Update ci.yaml --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 07c1871..6e8ae8c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,11 +14,11 @@ jobs: steps: - name: checkout uses: actions/checkout@v3 - - name: SwiftLint - run: swiftlint lint ./Sources --reporter github-actions-logging - name: xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: "14.2.0" - name: package - run: xcodebuild test -scheme Web3SwiftMpcProvider -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO \ No newline at end of file + run: xcodebuild test -scheme Web3SwiftMpcProvider -destination "platform=iOS Simulator,OS=16.2,name=iPhone 14" COMPILER_INDEX_STORE_ENABLE=NO + - name: SwiftLint + run: swiftlint lint ./Sources --reporter github-actions-logging \ No newline at end of file From b2dac994f90ee62402912370f9b69d1dbd956eda Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:51:03 +0200 Subject: [PATCH 31/33] Update MpcProviderTests.swift --- Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index ba02155..d8b91ab 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -93,7 +93,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let _ = try account.sign(message: msg) } - func testSigningTransaction() async throws { + func testSigningTransaction() throws { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) let tssAccount = try EthereumTssAccount(params: params) let RPC_URL = "https://rpc.ankr.com/eth_goerli" @@ -103,21 +103,21 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let amount = 0.001 let toAddress = tssAccount.address let fromAddress = tssAccount.address - let gasPrice = try await web3Client.eth_gasPrice() + let gasPrice = BigUInt(938) let maxTipInGwie = BigUInt(try TorusWeb3Utils.toEther(gwei: BigUInt(amount))) let totalGas = gasPrice + maxTipInGwie let gasLimit = BigUInt(21000) let amtInGwie = TorusWeb3Utils.toWei(ether: amount) - let nonce = try await web3Client.eth_getTransactionCount(address: fromAddress, block: .Latest) + let nonce = 0 let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) let _ = try tssAccount.sign(transaction: transaction) } - func testSignTyped() async throws { + func testSignTyped() throws { let typedData = try! decoder.decode(TypedData.self, from: example1) let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) let tssAccount = try EthereumTssAccount(params: params) - let signed = try tssAccount.signMessage(message: typedData) + let _ = try tssAccount.signMessage(message: typedData) } } From de35856ac5efc1edaa9e7db7706b71e3c5929dc9 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:58:04 +0200 Subject: [PATCH 32/33] Update MpcProviderTests.swift --- Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index d8b91ab..0b5c14d 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -96,10 +96,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { func testSigningTransaction() throws { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) let tssAccount = try EthereumTssAccount(params: params) - let RPC_URL = "https://rpc.ankr.com/eth_goerli" let chainID = 5 - let web3Client = EthereumHttpClient(url: URL(string: RPC_URL)!) - let amount = 0.001 let toAddress = tssAccount.address let fromAddress = tssAccount.address From 75247e8a6393b97c464aec4a3b223a5576ffc5b7 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:20:46 +0200 Subject: [PATCH 33/33] update: docs and formatting --- .../EthTssAccountParams.swift | 15 ++ .../EthereumTssAccount.swift | 79 ++++++++-- .../Web3SwiftMpcProvider/TorusWeb3Utils.swift | 42 +++++- .../MpcProviderTests.swift | 140 +++++++++--------- 4 files changed, 193 insertions(+), 83 deletions(-) diff --git a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift index 48aae39..719622c 100644 --- a/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift +++ b/Sources/Web3SwiftMpcProvider/EthTssAccountParams.swift @@ -10,6 +10,21 @@ public final class EthTssAccountParams { private(set) var nodeIndexes: [Int] private(set) var tssEndpoints: [String] private(set) var authSigs: [String] + /// Instantiates EthTssAccountParams which are used to instantiate an EtheriumTssAccount + /// + /// - Parameters: + /// - publicKey : Public key for the account, EtheriumAddress is derived from this. + /// - factorKey: The factor key + /// - tssNonce: The current tss nonce + /// - tssShare: The current tss share + /// - tssIndex: The index corresponding to the tssShare + /// - selectedTag: The current tss tag + /// - verifier: The verifier for the account + /// - verifierID: The identifier for the account + /// - nodeIndexes: The node indexes returned form the sapphire network + /// - tssEndpoints: The tss endpoints for the sapphire network + /// - authSigs: The signatures returned for the sapphire network + /// // swiftlint:disable:next line_length public init(publicKey: String, factorKey: String, tssNonce: Int32, tssShare: String, tssIndex: String, selectedTag: String, verifier: String, verifierID: String, nodeIndexes: [Int], tssEndpoints: [String], authSigs: [String]) { self.publicKey = publicKey diff --git a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift index 2e19012..ad391ac 100644 --- a/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift +++ b/Sources/Web3SwiftMpcProvider/EthereumTssAccount.swift @@ -24,20 +24,39 @@ public final class EthereumTssAccount: EthereumAccountProtocol { public var address: web3.EthereumAddress public var ethAccountParams: EthTssAccountParams - public required init(params: EthTssAccountParams) throws { + /// Instantiates an EtheriumTssAccount + /// + /// - Parameters: + /// - params : Parameters used to initialize the account + /// + public required init(params: EthTssAccountParams) { ethAccountParams = params // swiftlint:disable:next line_length address = EthereumAddress(KeyUtil.generateAddress(from: Data(hex: ethAccountParams.publicKey).suffix(64)).toChecksumAddress()) } - /// hash and sign data + /// Signs using provided Data + /// + /// - Parameters: + /// - data : Data to be signed + /// + /// - Returns: `Data` + /// + /// - Throws: On signing failure public func sign(data: Data) throws -> Data { let hash = data.sha3(.keccak256) let signature = try sign(message: hash) return signature } - /// hash and sign hex string + /// Signs using provided Hex String + /// + /// - Parameters: + /// - hex : Hex string to be signed + /// + /// - Returns: `Data` + /// + /// - Throws: On signing failure public func sign(hex: String) throws -> Data { if let data = Data(hex: hex) { return try sign(data: data) @@ -46,7 +65,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { } } - /// Signing hashed string + /// Signs using provided hash + /// + /// - Parameters: + /// - hash : Hash to be used for signing + /// + /// - Returns: `Data` + /// + /// - Throws: On signing failure public func sign(hash: String) throws -> Data { if let data = hash.web3.hexData { return try sign(message: data) @@ -55,7 +81,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { } } - /// Signing Data without hashing + /// Signs using provided message data + /// + /// - Parameters: + /// - message : message to be used for signing + /// + /// - Returns: `Data` + /// + /// - Throws: On signing failure public func sign(message: Data) throws -> Data { // Create tss Client using helper let (client, coeffs) = try bootstrapTssClient(params: ethAccountParams) @@ -92,7 +125,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { return signature } - /// Signing utf8 encoded message String + /// Signs using provided message string + /// + /// - Parameters: + /// - message : message to be used for signing + /// + /// - Returns: `Data` + /// + /// - Throws: On signing failure public func sign(message: String) throws -> Data { if let data = message.data(using: .utf8) { return try sign(data: data) @@ -101,7 +141,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { } } - /// prefix message and hash it before signing + /// Signs using provided message data, prefixing the data first + /// + /// - Parameters: + /// - message : message to be used for signing + /// + /// - Returns: `String` + /// + /// - Throws: On signing failure public func signMessage(message: Data) throws -> String { let prefix = "\u{19}Ethereum Signed Message:\n\(String(message.count))" guard var data = prefix.data(using: .ascii) else { @@ -125,7 +172,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { return signed.web3.hexString } - /// signing TypedData + /// Signs using provided structured typed message (EIP712) + /// + /// - Parameters: + /// - message : message to be used for signing + /// + /// - Returns: `String` + /// + /// - Throws: On signing failure public func signMessage(message: TypedData) throws -> String { let hash = try message.signableHash() @@ -144,7 +198,14 @@ public final class EthereumTssAccount: EthereumAccountProtocol { return signed.web3.hexString } - /// Signing EthereumTransaction + /// Signs an ethereum transaction + /// + /// - Parameters: + /// - transaction : Transaction to be signed + /// + /// - Returns: `SignedTransaction` + /// + /// - Throws: On signing failure public func sign(transaction: EthereumTransaction) throws -> SignedTransaction { guard let raw = transaction.raw else { throw EthereumSignerError.emptyRawTransaction diff --git a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift index 7b8868d..21837c8 100644 --- a/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift +++ b/Sources/Web3SwiftMpcProvider/TorusWeb3Utils.swift @@ -14,7 +14,14 @@ public final class TorusWeb3Utils { private static let etherInWei = pow(Double(10), 18) private static let etherInGwei = pow(Double(10), 9) - /// Convert Wei(BInt) unit to Ether(Decimal) unit + /// Converts Wei to Ether + /// + /// - Parameters: + /// - wei : Amount of Wei + /// + /// - Returns: `Ether` + /// + /// - Throws: On conversion failure public static func toEther(wei: Wei) throws -> Ether { guard let decimalWei = Double(wei.description) else { throw TorusWeb3UtilsError.conversionError @@ -22,6 +29,14 @@ public final class TorusWeb3Utils { return decimalWei / etherInWei } + /// Converts Gwei to Ether + /// + /// - Parameters: + /// - gwei : Amount of gwei + /// + /// - Returns: `Ether` + /// + /// - Throws: On conversion failure public static func toEther(gwei: BigUInt) throws -> Ether { guard let decimalWei = Double(gwei.description) else { throw TorusWeb3UtilsError.conversionError @@ -29,13 +44,25 @@ public final class TorusWeb3Utils { return decimalWei / etherInGwei } - /// Convert Ether(Decimal) unit to Wei(BInt) unit + /// Converts Ether to Wei + /// + /// - Parameters: + /// - ether : Amount of Ether + /// + /// - Returns: `Wei` public static func toWei(ether: Ether) -> Wei { let wei = Wei(ether * etherInWei) return wei } - /// Convert Ether(String) unit to Wei(BInt) unit + /// Converts Ether to Wei + /// + /// - Parameters: + /// - ether : Amount of Ether in string format + /// + /// - Returns: `Wei` + /// + /// - Throws: On conversion failure public static func toWei(ether: String) throws -> Wei { guard let decimalEther = Double(ether) else { throw TorusWeb3UtilsError.conversionError @@ -43,7 +70,14 @@ public final class TorusWeb3Utils { return toWei(ether: decimalEther) } - // Only used for calcurating gas price and gas limit. + /// Converts Gwei to Wei for calculating gas prive and gas limit + /// + /// - Parameters: + /// - gwei : Amount of Gwei + /// + /// - Returns: `Wei` + /// + /// - Throws: On conversion failure public static func toWei(gwei: Double) -> Wei { return Wei(gwei * 1000000000) } diff --git a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift index 0b5c14d..efd6fd7 100644 --- a/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift +++ b/Tests/Web3SwiftMpcProviderTests/MpcProviderTests.swift @@ -5,72 +5,72 @@ import XCTest final class Web3SwiftMpcProviderTests: XCTestCase { let example1 = """ - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person" - }, - { - "name": "contents", - "type": "string" - } - ] + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + { + "name": "version", + "type": "string" }, - "message": { - "from": { - "name": "Account", - "wallet": "0x048975d4997d7578a3419851639c10318db430b6" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" } - } - """.data(using: .utf8)! - + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Account", + "wallet": "0x048975d4997d7578a3419851639c10318db430b6" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } + """.data(using: .utf8)! + let fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e" let factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0" let tssNonce = 0 @@ -81,13 +81,13 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let verifierId = "hqjang95@gmail.com" let tssEndpoints = ["https://sapphire-1.auth.network/tss", "https://sapphire-2.auth.network/tss", "https://sapphire-3.auth.network/tss", "https://sapphire-4.auth.network/tss", "https://sapphire-5.auth.network/tss"] let sigs = ["{\"sig\":\"16de7c5812aedf492e7afe4a9c0607dba6d8d908d30ef1eb2e4761bc300bb3fc62bfbd0e94b03aa5eb496b5ed7adfa4203fa9745d90673cf789d3a989f872ae41b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"50a7451f2a8af5f3e193b3e53768e3107f8d606ef5e9ee70aba15fba8e67a1be279d71f8d3b6a954beef5e5119a10195c3017e48b3f0a93b557ed9366ce38f171c\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}", "{\"sig\":\"d94979a0f743a8a41630167622c5b443b148f231bb2293e60a17ab4ea7ebdf38713b81b0bc9161ecd3949ddcf8cfca9734f136ba02c2e4e670fb4b8523299ab01b\",\"data\":\"eyJleHAiOjE2OTM0NjYxMTAsInRlbXBfa2V5X3giOiI2MTg3NTM3ZTc1YThhNWQ3NWQzZjhkMGZmYzE4NjMwNTRjYjEzNmE3YzRjYWVjNWRkYjUyZjViNmY1MTcyZDEwIiwidGVtcF9rZXlfeSI6ImFhNTNhNmE2N2YzOTE1NzNmYTA1YTVkZWViZjM2MDVkM2MzODljNjhjMDhlOGI5YzllNDQyODU1ZWYyYWE2ZTkiLCJ2ZXJpZmllcl9uYW1lIjoiZ29vZ2xlLWxyYyIsInZlcmlmaWVyX2lkIjoiaHFqYW5nOTVAZ21haWwuY29tIiwic2NvcGUiOiIifQ==\"}"] - + let decoder = JSONDecoder() - + func testSigningMessage() throws { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - let account = try EthereumTssAccount(params: params) + let account = EthereumTssAccount(params: params) let msg = "hello world" let _ = try account.sign(message: msg) @@ -95,7 +95,7 @@ final class Web3SwiftMpcProviderTests: XCTestCase { func testSigningTransaction() throws { let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - let tssAccount = try EthereumTssAccount(params: params) + let tssAccount = EthereumTssAccount(params: params) let chainID = 5 let amount = 0.001 let toAddress = tssAccount.address @@ -110,11 +110,11 @@ final class Web3SwiftMpcProviderTests: XCTestCase { let transaction = EthereumTransaction(from: fromAddress, to: toAddress, value: amtInGwie, data: Data(), nonce: nonce + 1, gasPrice: totalGas, gasLimit: gasLimit, chainId: chainID) let _ = try tssAccount.sign(transaction: transaction) } - + func testSignTyped() throws { - let typedData = try! decoder.decode(TypedData.self, from: example1) + let typedData = try decoder.decode(TypedData.self, from: example1) let params = EthTssAccountParams(publicKey: fullAddress, factorKey: factorKey, tssNonce: Int32(tssNonce), tssShare: tssShare, tssIndex: tssIndex, selectedTag: selected_tag, verifier: verifier, verifierID: verifierId, nodeIndexes: [], tssEndpoints: tssEndpoints, authSigs: sigs) - let tssAccount = try EthereumTssAccount(params: params) + let tssAccount = EthereumTssAccount(params: params) let _ = try tssAccount.signMessage(message: typedData) } }