How to make my Unity project deterministic for replays?

I am working on an arcade-style 2D shmup and recently started implementing a replay system that allows players to view their runs of the game.

I use the technique of recording input each FixedUpdate() and rerunning the game as a simulation, reading the saved input each frame and processing it in the core game loop as if it was real-time input from the player.

This requires an extremely deterministic game, and in order to get perfectly synced movement and scoring in the replay, I have had to shift to a paradigm of using exclusively FixedUpdate() and Time.fixedDeltaTime.

I don’t mind this, as I now have 100% reliable replays with no desyncing.

My question concerns whether some of the techniques I used to port my game to the deterministic FixedUpdate paradigm are problematic, or if there are better ways to achieve the same effect.

For example, previously I relied heavily on coroutines yielding using WaitForSeconds(). This method is underpinned by normal Update() loop and so introduced indeterminism into the game leading to desyncs.

To fix it, I still use coroutines, but any time I need to wait, I do it by waiting for n number of calls of FixedUpdate(). For example,

for (int i = 0; i < 60; i ++) {     yield return new WaitForFixedUpdate(); } 

This seems to be working just fine to keep the game deterministic, but I wonder if there’s a more straightforward way, or if there are potential issues this type of technique might cause?

In general, are there any other techniques or pitfalls I need to be aware of to keep my game deterministic enough for perfectly synced replays?