From ede81225aec813acb1061c76ffbb2fcc6b07fea3 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 13 Sep 2024 13:22:24 -0600 Subject: [PATCH 01/25] update package --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index a874b2a3..4d3d866a 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "06e890646a32c3ae9b9ac78150a7ec4971e54c9d", - "version" : "0.5.8-beta3" + "revision" : "abd4f896f539e5bb090c85022177d775ad08dcb1", + "version" : "0.5.8-beta4" } }, { From 2f9cca8b451edf5ee3f2e29958c74550b15bfa39 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 20 Sep 2024 16:38:06 -0600 Subject: [PATCH 02/25] add chain id and SCW check --- Sources/XMTPiOS/SigningKey.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 7eb93eab..4acd7011 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -19,6 +19,12 @@ import LibXMTP public protocol SigningKey { /// A wallet address for this key var address: String { get } + + /// If this signing key is a smart contract wallet + var isSmartContractWallet: Bool { get } + + /// The name of the chainId for example "eip155:1" + var chainId: String { get } /// Sign the data and return a secp256k1 compact recoverable signature. func sign(_ data: Data) async throws -> Signature @@ -29,6 +35,14 @@ public protocol SigningKey { } extension SigningKey { + public var isSmartContractWallet: Bool { + return false + } + + public var chainId: String { + return "eip155:1" + } + func createIdentity(_ identity: PrivateKey, preCreateIdentityCallback: PreEventCallback? = nil) async throws -> AuthorizedIdentity { var slimKey = PublicKey() slimKey.timestamp = UInt64(Date().millisecondsSinceEpoch) From 4e43786498a0ae0fafe945e2f495ea9c3ef83b31 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 20 Sep 2024 16:46:02 -0600 Subject: [PATCH 03/25] add implementation --- Sources/XMTPiOS/Client.swift | 27 ++++++++++++++++++++++++++- Sources/XMTPiOS/SigningKey.swift | 11 +++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index e0da501d..423a1a2c 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -247,7 +247,14 @@ public final class Client { if let signingKey = signingKey { do { let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) - try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) + if signingKey.isSmartContractWallet { + guard isValidAccountID(signingKey.address) else { + throw ClientError.creationError("Account address must conform to CAIP format") + } + try await signatureRequest.addScwSignature(signatureBytes: signedData.rawData, address: signingKey.address, chainId: signingKey.chainId, blockNumber: signingKey.blockNumber) + } else { + try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) + } try await v3Client.registerIdentity(signatureRequest: signatureRequest) } catch { throw ClientError.creationError("Failed to sign the message: \(error.localizedDescription)") @@ -696,4 +703,22 @@ public final class Client { } return InboxState(ffiInboxState: try await client.inboxState(refreshFromNetwork: refreshFromNetwork)) } + + // See for more details https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md + public func isValidAccountID(_ accountAddress: String) -> Bool { + // Define the regular expressions for chain_id and account_address + let chainIDPattern = "[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}" + let accountAddressPattern = "[-.%a-zA-Z0-9]{1,128}" + + // Combine them to match the entire account_id format + let accountIDPattern = "^\(chainIDPattern):\(accountAddressPattern)$" + + let regex = try? NSRegularExpression(pattern: accountIDPattern) + + if let match = regex?.firstMatch(in: accountAddress, options: [], range: NSRange(location: 0, length: accountAddress.utf16.count)) { + return match.range.location != NSNotFound + } else { + return false + } + } } diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 4acd7011..9a2b0cca 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -24,7 +24,10 @@ public protocol SigningKey { var isSmartContractWallet: Bool { get } /// The name of the chainId for example "eip155:1" - var chainId: String { get } + var chainId: UInt64 { get } + + /// The blockNumber of the chain for example "1" + var blockNumber: UInt64 { get } /// Sign the data and return a secp256k1 compact recoverable signature. func sign(_ data: Data) async throws -> Signature @@ -39,7 +42,11 @@ extension SigningKey { return false } - public var chainId: String { + public var chainId: UInt64 { + return "eip155:1" + } + + public var blockNumber: UInt64 { return "eip155:1" } From ede8c2958518e4d3334bf8496345b51b0b378f5e Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 20 Sep 2024 18:15:10 -0600 Subject: [PATCH 04/25] fix a little formatting --- Sources/XMTPiOS/Client.swift | 21 --------------------- Sources/XMTPiOS/SigningKey.swift | 6 +++--- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 423a1a2c..1aadce17 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -248,9 +248,6 @@ public final class Client { do { let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) if signingKey.isSmartContractWallet { - guard isValidAccountID(signingKey.address) else { - throw ClientError.creationError("Account address must conform to CAIP format") - } try await signatureRequest.addScwSignature(signatureBytes: signedData.rawData, address: signingKey.address, chainId: signingKey.chainId, blockNumber: signingKey.blockNumber) } else { try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) @@ -703,22 +700,4 @@ public final class Client { } return InboxState(ffiInboxState: try await client.inboxState(refreshFromNetwork: refreshFromNetwork)) } - - // See for more details https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md - public func isValidAccountID(_ accountAddress: String) -> Bool { - // Define the regular expressions for chain_id and account_address - let chainIDPattern = "[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}" - let accountAddressPattern = "[-.%a-zA-Z0-9]{1,128}" - - // Combine them to match the entire account_id format - let accountIDPattern = "^\(chainIDPattern):\(accountAddressPattern)$" - - let regex = try? NSRegularExpression(pattern: accountIDPattern) - - if let match = regex?.firstMatch(in: accountAddress, options: [], range: NSRange(location: 0, length: accountAddress.utf16.count)) { - return match.range.location != NSNotFound - } else { - return false - } - } } diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 9a2b0cca..2c4a63b1 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -23,7 +23,7 @@ public protocol SigningKey { /// If this signing key is a smart contract wallet var isSmartContractWallet: Bool { get } - /// The name of the chainId for example "eip155:1" + /// The name of the chainId for example "8453" is the chainId for base var chainId: UInt64 { get } /// The blockNumber of the chain for example "1" @@ -43,11 +43,11 @@ extension SigningKey { } public var chainId: UInt64 { - return "eip155:1" + return 8453 } public var blockNumber: UInt64 { - return "eip155:1" + return 0 } func createIdentity(_ identity: PrivateKey, preCreateIdentityCallback: PreEventCallback? = nil) async throws -> AuthorizedIdentity { From fd8ddc1822e15117f32bfdfb1397232eb90f863a Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 20 Sep 2024 18:16:19 -0600 Subject: [PATCH 05/25] change defaults --- Sources/XMTPiOS/SigningKey.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 2c4a63b1..8e40cace 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -23,7 +23,7 @@ public protocol SigningKey { /// If this signing key is a smart contract wallet var isSmartContractWallet: Bool { get } - /// The name of the chainId for example "8453" is the chainId for base + /// The name of the chainId for example "1" var chainId: UInt64 { get } /// The blockNumber of the chain for example "1" @@ -43,11 +43,11 @@ extension SigningKey { } public var chainId: UInt64 { - return 8453 + return 1 } public var blockNumber: UInt64 { - return 0 + return 1 } func createIdentity(_ identity: PrivateKey, preCreateIdentityCallback: PreEventCallback? = nil) async throws -> AuthorizedIdentity { From 65a4aaa7cf1cb09a693f6eb7441f971ffdeb9c55 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 24 Sep 2024 11:22:41 -0600 Subject: [PATCH 06/25] make a test release pod --- XMTP.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XMTP.podspec b/XMTP.podspec index efe9d3b0..3a90780e 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.14.14" + spec.version = "0.15.0-alpha0" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From a3665034445a241ce130ab2c7bf3b712ed60dcfa Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 24 Sep 2024 15:25:51 -0600 Subject: [PATCH 07/25] bump the latest libxmtp --- Package.swift | 2 +- Sources/XMTPiOS/Group.swift | 8 ++++---- XMTP.podspec | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Package.swift b/Package.swift index fe417580..13882418 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.8-beta5"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-alpha0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index a255bd3a..3d43e151 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -112,16 +112,16 @@ public struct Group: Identifiable, Equatable, Hashable { } public var members: [Member] { - get throws { - return try ffiGroup.listMembers().map { ffiGroupMember in + get async throws { + return try await ffiGroup.listMembers().map { ffiGroupMember in Member(ffiGroupMember: ffiGroupMember) } } } public var peerInboxIds: [String] { - get throws { - var ids = try members.map(\.inboxId) + get async throws { + var ids = try await members.map(\.inboxId) if let index = ids.firstIndex(of: client.inboxID) { ids.remove(at: index) } diff --git a/XMTP.podspec b/XMTP.podspec index 3a90780e..3873598a 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.0-alpha0" + spec.version = "0.15.0-alpha1" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.8-beta5' + spec.dependency 'LibXMTP', '= 0.5.9-alpha0' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 73812576..f5d7e620 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "9d5153926ac1bfcab76802d5a7626c2cf47212a4", - "version" : "0.5.8-beta5" + "revision" : "8ebeeaf8ebfe056be0b306910f5128a21795aca9", + "version" : "0.5.9-alpha0" } }, { From a46302b82d3f61c376759e8caa1d1319147fedf2 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 24 Sep 2024 15:37:46 -0600 Subject: [PATCH 08/25] fix up all the async tests --- Sources/XMTPiOS/Conversation.swift | 4 +- Tests/XMTPTests/GroupPermissionsTests.swift | 6 +- Tests/XMTPTests/GroupTests.swift | 62 +++++++++++++-------- Tests/XMTPTests/V3ClientTests.swift | 2 +- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Sources/XMTPiOS/Conversation.swift b/Sources/XMTPiOS/Conversation.swift index ad0f88ba..a7de6f20 100644 --- a/Sources/XMTPiOS/Conversation.swift +++ b/Sources/XMTPiOS/Conversation.swift @@ -83,7 +83,7 @@ public enum Conversation: Sendable { case let .v2(conversationV2): return conversationV2.peerAddress case let .group(group): - return try group.peerInboxIds.joined(separator: ",") + throw GroupError.notSupportedByGroups } } } @@ -96,7 +96,7 @@ public enum Conversation: Sendable { case let .v2(conversationV2): return [conversationV2.peerAddress] case let .group(group): - return try group.peerInboxIds + throw GroupError.notSupportedByGroups } } } diff --git a/Tests/XMTPTests/GroupPermissionsTests.swift b/Tests/XMTPTests/GroupPermissionsTests.swift index d1293a91..8f362d6f 100644 --- a/Tests/XMTPTests/GroupPermissionsTests.swift +++ b/Tests/XMTPTests/GroupPermissionsTests.swift @@ -213,7 +213,7 @@ class GroupPermissionTests: XCTestCase { let aliceGroup = try await fixtures.aliceClient.conversations.groups().first! // Initial checks for group members and their permissions - var members = try bobGroup.members + var members = try await bobGroup.members var admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } var superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } var regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } @@ -227,7 +227,7 @@ class GroupPermissionTests: XCTestCase { try await bobGroup.sync() try await aliceGroup.sync() - members = try bobGroup.members + members = try await bobGroup.members admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } @@ -241,7 +241,7 @@ class GroupPermissionTests: XCTestCase { try await bobGroup.sync() try await aliceGroup.sync() - members = try bobGroup.members + members = try await bobGroup.members admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } diff --git a/Tests/XMTPTests/GroupTests.swift b/Tests/XMTPTests/GroupTests.swift index 7662a614..a255a29b 100644 --- a/Tests/XMTPTests/GroupTests.swift +++ b/Tests/XMTPTests/GroupTests.swift @@ -98,16 +98,20 @@ class GroupTests: XCTestCase { try await aliceGroup.addMembers(addresses: [fixtures.fred.address]) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + let aliceMembers = try await aliceGroup.members.count + let bobMembers = try await bobGroup.members.count + XCTAssertEqual(aliceMembers, 3) + XCTAssertEqual(bobMembers, 3) try await bobGroup.addAdmin(inboxId: fixtures.aliceClient.inboxID) try await aliceGroup.removeMembers(addresses: [fixtures.fred.address]) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + let aliceMembers2 = try await aliceGroup.members.count + let bobMembers2 = try await bobGroup.members.count + XCTAssertEqual(aliceMembers2, 2) + XCTAssertEqual(bobMembers2, 2) try await bobGroup.addMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() @@ -115,8 +119,10 @@ class GroupTests: XCTestCase { try await bobGroup.removeAdmin(inboxId: fixtures.aliceClient.inboxID) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + let aliceMembers3 = try await aliceGroup.members.count + let bobMembers3 = try await bobGroup.members.count + XCTAssertEqual(aliceMembers3, 3) + XCTAssertEqual(bobMembers3, 3) XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .allow) XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .allow) @@ -145,30 +151,38 @@ class GroupTests: XCTestCase { try await bobGroup.addMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + let aliceMembers = try await aliceGroup.members.count + let bobMembers = try await bobGroup.members.count + XCTAssertEqual(aliceMembers, 3) + XCTAssertEqual(bobMembers, 3) await assertThrowsAsyncError( try await aliceGroup.removeMembers(addresses: [fixtures.fred.address]) ) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + let aliceMembers1 = try await aliceGroup.members.count + let bobMembers1 = try await bobGroup.members.count + XCTAssertEqual(aliceMembers1, 3) + XCTAssertEqual(bobMembers1, 3) try await bobGroup.removeMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + let aliceMembers2 = try await aliceGroup.members.count + let bobMembers2 = try await bobGroup.members.count + XCTAssertEqual(aliceMembers2, 2) + XCTAssertEqual(bobMembers2, 2) await assertThrowsAsyncError( try await aliceGroup.addMembers(addresses: [fixtures.fred.address]) ) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + let aliceMembers3 = try await aliceGroup.members.count + let bobMembers3 = try await bobGroup.members.count + XCTAssertEqual(aliceMembers3, 2) + XCTAssertEqual(bobMembers2, 2) XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .admin) XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .admin) @@ -210,7 +224,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() let peerMembers = try Conversation.group(group).peerAddresses.sorted() XCTAssertEqual([fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID].sorted(), members) @@ -224,7 +238,7 @@ class GroupTests: XCTestCase { try await group.addMembers(addresses: [fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -243,7 +257,7 @@ class GroupTests: XCTestCase { try await group.addMembersByInboxId(inboxIds: [fixtures.fredClient.inboxID]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -260,7 +274,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -272,7 +286,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -287,7 +301,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -299,7 +313,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -323,7 +337,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -345,7 +359,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -907,7 +921,7 @@ class GroupTests: XCTestCase { await withThrowingTaskGroup(of: [Member].self) { taskGroup in for group in groups { taskGroup.addTask { - return try group.members + return try await group.members } } } diff --git a/Tests/XMTPTests/V3ClientTests.swift b/Tests/XMTPTests/V3ClientTests.swift index 1cbd5a6e..573e7874 100644 --- a/Tests/XMTPTests/V3ClientTests.swift +++ b/Tests/XMTPTests/V3ClientTests.swift @@ -64,7 +64,7 @@ class V3ClientTests: XCTestCase { func testsCanCreateGroup() async throws { let fixtures = try await localFixtures() let group = try await fixtures.boV3Client.conversations.newGroup(with: [fixtures.caroV2V3.address]) - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([fixtures.caroV2V3Client.inboxID, fixtures.boV3Client.inboxID].sorted(), members) await assertThrowsAsyncError( From 16e2e6d59f4a18115fc9860e232bc0d934b711dd Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 25 Sep 2024 23:22:52 -0600 Subject: [PATCH 09/25] add installation timestamps and async members --- Package.swift | 2 +- Sources/XMTPiOS/Group.swift | 8 +-- Sources/XMTPiOS/Mls/InboxState.swift | 4 +- Sources/XMTPiOS/Mls/Installation.swift | 27 ++++++++ Tests/XMTPTests/ClientTests.swift | 5 +- Tests/XMTPTests/GroupPermissionsTests.swift | 6 +- Tests/XMTPTests/GroupTests.swift | 66 +++++++++++-------- XMTP.podspec | 4 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- 9 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 Sources/XMTPiOS/Mls/Installation.swift diff --git a/Package.swift b/Package.swift index f3431147..078c325f 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.8-beta6"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.8-beta7"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index 05446058..b9ee9d24 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -112,16 +112,16 @@ public struct Group: Identifiable, Equatable, Hashable { } public var members: [Member] { - get throws { - return try ffiGroup.listMembers().map { ffiGroupMember in + get async throws { + return try await ffiGroup.listMembers().map { ffiGroupMember in Member(ffiGroupMember: ffiGroupMember) } } } public var peerInboxIds: [String] { - get throws { - var ids = try members.map(\.inboxId) + get async throws { + var ids = try await members.map(\.inboxId) if let index = ids.firstIndex(of: client.inboxID) { ids.remove(at: index) } diff --git a/Sources/XMTPiOS/Mls/InboxState.swift b/Sources/XMTPiOS/Mls/InboxState.swift index f604f15c..bad69551 100644 --- a/Sources/XMTPiOS/Mls/InboxState.swift +++ b/Sources/XMTPiOS/Mls/InboxState.swift @@ -23,8 +23,8 @@ public struct InboxState { ffiInboxState.accountAddresses } - public var installationIds: [String] { - ffiInboxState.installationIds.map { $0.toHex } + public var installations: [Installation] { + ffiInboxState.installations.map { Installation(ffiInstallation: $0) } } public var recoveryAddress: String { diff --git a/Sources/XMTPiOS/Mls/Installation.swift b/Sources/XMTPiOS/Mls/Installation.swift new file mode 100644 index 00000000..fa237ee0 --- /dev/null +++ b/Sources/XMTPiOS/Mls/Installation.swift @@ -0,0 +1,27 @@ +// +// Installation.swift +// +// +// Created by Naomi Plasterer on 9/25/24. +// + +import Foundation +import LibXMTP + +public struct Installation { + var ffiInstallation: FfiInstallation + + init(ffiInstallation: FfiInstallation) { + self.ffiInstallation = ffiInstallation + } + + public var id: String { + ffiInstallation.id.toHex + } + + var createdAt: Date? { + guard let timestampNs = ffiInstallation.clientTimestampNs else { return nil } + return Date(timeIntervalSince1970: TimeInterval(timestampNs) / 1_000_000_000) + } +} + diff --git a/Tests/XMTPTests/ClientTests.swift b/Tests/XMTPTests/ClientTests.swift index 234e6b7d..40b2495e 100644 --- a/Tests/XMTPTests/ClientTests.swift +++ b/Tests/XMTPTests/ClientTests.swift @@ -506,11 +506,12 @@ class ClientTests: XCTestCase { ) let state = try await alixClient3.inboxState(refreshFromNetwork: true) - XCTAssertEqual(state.installationIds.count, 3) + XCTAssertEqual(state.installations.count, 3) + XCTAssert(state.installations.first?.createdAt != nil) try await alixClient3.revokeAllOtherInstallations(signingKey: alix) let newState = try await alixClient3.inboxState(refreshFromNetwork: true) - XCTAssertEqual(newState.installationIds.count, 1) + XCTAssertEqual(newState.installations.count, 1) } } diff --git a/Tests/XMTPTests/GroupPermissionsTests.swift b/Tests/XMTPTests/GroupPermissionsTests.swift index d1293a91..8f362d6f 100644 --- a/Tests/XMTPTests/GroupPermissionsTests.swift +++ b/Tests/XMTPTests/GroupPermissionsTests.swift @@ -213,7 +213,7 @@ class GroupPermissionTests: XCTestCase { let aliceGroup = try await fixtures.aliceClient.conversations.groups().first! // Initial checks for group members and their permissions - var members = try bobGroup.members + var members = try await bobGroup.members var admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } var superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } var regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } @@ -227,7 +227,7 @@ class GroupPermissionTests: XCTestCase { try await bobGroup.sync() try await aliceGroup.sync() - members = try bobGroup.members + members = try await bobGroup.members admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } @@ -241,7 +241,7 @@ class GroupPermissionTests: XCTestCase { try await bobGroup.sync() try await aliceGroup.sync() - members = try bobGroup.members + members = try await bobGroup.members admins = members.filter { $0.permissionLevel == PermissionLevel.Admin } superAdmins = members.filter { $0.permissionLevel == PermissionLevel.SuperAdmin } regularMembers = members.filter { $0.permissionLevel == PermissionLevel.Member } diff --git a/Tests/XMTPTests/GroupTests.swift b/Tests/XMTPTests/GroupTests.swift index 1d4d25e7..6dfb9c61 100644 --- a/Tests/XMTPTests/GroupTests.swift +++ b/Tests/XMTPTests/GroupTests.swift @@ -98,16 +98,20 @@ class GroupTests: XCTestCase { try await aliceGroup.addMembers(addresses: [fixtures.fred.address]) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + var aliceMembersCount = try await aliceGroup.members.count + var bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 3) + XCTAssertEqual(bobMembersCount, 3) try await bobGroup.addAdmin(inboxId: fixtures.aliceClient.inboxID) try await aliceGroup.removeMembers(addresses: [fixtures.fred.address]) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + aliceMembersCount = try await aliceGroup.members.count + bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 2) + XCTAssertEqual(bobMembersCount, 2) try await bobGroup.addMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() @@ -115,8 +119,10 @@ class GroupTests: XCTestCase { try await bobGroup.removeAdmin(inboxId: fixtures.aliceClient.inboxID) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + aliceMembersCount = try await aliceGroup.members.count + bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 3) + XCTAssertEqual(bobMembersCount, 3) XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .allow) XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .allow) @@ -145,30 +151,38 @@ class GroupTests: XCTestCase { try await bobGroup.addMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + var aliceMembersCount = try await aliceGroup.members.count + var bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 3) + XCTAssertEqual(bobMembersCount, 3) await assertThrowsAsyncError( try await aliceGroup.removeMembers(addresses: [fixtures.fred.address]) ) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 3) - XCTAssertEqual(try bobGroup.members.count, 3) + aliceMembersCount = try await aliceGroup.members.count + bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 3) + XCTAssertEqual(bobMembersCount, 3) try await bobGroup.removeMembers(addresses: [fixtures.fred.address]) try await aliceGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + aliceMembersCount = try await aliceGroup.members.count + bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 2) + XCTAssertEqual(bobMembersCount, 2) await assertThrowsAsyncError( try await aliceGroup.addMembers(addresses: [fixtures.fred.address]) ) try await bobGroup.sync() - XCTAssertEqual(try aliceGroup.members.count, 2) - XCTAssertEqual(try bobGroup.members.count, 2) + aliceMembersCount = try await aliceGroup.members.count + bobMembersCount = try await bobGroup.members.count + XCTAssertEqual(aliceMembersCount, 2) + XCTAssertEqual(bobMembersCount, 2) XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .admin) XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .admin) @@ -210,7 +224,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() let peerMembers = try Conversation.group(group).peerAddresses.sorted() XCTAssertEqual([fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID].sorted(), members) @@ -224,7 +238,7 @@ class GroupTests: XCTestCase { try await group.addMembers(addresses: [fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -243,7 +257,7 @@ class GroupTests: XCTestCase { try await group.addMembersByInboxId(inboxIds: [fixtures.fredClient.inboxID]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -260,7 +274,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -272,7 +286,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -287,7 +301,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -299,7 +313,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -323,7 +337,7 @@ class GroupTests: XCTestCase { let group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address, fixtures.fred.address]) try await group.sync() - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, @@ -345,7 +359,7 @@ class GroupTests: XCTestCase { try await group.sync() - let newMembers = try group.members.map(\.inboxId).sorted() + let newMembers = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([ fixtures.bobClient.inboxID, fixtures.aliceClient.inboxID, @@ -786,7 +800,7 @@ class GroupTests: XCTestCase { try await fixtures.bobClient.contacts.allowInboxes(inboxIds: [fixtures.aliceClient.inboxID]) - var alixMember = try boGroup.members.first(where: { member in member.inboxId == fixtures.aliceClient.inboxID }) + var alixMember = try await boGroup.members.first(where: { member in member.inboxId == fixtures.aliceClient.inboxID }) XCTAssertEqual(alixMember?.consentState, .allowed) isInboxAllowed = try await fixtures.bobClient.contacts.isInboxAllowed(inboxId: fixtures.aliceClient.inboxID) @@ -796,7 +810,7 @@ class GroupTests: XCTestCase { try await fixtures.bobClient.contacts.denyInboxes(inboxIds: [fixtures.aliceClient.inboxID]) - alixMember = try boGroup.members.first(where: { member in member.inboxId == fixtures.aliceClient.inboxID }) + alixMember = try await boGroup.members.first(where: { member in member.inboxId == fixtures.aliceClient.inboxID }) XCTAssertEqual(alixMember?.consentState, .denied) isInboxAllowed = try await fixtures.bobClient.contacts.isInboxAllowed(inboxId: fixtures.aliceClient.inboxID) @@ -941,7 +955,7 @@ class GroupTests: XCTestCase { await withThrowingTaskGroup(of: [Member].self) { taskGroup in for group in groups { taskGroup.addTask { - return try group.members + return try await group.members } } } diff --git a/XMTP.podspec b/XMTP.podspec index 2071549c..a6496c21 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.14.14" + spec.version = "0.14.15" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.8-beta6' + spec.dependency 'LibXMTP', '= 0.5.8-beta7' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b86f6275..60210e9d 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "9398f5516b18044bb94e5d21dabd7a5ddfc25062", - "version" : "0.5.8-beta6" + "revision" : "859333faaddc04128443709182bbcbf41b2209a5", + "version" : "0.5.8-beta7" } }, { From f02d4898b042cf95c4af67b1b50538252eb63abf Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 25 Sep 2024 23:30:54 -0600 Subject: [PATCH 10/25] fix up the tests and bump the pod --- Sources/XMTPiOS/Conversation.swift | 4 ++-- Tests/XMTPTests/V3ClientTests.swift | 6 +++--- XMTP.podspec | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/XMTPiOS/Conversation.swift b/Sources/XMTPiOS/Conversation.swift index 807a5701..737bb1f2 100644 --- a/Sources/XMTPiOS/Conversation.swift +++ b/Sources/XMTPiOS/Conversation.swift @@ -83,7 +83,7 @@ public enum Conversation: Sendable { case let .v2(conversationV2): return conversationV2.peerAddress case let .group(group): - return try group.peerInboxIds.joined(separator: ",") + throw GroupError.notSupportedByGroups } } } @@ -96,7 +96,7 @@ public enum Conversation: Sendable { case let .v2(conversationV2): return [conversationV2.peerAddress] case let .group(group): - return try group.peerInboxIds + throw GroupError.notSupportedByGroups } } } diff --git a/Tests/XMTPTests/V3ClientTests.swift b/Tests/XMTPTests/V3ClientTests.swift index a4ed952d..4cb7d59e 100644 --- a/Tests/XMTPTests/V3ClientTests.swift +++ b/Tests/XMTPTests/V3ClientTests.swift @@ -64,7 +64,7 @@ class V3ClientTests: XCTestCase { func testsCanCreateGroup() async throws { let fixtures = try await localFixtures() let group = try await fixtures.boV3Client.conversations.newGroup(with: [fixtures.caroV2V3.address]) - let members = try group.members.map(\.inboxId).sorted() + let members = try await group.members.map(\.inboxId).sorted() XCTAssertEqual([fixtures.caroV2V3Client.inboxID, fixtures.boV3Client.inboxID].sorted(), members) await assertThrowsAsyncError( @@ -123,7 +123,7 @@ class V3ClientTests: XCTestCase { try await fixtures.boV3Client.contacts.allowInboxes(inboxIds: [fixtures.caroV2V3Client.inboxID]) - var caroMember = try boGroup.members.first(where: { member in member.inboxId == fixtures.caroV2V3Client.inboxID }) + var caroMember = try await boGroup.members.first(where: { member in member.inboxId == fixtures.caroV2V3Client.inboxID }) XCTAssertEqual(caroMember?.consentState, .allowed) isInboxAllowed = try await fixtures.boV3Client.contacts.isInboxAllowed(inboxId: fixtures.caroV2V3Client.inboxID) @@ -136,7 +136,7 @@ class V3ClientTests: XCTestCase { XCTAssert(!isAddressDenied) try await fixtures.boV3Client.contacts.denyInboxes(inboxIds: [fixtures.caroV2V3Client.inboxID]) - caroMember = try boGroup.members.first(where: { member in member.inboxId == fixtures.caroV2V3Client.inboxID }) + caroMember = try await boGroup.members.first(where: { member in member.inboxId == fixtures.caroV2V3Client.inboxID }) XCTAssertEqual(caroMember?.consentState, .denied) isInboxAllowed = try await fixtures.boV3Client.contacts.isInboxAllowed(inboxId: fixtures.caroV2V3Client.inboxID) diff --git a/XMTP.podspec b/XMTP.podspec index a6496c21..8601d828 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.14.15" + spec.version = "0.14.16" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From e246103affdf1865d2af0f919b61113856cd1817 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 26 Sep 2024 08:51:23 -0600 Subject: [PATCH 11/25] bump to the next version --- Package.swift | 2 +- XMTP.podspec | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 13882418..f08b3777 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-alpha0"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-alpha1"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/XMTP.podspec b/XMTP.podspec index 3873598a..bc36b56c 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.9-alpha0' + spec.dependency 'LibXMTP', '= 0.5.9-alpha1' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f5d7e620..7f528946 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "8ebeeaf8ebfe056be0b306910f5128a21795aca9", - "version" : "0.5.9-alpha0" + "revision" : "c51b13046b35229b1a5fabb4f1a395c96ec262f2", + "version" : "0.5.9-alpha1" } }, { From ef8dea9a47aeb59cc2bd9d5a8b99d8cc23e64b00 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 26 Sep 2024 08:53:05 -0600 Subject: [PATCH 12/25] bad merge --- XMTP.podspec | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/XMTP.podspec b/XMTP.podspec index b8fe7480..755b1ba7 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,13 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" -<<<<<<< HEAD - spec.version = "0.15.0-alpha1" -||||||| e7ed584 - spec.version = "0.14.14" -======= - spec.version = "0.14.16" ->>>>>>> 25e45d18b1b962231eb7a7bf469d47bb094b4842 + spec.version = "0.15.0-alpha2" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From 67a88fc56c32d56c773a88884a3667b8ff36d26e Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 2 Oct 2024 14:04:48 -0600 Subject: [PATCH 13/25] update the package --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7f528946..74a34233 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "c51b13046b35229b1a5fabb4f1a395c96ec262f2", - "version" : "0.5.9-alpha1" + "revision" : "156cbd2d5aa09db45f58137a2352ece6b4b186e7", + "version" : "0.5.9-alpha2" } }, { From 929ac8453ecd86deb35f1e4cdda6f035c156776d Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 2 Oct 2024 15:55:23 -0600 Subject: [PATCH 14/25] fix up bad merge --- XMTP.podspec | 1 - 1 file changed, 1 deletion(-) diff --git a/XMTP.podspec b/XMTP.podspec index 2a22e80b..e8d176c1 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -45,5 +45,4 @@ Pod::Spec.new do |spec| spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" spec.dependency 'LibXMTP', '= 0.5.9-alpha2' ->>>>>>> 8197ea4bb2a8a61f1e3b483c0a96f706dba6be34 end From 63b79e1d2300045c4dc9868903e83bea1ddbc948 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 8 Oct 2024 19:52:44 -0700 Subject: [PATCH 15/25] make block number optional --- Sources/XMTPiOS/Client.swift | 6 +++++- Sources/XMTPiOS/SigningKey.swift | 10 +++++----- XMTP.podspec | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 1aadce17..83febe9c 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -248,7 +248,11 @@ public final class Client { do { let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) if signingKey.isSmartContractWallet { - try await signatureRequest.addScwSignature(signatureBytes: signedData.rawData, address: signingKey.address, chainId: signingKey.chainId, blockNumber: signingKey.blockNumber) + try await signatureRequest.addScwSignature(signatureBytes: signedData.rawData, + address: signingKey.address, + chainId: UInt64(signingKey.chainId), + blockNumber: signingKey.blockNumber.flatMap { $0 >= 0 ? UInt64($0) : nil }) + } else { try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) } diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 8e40cace..72ebb0f4 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -24,10 +24,10 @@ public protocol SigningKey { var isSmartContractWallet: Bool { get } /// The name of the chainId for example "1" - var chainId: UInt64 { get } + var chainId: Int64 { get } /// The blockNumber of the chain for example "1" - var blockNumber: UInt64 { get } + var blockNumber: Int64? { get } /// Sign the data and return a secp256k1 compact recoverable signature. func sign(_ data: Data) async throws -> Signature @@ -42,12 +42,12 @@ extension SigningKey { return false } - public var chainId: UInt64 { + public var chainId: Int64 { return 1 } - public var blockNumber: UInt64 { - return 1 + public var blockNumber: Int64? { + return nil } func createIdentity(_ identity: PrivateKey, preCreateIdentityCallback: PreEventCallback? = nil) async throws -> AuthorizedIdentity { diff --git a/XMTP.podspec b/XMTP.podspec index 76198185..ef7c81a7 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.1" + spec.version = "0.15.1-alpha0" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From 402ee51c02b7ee360b43f87297a6a8f9bc5239d0 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 8 Oct 2024 20:49:46 -0700 Subject: [PATCH 16/25] add a test to reproduce the scw error --- Sources/XMTPTestHelpers/TestHelpers.swift | 40 +++++++++++++++++++++++ Tests/XMTPTests/ClientTests.swift | 13 ++++++++ Tests/XMTPTests/V3ClientTests.swift | 14 +++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Sources/XMTPTestHelpers/TestHelpers.swift b/Sources/XMTPTestHelpers/TestHelpers.swift index d9a43f26..addd07d5 100644 --- a/Sources/XMTPTestHelpers/TestHelpers.swift +++ b/Sources/XMTPTestHelpers/TestHelpers.swift @@ -7,6 +7,7 @@ #if canImport(XCTest) import Combine +import CryptoKit import XCTest @testable import XMTPiOS import LibXMTP @@ -67,6 +68,45 @@ public struct FakeWallet: SigningKey { } } +public struct FakeSCWWallet: SigningKey { + public var walletAddress: String + private var internalSignature: String + + public init() throws { + // Simulate a wallet address (could be derived from a hash of some internal data) + self.walletAddress = UUID().uuidString // Using UUID for uniqueness in this fake example + self.internalSignature = Data(repeating: 0x01, count: 64).toHex // Fake internal signature + } + + public var address: String { + walletAddress + } + + public var isSmartContractWallet: Bool { + true + } + + public var chainId: Int64 { + 1 + } + + public static func generate() throws -> FakeSCWWallet { + return try FakeSCWWallet() + } + + public func sign(_ data: Data) async throws -> XMTPiOS.Signature { + let signature = XMTPiOS.Signature.with { + $0.ecdsaCompact.bytes = internalSignature.hexToData + } + return signature + } + + public func sign(message: String) async throws -> XMTPiOS.Signature { + let digest = SHA256.hash(data: message.data(using: .utf8)!) + return try await sign(Data(digest)) + } +} + @available(iOS 15, *) public struct Fixtures { public var alice: PrivateKey! diff --git a/Tests/XMTPTests/ClientTests.swift b/Tests/XMTPTests/ClientTests.swift index 40b2495e..eb687e23 100644 --- a/Tests/XMTPTests/ClientTests.swift +++ b/Tests/XMTPTests/ClientTests.swift @@ -514,4 +514,17 @@ class ClientTests: XCTestCase { let newState = try await alixClient3.inboxState(refreshFromNetwork: true) XCTAssertEqual(newState.installations.count, 1) } + + func testCanCreateASCW() async throws { + let key = try Crypto.secureRandomBytes(count: 32) + let davonSCW = try FakeSCWWallet.generate() + let davonSCWClient = try await Client.createOrBuild( + account: davonSCW, + options: .init( + api: .init(env: .local, isSecure: false), + enableV3: true, + encryptionKey: key + ) + ) + } } diff --git a/Tests/XMTPTests/V3ClientTests.swift b/Tests/XMTPTests/V3ClientTests.swift index 4cb7d59e..9a19b5e0 100644 --- a/Tests/XMTPTests/V3ClientTests.swift +++ b/Tests/XMTPTests/V3ClientTests.swift @@ -5,7 +5,6 @@ // Created by Naomi Plasterer on 9/19/24. // -import CryptoKit import XCTest @testable import XMTPiOS import LibXMTP @@ -18,9 +17,11 @@ class V3ClientTests: XCTestCase { var alixV2: PrivateKey! var boV3: PrivateKey! var caroV2V3: PrivateKey! + var davonSCW: FakeSCWWallet! var alixV2Client: Client! var boV3Client: Client! var caroV2V3Client: Client! + var davonSCWClient: Client! } func localFixtures() async throws -> LocalFixtures { @@ -51,6 +52,17 @@ class V3ClientTests: XCTestCase { ) ) + let davonSCW = try FakeSCWWallet.generate() + let davonSCWClient = try await Client.createOrBuild( + account: davonSCW, + options: .init( + api: .init(env: .local, isSecure: false), + enableV3: true, + encryptionKey: key + ) + ) + + return .init( alixV2: alixV2, boV3: boV3, From d1f509d0ada405b277cebb53f9e29b5de1423965 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 11 Oct 2024 07:56:57 -0700 Subject: [PATCH 17/25] update to latest libxmtp --- Package.swift | 2 +- XMTP.podspec | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index f83b6b7b..8a1e166e 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta1"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta2"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/XMTP.podspec b/XMTP.podspec index ef7c81a7..5f024aeb 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.1-alpha0" + spec.version = "0.15.1-alpha1" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.9-beta1' + spec.dependency 'LibXMTP', '= 0.5.9-beta2' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 321e8126..fc48b889 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "f07383efdee7bed94120dd73efa4ff1c4dcead3c", - "version" : "0.5.9-beta1" + "revision" : "d5d5134ccd177bbad3d74d8ebb6bd2cdd7d2f197", + "version" : "0.5.9-beta2" } }, { From abe6af890b8ea9329de90e76a5cc3878133fd8fe Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 21:35:31 -0700 Subject: [PATCH 18/25] update the signers --- Package.swift | 2 +- Sources/XMTPiOS/Client.swift | 57 ++++++++++++++----- Sources/XMTPiOS/SigningKey.swift | 3 + XMTP.podspec | 4 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Package.swift b/Package.swift index 8a1e166e..8e1f5b49 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta2"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta3"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 83febe9c..a53a06af 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -161,23 +161,26 @@ public final class Client { } } - // This is a V3 only feature - public static func createOrBuild(account: SigningKey, options: ClientOptions) async throws -> Client { - let inboxId = try await getOrCreateInboxId(options: options, address: account.address) - + private static func initializeClient( + accountAddress: String, + options: ClientOptions, + signingKey: SigningKey?, + inboxId: String + ) async throws -> Client { let (libxmtpClient, dbPath) = try await initV3Client( - accountAddress: account.address, + accountAddress: accountAddress, options: options, privateKeyBundleV1: nil, - signingKey: account, + signingKey: signingKey, inboxId: inboxId ) + guard let v3Client = libxmtpClient else { throw ClientError.noV3Client("Error no V3 client initialized") } let client = try Client( - address: account.address, + address: accountAddress, v3Client: v3Client, dbPath: dbPath, installationID: v3Client.installationId().toHex, @@ -185,15 +188,40 @@ public final class Client { environment: options.api.env ) - let conversations = client.conversations - let contacts = client.contacts - - for codec in (options.codecs) { + // Register codecs + for codec in options.codecs { client.register(codec: codec) } + return client } + public static func createV3(account: SigningKey, options: ClientOptions) async throws -> Client { + let accountAddress = if(account.isSmartContractWallet) { "eip155:\(String(describing: account.chainId)):\(account.address.lowercased())" } else { account.address } + + + let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) + + return try await initializeClient( + accountAddress: accountAddress, + options: options, + signingKey: account, + inboxId: inboxId + ) + } + + public static func buildV3(address: String, scwChainId: Int64?, options: ClientOptions) async throws -> Client { + let accountAddress = if(scwChainId != nil) { "eip155:\(String(describing: scwChainId)):\(address.lowercased())" } else { address } + let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) + + return try await initializeClient( + accountAddress: accountAddress, + options: options, + signingKey: nil, + inboxId: inboxId + ) + } + static func initV3Client( accountAddress: String, options: ClientOptions?, @@ -224,7 +252,7 @@ public final class Client { let alias = "xmtp-\(options?.api.env.rawValue ?? "")-\(inboxId).db3" let dbURL = directoryURL.appendingPathComponent(alias).path - var encryptionKey = options?.dbEncryptionKey + let encryptionKey = options?.dbEncryptionKey if (encryptionKey == nil) { throw ClientError.creationError("No encryption key passed for the database. Please store and provide a secure encryption key.") } @@ -246,14 +274,15 @@ public final class Client { if let signatureRequest = v3Client.signatureRequest() { if let signingKey = signingKey { do { - let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) if signingKey.isSmartContractWallet { - try await signatureRequest.addScwSignature(signatureBytes: signedData.rawData, + let signedData = try await signingKey.signSCW(message: signatureRequest.signatureText()) + try await signatureRequest.addScwSignature(signatureBytes: signedData, address: signingKey.address, chainId: UInt64(signingKey.chainId), blockNumber: signingKey.blockNumber.flatMap { $0 >= 0 ? UInt64($0) : nil }) } else { + let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) } try await v3Client.registerIdentity(signatureRequest: signatureRequest) diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 72ebb0f4..4208cba6 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -35,6 +35,9 @@ public protocol SigningKey { /// Pass a personal Ethereum signed message string text to be signed, returning /// a secp256k1 compact recoverable signature. You can use ``Signature.ethPersonalMessage`` to generate this text. func sign(message: String) async throws -> Signature + + /// Pass a personal Ethereum signed message string text to be signed, return bytes to be verified + func signSCW(message: String) async throws -> Data } extension SigningKey { diff --git a/XMTP.podspec b/XMTP.podspec index 5f024aeb..509c5a04 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.1-alpha1" + spec.version = "0.15.1-alpha2" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.9-beta2' + spec.dependency 'LibXMTP', '= 0.5.9-beta3' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fc48b889..4568be0a 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "d5d5134ccd177bbad3d74d8ebb6bd2cdd7d2f197", - "version" : "0.5.9-beta2" + "revision" : "a103132088fb9657b03c25006fe6a6686fa4d082", + "version" : "0.5.9-beta3" } }, { From 2cd20cefa9b87f3c6be87fd69e273431326534df Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 21:46:17 -0700 Subject: [PATCH 19/25] update to the latest libxmtp functions --- Sources/XMTPiOS/Client.swift | 4 ++-- Sources/XMTPiOS/Contacts.swift | 2 +- Sources/XMTPiOS/Conversations.swift | 14 +++++++------- Sources/XMTPiOS/Extensions/Ffi.swift | 6 +++--- Sources/XMTPiOS/Group.swift | 8 ++++---- Sources/XMTPiOS/Mls/Member.swift | 4 ++-- Sources/XMTPiOS/SigningKey.swift | 12 ++++++++++++ Tests/XMTPTests/ClientTests.swift | 22 ++++++++-------------- Tests/XMTPTests/V3ClientTests.swift | 12 +----------- 9 files changed, 40 insertions(+), 44 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index a53a06af..e9039bde 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -210,7 +210,7 @@ public final class Client { ) } - public static func buildV3(address: String, scwChainId: Int64?, options: ClientOptions) async throws -> Client { + public static func buildV3(address: String, scwChainId: Int64? = nil, options: ClientOptions) async throws -> Client { let accountAddress = if(scwChainId != nil) { "eip155:\(String(describing: scwChainId)):\(address.lowercased())" } else { address } let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) @@ -688,7 +688,7 @@ public final class Client { throw ClientError.noV3Client("Error no V3 client initialized") } do { - return Group(ffiGroup: try client.group(groupId: groupId.hexToData), client: self) + return Group(ffiGroup: try client.conversation(conversationId: groupId.hexToData), client: self) } catch { return nil } diff --git a/Sources/XMTPiOS/Contacts.swift b/Sources/XMTPiOS/Contacts.swift index c6c7e6ec..d7963054 100644 --- a/Sources/XMTPiOS/Contacts.swift +++ b/Sources/XMTPiOS/Contacts.swift @@ -248,7 +248,7 @@ public class ConsentList { func groupState(groupId: String) async throws -> ConsentState { if let client = client.v3Client { return try await client.getConsentState( - entityType: .groupId, + entityType: .conversationId, entity: groupId ).fromFFI } diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 91c47095..98dc482b 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -54,7 +54,7 @@ final class GroupStreamCallback: FfiConversationCallback { self.callback = callback } - func onConversation(conversation: FfiGroup) { + func onConversation(conversation: FfiConversation) { self.callback(conversation.fromFFI(client: client)) } } @@ -119,7 +119,7 @@ public actor Conversations { guard let v3Client = client.v3Client else { return 0 } - return try await v3Client.conversations().syncAllGroups() + return try await v3Client.conversations().syncAllConversations() } public func groups(createdAfter: Date? = nil, createdBefore: Date? = nil, limit: Int? = nil) async throws -> [Group] { @@ -136,7 +136,7 @@ public actor Conversations { if let limit { options.limit = Int64(limit) } - return try await v3Client.conversations().list(opts: options).map { $0.fromFFI(client: client) } + return try await v3Client.conversations().listGroups(opts: options).map { $0.fromFFI(client: client) } } public func streamGroups() async throws -> AsyncThrowingStream { @@ -150,7 +150,7 @@ public actor Conversations { } continuation.yield(group) } - guard let stream = await self.client.v3Client?.conversations().stream(callback: groupCallback) else { + guard let stream = await self.client.v3Client?.conversations().streamGroups(callback: groupCallback) else { continuation.finish(throwing: GroupError.streamingFailure) return } @@ -175,7 +175,7 @@ public actor Conversations { AsyncThrowingStream { continuation in let ffiStreamActor = FfiStreamActor() let task = Task { - let stream = await self.client.v3Client?.conversations().stream( + let stream = await self.client.v3Client?.conversations().streamGroups( callback: GroupStreamCallback(client: self.client) { group in guard !Task.isCancelled else { continuation.finish() @@ -435,7 +435,7 @@ public actor Conversations { AsyncThrowingStream { continuation in let ffiStreamActor = FfiStreamActor() let task = Task { - let stream = await self.client.v3Client?.conversations().streamAllMessages( + let stream = await self.client.v3Client?.conversations().streamAllGroupMessages( messageCallback: MessageCallback(client: self.client) { message in guard !Task.isCancelled else { continuation.finish() @@ -500,7 +500,7 @@ public actor Conversations { AsyncThrowingStream { continuation in let ffiStreamActor = FfiStreamActor() let task = Task { - let stream = await self.client.v3Client?.conversations().streamAllMessages( + let stream = await self.client.v3Client?.conversations().streamAllGroupMessages( messageCallback: MessageCallback(client: self.client) { message in guard !Task.isCancelled else { continuation.finish() diff --git a/Sources/XMTPiOS/Extensions/Ffi.swift b/Sources/XMTPiOS/Extensions/Ffi.swift index 23c58f8f..60e6787b 100644 --- a/Sources/XMTPiOS/Extensions/Ffi.swift +++ b/Sources/XMTPiOS/Extensions/Ffi.swift @@ -195,13 +195,13 @@ extension FfiV2SubscribeRequest { // MARK: Group -extension FfiGroup { +extension FfiConversation { func fromFFI(client: Client) -> Group { Group(ffiGroup: self, client: client) } } -extension FfiGroupMember { +extension FfiConversationMember { var fromFFI: Member { Member(ffiGroupMember: self) } @@ -230,7 +230,7 @@ extension FfiConsentState { extension EntryType { var toFFI: FfiConsentEntityType{ switch (self) { - case .group_id: return FfiConsentEntityType.groupId + case .group_id: return FfiConsentEntityType.conversationId case .inbox_id: return FfiConsentEntityType.inboxId case .address: return FfiConsentEntityType.address } diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index b9ee9d24..dfc4a2e1 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -27,7 +27,7 @@ final class StreamHolder { } public struct Group: Identifiable, Equatable, Hashable { - var ffiGroup: FfiGroup + var ffiGroup: FfiConversation var client: Client let streamHolder = StreamHolder() @@ -39,7 +39,7 @@ public struct Group: Identifiable, Equatable, Hashable { Topic.groupMessage(id).description } - func metadata() throws -> FfiGroupMetadata { + func metadata() throws -> FfiConversationMetadata { return try ffiGroup.groupMetadata() } @@ -230,12 +230,12 @@ public struct Group: Identifiable, Equatable, Hashable { } public func processMessage(envelopeBytes: Data) async throws -> DecodedMessage { - let message = try await ffiGroup.processStreamedGroupMessage(envelopeBytes: envelopeBytes) + let message = try await ffiGroup.processStreamedConversationMessage(envelopeBytes: envelopeBytes) return try MessageV3(client: client, ffiMessage: message).decode() } public func processMessageDecrypted(envelopeBytes: Data) async throws -> DecryptedMessage { - let message = try await ffiGroup.processStreamedGroupMessage(envelopeBytes: envelopeBytes) + let message = try await ffiGroup.processStreamedConversationMessage(envelopeBytes: envelopeBytes) return try MessageV3(client: client, ffiMessage: message).decrypt() } diff --git a/Sources/XMTPiOS/Mls/Member.swift b/Sources/XMTPiOS/Mls/Member.swift index 1e0885e3..fcc4a1e4 100644 --- a/Sources/XMTPiOS/Mls/Member.swift +++ b/Sources/XMTPiOS/Mls/Member.swift @@ -13,9 +13,9 @@ public enum PermissionLevel { } public struct Member { - var ffiGroupMember: FfiGroupMember + var ffiGroupMember: FfiConversationMember - init(ffiGroupMember: FfiGroupMember) { + init(ffiGroupMember: FfiConversationMember) { self.ffiGroupMember = ffiGroupMember } diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 4208cba6..20523242 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -74,4 +74,16 @@ extension SigningKey { return AuthorizedIdentity(address: address, authorized: authorized, identity: identity) } + + public func sign(_ data: Data) async throws -> Signature { + throw NSError(domain: "NotImplemented", code: 1, userInfo: [NSLocalizedDescriptionKey: "sign(Data) not implemented."]) + } + + public func sign(message: String) async throws -> Signature { + throw NSError(domain: "NotImplemented", code: 1, userInfo: [NSLocalizedDescriptionKey: "sign(String) not implemented."]) + } + + public func signSCW(message: String) async throws -> Data { + throw NSError(domain: "NotImplemented", code: 1, userInfo: [NSLocalizedDescriptionKey: "signSCW(String) not implemented."]) + } } diff --git a/Tests/XMTPTests/ClientTests.swift b/Tests/XMTPTests/ClientTests.swift index eb687e23..00843749 100644 --- a/Tests/XMTPTests/ClientTests.swift +++ b/Tests/XMTPTests/ClientTests.swift @@ -469,12 +469,19 @@ class ClientTests: XCTestCase { let inboxId = try await Client.getOrCreateInboxId(options: options, address: alix.address) - let alixClient = try await Client.createOrBuild( + let alixClient = try await Client.createV3( account: alix, options: options ) XCTAssertEqual(inboxId, alixClient.inboxID) + + let alixClient2 = try await Client.buildV3( + address: alix.address, + options: options + ) + + XCTAssertEqual(alixClient2.inboxID, alixClient.inboxID) } func testRevokesAllOtherInstallations() async throws { @@ -514,17 +521,4 @@ class ClientTests: XCTestCase { let newState = try await alixClient3.inboxState(refreshFromNetwork: true) XCTAssertEqual(newState.installations.count, 1) } - - func testCanCreateASCW() async throws { - let key = try Crypto.secureRandomBytes(count: 32) - let davonSCW = try FakeSCWWallet.generate() - let davonSCWClient = try await Client.createOrBuild( - account: davonSCW, - options: .init( - api: .init(env: .local, isSecure: false), - enableV3: true, - encryptionKey: key - ) - ) - } } diff --git a/Tests/XMTPTests/V3ClientTests.swift b/Tests/XMTPTests/V3ClientTests.swift index 9a19b5e0..91a70fd8 100644 --- a/Tests/XMTPTests/V3ClientTests.swift +++ b/Tests/XMTPTests/V3ClientTests.swift @@ -34,7 +34,7 @@ class V3ClientTests: XCTestCase { ) ) let boV3 = try PrivateKey.generate() - let boV3Client = try await Client.createOrBuild( + let boV3Client = try await Client.createV3( account: boV3, options: .init( api: .init(env: .local, isSecure: false), @@ -52,16 +52,6 @@ class V3ClientTests: XCTestCase { ) ) - let davonSCW = try FakeSCWWallet.generate() - let davonSCWClient = try await Client.createOrBuild( - account: davonSCW, - options: .init( - api: .init(env: .local, isSecure: false), - enableV3: true, - encryptionKey: key - ) - ) - return .init( alixV2: alixV2, From 2812b8a469897d682e8ab7b6ca35580db9c27d81 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 17 Oct 2024 21:58:35 -0700 Subject: [PATCH 20/25] fix the linter --- Sources/XMTPTestHelpers/TestHelpers.swift | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Sources/XMTPTestHelpers/TestHelpers.swift b/Sources/XMTPTestHelpers/TestHelpers.swift index addd07d5..41a8fa52 100644 --- a/Sources/XMTPTestHelpers/TestHelpers.swift +++ b/Sources/XMTPTestHelpers/TestHelpers.swift @@ -94,16 +94,11 @@ public struct FakeSCWWallet: SigningKey { return try FakeSCWWallet() } - public func sign(_ data: Data) async throws -> XMTPiOS.Signature { - let signature = XMTPiOS.Signature.with { - $0.ecdsaCompact.bytes = internalSignature.hexToData - } - return signature - } - - public func sign(message: String) async throws -> XMTPiOS.Signature { + public func signSCW(message: String) async throws -> Data { + // swiftlint:disable force_unwrapping let digest = SHA256.hash(data: message.data(using: .utf8)!) - return try await sign(Data(digest)) + // swiftlint:enable force_unwrapping + return Data(digest) } } From b03101f0e5d8116921d336a976a71409d31f6065 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 19 Oct 2024 12:33:51 -0700 Subject: [PATCH 21/25] get on a working version --- Package.swift | 2 +- XMTP.podspec | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 8e1f5b49..3a990488 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta3"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.9-beta4"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/XMTP.podspec b/XMTP.podspec index 509c5a04..157446e1 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.1-alpha2" + spec.version = "0.15.2" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.9-beta3' + spec.dependency 'LibXMTP', '= 0.5.9-beta4' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4568be0a..c7bf0b25 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "a103132088fb9657b03c25006fe6a6686fa4d082", - "version" : "0.5.9-beta3" + "revision" : "dad96a78a12fdeeb22e5fea5c2e39d073084b0d7", + "version" : "0.5.9-beta4" } }, { From 263bf64e289b133413183c29933bf59ad24db901 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 19 Oct 2024 12:51:16 -0700 Subject: [PATCH 22/25] check the chain id --- Sources/XMTPiOS/Client.swift | 11 +++++++---- Sources/XMTPiOS/SigningKey.swift | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index e9039bde..f87c0e3f 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -161,7 +161,7 @@ public final class Client { } } - private static func initializeClient( + static func initializeClient( accountAddress: String, options: ClientOptions, signingKey: SigningKey?, @@ -210,8 +210,8 @@ public final class Client { ) } - public static func buildV3(address: String, scwChainId: Int64? = nil, options: ClientOptions) async throws -> Client { - let accountAddress = if(scwChainId != nil) { "eip155:\(String(describing: scwChainId)):\(address.lowercased())" } else { address } + public static func buildV3(address: String, chainId: Int64? = nil, options: ClientOptions) async throws -> Client { + let accountAddress = if(chainId != nil) { "eip155:\(String(describing: chainId)):\(address.lowercased())" } else { address } let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) return try await initializeClient( @@ -275,10 +275,13 @@ public final class Client { if let signingKey = signingKey { do { if signingKey.isSmartContractWallet { + guard let chainId = signingKey.chainId else { + throw ClientError.creationError("Chain id must be present to sign Smart Contract Wallet") + } let signedData = try await signingKey.signSCW(message: signatureRequest.signatureText()) try await signatureRequest.addScwSignature(signatureBytes: signedData, address: signingKey.address, - chainId: UInt64(signingKey.chainId), + chainId: UInt64(chainId), blockNumber: signingKey.blockNumber.flatMap { $0 >= 0 ? UInt64($0) : nil }) } else { diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 20523242..70d29de7 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -45,8 +45,8 @@ extension SigningKey { return false } - public var chainId: Int64 { - return 1 + public var chainId: Int64? { + return nil } public var blockNumber: Int64? { From 14b0cffe3bca9bfd134c08458b269686fc75a121 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 19 Oct 2024 12:54:11 -0700 Subject: [PATCH 23/25] chain id is optional --- Sources/XMTPiOS/Client.swift | 2 -- Sources/XMTPiOS/SigningKey.swift | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index f87c0e3f..d7a6b257 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -198,8 +198,6 @@ public final class Client { public static func createV3(account: SigningKey, options: ClientOptions) async throws -> Client { let accountAddress = if(account.isSmartContractWallet) { "eip155:\(String(describing: account.chainId)):\(account.address.lowercased())" } else { account.address } - - let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) return try await initializeClient( diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index 70d29de7..5c720edf 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -24,7 +24,7 @@ public protocol SigningKey { var isSmartContractWallet: Bool { get } /// The name of the chainId for example "1" - var chainId: Int64 { get } + var chainId: Int64? { get } /// The blockNumber of the chain for example "1" var blockNumber: Int64? { get } From b98637037242867d7046c0f49190ebc38c1b83e4 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sun, 20 Oct 2024 07:03:50 -0700 Subject: [PATCH 24/25] fix the lint issue --- Sources/XMTPiOS/Client.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index d7a6b257..010602d2 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -197,7 +197,9 @@ public final class Client { } public static func createV3(account: SigningKey, options: ClientOptions) async throws -> Client { - let accountAddress = if(account.isSmartContractWallet) { "eip155:\(String(describing: account.chainId)):\(account.address.lowercased())" } else { account.address } + let accountAddress = account.isSmartContractWallet ? + "eip155:\(String(describing: account.chainId)):\(account.address.lowercased())" : + account.address let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) return try await initializeClient( @@ -209,7 +211,9 @@ public final class Client { } public static func buildV3(address: String, chainId: Int64? = nil, options: ClientOptions) async throws -> Client { - let accountAddress = if(chainId != nil) { "eip155:\(String(describing: chainId)):\(address.lowercased())" } else { address } + let accountAddress = chainId != nil ? + "eip155:\(String(describing: chainId)):\(address.lowercased())" : + address let inboxId = try await getOrCreateInboxId(options: options, address: accountAddress) return try await initializeClient( From 87b8b4292061e86b2996679ab49cd5559c440dcf Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sun, 20 Oct 2024 07:04:44 -0700 Subject: [PATCH 25/25] tag --- XMTP.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XMTP.podspec b/XMTP.podspec index 157446e1..ecec0f30 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.15.2" + spec.version = "0.15.2-alpha0" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results.