Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gas overhead per word to wrapper #12669

Merged
merged 10 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tender-crews-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

vrfv2plus - account for num words in coordinator gas overhead in v2plus wrapper
5 changes: 5 additions & 0 deletions contracts/.changeset/new-crews-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

vrfv2plus - account for num words in coordinator gas overhead in v2plus wrapper
4 changes: 2 additions & 2 deletions contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,12 @@ abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, Confirm
* @param randomWords the VRF output expanded to the requested number of words
*/
// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal virtual;

// rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
// proof. rawFulfillRandomness then calls fulfillRandomness, after validating
// the origin of the call
function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {
function rawFulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external {
if (msg.sender != address(s_vrfCoordinator)) {
revert OnlyCoordinatorCanFulfill(msg.sender, address(s_vrfCoordinator));
}
Expand Down
48 changes: 35 additions & 13 deletions contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
// in the pricing for wrapped requests. This includes the gas costs of proof verification and
// payment calculation in the coordinator.
uint32 private s_coordinatorGasOverhead;
uint16 private s_coordinatorGasOverheadPerWord;

// s_fulfillmentFlatFeeLinkPPM is the flat fee in millionths of native that VRFCoordinatorV2
// charges for native payment.
Expand All @@ -119,7 +120,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
// Wrapper has no premium. This premium is for VRFCoordinator.
uint8 private s_coordinatorLinkPremiumPercentage;

// 6 bytes left
// 4 bytes left
/* Storage Slot 5: END */

struct Callback {
Expand Down Expand Up @@ -202,6 +203,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
function setConfig(
uint32 _wrapperGasOverhead,
uint32 _coordinatorGasOverhead,
uint16 _coordinatorGasOverheadPerWord,
uint8 _coordinatorNativePremiumPercentage,
uint8 _coordinatorLinkPremiumPercentage,
bytes32 _keyHash,
Expand All @@ -223,6 +225,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume

s_wrapperGasOverhead = _wrapperGasOverhead;
s_coordinatorGasOverhead = _coordinatorGasOverhead;
s_coordinatorGasOverheadPerWord = _coordinatorGasOverheadPerWord;
s_coordinatorNativePremiumPercentage = _coordinatorNativePremiumPercentage;
s_coordinatorLinkPremiumPercentage = _coordinatorLinkPremiumPercentage;
s_keyHash = _keyHash;
Expand All @@ -238,6 +241,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
emit ConfigSet(
_wrapperGasOverhead,
_coordinatorGasOverhead,
_coordinatorGasOverheadPerWord,
_coordinatorNativePremiumPercentage,
_coordinatorLinkPremiumPercentage,
_keyHash,
Expand Down Expand Up @@ -270,6 +274,9 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
* @return coordinatorGasOverhead reflects the gas overhead of the coordinator's
* fulfillRandomWords function.
*
* @return coordinatorGasOverheadPerWord reflects the gas overhead per word of the coordinator's
* fulfillRandomWords function.
*
* @return wrapperNativePremiumPercentage is the premium ratio in percentage for native payment. For example, a value of 0
* indicates no premium. A value of 15 indicates a 15 percent premium.
*
Expand All @@ -292,6 +299,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
uint32 fulfillmentFlatFeeLinkDiscountPPM,
uint32 wrapperGasOverhead,
uint32 coordinatorGasOverhead,
uint16 coordinatorGasOverheadPerWord,
uint8 wrapperNativePremiumPercentage,
uint8 wrapperLinkPremiumPercentage,
bytes32 keyHash,
Expand All @@ -305,6 +313,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
s_fulfillmentFlatFeeLinkDiscountPPM,
s_wrapperGasOverhead,
s_coordinatorGasOverhead,
s_coordinatorGasOverheadPerWord,
s_coordinatorNativePremiumPercentage,
s_coordinatorLinkPremiumPercentage,
s_keyHash,
Expand All @@ -322,16 +331,18 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
* @param _callbackGasLimit is the gas limit used to estimate the price.
*/
function calculateRequestPrice(
uint32 _callbackGasLimit
uint32 _callbackGasLimit,
uint32 _numWords
) external view override onlyConfiguredNotDisabled returns (uint256) {
(int256 weiPerUnitLink, ) = _getFeedData();
return _calculateRequestPrice(_callbackGasLimit, tx.gasprice, weiPerUnitLink);
return _calculateRequestPrice(_callbackGasLimit, _numWords, tx.gasprice, weiPerUnitLink);
}

function calculateRequestPriceNative(
uint32 _callbackGasLimit
uint32 _callbackGasLimit,
uint32 _numWords
) external view override onlyConfiguredNotDisabled returns (uint256) {
return _calculateRequestPriceNative(_callbackGasLimit, tx.gasprice);
return _calculateRequestPriceNative(_callbackGasLimit, _numWords, tx.gasprice);
}

/**
Expand All @@ -345,28 +356,34 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
*/
function estimateRequestPrice(
uint32 _callbackGasLimit,
uint32 _numWords,
uint256 _requestGasPriceWei
) external view override onlyConfiguredNotDisabled returns (uint256) {
(int256 weiPerUnitLink, ) = _getFeedData();
return _calculateRequestPrice(_callbackGasLimit, _requestGasPriceWei, weiPerUnitLink);
return _calculateRequestPrice(_callbackGasLimit, _numWords, _requestGasPriceWei, weiPerUnitLink);
}

function estimateRequestPriceNative(
uint32 _callbackGasLimit,
uint32 _numWords,
uint256 _requestGasPriceWei
) external view override onlyConfiguredNotDisabled returns (uint256) {
return _calculateRequestPriceNative(_callbackGasLimit, _requestGasPriceWei);
return _calculateRequestPriceNative(_callbackGasLimit, _numWords, _requestGasPriceWei);
}

function _calculateRequestPriceNative(uint256 _gas, uint256 _requestGasPrice) internal view returns (uint256) {
function _calculateRequestPriceNative(
uint256 _gas,
uint32 _numWords,
uint256 _requestGasPrice
) internal view returns (uint256) {
// costWei is the base fee denominated in wei (native)
// (wei/gas) * gas
uint256 wrapperCostWei = _requestGasPrice * s_wrapperGasOverhead;

// coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2.
// (wei/gas) * gas + l1wei
uint256 coordinatorCostWei = _requestGasPrice *
(_gas + s_coordinatorGasOverhead) +
(_gas + _getCoordinatorGasOverhead(_numWords)) +
ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes);

// coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied
Expand All @@ -379,6 +396,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume

function _calculateRequestPrice(
uint256 _gas,
uint32 _numWords,
uint256 _requestGasPrice,
int256 _weiPerUnitLink
) internal view returns (uint256) {
Expand All @@ -389,7 +407,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
// coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2.
// (wei/gas) * gas + l1wei
uint256 coordinatorCostWei = _requestGasPrice *
(_gas + s_coordinatorGasOverhead) +
(_gas + _getCoordinatorGasOverhead(_numWords)) +
ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes);

// coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied
Expand Down Expand Up @@ -427,7 +445,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
checkPaymentMode(extraArgs, true);
uint32 eip150Overhead = _getEIP150Overhead(callbackGasLimit);
(int256 weiPerUnitLink, bool isFeedStale) = _getFeedData();
uint256 price = _calculateRequestPrice(callbackGasLimit, tx.gasprice, weiPerUnitLink);
uint256 price = _calculateRequestPrice(callbackGasLimit, numWords, tx.gasprice, weiPerUnitLink);
// solhint-disable-next-line gas-custom-errors
require(_amount >= price, "fee too low");
// solhint-disable-next-line gas-custom-errors
Expand Down Expand Up @@ -486,7 +504,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
checkPaymentMode(extraArgs, false);

uint32 eip150Overhead = _getEIP150Overhead(_callbackGasLimit);
uint256 price = _calculateRequestPriceNative(_callbackGasLimit, tx.gasprice);
uint256 price = _calculateRequestPriceNative(_callbackGasLimit, _numWords, tx.gasprice);
// solhint-disable-next-line gas-custom-errors
require(msg.value >= price, "fee too low");
// solhint-disable-next-line gas-custom-errors
Expand Down Expand Up @@ -557,7 +575,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
function fulfillRandomWords(uint256 _requestId, uint256[] calldata _randomWords) internal override {
Callback memory callback = s_callbacks[_requestId];
delete s_callbacks[_requestId];

Expand Down Expand Up @@ -603,6 +621,10 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume
return gas / 63 + 1;
}

function _getCoordinatorGasOverhead(uint32 numWords) internal view returns (uint32) {
return s_coordinatorGasOverhead + numWords * s_coordinatorGasOverheadPerWord;
}

/**
* @dev calls target address with exactly gasAmount gas and data as calldata
* or reverts if at least gasAmount gas is not available.
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ abstract contract VRFV2PlusWrapperConsumerBase {
uint32 _numWords,
bytes memory extraArgs
) internal returns (uint256 requestId, uint256 reqPrice) {
reqPrice = i_vrfV2PlusWrapper.calculateRequestPrice(_callbackGasLimit);
reqPrice = i_vrfV2PlusWrapper.calculateRequestPrice(_callbackGasLimit, _numWords);
i_linkToken.transferAndCall(
address(i_vrfV2PlusWrapper),
reqPrice,
Expand All @@ -79,7 +79,7 @@ abstract contract VRFV2PlusWrapperConsumerBase {
uint32 _numWords,
bytes memory extraArgs
) internal returns (uint256 requestId, uint256 requestPrice) {
requestPrice = i_vrfV2PlusWrapper.calculateRequestPriceNative(_callbackGasLimit);
requestPrice = i_vrfV2PlusWrapper.calculateRequestPriceNative(_callbackGasLimit, _numWords);
return (
i_vrfV2PlusWrapper.requestRandomWordsInNative{value: requestPrice}(
_callbackGasLimit,
Expand Down
18 changes: 14 additions & 4 deletions contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface IVRFV2PlusWrapper {
event ConfigSet(
uint32 wrapperGasOverhead,
uint32 coordinatorGasOverhead,
uint16 coordinatorGasOverheadPerWord,
uint8 coordinatorNativePremiumPercentage,
uint8 coordinatorLinkPremiumPercentage,
bytes32 keyHash,
Expand Down Expand Up @@ -35,8 +36,9 @@ interface IVRFV2PlusWrapper {
* @dev simulation. To estimate the price at a specific gas price, use the estimatePrice function.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _numWords is the number of words to request.
*/
function calculateRequestPrice(uint32 _callbackGasLimit) external view returns (uint256);
function calculateRequestPrice(uint32 _callbackGasLimit, uint32 _numWords) external view returns (uint256);

/**
* @notice Calculates the price of a VRF request in native with the given callbackGasLimit at the current
Expand All @@ -46,8 +48,9 @@ interface IVRFV2PlusWrapper {
* @dev simulation. To estimate the price at a specific gas price, use the estimatePrice function.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _numWords is the number of words to request.
*/
function calculateRequestPriceNative(uint32 _callbackGasLimit) external view returns (uint256);
function calculateRequestPriceNative(uint32 _callbackGasLimit, uint32 _numWords) external view returns (uint256);

/**
* @notice Estimates the price of a VRF request with a specific gas limit and gas price.
Expand All @@ -56,9 +59,14 @@ interface IVRFV2PlusWrapper {
* @dev pricing.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _numWords is the number of words to request.
* @param _requestGasPriceWei is the gas price in wei used for the estimation.
*/
function estimateRequestPrice(uint32 _callbackGasLimit, uint256 _requestGasPriceWei) external view returns (uint256);
function estimateRequestPrice(
uint32 _callbackGasLimit,
uint32 _numWords,
uint256 _requestGasPriceWei
) external view returns (uint256);

/**
* @notice Estimates the price of a VRF request in native with a specific gas limit and gas price.
Expand All @@ -67,10 +75,12 @@ interface IVRFV2PlusWrapper {
* @dev pricing.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _numWords is the number of words to request.
* @param _requestGasPriceWei is the gas price in wei used for the estimation.
*/
function estimateRequestPriceNative(
uint32 _callbackGasLimit,
uint32 _numWords,
uint256 _requestGasPriceWei
) external view returns (uint256);

Expand All @@ -85,7 +95,7 @@ interface IVRFV2PlusWrapper {
uint32 _callbackGasLimit,
uint16 _requestConfirmations,
uint32 _numWords,
bytes memory extraArgs
bytes calldata extraArgs
) external payable returns (uint256 requestId);

function link() external view returns (address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract VRFMaliciousConsumerV2Plus is VRFConsumerBaseV2Plus {
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override {
s_gasAvailable = gasleft();
s_randomWords = randomWords;
s_requestId = requestId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus {
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override {
// solhint-disable-next-line gas-custom-errors
require(requestId == s_recentRequestId, "request ID is incorrect");
s_requests[requestId].randomWords = randomWords;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract VRFV2PlusExternalSubOwnerExample is VRFConsumerBaseV2Plus {
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override {
// solhint-disable-next-line gas-custom-errors
require(requestId == s_requestId, "request ID is incorrect");
s_randomWords = randomWords;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus {
constructor(address _vrfCoordinator) VRFConsumerBaseV2Plus(_vrfCoordinator) {}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
function fulfillRandomWords(uint256 _requestId, uint256[] calldata _randomWords) internal override {
s_requests[_requestId].fulfilled = true;
s_requests[_requestId].randomWords = _randomWords;
s_requests[_requestId].fulfilmentTimestamp = block.timestamp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract VRFV2PlusRevertingExample is VRFConsumerBaseV2Plus {
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256, uint256[] memory) internal pure override {
function fulfillRandomWords(uint256, uint256[] calldata) internal pure override {
// solhint-disable-next-line gas-custom-errors, reason-string
revert();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus {
}

// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override {
// solhint-disable-next-line gas-custom-errors
require(requestId == s_requestId, "request ID is incorrect");
s_randomWords = randomWords;
Expand Down
Loading
Loading