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

initial design for automation chain expansion and FG/LN feeds removal #11139

Closed
wants to merge 11 commits into from
Closed
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

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IE
logicA.getMode(),
logicA.getLinkAddress(),
logicA.getLinkNativeFeedAddress(),
logicA.getFastGasFeedAddress(),
logicA.getAutomationForwarderLogic()
)
Chainable(address(logicA))
Expand Down Expand Up @@ -90,10 +89,13 @@ contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IE
upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]);
upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment(
hotVars,
report.cfgs[i],
upkeepTransmitInfo[i].triggerType,
uint32(report.gasLimits[i]),
uint32(report.performDatas[i].length),
report.fastGasWei,
report.l1GasPrice,
report.l1GasCosts[i],
report.fastGas,
report.linkNative,
true
);
Expand Down Expand Up @@ -152,11 +154,13 @@ contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IE

(reimbursement, premium) = _postPerformPayment(
hotVars,
report.l1GasPrice,
report.l1GasCosts[i],
report.performDatas[i].length,
report.upkeepIds[i],
upkeepTransmitInfo[i],
report.fastGasWei,
report.fastGas,
report.linkNative,
numUpkeepsPassedChecks
upkeepTransmitInfo[i]
);
totalPremium += premium;
totalReimbursement += reimbursement;
Expand Down
110 changes: 50 additions & 60 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {

LinkTokenInterface internal immutable i_link;
AggregatorV3Interface internal immutable i_linkNativeFeed;
AggregatorV3Interface internal immutable i_fastGasFeed;
Mode internal immutable i_mode;
address internal immutable i_automationForwarderLogic;

Expand Down Expand Up @@ -341,7 +340,9 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {

/// @dev Report transmitted by OCR to transmit function
struct Report {
uint256 fastGasWei;
uint256[] l1GasCosts; // if we query L1 gas cost for every upkeep from precompiles or chain APIs
uint256 l1GasPrice; // if we use a general l1GasPrice to estimate L1 gas cost
uint256 fastGas;
uint256 linkNative;
uint256[] upkeepIds;
uint256[] gasLimits;
Expand Down Expand Up @@ -446,19 +447,16 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
* @param mode the contract mode of default, Arbitrum, or Optimism
* @param link address of the LINK Token
* @param linkNativeFeed address of the LINK/Native price feed
* @param fastGasFeed address of the Fast Gas price feed
*/
constructor(
Mode mode,
address link,
address linkNativeFeed,
address fastGasFeed,
address automationForwarderLogic
) ConfirmedOwner(msg.sender) {
i_mode = mode;
i_link = LinkTokenInterface(link);
i_linkNativeFeed = AggregatorV3Interface(linkNativeFeed);
i_fastGasFeed = AggregatorV3Interface(fastGasFeed);
i_automationForwarderLogic = automationForwarderLogic;
}

Expand Down Expand Up @@ -522,24 +520,15 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
}

/**
* @dev retrieves feed data for fast gas/native and link/native prices. if the feed
* data is stale it uses the configured fallback price. Once a price is picked
* for gas it takes the min of gas price in the transaction or the fast gas
* @dev retrieves feed data link/native prices. if the feed data is stale it uses the configured fallback price.
* Once a price is picked for gas it takes the min of gas price in the transaction or the fast gas
* price in order to reduce costs for the upkeep clients.
*/
function _getFeedData(HotVars memory hotVars) internal view returns (uint256 gasWei, uint256 linkNative) {
function _getFeedData(HotVars memory hotVars) internal view returns (uint256 linkNative) {
uint32 stalenessSeconds = hotVars.stalenessSeconds;
bool staleFallback = stalenessSeconds > 0;
uint256 timestamp;
int256 feedValue;
(, feedValue, , timestamp, ) = i_fastGasFeed.latestRoundData();
if (
feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp)
) {
gasWei = s_fallbackGasPrice;
} else {
gasWei = uint256(feedValue);
}
(, feedValue, , timestamp, ) = i_linkNativeFeed.latestRoundData();
if (
feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp)
Expand All @@ -548,65 +537,57 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
} else {
linkNative = uint256(feedValue);
}
return (gasWei, linkNative);
return linkNative;
}

/**
* @dev calculates LINK paid for gas spent plus a configure premium percentage
* @param gasLimit the amount of gas used
* @param gasOverhead the amount of gas overhead
* @param fastGasWei the fast gas price
* @param linkNative the exchange ratio between LINK and Native token
* @param numBatchedUpkeeps the number of upkeeps in this batch. Used to divide the L1 cost
* @param isExecution if this is triggered by a perform upkeep function
*/
function _calculatePaymentAmount(
HotVars memory hotVars,
uint256 l1GasPrice,
uint256 l1GasCost,
uint256 performDataLength,
uint256 fastGas,
uint256 linkNative,
uint256 gasLimit,
uint256 gasOverhead,
uint256 fastGasWei,
uint256 linkNative,
uint16 numBatchedUpkeeps,
bool isExecution
) internal view returns (uint96, uint96) {
uint256 gasWei = fastGasWei * hotVars.gasCeilingMultiplier;
// since tx.gasprice is from txm, should we remove these logic??
uint256 gasWei = fastGas * hotVars.gasCeilingMultiplier;
// in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier
if (isExecution && tx.gasprice < gasWei) {
if (isExecution && tx.gasprice < gasWei) { // can we remove this?
gasWei = tx.gasprice;
}

uint256 l1CostWei = 0;
if (i_mode == Mode.OPTIMISM) {
bytes memory txCallData = new bytes(0);
if (isExecution) {
txCallData = bytes.concat(msg.data, L1_FEE_DATA_PADDING);
} else {
// fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have
// s_storage.maxPerformDataSize non zero-bytes. Instead of setting bytes to non-zero
// we initialize 'new bytes' of length 4*maxPerformDataSize to cover for zero bytes.
txCallData = new bytes(4 * s_storage.maxPerformDataSize);
}
l1CostWei = OPTIMISM_ORACLE.getL1Fee(txCallData);
} else if (i_mode == Mode.ARBITRUM) {
if (isExecution) {
l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees();
} else {
// fee is 4 per 0 byte, 16 per non-zero byte - we assume all non-zero and
// max data size to calculate max payment
(, uint256 perL1CalldataUnit, , , , ) = ARB_NITRO_ORACLE.getPricesInWei();
l1CostWei = perL1CalldataUnit * s_storage.maxPerformDataSize * 16;
}
uint256 l1CostWei;
if use l1 gas price {
l1CostWei = L1PosterOverhead + scalar * l1GasPrice * (performDataLength + configurable overhead);
} else {
l1CostWei = l1GasCost;
}

// if it's not performing upkeeps, use gas ceiling multiplier to estimate the upper bound
if (!isExecution) {
l1CostWei = hotVars.gasCeilingMultiplier * l1CostWei;
} else {
l1CostWei = l1CostWei;
}
// Divide l1CostWei among all batched upkeeps. Spare change from division is not charged
l1CostWei = l1CostWei / numBatchedUpkeeps;

// this calculation was for splitting the L1 gas cost evenly because the old way of calculation depends on msg.data
// since this transmit function's msg.data is the combined call data of all txs, we have to divide it by number of
// performs in this tx. this evens out L1 gas cost to all performs.
// in the new approach, L1 gas cost is calculated in offchain for individual upkeep, this division is not needed.
// l1CostWei = l1CostWei / numBatchedUpkeeps;

uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / linkNative;
uint256 premium = (((gasWei * gasLimit) + l1CostWei) * 1e9 * hotVars.paymentPremiumPPB) /
linkNative +
// gas-wise, how does this compare to transmitting this value every time?
uint256(hotVars.flatFeeMicroLink) *
1e12;
// LINK_TOTAL_SUPPLY < UINT96_MAX
Expand All @@ -622,18 +603,22 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
Trigger triggerType,
uint32 performGas,
uint32 performDataLength,
uint256 fastGasWei,
uint256 l1GasPrice,
uint256 l1GasCost,
uint256 fastGas,
uint256 linkNative,
bool isExecution // Whether this is an actual perform execution or just a simulation
) internal view returns (uint96) {
uint256 gasOverhead = _getMaxGasOverhead(triggerType, performDataLength, hotVars.f);
(uint96 reimbursement, uint96 premium) = _calculatePaymentAmount(
hotVars,
l1GasPrice,
l1GasCost,
performDataLength,
fastGas,
linkNative,
performGas,
gasOverhead,
fastGasWei,
linkNative,
1, // Consider only 1 upkeep in batch to get maxPayment
isExecution
);

Expand Down Expand Up @@ -718,7 +703,8 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
if (
report.gasLimits.length != expectedLength ||
report.triggers.length != expectedLength ||
report.performDatas.length != expectedLength
report.performDatas.length != expectedLength ||
report.l1GasCosts.length != expectedLength
) {
revert InvalidReport();
}
Expand Down Expand Up @@ -792,7 +778,7 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
function _validateLogTrigger(
uint256 upkeepId,
bytes memory rawTrigger,
UpkeepTransmitInfo memory transmitInfo
UpkeepTransmitInfo memory transmitInfo // not used, remove?
) internal returns (bool, bytes32) {
LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger));
bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex));
Expand Down Expand Up @@ -871,19 +857,23 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
*/
function _postPerformPayment(
HotVars memory hotVars,
uint256 l1GasPrice,
uint256 l1GasCost,
uint256 performDataLength,
uint256 upkeepId,
UpkeepTransmitInfo memory upkeepTransmitInfo,
uint256 fastGasWei,
uint256 fastGas,
uint256 linkNative,
uint16 numBatchedUpkeeps
UpkeepTransmitInfo memory upkeepTransmitInfo
) internal returns (uint96 gasReimbursement, uint96 premium) {
(gasReimbursement, premium) = _calculatePaymentAmount(
hotVars,
l1GasPrice,
l1GasCost,
performDataLength,
fastGas,
upkeepTransmitInfo.gasUsed,
upkeepTransmitInfo.gasOverhead,
fastGasWei,
linkNative,
numBatchedUpkeeps,
true
);

Expand Down
Loading
Loading