Here is a wireframe demo of how the wave/object buoyancy interaction works.
The water reports the surface vertices and a buoyancy script attached to each block finds the nearest water vertex and uses it's height to calculate a buoyancy force. The water itself is just a 42 vertex plane (no collider) whose vertices are edited each frame to give the wave effect. The force added is simply proportional to the difference between the water vertex closest to the object and the object transform.
Now if we include multiple blocks, all receiving their own unique buoyancy calculation based on wave height, we get boat movement that looks pretty good:
I initially wanted to move away from physics and just add some additional part components but I'm now working on some code which builds information about the boat after its constructed that could inform even more realistic buoyancy calculations and further down the road allow the boat to take on water. The first step is to construct a mesh that represents the boats hull and will inform for example how much empty space in the boat is displacing water (which should be contributing more buoyancy). Additionally, I want to know much space is there for water to fill the boat.