Skip to content

Commit

Permalink
Merge branch 'develop' into task/BCF-2833/dynamic-pipeline-runs
Browse files Browse the repository at this point in the history
  • Loading branch information
vyzaldysanchez authored Mar 26, 2024
2 parents 1ba3a81 + b3086d0 commit fa4beee
Show file tree
Hide file tree
Showing 33 changed files with 508 additions and 266 deletions.
5 changes: 5 additions & 0 deletions .changeset/quick-berries-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

fix bug in auto2.3 withdrawERC20Fees
5 changes: 5 additions & 0 deletions .changeset/silent-pets-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

Exposing information about LogPoller finality violation via Healthy method. It's raised whenever LogPoller sees reorg deeper than the finality
5 changes: 5 additions & 0 deletions .changeset/thin-coats-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

fix withdraw LINK bug in auto 2.3
5 changes: 5 additions & 0 deletions .changeset/tiny-suns-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

add test for billing override
5 changes: 5 additions & 0 deletions .changeset/wicked-gorillas-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

VRFV2PlusWrapper config refactor
2 changes: 1 addition & 1 deletion CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ core/scripts/gateway @smartcontractkit/functions
/contracts/src/v0.8/l2ep @chris-de-leon-cll
/contracts/src/v0.8/llo-feeds @smartcontractkit/mercury-team
# TODO: mocks folder, folder should be removed and files moved to the correct folders
/contracts/src/v0.8/operatorforwarder @smartcontractkit/foundations
/contracts/src/v0.8/operatorforwarder @RensR
/contracts/src/v0.8/shared @RensR
# TODO: tests folder, folder should be removed and files moved to the correct folders
# TODO: transmission folder, owner should be found
Expand Down
5 changes: 5 additions & 0 deletions contracts/.changeset/early-hairs-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

fix bug in auto2.3 withdrawERC20Fees
5 changes: 5 additions & 0 deletions contracts/.changeset/eight-peas-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": minor
---

VRFV2PlusWrapper config refactor
5 changes: 5 additions & 0 deletions contracts/.changeset/famous-feet-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

fix withdraw LINK bug in auto 2.3
5 changes: 5 additions & 0 deletions contracts/.changeset/tasty-rings-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

add billing override test

Large diffs are not rendered by default.

120 changes: 83 additions & 37 deletions contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ contract SetUp is BaseTest {
"",
""
);

vm.startPrank(OWNER);
registry.addFunds(linkUpkeepID, registry.getMinBalanceForUpkeep(linkUpkeepID));
registry.addFunds(usdUpkeepID, registry.getMinBalanceForUpkeep(usdUpkeepID));
registry.addFunds(nativeUpkeepID, registry.getMinBalanceForUpkeep(nativeUpkeepID));
vm.stopPrank();
}
}

Expand Down Expand Up @@ -124,7 +130,7 @@ contract AddFunds is SetUp {

// it fails when the billing token is not native, but trying to pay with native
function test_RevertsWhen_NativePaymentDoesntMatchBillingToken() external {
vm.expectRevert(abi.encodeWithSelector(Registry.InvalidBillingToken.selector));
vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector));
registry.addFunds{value: 1}(linkUpkeepID, 0);
}

Expand All @@ -140,32 +146,34 @@ contract AddFunds is SetUp {
}

function test_anyoneCanAddFunds() public {
assertEq(registry.getBalance(linkUpkeepID), 0);
uint256 startAmount = registry.getBalance(linkUpkeepID);
vm.prank(UPKEEP_ADMIN);
registry.addFunds(linkUpkeepID, 1);
assertEq(registry.getBalance(linkUpkeepID), 1);
assertEq(registry.getBalance(linkUpkeepID), startAmount + 1);
vm.prank(STRANGER);
registry.addFunds(linkUpkeepID, 1);
assertEq(registry.getBalance(linkUpkeepID), 2);
assertEq(registry.getBalance(linkUpkeepID), startAmount + 2);
}

function test_movesFundFromCorrectToken() public {
vm.startPrank(UPKEEP_ADMIN);

uint256 startBalanceLINK = linkToken.balanceOf(address(registry));
uint256 startBalanceUSDToken = usdToken.balanceOf(address(registry));
uint256 startLinkUpkeepBalance = registry.getBalance(linkUpkeepID);
uint256 startUSDUpkeepBalance = registry.getBalance(usdUpkeepID);

registry.addFunds(linkUpkeepID, 1);
assertEq(registry.getBalance(linkUpkeepID), 1);
assertEq(registry.getBalance(usdUpkeepID), 0);
assertEq(linkToken.balanceOf(address(registry)), startBalanceLINK + 1);
assertEq(usdToken.balanceOf(address(registry)), startBalanceUSDToken);
assertEq(registry.getBalance(linkUpkeepID), startBalanceLINK + 1);
assertEq(registry.getBalance(usdUpkeepID), startBalanceUSDToken);
assertEq(linkToken.balanceOf(address(registry)), startLinkUpkeepBalance + 1);
assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance);

registry.addFunds(usdUpkeepID, 2);
assertEq(registry.getBalance(linkUpkeepID), 1);
assertEq(registry.getBalance(usdUpkeepID), 2);
assertEq(linkToken.balanceOf(address(registry)), startBalanceLINK + 1);
assertEq(usdToken.balanceOf(address(registry)), startBalanceUSDToken + 2);
assertEq(registry.getBalance(linkUpkeepID), startBalanceLINK + 1);
assertEq(registry.getBalance(usdUpkeepID), startBalanceUSDToken + 2);
assertEq(linkToken.balanceOf(address(registry)), startLinkUpkeepBalance + 1);
assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance + 2);
}

function test_emitsAnEvent() public {
Expand All @@ -177,78 +185,97 @@ contract AddFunds is SetUp {
}

contract Withdraw is SetUp {
address internal aMockAddress = address(0x1111111111111111111111111111111111111113);
address internal aMockAddress = randomAddress();

function testLinkAvailableForPaymentReturnsLinkBalance() public {
uint256 startBalance = linkToken.balanceOf(address(registry));
int256 startLinkAvailable = registry.linkAvailableForPayment();

//simulate a deposit of link to the liquidity pool
_mintLink(address(registry), 1e10);

//check there's a balance
assertGt(linkToken.balanceOf(address(registry)), 0);
assertEq(linkToken.balanceOf(address(registry)), startBalance + 1e10);

//check the link available for payment is the link balance
assertEq(uint256(registry.linkAvailableForPayment()), linkToken.balanceOf(address(registry)));
//check the link available has increased by the same amount
assertEq(uint256(registry.linkAvailableForPayment()), uint256(startLinkAvailable) + 1e10);
}

function testWithdrawLinkFeesRevertsBecauseOnlyFinanceAdminAllowed() public {
function testWithdrawLinkRevertsBecauseOnlyFinanceAdminAllowed() public {
vm.expectRevert(abi.encodeWithSelector(Registry.OnlyFinanceAdmin.selector));
registry.withdrawLinkFees(aMockAddress, 1);
registry.withdrawLink(aMockAddress, 1);
}

function testWithdrawLinkFeesRevertsBecauseOfInsufficientBalance() public {
function testWithdrawLinkRevertsBecauseOfInsufficientBalance() public {
vm.startPrank(FINANCE_ADMIN);

// try to withdraw 1 link while there is 0 balance
vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1));
registry.withdrawLinkFees(aMockAddress, 1);
registry.withdrawLink(aMockAddress, 1);

vm.stopPrank();
}

function testWithdrawLinkFeesRevertsBecauseOfInvalidRecipient() public {
function testWithdrawLinkRevertsBecauseOfInvalidRecipient() public {
vm.startPrank(FINANCE_ADMIN);

// try to withdraw 1 link while there is 0 balance
vm.expectRevert(abi.encodeWithSelector(Registry.InvalidRecipient.selector));
registry.withdrawLinkFees(ZERO_ADDRESS, 1);
registry.withdrawLink(ZERO_ADDRESS, 1);

vm.stopPrank();
}

function testWithdrawLinkFeeSuccess() public {
function testWithdrawLinkSuccess() public {
//simulate a deposit of link to the liquidity pool
_mintLink(address(registry), 1e10);

//check there's a balance
assertGt(linkToken.balanceOf(address(registry)), 0);
uint256 startBalance = linkToken.balanceOf(address(registry));

vm.startPrank(FINANCE_ADMIN);

// try to withdraw 1 link while there is a ton of link available
registry.withdrawLinkFees(aMockAddress, 1);
registry.withdrawLink(aMockAddress, 1);

vm.stopPrank();

assertEq(linkToken.balanceOf(address(aMockAddress)), 1);
assertEq(linkToken.balanceOf(address(registry)), 1e10 - 1);
assertEq(linkToken.balanceOf(address(registry)), startBalance - 1);
}

function test_WithdrawERC20Fees_RespectsReserveAmount() public {
assertEq(registry.getBalance(usdUpkeepID), registry.getReserveAmount(address(usdToken)));
vm.startPrank(FINANCE_ADMIN);
vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1));
registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1);
}

function test_WithdrawERC20Fees_RevertsWhenAttemptingToWithdrawLINK() public {
_mintLink(address(registry), 1e10);
vm.startPrank(FINANCE_ADMIN);
vm.expectRevert(Registry.InvalidToken.selector);
registry.withdrawERC20Fees(address(linkToken), FINANCE_ADMIN, 1); // should revert
registry.withdrawLink(FINANCE_ADMIN, 1); // but using link withdraw functions succeeds
}

function testWithdrawERC20FeeSuccess() public {
// simulate a deposit of ERC20 to the liquidity pool
// deposit excess USDToken to the registry (this goes to the "finance withdrawable" pool be default)
uint256 startReserveAmount = registry.getReserveAmount(address(usdToken));
uint256 startAmount = usdToken.balanceOf(address(registry));
_mintERC20(address(registry), 1e10);

// check there's a balance
assertGt(usdToken.balanceOf(address(registry)), 0);
// depositing shouldn't change reserve amount
assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount);

vm.startPrank(FINANCE_ADMIN);

// try to withdraw 1 link while there is a ton of link available
// try to withdraw 1 USDToken
registry.withdrawERC20Fees(address(usdToken), aMockAddress, 1);

vm.stopPrank();

assertEq(usdToken.balanceOf(address(aMockAddress)), 1);
assertEq(usdToken.balanceOf(address(registry)), 1e10 - 1);
assertEq(usdToken.balanceOf(address(registry)), startAmount + 1e10 - 1);
assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount);
}
}

Expand Down Expand Up @@ -530,7 +557,7 @@ contract SetConfig is SetUp {
);
}

function testSetConfigRevertDueToInvalidBillingToken() public {
function testSetConfigRevertDueToInvalidToken() public {
address[] memory billingTokens = new address[](1);
billingTokens[0] = address(linkToken);

Expand All @@ -547,7 +574,7 @@ contract SetConfig is SetUp {
// deploy registry with OFF_CHAIN payout mode
registry = deployRegistry(AutoBase.PayoutMode.OFF_CHAIN);

vm.expectRevert(abi.encodeWithSelector(Registry.InvalidBillingToken.selector));
vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector));
registry.setConfigTypeSafe(
SIGNERS,
TRANSMITTERS,
Expand Down Expand Up @@ -792,7 +819,7 @@ contract RegisterUpkeep is SetUp {
}

function test_RevertsWhen_TheBillingTokenIsNotConfigured() public {
vm.expectRevert(Registry.InvalidBillingToken.selector);
vm.expectRevert(Registry.InvalidToken.selector);
registry.registerUpkeep(
address(TARGET1),
config.maxPerformGas,
Expand Down Expand Up @@ -871,7 +898,7 @@ contract OnTokenTransfer is SetUp {

function test_RevertsWhen_TheUpkeepDoesNotUseLINKAsItsBillingToken() public {
vm.startPrank(address(linkToken));
vm.expectRevert(Registry.InvalidBillingToken.selector);
vm.expectRevert(Registry.InvalidToken.selector);
registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(usdUpkeepID));
}

Expand Down Expand Up @@ -948,4 +975,23 @@ contract BillingOverrides is SetUp {
emit BillingConfigOverrideRemoved(linkUpkeepID);
registry.removeBillingOverrides(linkUpkeepID);
}

function test_Happy_MaxGasPayment_WithBillingOverrides() public {
uint96 maxPayment1 = registry.getMaxPaymentForGas(linkUpkeepID, 0, 5_000_000, address(linkToken));

// Double the two billing values
AutomationRegistryBase2_3.BillingOverrides memory billingOverrides = AutomationRegistryBase2_3.BillingOverrides({
gasFeePPB: DEFAULT_GAS_FEE_PPB * 2,
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS * 2
});

vm.startPrank(PRIVILEGE_MANAGER);
registry.setBillingOverrides(linkUpkeepID, billingOverrides);

// maxPayment2 should be greater than maxPayment1 after the overrides
// The 2 numbers should follow this: maxPayment2 - maxPayment1 == 2 * recepit.premium
// We do not apply the exact equation since we couldn't get the receipt.premium value
uint96 maxPayment2 = registry.getMaxPaymentForGas(linkUpkeepID, 0, 5_000_000, address(linkToken));
assertGt(maxPayment2, maxPayment1);
}
}
14 changes: 8 additions & 6 deletions contracts/src/v0.8/automation/dev/test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ contract BaseTest is Test {

// constants
address internal constant ZERO_ADDRESS = address(0);
uint32 internal constant DEFAULT_GAS_FEE_PPB = 10_000_000;
uint24 internal constant DEFAULT_FLAT_FEE_MILLI_CENTS = 2_000;

// config
uint8 internal constant F = 1; // number of faulty nodes
Expand Down Expand Up @@ -153,22 +155,22 @@ contract BaseTest is Test {
AutomationRegistryBase2_3.BillingConfig[]
memory billingTokenConfigs = new AutomationRegistryBase2_3.BillingConfig[](billingTokens.length);
billingTokenConfigs[0] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: 10_000_000, // 15%
flatFeeMilliCents: 2_000, // 2 cents
gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15%
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(USDTOKEN_USD_FEED),
fallbackPrice: 100_000_000, // $1
minSpend: 100000000000000000000 // 100 USD
});
billingTokenConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: 10_000_000, // 15%
flatFeeMilliCents: 2_000, // 2 cents
gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15%
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(NATIVE_USD_FEED),
fallbackPrice: 100_000_000, // $1
minSpend: 5000000000000000000 // 5 Native
});
billingTokenConfigs[2] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: 10_000_000, // 10%
flatFeeMilliCents: 2_000, // 2 cents
gasFeePPB: DEFAULT_GAS_FEE_PPB, // 10%
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(LINK_USD_FEED),
fallbackPrice: 1_000_000_000, // $10
minSpend: 5000000000000000000 // 5 LINK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain
if (data.length != 32) revert InvalidDataLength();
uint256 id = abi.decode(data, (uint256));
if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
if (address(s_upkeep[id].billingToken) != address(i_link)) revert InvalidBillingToken();
if (address(s_upkeep[id].billingToken) != address(i_link)) revert InvalidToken();
s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount);
s_reserveAmounts[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] + amount;
emit FundsAdded(id, sender, uint96(amount));
Expand Down
Loading

0 comments on commit fa4beee

Please sign in to comment.