From 9dc6cb227ebebfb0b4cfd72d13b9f53031346df8 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 14 Nov 2024 07:36:15 -0800 Subject: [PATCH 1/4] Revert "Dual Send 1to1 Conversations in V3 (#414)" This reverts commit 1bb951dfac56fa395bbce2ed59cb4936e4aeaf2e. --- Sources/XMTPiOS/ConversationV1.swift | 12 +----- Sources/XMTPiOS/ConversationV2.swift | 12 +----- Sources/XMTPiOS/Conversations.swift | 44 +++++++++++++++++---- Sources/XMTPiOS/PreparedMessage.swift | 3 +- Tests/XMTPTests/GroupTests.swift | 57 --------------------------- XMTP.podspec | 2 +- 6 files changed, 41 insertions(+), 89 deletions(-) diff --git a/Sources/XMTPiOS/ConversationV1.swift b/Sources/XMTPiOS/ConversationV1.swift index aa6960c0..ed2c395a 100644 --- a/Sources/XMTPiOS/ConversationV1.swift +++ b/Sources/XMTPiOS/ConversationV1.swift @@ -88,7 +88,7 @@ public struct ConversationV1 { await client.contacts.markIntroduced(peerAddress, true) } - return PreparedMessage(envelopes: envelopes, encodedContent: encodedContent) + return PreparedMessage(envelopes: envelopes) } func prepareMessage(content: T, options: SendOptions?) async throws -> PreparedMessage { @@ -139,16 +139,6 @@ public struct ConversationV1 { } @discardableResult func send(prepared: PreparedMessage) async throws -> String { - if (client.v3Client != nil) { - do { - let dm = try await client.conversations.findOrCreateDm(with: peerAddress) - if let encodedContent = prepared.encodedContent { - try await dm.send(encodedContent: encodedContent) - } - } catch { - print("ConversationV1 send \(error)") - } - } try await client.publish(envelopes: prepared.envelopes) if((try await client.contacts.consentList.state(address: peerAddress)) == .unknown) { try await client.contacts.allow(addresses: [peerAddress]) diff --git a/Sources/XMTPiOS/ConversationV2.swift b/Sources/XMTPiOS/ConversationV2.swift index d119e1ea..e898a485 100644 --- a/Sources/XMTPiOS/ConversationV2.swift +++ b/Sources/XMTPiOS/ConversationV2.swift @@ -96,7 +96,7 @@ public struct ConversationV2 { let topic = options?.ephemeral == true ? ephemeralTopic : topic let envelope = Envelope(topic: topic, timestamp: Date(), message: try Message(v2: message).serializedData()) - return PreparedMessage(envelopes: [envelope], encodedContent: encodedContent) + return PreparedMessage(envelopes: [envelope]) } func prepareMessage(content: T, options: SendOptions?) async throws -> PreparedMessage { @@ -255,16 +255,6 @@ public struct ConversationV2 { } @discardableResult func send(prepared: PreparedMessage) async throws -> String { - if (client.v3Client != nil) { - do { - let dm = try await client.conversations.findOrCreateDm(with: peerAddress) - if let encodedContent = prepared.encodedContent { - try await dm.send(encodedContent: encodedContent) - } - } catch { - print("ConversationV2 send \(error)") - } - } try await client.publish(envelopes: prepared.envelopes) if((try await client.contacts.consentList.state(address: peerAddress)) == .unknown) { try await client.contacts.allow(addresses: [peerAddress]) diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index d2b0fbe1..1691051c 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -183,6 +183,11 @@ public actor Conversations { public func dms( createdAfter: Date? = nil, createdBefore: Date? = nil, limit: Int? = nil ) async throws -> [Dm] { + if client.hasV2Client { + throw ConversationError.v2NotSupported( + "Only supported with V3 only clients use newConversation instead" + ) + } guard let v3Client = client.v3Client else { return [] } @@ -209,6 +214,11 @@ public actor Conversations { limit: Int? = nil, order: ConversationOrder = .createdAt, consentState: ConsentState? = nil ) async throws -> [Conversation] { + if client.hasV2Client { + throw ConversationError.v2NotSupported( + "Only supported with V3 only clients use list instead") + } + // Todo: add ability to order and consent state guard let v3Client = client.v3Client else { return [] } @@ -340,6 +350,13 @@ public actor Conversations { Conversation, Error > { AsyncThrowingStream { continuation in + if client.hasV2Client { + continuation.finish( + throwing: ConversationError.v2NotSupported( + "Only supported with V3 only clients use stream instead" + )) + return + } let ffiStreamActor = FfiStreamActor() let task = Task { let stream = await self.client.v3Client?.conversations().stream( @@ -388,6 +405,12 @@ public actor Conversations { } public func findOrCreateDm(with peerAddress: String) async throws -> Dm { + if client.hasV2Client { + throw ConversationError.v2NotSupported( + "Only supported with V3 only clients use newConversation instead" + ) + } + guard let v3Client = client.v3Client else { throw GroupError.alphaMLSNotEnabled } @@ -514,6 +537,13 @@ public actor Conversations { DecodedMessage, Error > { AsyncThrowingStream { continuation in + if client.hasV2Client { + continuation.finish( + throwing: ConversationError.v2NotSupported( + "Only supported with V3 clients. Use streamAllMessages instead." + )) + return + } let ffiStreamActor = FfiStreamActor() let task = Task { let stream = await self.client.v3Client?.conversations() @@ -553,6 +583,13 @@ public actor Conversations { DecryptedMessage, Error > { AsyncThrowingStream { continuation in + if client.hasV2Client { + continuation.finish( + throwing: ConversationError.v2NotSupported( + "Only supported with V3 clients. Use streamAllMessages instead." + )) + return + } let ffiStreamActor = FfiStreamActor() let task = Task { let stream = await self.client.v3Client?.conversations() @@ -816,13 +853,6 @@ public actor Conversations { Task { await self.addConversation(conversation) } - if client.v3Client != nil { - do { - try await client.conversations.findOrCreateDm(with: peerAddress) - } catch { - print("newConversation \(error)") - } - } return conversation } diff --git a/Sources/XMTPiOS/PreparedMessage.swift b/Sources/XMTPiOS/PreparedMessage.swift index 721d0bfd..f44ced6e 100644 --- a/Sources/XMTPiOS/PreparedMessage.swift +++ b/Sources/XMTPiOS/PreparedMessage.swift @@ -13,12 +13,11 @@ public struct PreparedMessage { // Any more are for required intros/invites etc. // A client can just publish these when it has connectivity. public let envelopes: [Envelope] - public let encodedContent: EncodedContent? // Note: we serialize as a PublishRequest as a convenient `envelopes` wrapper. public static func fromSerializedData(_ serializedData: Data) throws -> PreparedMessage { let req = try Xmtp_MessageApi_V1_PublishRequest(serializedData: serializedData) - return PreparedMessage(envelopes: req.envelopes, encodedContent: nil) + return PreparedMessage(envelopes: req.envelopes) } // Note: we serialize as a PublishRequest as a convenient `envelopes` wrapper. diff --git a/Tests/XMTPTests/GroupTests.swift b/Tests/XMTPTests/GroupTests.swift index 0a392e4e..80945344 100644 --- a/Tests/XMTPTests/GroupTests.swift +++ b/Tests/XMTPTests/GroupTests.swift @@ -87,63 +87,6 @@ class GroupTests: XCTestCase { davonV3Client: davonV3Client ) } - - func testCanDualSendConversations() async throws { - let fixtures = try await localFixtures() - let v2Convo = try await fixtures.aliceClient.conversations.newConversation(with: fixtures.bob.walletAddress) - - try await fixtures.aliceClient.conversations.sync() - try await fixtures.bobClient.conversations.sync() - - let alixDm = try await fixtures.aliceClient.findDm(address: fixtures.bob.walletAddress) - let boDm = try await fixtures.bobClient.findDm(address: fixtures.alice.walletAddress) - - XCTAssertEqual(alixDm?.id, boDm?.id) - - let alixConversationsListCount = try await fixtures.aliceClient.conversations.list().count - XCTAssertEqual(alixConversationsListCount, 1) - - let alixDmsListCount = try await fixtures.aliceClient.conversations.dms().count - XCTAssertEqual(alixDmsListCount, 1) - - let boDmsListCount = try await fixtures.bobClient.conversations.dms().count - XCTAssertEqual(boDmsListCount, 1) - - let boConversationsListCount = try await fixtures.bobClient.conversations.list().count - XCTAssertEqual(boConversationsListCount, 1) - - let boFirstTopic = try await fixtures.bobClient.conversations.list().first?.topic - XCTAssertEqual(v2Convo.topic, boFirstTopic) - } - - func testCanDualSendMessages() async throws { - let fixtures = try await localFixtures() - let alixV2Convo = try await fixtures.aliceClient.conversations.newConversation(with: fixtures.bob.walletAddress) - let boV2Convo = try await fixtures.bobClient.conversations.list().first! - - try await fixtures.bobClient.conversations.sync() - - let alixDm = try await fixtures.aliceClient.findDm(address: fixtures.bob.walletAddress) - let boDm = try await fixtures.bobClient.findDm(address: fixtures.alice.walletAddress) - - try await alixV2Convo.send(content: "first") - try await boV2Convo.send(content: "second") - - try await alixDm?.sync() - try await boDm?.sync() - - let alixV2ConvoMessageCount = try await alixV2Convo.messages().count - XCTAssertEqual(alixV2ConvoMessageCount, 2) - - let boV2ConvoMessageCount = try await boV2Convo.messages().count - XCTAssertEqual(alixV2ConvoMessageCount, boV2ConvoMessageCount) - - let boDmMessageCount = try await boDm?.messages().count - XCTAssertEqual(boDmMessageCount, 2) - - let alixDmMessageCount = try await alixDm?.messages().count - XCTAssertEqual(alixDmMessageCount, 3) // Including the group membership update in the DM - } func testCanCreateAGroupWithDefaultPermissions() async throws { let fixtures = try await localFixtures() diff --git a/XMTP.podspec b/XMTP.podspec index c5f17f92..e95d7f7c 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.16.2" + spec.version = "0.16.1" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From a2bad89f26030d892f17fa7ed1cdef68006be467 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 14 Nov 2024 21:04:29 -0800 Subject: [PATCH 2/4] update legacy branch to fork fix --- Package.swift | 2 +- Sources/XMTPiOS/ApiClient.swift | 2 ++ Sources/XMTPiOS/Client.swift | 14 +++++++------- Sources/XMTPiOS/Conversations.swift | 7 +++---- Sources/XMTPiOS/Extensions/Ffi.swift | 2 +- XMTP.podspec | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Package.swift b/Package.swift index 6b39be7d..2dae8028 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.6.0"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.1"), ], 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/ApiClient.swift b/Sources/XMTPiOS/ApiClient.swift index bc58da9d..4272924b 100644 --- a/Sources/XMTPiOS/ApiClient.swift +++ b/Sources/XMTPiOS/ApiClient.swift @@ -40,6 +40,8 @@ extension GenericErrorDescribing { let .SignatureRequestError(message), let .Erc1271SignatureError(message), let .FailedToConvertToU32(message), + let .Association(message), + let .DeviceSync(message), let .Verifier(message): return message } diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index bbd9cd0a..60549b76 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -180,7 +180,7 @@ public final class Client { inboxId: String ) async throws -> Client { let (libxmtpClient, dbPath) = try await initV3Client( - accountAddress: accountAddress, + accountAddress: accountAddress.lowercased(), options: options, privateKeyBundleV1: nil, signingKey: signingKey, @@ -192,7 +192,7 @@ public final class Client { } let client = try Client( - address: accountAddress, + address: accountAddress.lowercased(), v3Client: v3Client, dbPath: dbPath, installationID: v3Client.installationId().toHex, @@ -307,7 +307,7 @@ public final class Client { message: signatureRequest.signatureText()) try await signatureRequest.addScwSignature( signatureBytes: signedData, - address: signingKey.address, + address: signingKey.address.lowercased(), chainId: UInt64(chainId), blockNumber: signingKey.blockNumber.flatMap { $0 >= 0 ? UInt64($0) : nil @@ -445,10 +445,10 @@ public final class Client { logger: XMTPLogger(), host: options.api.env.url, isSecure: options.api.env.isSecure == true, - accountAddress: address - ) ?? generateInboxId(accountAddress: address, nonce: 0) + accountAddress: address.lowercased() + ) ?? generateInboxId(accountAddress: address.lowercased(), nonce: 0) } catch { - inboxId = generateInboxId(accountAddress: address, nonce: 0) + inboxId = try generateInboxId(accountAddress: address.lowercased(), nonce: 0) } return inboxId } @@ -882,7 +882,7 @@ public final class Client { guard let client = v3Client else { throw ClientError.noV3Client("Error no V3 client initialized") } - try await client.requestHistorySync() + try await client.sendSyncRequest(kind: .messages) } public func revokeAllOtherInstallations(signingKey: SigningKey) async throws diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 1691051c..6f77f9e8 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -367,15 +367,14 @@ public actor Conversations { } do { let conversationType = - try conversation.groupMetadata() - .conversationType() - if conversationType == "dm" { + try conversation().conversationType() + if conversationType == .dm { continuation.yield( Conversation.dm( conversation.dmFromFFI( client: self.client)) ) - } else if conversationType == "group" { + } else if conversationType == .group { continuation.yield( Conversation.group( conversation.groupFromFFI( diff --git a/Sources/XMTPiOS/Extensions/Ffi.swift b/Sources/XMTPiOS/Extensions/Ffi.swift index 9da6402c..7190ac37 100644 --- a/Sources/XMTPiOS/Extensions/Ffi.swift +++ b/Sources/XMTPiOS/Extensions/Ffi.swift @@ -205,7 +205,7 @@ extension FfiConversation { } func toConversation(client: Client) throws -> Conversation { - if (try groupMetadata().conversationType() == "dm") { + if (try conversationType() == .dm) { return Conversation.dm(self.dmFromFFI(client: client)) } else { return Conversation.group(self.groupFromFFI(client: client)) diff --git a/XMTP.podspec b/XMTP.podspec index ba8f3070..b80eeecd 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.16.3" + spec.version = "0.16.4" 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.6.0' + spec.dependency 'LibXMTP', '= 3.0.1' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c4ca3104..1e1fef94 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" : "91653cdaf999119f99189178867e32dcc53b11e8", - "version" : "0.6.0" + "revision" : "f495d4feaab40a0a6a48c1d5a99585de8107f5d2", + "version" : "3.0.1" } }, { From fb7b2d56ca061fe0596136a367096cfa9adf4c2f Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 15 Nov 2024 07:13:07 -0800 Subject: [PATCH 3/4] fix up the lint --- Sources/XMTPiOS/Conversations.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 6f77f9e8..6af9ab90 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -367,7 +367,7 @@ public actor Conversations { } do { let conversationType = - try conversation().conversationType() + try conversation.conversationType() if conversationType == .dm { continuation.yield( Conversation.dm( From 1a597a5204ba5de2bb242c27964a08604075ac0d Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 15 Nov 2024 07:16:27 -0800 Subject: [PATCH 4/4] fix up a few tests --- Tests/XMTPTests/DmTests.swift | 2 +- Tests/XMTPTests/V3ClientTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/XMTPTests/DmTests.swift b/Tests/XMTPTests/DmTests.swift index 443352b4..3329a838 100644 --- a/Tests/XMTPTests/DmTests.swift +++ b/Tests/XMTPTests/DmTests.swift @@ -130,7 +130,7 @@ class DmTests: XCTestCase { XCTAssertEqual(firstMessage.id, messageId) XCTAssertEqual(firstMessage.deliveryStatus, .published) let messages = try await dm.messages() - XCTAssertEqual(messages.count, 3) + XCTAssertEqual(messages.count, 2) try await fixtures.alixClient.conversations.sync() let sameDm = try await fixtures.alixClient.conversations.dms().last! diff --git a/Tests/XMTPTests/V3ClientTests.swift b/Tests/XMTPTests/V3ClientTests.swift index fe6f8085..d5cfc030 100644 --- a/Tests/XMTPTests/V3ClientTests.swift +++ b/Tests/XMTPTests/V3ClientTests.swift @@ -241,7 +241,7 @@ class V3ClientTests: XCTestCase { XCTAssertEqual(dmMessages.first?.body, "gm") XCTAssertEqual(dmMessages.first?.id, messageId) XCTAssertEqual(dmMessages.first?.deliveryStatus, .published) - XCTAssertEqual(dmMessages.count, 3) + XCTAssertEqual(dmMessages.count, 2) try await fixtures.caroV2V3Client.conversations.sync() let sameDm = try await fixtures.caroV2V3Client.findDm(