diff --git a/protocol/common/message.go b/protocol/common/message.go index ad11e98b7..e77ecd31d 100644 --- a/protocol/common/message.go +++ b/protocol/common/message.go @@ -283,6 +283,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { ContactVerificationState ContactVerificationState `json:"contactVerificationState,omitempty"` DiscordMessage *protobuf.DiscordMessage `json:"discordMessage,omitempty"` BridgeMessage *protobuf.BridgeMessage `json:"bridgeMessage,omitempty"` + PaymentRequests []*protobuf.PaymentRequest `json:"paymentRequests,omitempty"` } item := MessageStructType{ ID: m.ID, @@ -325,6 +326,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { DeletedForMe: m.DeletedForMe, ContactRequestState: m.ContactRequestState, ContactVerificationState: m.ContactVerificationState, + PaymentRequests: m.PaymentRequests, } if sticker := m.GetSticker(); sticker != nil { @@ -370,21 +372,22 @@ func (m *Message) UnmarshalJSON(data []byte) error { type Alias Message aux := struct { *Alias - ResponseTo string `json:"responseTo"` - EnsName string `json:"ensName"` - DisplayName string `json:"displayName"` - ChatID string `json:"chatId"` - Sticker *protobuf.StickerMessage `json:"sticker"` - AudioDurationMs uint64 `json:"audioDurationMs"` - ParsedText json.RawMessage `json:"parsedText"` - ContentType protobuf.ChatMessage_ContentType `json:"contentType"` - AlbumID string `json:"albumId"` - ImageWidth uint32 `json:"imageWidth"` - ImageHeight uint32 `json:"imageHeight"` - AlbumImagesCount uint32 `json:"albumImagesCount"` - From string `json:"from"` - Deleted bool `json:"deleted,omitempty"` - DeletedForMe bool `json:"deletedForMe,omitempty"` + ResponseTo string `json:"responseTo"` + EnsName string `json:"ensName"` + DisplayName string `json:"displayName"` + ChatID string `json:"chatId"` + Sticker *protobuf.StickerMessage `json:"sticker"` + AudioDurationMs uint64 `json:"audioDurationMs"` + ParsedText json.RawMessage `json:"parsedText"` + ContentType protobuf.ChatMessage_ContentType `json:"contentType"` + AlbumID string `json:"albumId"` + ImageWidth uint32 `json:"imageWidth"` + ImageHeight uint32 `json:"imageHeight"` + AlbumImagesCount uint32 `json:"albumImagesCount"` + From string `json:"from"` + PaymentRequestList []*protobuf.PaymentRequest `json:"paymentRequests"` + Deleted bool `json:"deleted,omitempty"` + DeletedForMe bool `json:"deletedForMe,omitempty"` }{ Alias: (*Alias)(m), } @@ -410,6 +413,7 @@ func (m *Message) UnmarshalJSON(data []byte) error { } } + m.PaymentRequests = aux.PaymentRequestList m.ResponseTo = aux.ResponseTo m.EnsName = aux.EnsName m.DisplayName = aux.DisplayName diff --git a/protocol/common/message_test.go b/protocol/common/message_test.go index cce0d707b..e8b779e15 100644 --- a/protocol/common/message_test.go +++ b/protocol/common/message_test.go @@ -640,25 +640,32 @@ func assertMarshalAndUnmarshalJSON[T any](t *testing.T, obj *T, msgAndArgs ...an } func TestMarshalMessageJSON(t *testing.T) { - msg := &Message{ - ID: "1", - From: "0x04c51631b3354242d5a56f044c3b7703bcc001e8c725c4706928b3fac3c2a12ec9019e1e224d487f5c893389405bcec998bc687307f290a569d6a97d24b711bca8", - LinkPreviews: []LinkPreview{ - { - Type: protobuf.UnfurledLink_LINK, - Description: "GitHub is where people build software.", - Hostname: "github.com", - Title: "Build software better, together", - URL: "https://github.com", - Thumbnail: LinkPreviewThumbnail{ - Width: 100, - Height: 200, - URL: "http://localhost:9999", - DataURI: "data:image/png;base64,iVBORw0KGgoAAAANSUg=", - }, + msg := NewMessage() + msg.ID = "1" + msg.From = "0x04c51631b3354242d5a56f044c3b7703bcc001e8c725c4706928b3fac3c2a12ec9019e1e224d487f5c893389405bcec998bc687307f290a569d6a97d24b711bca8" + msg.LinkPreviews = []LinkPreview{ + { + Type: protobuf.UnfurledLink_LINK, + Description: "GitHub is where people build software.", + Hostname: "github.com", + Title: "Build software better, together", + URL: "https://github.com", + Thumbnail: LinkPreviewThumbnail{ + Width: 100, + Height: 200, + URL: "http://localhost:9999", + DataURI: "data:image/png;base64,iVBORw0KGgoAAAANSUg=", }, }, } + msg.PaymentRequests = []*protobuf.PaymentRequest{ + { + Amount: "1000000000000000000", + Receiver: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882", + Symbol: "ETH", + ChainId: 1, + }, + } assertMarshalAndUnmarshalJSON(t, msg, "message ID='%s'", msg.ID) } diff --git a/protocol/message_persistence.go b/protocol/message_persistence.go index a7eed93cd..fe0958f62 100644 --- a/protocol/message_persistence.go +++ b/protocol/message_persistence.go @@ -115,7 +115,8 @@ func (db sqlitePersistence) tableUserMessagesAllFields() string { contact_verification_status, mentioned, replied, - discord_message_id` + discord_message_id, + payment_requests` } // keep the same order as in tableUserMessagesScanAllFields @@ -148,6 +149,7 @@ func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string { m1.links, m1.unfurled_links, m1.unfurled_status_links, + m1.payment_requests, m1.command_id, m1.command_value, m1.command_from, @@ -243,6 +245,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message var serializedLinks []byte var serializedUnfurledLinks []byte var serializedUnfurledStatusLinks []byte + var serializedPaymentRequests []byte var alias sql.NullString var identicon sql.NullString var communityID sql.NullString @@ -303,6 +306,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message &serializedLinks, &serializedUnfurledLinks, &serializedUnfurledStatusLinks, + &serializedPaymentRequests, &command.ID, &command.Value, &command.From, @@ -474,6 +478,13 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message message.UnfurledStatusLinks = &links } + if serializedPaymentRequests != nil { + err := json.Unmarshal(serializedPaymentRequests, &message.PaymentRequests) + if err != nil { + return err + } + } + if attachment.Id != "" { discordMessage.Attachments = append(discordMessage.Attachments, attachment) } @@ -581,6 +592,14 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) } } + var serializedPaymentRequests []byte + if len(message.PaymentRequests) != 0 { + serializedPaymentRequests, err = json.Marshal(message.PaymentRequests) + if err != nil { + return nil, err + } + } + return []interface{}{ message.ID, message.WhisperTimestamp, @@ -638,6 +657,7 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) message.Mentioned, message.Replied, discordMessage.Id, + serializedPaymentRequests, }, nil } diff --git a/protocol/migrations/sqlite/1731902422_payment_requests.up.sql b/protocol/migrations/sqlite/1731902422_payment_requests.up.sql new file mode 100644 index 000000000..0421fd26e --- /dev/null +++ b/protocol/migrations/sqlite/1731902422_payment_requests.up.sql @@ -0,0 +1 @@ +ALTER TABLE user_messages ADD COLUMN payment_requests BLOB; \ No newline at end of file diff --git a/protocol/persistence_test.go b/protocol/persistence_test.go index 6ec300b4d..329418d00 100644 --- a/protocol/persistence_test.go +++ b/protocol/persistence_test.go @@ -2128,3 +2128,45 @@ func TestGetCommunityMemberMessages(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) } + +func TestPaymentRequestMessages(t *testing.T) { + db, err := openTestDB() + require.NoError(t, err) + p := newSQLitePersistence(db) + chatID := testPublicChatID + var messages []*common.Message + + message := common.Message{ + ID: strconv.Itoa(1), + LocalChatID: chatID, + ChatMessage: &protobuf.ChatMessage{ + Clock: uint64(1), + }, + From: testPK, + } + message.PaymentRequests = []*protobuf.PaymentRequest{ + { + Amount: "1.123", + Symbol: "ETH", + Receiver: "0x123", + ChainId: 1, + }, + { + Amount: "1.124", + Symbol: "DAI", + Receiver: "0x124", + ChainId: 11, + }, + } + + messages = append(messages, &message) + + err = p.SaveMessages(messages) + require.NoError(t, err) + + m, _, err := p.MessageByChatID(testPublicChatID, "", 10) + require.NoError(t, err) + require.Len(t, m, 1) + + require.Equal(t, m[0].PaymentRequests, message.PaymentRequests) +} diff --git a/protocol/protobuf/chat_message.proto b/protocol/protobuf/chat_message.proto index 9cbfe303b..f35f89bfa 100644 --- a/protocol/protobuf/chat_message.proto +++ b/protocol/protobuf/chat_message.proto @@ -119,6 +119,13 @@ message BridgeMessage { string parentMessageID = 7; } +message PaymentRequest { + string receiver = 1; + string symbol = 2; + string amount = 3; + uint32 chainId = 4; +} + message UnfurledLinkThumbnail { bytes payload = 1; uint32 width = 2; @@ -234,6 +241,8 @@ message ChatMessage { uint32 customization_color = 19; + repeated PaymentRequest payment_requests = 20; + enum ContentType { UNKNOWN_CONTENT_TYPE = 0; TEXT_PLAIN = 1;