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

Upkeep Balance Monitor #11180

Merged
merged 34 commits into from
Nov 27, 2023
Merged

Upkeep Balance Monitor #11180

merged 34 commits into from
Nov 27, 2023

Conversation

RyanRHall
Copy link
Contributor

No description provided.

@RyanRHall RyanRHall requested a review from a team as a code owner November 6, 2023 15:39
Copy link
Contributor

github-actions bot commented Nov 6, 2023

I see that you haven't updated any CHANGELOG files. Would it make sense to do so?

@RyanRHall RyanRHall force-pushed the upkeepbalancemonitor branch from 10a6831 to f73ab09 Compare November 6, 2023 15:43
@RyanRHall RyanRHall force-pushed the upkeepbalancemonitor branch from fa154d8 to 975f015 Compare November 6, 2023 16:29
shileiwill
shileiwill previously approved these changes Nov 7, 2023
Copy link
Contributor

@shileiwill shileiwill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is neat and clean! As a n00b, I was able to understand :)

Accepted to unblock and also I added a bunch of really n00b, nit questions. Thanks for help me understand this better.

uint8 maxBatchSize;
uint24 minPercentage;
uint24 targetPercentage;
uint96 maxTopUpAmount;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, any specific reason of using those int types? I guess uint8 should be enough for percentage?

/// @notice Sets the list of upkeeps to watch and their funding parameters.
/// @param watchlist the list of subscription ids to watch
function setWatchList(uint256[] calldata watchlist) external onlyOwner {
s_watchList = watchlist;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to check if the upkeep belongs to this owner?

/// @notice Called by the keeper to send funds to underfunded addresses.
/// @param performData the abi encoded list of addresses to fund
function performUpkeep(bytes calldata performData) external whenNotPaused {
(uint256[] memory upkeepIDs, uint96[] memory topUpAmounts) = abi.decode(performData, (uint256[], uint96[]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the uint256[], uint96[] align with uint256[] memory needsFunding, uint256[] memory topUpAmounts as in L137? Since you tested this, I guess it doesn't matter? But curious to know the reasoning behind those types :)

/// secure the output of getUnderfundedUpkeeps() as the input to topUp(), and we are treating the owner
/// as a privileged user that can perform arbitrary top-ups to any upkeepID.
function topUp(uint256[] memory upkeepIDs, uint96[] memory topUpAmounts) public {
IAutomationForwarder forwarder = s_forwarder;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see the setForwarder function is invoked anywhere in this contract, how is forwarder set?

continue;
}
} catch {}
emit TopUpFailed(upkeepIDs[i]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, if there is any upkeep fails to topUp, we log this event and carry on.

Nit: is it more readable to have this emit TopUpFailed(upkeepIDs[i]); in the catch clause?

IAutomationForwarder forwarder = s_forwarder;
if (msg.sender != address(s_forwarder) && msg.sender != owner()) revert OnlyForwarderOrOwner();
if (upkeepIDs.length != topUpAmounts.length) revert InvalidTopUpData();
address registryAddress = address(forwarder.getRegistry());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: instead of forwarder.getRegistry(), just use getRegistry()?

if (count < numUpkeeps) {
assembly {
mstore(needsFunding, count)
mstore(topUpAmounts, count)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n00b, what does this mean? we are setting the value of count to the address of topUpAmounts? isn't topUpAmounts of type uint256[]?

Copy link
Contributor

@FelixFan1992 FelixFan1992 Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these arrays are created by the size of config.maxBatchSize
however, we only have count number of underfunded upkeeps
this basically cuts the array size to count and saves the gas using inline assembly.

see https://docs.soliditylang.org/en/v0.8.16/internals/layout_in_storage.html#mappings-and-dynamic-arrays

uint256[] memory topUpAmounts = new uint256[](numUpkeeps);
Config memory config = s_config;
IAutomationRegistryConsumer registry = getRegistry();
uint256 availableFunds = LINK_TOKEN.balanceOf(address(this));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means this current contract holds LINK which will be used to auto fund the upkeeps. Is it possible to give a warning when this availableFunds is lower than topUpAmount as in L83?

@RyanRHall RyanRHall enabled auto-merge November 27, 2023 16:47
@cl-sonarqube-production
Copy link

SonarQube Quality Gate

Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@RyanRHall RyanRHall added this pull request to the merge queue Nov 27, 2023
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 27, 2023
@RyanRHall RyanRHall added this pull request to the merge queue Nov 27, 2023
Merged via the queue into develop with commit ab14bdc Nov 27, 2023
99 of 100 checks passed
@RyanRHall RyanRHall deleted the upkeepbalancemonitor branch November 27, 2023 17:49
fbac pushed a commit that referenced this pull request Dec 14, 2023
* write UpkeepBalanceMonWithBuffer

* Update AutomationRegistryInterface2_0.sol

Support getMinBalanceForUpkeep

* reformat

* remove modifier

* add typeAndVersion check in constructor

* restore AutomationRegistryInterface2_0.sol function

* update import paths

* update comments

* cleanup

* get rid of redundant REGISTRY variable

* cleanup

* rename

* cleanup

* remove target, min wait period, switch to min/target percentages

* refactor getUnderfundedUpkeeps() to return top up amounts

* refactor topUp() function

* switch to max batch size

* add max top up amount

* add maxTopUpAmount

* whitelist performUpkeep to forwarder

* cleanup

* rename

* bring topUp() back

* write initial test suite

* fix solhint errors

* update test for getUnderfundedUpkeeps()

* add tests for owner only functions and events

* add topUp and performUpkeep tests

* rearrange functions on contract

* add support for multiple registries

* cleanup

* change topUpAmounts to uint96[]

* move pausable to topUp(); add length check to topUp()

---------

Co-authored-by: De Clercq Wentzel <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants