You can solve this by creating two additional packages
SalesEvents(OrderPlaced)
BillingEvents(PaymentReceived)
instead of one Events package. It should be clear that the cyclic dependency vanishes here, since SalesEvents and BillingEvents don't reference each other, and Sales as well as Billing both reference SalesEvents and BillingEvents, but not each other.
Now let us compare this solution to the drawbacks you listed:
For example,
SalesandSalesEventsbelong to the same bounded context, so each corresponding Event stays in it'sits context.There is not one "god" package any more which is going to "explode" by getting more and more events with each new microservice.
Additional services can exactly reference the events they require.
so this solves all the three issues.
This is also known as "Interface segregation principle", which can be applied not only to classes, but to packages as well.