VRF subscription cannot be cancelled#
Medium Risk
In VRF.sol there is a cancelSubscription function.
It is used to cancel a subscription of a canvas to VRF. But the code has a bug that prevents the actual subscription from being canceled.
The mapping canvasIdToSubscription[canvasId] is cleared first and after that it calls cancelSubscription on vrfCoordinator.
In the parameters of cancelSubscription it forwards the canvasIdToSubscription[canvasId], which is already cleared and therefore does not match the subscription
that should be canceled.
function cancelSubscription(uint256 canvasId) external {
address admin = ICanvas(canvasAddress).getVRFHelper(canvasId).admin;
if (msg.sender != admin) revert NoPermission();
canvasIdToSubscriptionId[canvasId] = 0;
vrfCoordinator.cancelSubscription(canvasIdToSubscriptionId[canvasId], admin);
ICanvas(canvasAddress).setVrfSubscription(canvasId, 0);
}
Recommendation#
Either cache the subscription ID before deleting it from the mapping and use the cached ID in vrfCoordinator.cancelSubscription, or execute the call first and
delete the subscription ID after.
function cancelSubscription(uint256 canvasId) external {
address admin = ICanvas(canvasAddress).getVRFHelper(canvasId).admin;
if (msg.sender != admin) revert NoPermission();
vrfCoordinator.cancelSubscription(canvasIdToSubscriptionId[canvasId], admin);
delete canvasIdToSubscriptionId[canvasId];
ICanvas(canvasAddress).setVrfSubscription(canvasId, 0);
}