@@ -40,6 +40,13 @@ import {
4040
4141const log = prefixedLogger ( "Discord" ) ;
4242
43+ /**
44+ * Escapes Discord markdown special characters to prevent formatting issues.
45+ * Characters escaped: _ * ~ ` | >
46+ */
47+ const escapeMarkdown = ( text : string ) : string =>
48+ text . replace ( / (?< special > [ _ * ~ ` | > ] ) / g, "\\$<special>" ) ;
49+
4350// Initialize event group manager for Discord
4451const groupConfig = getDefaultEventGroupConfig ( "DISCORD" ) ;
4552const groupManager = new EventGroupManager ( groupConfig ) ;
@@ -99,25 +106,40 @@ const buildOrderEmbed = async (
99106 order_type : string ;
100107 expiration_date : number ;
101108 maker : string ;
102- criteria : { trait : { type : string ; value : string } } ;
109+ criteria : {
110+ trait ?: { type : string ; value : string } ;
111+ traits ?: Array < { type : string ; value : string } > ;
112+ } ;
103113 } ;
104114 const fields : Field [ ] = [ ] ;
105115 let title = "" ;
106- const { quantity, decimals, symbol } = payment ;
107- const inTime = format ( new Date ( expiration_date * MS_PER_SECOND ) ) ;
116+ const { quantity, decimals, symbol } = payment ?? {
117+ quantity : "0" ,
118+ decimals : 18 ,
119+ symbol : "ETH" ,
120+ } ;
121+ const inTime = expiration_date
122+ ? format ( new Date ( expiration_date * MS_PER_SECOND ) )
123+ : "Unknown" ;
108124 if ( order_type === "auction" ) {
109125 title += "Auction:" ;
110126 const price = formatAmount ( quantity , decimals , symbol ) ;
111127 fields . push ( { name : "Starting Price" , value : price } ) ;
112128 fields . push ( { name : "Ends" , value : inTime } ) ;
113129 } else if ( order_type === "trait_offer" ) {
114- const traitType = criteria . trait . type ;
115- const traitValue = criteria . trait . value ;
130+ // Get trait info from criteria - can be in trait or traits array
131+ const traitInfo = criteria ?. trait ?? criteria ?. traits ?. [ 0 ] ;
132+ const traitType = traitInfo ?. type ?? "Unknown" ;
133+ const traitValue = traitInfo ?. value ?? "Unknown" ;
116134 title += `Trait offer: ${ traitType } -> ${ traitValue } ` ;
117135 const price = formatAmount ( quantity , decimals , symbol ) ;
118136 fields . push ( { name : "Price" , value : price } ) ;
119137 fields . push ( { name : "Expires" , value : inTime } ) ;
120- } else if ( order_type === "item_offer" ) {
138+ } else if (
139+ order_type === "item_offer" ||
140+ order_type === "offer" ||
141+ order_type === "criteria_offer"
142+ ) {
121143 title += "Item offer:" ;
122144 const price = formatAmount ( quantity , decimals , symbol ) ;
123145 fields . push ( { name : "Price" , value : price } ) ;
@@ -128,12 +150,15 @@ const buildOrderEmbed = async (
128150 fields . push ( { name : "Price" , value : price } ) ;
129151 fields . push ( { name : "Expires" , value : inTime } ) ;
130152 } else {
153+ // Default to listing
131154 title += "Listed for sale:" ;
132155 const price = formatAmount ( quantity , decimals , symbol ) ;
133156 fields . push ( { name : "Price" , value : price } ) ;
134157 fields . push ( { name : "Expires" , value : inTime } ) ;
135158 }
136- fields . push ( { name : "By" , value : await username ( maker ) } ) ;
159+ if ( maker ) {
160+ fields . push ( { name : "By" , value : escapeMarkdown ( await username ( maker ) ) } ) ;
161+ }
137162 return { title, fields } ;
138163} ;
139164
@@ -148,7 +173,7 @@ const buildSaleEmbed = async (
148173 const { quantity, decimals, symbol } = payment ;
149174 const price = formatAmount ( quantity , decimals , symbol ) ;
150175 fields . push ( { name : "Price" , value : price } ) ;
151- fields . push ( { name : "By" , value : await username ( buyer ) } ) ;
176+ fields . push ( { name : "By" , value : escapeMarkdown ( await username ( buyer ) ) } ) ;
152177 return { title : "Purchased:" , fields } ;
153178} ;
154179
@@ -174,27 +199,48 @@ const buildTransferEmbed = async (
174199 ( event as unknown as { asset ?: { token_standard ?: string } } ) ?. asset
175200 ?. token_standard ;
176201
177- const toName = await username ( to_address ) ;
202+ const toName = escapeMarkdown ( await username ( to_address ) ) ;
178203 const toValue = formatEditionsText ( toName , tokenStandard , quantity ) ;
179204 fields . push ( { name : "To" , value : toValue } ) ;
180205 return { title : "Minted:" , fields } ;
181206 }
182207 if ( kind === "burn" ) {
183- fields . push ( { name : "From" , value : await username ( from_address ) } ) ;
208+ fields . push ( {
209+ name : "From" ,
210+ value : escapeMarkdown ( await username ( from_address ) ) ,
211+ } ) ;
184212 return { title : "Burned:" , fields } ;
185213 }
186- fields . push ( { name : "From" , value : await username ( from_address ) } ) ;
187- fields . push ( { name : "To" , value : await username ( to_address ) } ) ;
214+ fields . push ( {
215+ name : "From" ,
216+ value : escapeMarkdown ( await username ( from_address ) ) ,
217+ } ) ;
218+ fields . push ( {
219+ name : "To" ,
220+ value : escapeMarkdown ( await username ( to_address ) ) ,
221+ } ) ;
188222 return { title : "Transferred:" , fields } ;
189223} ;
190224
191- const isOrderLikeType = ( t : unknown ) : boolean => {
225+ const isOrderLikeType = ( t : unknown , orderType ?: string ) : boolean => {
192226 const s = String ( t ) ;
227+ // Check order_type for "order" events
228+ if ( s === "order" && orderType ) {
229+ return (
230+ orderType === "listing" ||
231+ orderType === "item_offer" ||
232+ orderType === "trait_offer" ||
233+ orderType === "collection_offer" ||
234+ orderType === "auction"
235+ ) ;
236+ }
237+ // Legacy event_type handling
193238 return (
194239 s === BotEvent . listing ||
195240 s === BotEvent . offer ||
196241 s === "trait_offer" ||
197- s === "collection_offer"
242+ s === "collection_offer" ||
243+ s === "listing"
198244 ) ;
199245} ;
200246
@@ -216,7 +262,7 @@ const embed = async (event: AggregatorEvent) => {
216262 }
217263 let fields : Field [ ] = [ ] ;
218264 let title = "" ;
219- if ( isOrderLikeType ( event_type ) ) {
265+ if ( isOrderLikeType ( event_type , order_type ) ) {
220266 ( { title, fields } = await buildOrderEmbed ( event ) ) ;
221267 } else if ( event_type === EventType . sale ) {
222268 ( { title, fields } = await buildSaleEmbed ( event ) ) ;
@@ -310,7 +356,7 @@ const buildGroupEmbed = async (group: GroupedEvent): Promise<EmbedBuilder> => {
310356
311357 if ( actorAddress ) {
312358 const label = getActorLabelForKind ( kind ) ;
313- const actorName = await username ( actorAddress ) ;
359+ const actorName = escapeMarkdown ( await username ( actorAddress ) ) ;
314360 fields . push ( { name : label , value : actorName , inline : true } ) ;
315361 }
316362
0 commit comments