example:
You would probably code the 721 smart contract as such (if you’re overriding the OZ implementation or similar)
contract GameAsset is ERC721 {
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal virtual override {
require(_transferLockCheck(from, to, tokenId), "TransferLocked");
super._transfer(from, to, tokenId);
}
function _transferLockCheck(address from, address to, uint256 tokenId) private view returns(bool) {
// DO YOUR GAME CHECKS HERE
}
}
If you were going to implement the function isTransferable(uint tokenId) function, it would point to the same private _transferLockCheck (because, why wouldn’t you)?
And if so, then the token transfer simulation would do exactly the same thing as the transferability check.