Skip to content

Commit

Permalink
initial design for automation chain expansion and FG/LN feeds removal
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixFan1992 committed Nov 1, 2023
1 parent 9fd1d5d commit c3cd635
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 60 deletions.
8 changes: 4 additions & 4 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ 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.linkNative,
// report.fastGasWei,
// report.linkNative,
true
);
(upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks(
Expand Down Expand Up @@ -152,10 +153,9 @@ contract KeeperRegistry2_1 is KeeperRegistryBase2_1, OCR2Abstract, Chainable, IE

(reimbursement, premium) = _postPerformPayment(
hotVars,
report.cfgs[i],
report.upkeepIds[i],
upkeepTransmitInfo[i],
report.fastGasWei,
report.linkNative,
numUpkeepsPassedChecks
);
totalPremium += premium;
Expand Down
55 changes: 16 additions & 39 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,7 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {

/// @dev Report transmitted by OCR to transmit function
struct Report {
uint256 fastGasWei;
uint256 linkNative;
ChainConfig[] cfgs;
uint256[] upkeepIds;
uint256[] gasLimits;
bytes[] triggers;
Expand Down Expand Up @@ -405,6 +404,12 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
bytes32 blockHash;
}

struct ChainConfig {
uint256 fastGas;
uint256 linkNative;
uint256 l1GasCost; // 0 for L1
}

event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig);
event CancelledUpkeepReport(uint256 indexed id, bytes trigger);
event DedupKeyAdded(bytes32 indexed dedupKey);
Expand Down Expand Up @@ -555,58 +560,34 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
* @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,
ChainConfig memory cfg,
uint256 gasLimit,
uint256 gasOverhead,
uint256 fastGasWei,
uint256 linkNative,
uint16 numBatchedUpkeeps,
bool isExecution
) internal view returns (uint96, uint96) {
uint256 gasWei = fastGasWei * hotVars.gasCeilingMultiplier;
uint256 gasWei = cfg.fastGas * hotVars.gasCeilingMultiplier;
// in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier
if (isExecution && tx.gasprice < gasWei) {
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 = cfg.l1GasCost;
// if it's not performing upkeeps, use gas ceiling multiplier to estimate the upper bound
if (!isExecution) {
l1CostWei = hotVars.gasCeilingMultiplier * l1CostWei;
}
// Divide l1CostWei among all batched upkeeps. Spare change from division is not charged
l1CostWei = l1CostWei / numBatchedUpkeeps;

uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / linkNative;
uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / cfg.linkNative;
uint256 premium = (((gasWei * gasLimit) + l1CostWei) * 1e9 * hotVars.paymentPremiumPPB) /
linkNative +
cfg.linkNative +
uint256(hotVars.flatFeeMicroLink) *
1e12;
// LINK_TOTAL_SUPPLY < UINT96_MAX
Expand All @@ -619,20 +600,18 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
*/
function _getMaxLinkPayment(
HotVars memory hotVars,
ChainConfig memory cfg,
Trigger triggerType,
uint32 performGas,
uint32 performDataLength,
uint256 fastGasWei,
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,
cfg,
performGas,
gasOverhead,
fastGasWei,
linkNative,
1, // Consider only 1 upkeep in batch to get maxPayment
isExecution
);
Expand Down Expand Up @@ -871,18 +850,16 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention {
*/
function _postPerformPayment(
HotVars memory hotVars,
ChainConfig memory cfg,
uint256 upkeepId,
UpkeepTransmitInfo memory upkeepTransmitInfo,
uint256 fastGasWei,
uint256 linkNative,
uint16 numBatchedUpkeeps
) internal returns (uint96 gasReimbursement, uint96 premium) {
(gasReimbursement, premium) = _calculatePaymentAmount(
hotVars,
cfg,
upkeepTransmitInfo.gasUsed,
upkeepTransmitInfo.gasOverhead,
fastGasWei,
linkNative,
numBatchedUpkeeps,
true
);
Expand Down
13 changes: 8 additions & 5 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ contract KeeperRegistryLogicA2_1 is KeeperRegistryBase2_1, Chainable {
*/
function checkUpkeep(
uint256 id,
bytes memory triggerData
bytes memory triggerData,
ChainConfig memory cfg
)
public
cannotExecute
Expand All @@ -72,11 +73,12 @@ contract KeeperRegistryLogicA2_1 is KeeperRegistryBase2_1, Chainable {
(fastGasWei, linkNative) = _getFeedData(hotVars);
uint96 maxLinkPayment = _getMaxLinkPayment(
hotVars,
cfg,
triggerType,
upkeep.performGas,
s_storage.maxPerformDataSize,
fastGasWei,
linkNative,
//fastGasWei,
//linkNative,
false
);
if (upkeep.balance < maxLinkPayment) {
Expand Down Expand Up @@ -144,7 +146,8 @@ contract KeeperRegistryLogicA2_1 is KeeperRegistryBase2_1, Chainable {
* @dev this function may be deprecated in a future version of chainlink automation
*/
function checkUpkeep(
uint256 id
uint256 id,
ChainConfig memory cfg
)
external
returns (
Expand All @@ -157,7 +160,7 @@ contract KeeperRegistryLogicA2_1 is KeeperRegistryBase2_1, Chainable {
uint256 linkNative
)
{
return checkUpkeep(id, bytes(""));
return checkUpkeep(id, bytes(""), cfg);
}

/**
Expand Down
12 changes: 6 additions & 6 deletions contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicB2_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -455,28 +455,28 @@ contract KeeperRegistryLogicB2_1 is KeeperRegistryBase2_1 {
* @notice calculates the minimum balance required for an upkeep to remain eligible
* @param id the upkeep id to calculate minimum balance for
*/
function getMinBalance(uint256 id) external view returns (uint96) {
return getMinBalanceForUpkeep(id);
function getMinBalance(uint256 id, ChainConfig memory cfg) external view returns (uint96) {
return getMinBalanceForUpkeep(id, cfg);
}

/**
* @notice calculates the minimum balance required for an upkeep to remain eligible
* @param id the upkeep id to calculate minimum balance for
* @dev this will be deprecated in a future version in favor of getMinBalance
*/
function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) {
return getMaxPaymentForGas(_getTriggerType(id), s_upkeep[id].performGas);
function getMinBalanceForUpkeep(uint256 id, ChainConfig memory cfg) public view returns (uint96 minBalance) {
return getMaxPaymentForGas(_getTriggerType(id), cfg, s_upkeep[id].performGas);
}

/**
* @notice calculates the maximum payment for a given gas limit
* @param gasLimit the gas to calculate payment for
*/
function getMaxPaymentForGas(Trigger triggerType, uint32 gasLimit) public view returns (uint96 maxPayment) {
function getMaxPaymentForGas(Trigger triggerType, ChainConfig memory cfg, uint32 gasLimit) public view returns (uint96 maxPayment) {
HotVars memory hotVars = s_hotVars;
(uint256 fastGasWei, uint256 linkNative) = _getFeedData(hotVars);
return
_getMaxLinkPayment(hotVars, triggerType, gasLimit, s_storage.maxPerformDataSize, fastGasWei, linkNative, false);
_getMaxLinkPayment(hotVars, cfg, triggerType, gasLimit, s_storage.maxPerformDataSize, false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error
}

report := automation_utils_2_1.KeeperRegistryBase21Report{
FastGasWei: big.NewInt(0),
LinkNative: big.NewInt(0),
FastGasWei: big.NewInt(0),
LinkNative: big.NewInt(0),
// Cfgs: make([]ChainConfig, len(results)),
UpkeepIds: make([]*big.Int, len(results)),
GasLimits: make([]*big.Int, len(results)),
Triggers: make([][]byte, len(results)),
Expand All @@ -55,7 +56,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error
report.LinkNative = result.LinkNative
}
}

// report.Cfgs[i] = ChainConfig(result.l1GasCost, result.fastGas, result.linkNative)
id := result.UpkeepID.BigInt()
report.UpkeepIds[i] = id
report.GasLimits[i] = big.NewInt(0).SetUint64(result.GasAllocated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,14 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr
GasLimits: make([]*big.Int, len(converted.GasLimits)),
Triggers: make([][]byte, len(converted.Triggers)),
PerformDatas: make([][]byte, len(converted.PerformDatas)),
// Cfgs: make([]ChainConfig, len(converted.Cfgs)),
}
if len(report.UpkeepIds) > 0 {
copy(report.UpkeepIds, converted.UpkeepIds)
copy(report.GasLimits, converted.GasLimits)
copy(report.Triggers, converted.Triggers)
copy(report.PerformDatas, converted.PerformDatas)
//copy(report.Cfgs, converted.Cfgs)
}

return report, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U
continue
}

// call gas estimator (ge) component to get L2 gas cost
// l1GasCost = ge.getL1GasCost(chain_id, block_id, block_hash, tx_call_data)
// fast_gas = ...
// link_native = ...
// results[i].l1GasCost = l1GasCost
// results[i].fastGas = fastGas
// results[i].linkNative = linkNative

opts := r.buildCallOpts(ctx, block)
var payload []byte
var err error
Expand All @@ -201,7 +209,7 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U
}

// check data will include the log trigger config
payload, err = r.abi.Pack("checkUpkeep", upkeepId, p.CheckData)
payload, err = r.abi.Pack("checkUpkeep", upkeepId, p.CheckData /* ChainConfig(l1GasCost, fast_gas, link_native) */)
if err != nil {
// pack error, no retryable
r.lggr.Warnf("failed to pack log trigger checkUpkeep data for upkeepId %s with check data %s: %s", upkeepId, hexutil.Encode(p.CheckData), err)
Expand All @@ -211,7 +219,7 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U
default:
// checkUpkeep is overloaded on the contract for conditionals and log upkeeps
// Need to use the first function (checkUpkeep0) for conditionals
payload, err = r.abi.Pack("checkUpkeep0", upkeepId)
payload, err = r.abi.Pack("checkUpkeep0", upkeepId /* ChainConfig(l1GasCost, fast_gas, link_native) */)
if err != nil {
// pack error, no retryable
r.lggr.Warnf("failed to pack conditional checkUpkeep data for upkeepId %s with check data %s: %s", upkeepId, hexutil.Encode(p.CheckData), err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa
// hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated
if len(response.Reports) != len(sl.Feeds) {
// TODO: AUTO-5044: calculate what reports are missing and log a warning
lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server retruned 200 status with %d reports while we requested %d feeds, treating as 404 (not found) and retrying", sl.Time.String(), sl.upkeepId.String(), len(response.Reports), len(sl.Feeds))
lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned 200 status with %d reports while we requested %d feeds, treating as 404 (not found) and retrying", sl.Time.String(), sl.upkeepId.String(), len(response.Reports), len(sl.Feeds))
retryable = true
state = encoding.MercuryFlakyFailure
return fmt.Errorf("%d", http.StatusNotFound)
Expand Down

0 comments on commit c3cd635

Please sign in to comment.