"lxc storage volume attach" is effectively just as shortcut for "lxc config device add", at the API level they are identical.
ZFS is a bit special in that it allows a "source path" to be some fancy string "POOL/DATASET" which isn't the case for any of the other Linux filesystems. So if you tell LXD that you want "POOL/DATASET" mounted to some path in the container, LXD will tell the kernel to do that, which will fail because the source path doesn't actually exist.
You can workaround that by using raw.lxc and tell liblxc exactly what you want, including the filesystem, which should get you around this particular problem.
lxc config set <container name> raw.lxc "lxc.mount.entry=POOL/DATASET some/path/in/the/container zfs defaults 0 0"
You are however pretty likely to then hit another ZFS issue which is that ZFS very much doesn't understand mount namespaces and containers. So if the dataset is mounted anywhere on the host, ZFS will refuse to have it mounted in the container. Similarly, if it's not mounted on the host and you attach it to the container, you'll then be unable to mount it on the host.
Even more annoyingly, the mount namespace cleanup code can take a long time. So when rebooting the container, it may be that the filesystem remains mounted in a dead mount namespace, preventing anyone from mounting it for serveral minutes/hours.
Also note that even if all of this is fine and you decide to use that raw.lxc trick. You'll still need to manually do the initial uid/gid mapping on the host as there's no kernel magic there to have it map those uids/gids based on where it's mounted.