Skip to content

Commit

Permalink
Merge sbrv (#14259)
Browse files Browse the repository at this point in the history
* Initial Impl of SBRV

* Generate wrappers/ABI

* Removed ZeroAddress check for feemanager & AC

* Update gethwrappers

* Rename RewardManager=>DestinationRewardManager

* Remove circular dependency between proxy and verifier

* Fixes to init logic

* Update gethwrappers

* llo-feeds: v0.4.0 reward manager tests

* Add check to remove assumption that feeManager cannot be nil

* Generate

* Fixed poolIdMismatch not being thrown

* Fix logic error when looking up the activeDonConfig

* Update gethwrappers

* Update interface sanity checks when setting verifier

* Add remaining interface functionality

* Update gethwrappers

* llo-feeds: verifier SetConfig tests

* llo-feeds: adding verifier contract get methods for easier testing

* adding rewards wire up for testing

* incomeplte fix for test_setConfigWithAddressesAndWeightsAreSetCorrectly

* llo-feeds: adjusting setConfig tests due to changes

* llo-feeds: fee manager v0.4.0 tests: making v0.3.0 tests pass

* llo-feeds: fee manager v0.4.0 tests: fee manager - adding test for PoolIdMismatch

* llo-feeds: fee manager v0.4.0 tests: nits

* llo-feeds: feeManager bulk reverts when PoolId is 0

* llo-feeds: feeManager tests revertOnSettingAnAddressZeroVerifier onlyCallableByOwnerReverts

* llo-feeds: feeManager test poolIdsCannotBeZeroAddress

* llo-feeds: rewardManager test_rewardsAreCorrectlySentToEachAssociatedPoolWhenVerifyingInBulk

* llo-feeds: verifier proxy tests

* llo-feeds: fixing DestinationProxy error handling

* llo-feeds: fixing DestinationProxy test remove verifiercontract zero check

* llo-feeds: remove interface checks for verifierProxy

* llo-feeds: clean up setConfig tests from checking internal state

* fix issue when processing rewards

* Apply suggestions from code review

* Update contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol

* Update contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifierProxy.sol

* llo-feeds: verifier proxy remove test test_setVerifierZeroVerifier

* llo-feeds: tests for verify and verifyBulk

* clean up

* temporal fix for compile error

* llo: v0.4.0 removing V1 report tests

* better comments

* llo-feeds: verify test test_rollingOutConfiguration

* llo-feeds: verify test test_verifyFailsWhenReportIsOlderThanConfig

* llo-feeds: verify test test_verifyFailsWhenReportIsOlderThanConfig

* llo-feeds: tests for billing / billing bulk

* fixing tests

* fixing tests names

* llo-feeds: fix proxy contract should send value in call to verify

* llo-feeds: fix billing tests

* squash me

* llo-feeds: billing bulk verify tests

* llo-feeds: clean up

* llo-feeds: VerifierSetAccessControllerTest

* llo-feeds: clean up

* llo-feeds: extra proxy tests

* Update contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol

* Fix issue with oldest config verifying incorrectly

* Fix issue with oldest config verifying incorrectly

* llo-feeds: fix underflow and test_verifyFailsWhenReportIsOlderThanConfig

* Update gethwrappers

* Update gethwrappers

* llo-feeds: DestinationVerifier setFeeManager tests

* llo-feeds: Tests for Rewards and configs

* llo-feeds: Tests for DestinationVerifier constructor

* llo-feeds: reverse looping efficiently

* Update contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifier.sol

* Update gethwrappers

* llo-feeds: fmt contract tests

* llo-feeds: npx prettify contract tests

* llo-feeds: npx prettify v0.4.0 contracts

* se --Add ability to amend config array

* Update gethwrappers

* Fix issue with future timestamps

* Update gethwrappers

* Small fix

* Fix broken tests

* Update gethwrappers

* llo-feeds: Tests setConfigWithActivationTime

* llo-feeds: Tests setConfigWithActivationTime

* llo-feeds: Tests VerifierRemoveLatestConfigTest

* llo-feeds: fixing linter errors (unused imports)

* llo-feeds: tests better filenaming

* Improve upgradability of contracts

* Update gethwrappers

* Small fix when setting rewardManager

* Update gethwrappers

* Fix var name to honour same interface

* Update gethwrappers

* Improve getter consistency

* Update gethwrappers

* Fix comments & conventions

* Update DON Config to camal case

* Update gethwrappers

* solhint + gas snapshot

* prettier

* Solhint fixes

* Update gethwrappers

* gas snapshot

* Fixed gas issue

* Gas snapshot

* llo-feeds: testing multiple fee managers and verifiers

* llo: fixing tests

* Update contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewardsMultiVefifierFeeManager.t.sol

Co-authored-by: msuchacz-cll <[email protected]>

* llo: v0.4.0 interfaces test

* Fixed gas snaposhot

* prettier

* Fixed issues when feeManager isn't set

* Fix IERC impl for v0.4.0 contracts

* Optimisations

* Add global discount

* Update gethwrappers

* Small fixes

* Fix conflicting configs on same timestamp

* Fix tests

* Update gethwrappers

* Prettier / cleanup

* Fix generate

---------

Co-authored-by: Sam Davies <[email protected]>
Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>
Co-authored-by: David Przybilla <[email protected]>
Co-authored-by: ad0ll <[email protected]>
Co-authored-by: msuchacz-cll <[email protected]>
  • Loading branch information
6 people authored Aug 30, 2024
1 parent 154ff5f commit df43633
Show file tree
Hide file tree
Showing 22 changed files with 628 additions and 398 deletions.
434 changes: 222 additions & 212 deletions contracts/gas-snapshots/llo-feeds.gas-snapshot

Large diffs are not rendered by default.

64 changes: 40 additions & 24 deletions contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,28 @@ import {Math} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/ma
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
import {IDestinationRewardManager} from "./interfaces/IDestinationRewardManager.sol";
import {IDestinationFeeManager} from "./interfaces/IDestinationFeeManager.sol";
import {IDestinationVerifierFeeManager} from "./interfaces/IDestinationVerifierFeeManager.sol";

/**
* @title FeeManager
* @author Michael Fletcher
* @author Austin Born
* @notice This contract is used for the handling of fees required for users verifying reports.
*/
contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAndVersionInterface {
contract DestinationFeeManager is
IDestinationFeeManager,
IDestinationVerifierFeeManager,
ConfirmedOwner,
TypeAndVersionInterface
{
using SafeERC20 for IERC20;

/// @notice list of subscribers and their discounts subscriberDiscounts[subscriber][feedId][token]
mapping(address => mapping(bytes32 => mapping(address => uint256))) public s_subscriberDiscounts;

/// @notice map of global discounts
mapping(address => mapping(address => uint256)) public s_globalDiscounts;

/// @notice keep track of any subsidised link that is owed to the reward manager.
mapping(bytes32 => uint256) public s_linkDeficit;

Expand Down Expand Up @@ -150,38 +159,24 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
}

modifier onlyOwnerOrVerifier() {
if (msg.sender != s_verifierAddressList[msg.sender] && msg.sender != owner()) revert Unauthorized();
_;
}

modifier onlyVerifier() {
if (msg.sender != s_verifierAddressList[msg.sender]) revert Unauthorized();
_;
}

/// @inheritdoc TypeAndVersionInterface
function typeAndVersion() external pure override returns (string memory) {
return "DestinationFeeManager 1.0.0";
return "DestinationFeeManager 0.4.0";
}

/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
//for each function in IDestinationFeeManager we need to check if it matches the selector
return
interfaceId == this.getFeeAndReward.selector ||
interfaceId == this.setNativeSurcharge.selector ||
interfaceId == this.updateSubscriberDiscount.selector ||
interfaceId == this.withdraw.selector ||
interfaceId == this.linkAvailableForPayment.selector ||
interfaceId == this.payLinkDeficit.selector ||
interfaceId == this.addVerifier.selector ||
interfaceId == this.removeVerifier.selector ||
interfaceId == this.processFee.selector ||
interfaceId == this.processFeeBulk.selector ||
interfaceId == this.setFeeRecipients.selector;
interfaceId == type(IDestinationFeeManager).interfaceId ||
interfaceId == type(IDestinationVerifierFeeManager).interfaceId;
}

/// @inheritdoc IDestinationVerifierFeeManager
function processFee(
bytes32 recipient,
bytes calldata payload,
Expand Down Expand Up @@ -209,7 +204,7 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
}
}

/// @inheritdoc IDestinationFeeManager
/// @inheritdoc IDestinationVerifierFeeManager
function processFeeBulk(
bytes32[] memory poolIds,
bytes[] calldata payloads,
Expand Down Expand Up @@ -304,9 +299,14 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
revert ExpiredReport();
}

//get the discount being applied
//check if feed discount has been applied
uint256 discount = s_subscriberDiscounts[subscriber][feedId][quoteAddress];

if (discount == 0) {
//check if a global discount has been applied
discount = s_globalDiscounts[subscriber][quoteAddress];
}

//the reward is always set in LINK
reward.assetAddress = i_linkAddress;
reward.amount = Math.ceilDiv(linkQuantity * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
Expand All @@ -326,11 +326,11 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
return (fee, reward, discount);
}

/// @inheritdoc IDestinationFeeManager
/// @inheritdoc IDestinationVerifierFeeManager
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external onlyOwnerOrVerifier {
) external onlyVerifier {
i_rewardManager.setRewardRecipients(configDigest, rewardRecipientAndWeights);
}

Expand Down Expand Up @@ -360,6 +360,17 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
emit SubscriberDiscountUpdated(subscriber, feedId, token, discount);
}

function updateSubscriberGlobalDiscount(address subscriber, address token, uint64 discount) external onlyOwner {
//make sure the discount is not greater than the total discount that can be applied
if (discount > PERCENTAGE_SCALAR) revert InvalidDiscount();
//make sure the token is either LINK or native
if (token != i_linkAddress && token != i_nativeAddress) revert InvalidAddress();

s_globalDiscounts[subscriber][token] = discount;

emit SubscriberDiscountUpdated(subscriber, bytes32(0), token, discount);
}

/// @inheritdoc IDestinationFeeManager
function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner {
//address 0 is used to withdraw native in the context of withdrawing
Expand Down Expand Up @@ -550,8 +561,13 @@ contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAn
/// @inheritdoc IDestinationFeeManager
function setRewardManager(address rewardManagerAddress) external onlyOwner {
if (rewardManagerAddress == address(0)) revert InvalidAddress();

if (!IERC165(rewardManagerAddress).supportsInterface(type(IDestinationRewardManager).interfaceId)) {
revert InvalidAddress();
}

IERC20(i_linkAddress).approve(address(i_rewardManager), 0);
i_rewardManager = IDestinationRewardManager(rewardManagerAddress);
IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
IERC20(i_linkAddress).approve(address(rewardManagerAddress), type(uint256).max);
}
}
16 changes: 4 additions & 12 deletions contracts/src/v0.8/llo-feeds/v0.4.0/DestinationRewardManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,29 +75,21 @@ contract DestinationRewardManager is IDestinationRewardManager, ConfirmedOwner,

// @inheritdoc TypeAndVersionInterface
function typeAndVersion() external pure override returns (string memory) {
return "RewardManager 1.0.0";
return "DestinationRewardManager 0.4.0";
}

// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == this.claimRewards.selector ||
interfaceId == this.setRewardRecipients.selector ||
interfaceId == this.updateRewardRecipients.selector ||
interfaceId == this.payRecipients.selector ||
interfaceId == this.addFeeManager.selector ||
interfaceId == this.removeFeeManager.selector ||
interfaceId == this.getAvailableRewardPoolIds.selector ||
interfaceId == this.onFeePaid.selector;
return interfaceId == type(IDestinationRewardManager).interfaceId;
}

modifier onlyOwnerOrFeeManager() {
if (msg.sender != owner() && msg.sender != s_feeManagerAddressList[msg.sender]) revert Unauthorized();
if (msg.sender != s_feeManagerAddressList[msg.sender] && msg.sender != owner()) revert Unauthorized();
_;
}

modifier onlyOwnerOrRecipientInPool(bytes32 poolId) {
if (msg.sender != owner() && s_rewardRecipientWeights[poolId][msg.sender] == 0) revert Unauthorized();
if (s_rewardRecipientWeights[poolId][msg.sender] == 0 && msg.sender != owner()) revert Unauthorized();
_;
}

Expand Down
73 changes: 41 additions & 32 deletions contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/inter
import {Common} from "../libraries/Common.sol";
import {IAccessController} from "../../shared/interfaces/IAccessController.sol";
import {IDestinationVerifierProxy} from "./interfaces/IDestinationVerifierProxy.sol";
import {IDestinationFeeManager} from "./interfaces/IDestinationFeeManager.sol";
import {IDestinationVerifierProxyVerifier} from "./interfaces/IDestinationVerifierProxyVerifier.sol";
import {IDestinationVerifierFeeManager} from "./interfaces/IDestinationVerifierFeeManager.sol";

// OCR2 standard
uint256 constant MAX_NUM_ORACLES = 31;
Expand All @@ -18,7 +19,12 @@ uint256 constant MAX_NUM_ORACLES = 31;
* @author Michael Fletcher
* @notice This contract will be used to verify reports based on the oracle signatures. This is not the source verifier which required individual fee configurations, instead, this checks that a report has been signed by one of the configured oracles.
*/
contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVersionInterface, IERC165 {
contract DestinationVerifier is
IDestinationVerifier,
IDestinationVerifierProxyVerifier,
ConfirmedOwner,
TypeAndVersionInterface
{
/// @notice The list of DON configurations by hash(address|donConfigId) - set to true if the signer is part of the config
mapping(bytes32 => bool) private s_signerByAddressAndDonConfigId;

Expand Down Expand Up @@ -84,9 +90,6 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
/// @notice This error is thrown whenever a config does not exist
error DonConfigDoesNotExist();

/// @notice this error is thrown when the verifierProxy is incorrect when initialising
error VerifierProxyInvalid();

/// @notice This error is thrown when the activation time is either in the future or less than the current configs
error BadActivationTime();

Expand All @@ -105,7 +108,8 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
bytes24 indexed donConfigId,
address[] signers,
uint8 f,
Common.AddressAndWeight[] recipientAddressesAndWeights
Common.AddressAndWeight[] recipientAddressesAndWeights,
uint16 donConfigIndex
);

/// @notice This event is emitted when a new fee manager is set
Expand Down Expand Up @@ -137,18 +141,25 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
i_verifierProxy = IDestinationVerifierProxy(verifierProxy);
}

/// @inheritdoc IDestinationVerifier
/// @inheritdoc IDestinationVerifierProxyVerifier
function verify(
bytes calldata signedReport,
bytes calldata parameterPayload,
address sender
) external payable override checkValidProxy checkAccess(sender) returns (bytes memory) {
) external payable override onlyProxy checkAccess(sender) returns (bytes memory) {
(bytes memory verifierResponse, bytes32 donConfigId) = _verify(signedReport, sender);

address fm = s_feeManager;
if (fm != address(0)) {
//process the fee and catch the error
try IDestinationFeeManager(fm).processFee{value: msg.value}(donConfigId, signedReport, parameterPayload, sender) {
try
IDestinationVerifierFeeManager(fm).processFee{value: msg.value}(
donConfigId,
signedReport,
parameterPayload,
sender
)
{
//do nothing
} catch {
// we purposefully obfuscate the error here to prevent information leaking leading to free verifications
Expand All @@ -159,12 +170,12 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
return verifierResponse;
}

/// @inheritdoc IDestinationVerifier
/// @inheritdoc IDestinationVerifierProxyVerifier
function verifyBulk(
bytes[] calldata signedReports,
bytes calldata parameterPayload,
address sender
) external payable override checkValidProxy checkAccess(sender) returns (bytes[] memory) {
) external payable override onlyProxy checkAccess(sender) returns (bytes[] memory) {
bytes[] memory verifierResponses = new bytes[](signedReports.length);
bytes32[] memory donConfigs = new bytes32[](signedReports.length);

Expand All @@ -178,7 +189,12 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
if (fm != address(0)) {
//process the fee and catch the error
try
IDestinationFeeManager(fm).processFeeBulk{value: msg.value}(donConfigs, signedReports, parameterPayload, sender)
IDestinationVerifierFeeManager(fm).processFeeBulk{value: msg.value}(
donConfigs,
signedReports,
parameterPayload,
sender
)
{
//do nothing
} catch {
Expand Down Expand Up @@ -276,7 +292,7 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
uint8 f,
Common.AddressAndWeight[] memory recipientAddressesAndWeights,
uint32 activationTime
) internal checkConfigValid(signers.length, f) onlyOwner {
) internal {
// Duplicate addresses would break protocol rules
if (Common._hasDuplicateAddresses(signers)) {
revert NonUniqueSignatures();
Expand Down Expand Up @@ -304,7 +320,7 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer

// Check the activation time is greater than the latest config
uint256 donConfigLength = s_donConfigs.length;
if (donConfigLength > 0 && s_donConfigs[donConfigLength - 1].activationTime > activationTime) {
if (donConfigLength > 0 && s_donConfigs[donConfigLength - 1].activationTime >= activationTime) {
revert BadActivationTime();
}

Expand All @@ -315,22 +331,22 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer

// We may want to register these later or skip this step in the unlikely scenario they've previously been registered in the RewardsManager
if (recipientAddressesAndWeights.length != 0) {
IDestinationFeeManager(s_feeManager).setFeeRecipients(donConfigId, recipientAddressesAndWeights);
if (s_feeManager == address(0)) {
revert FeeManagerInvalid();
}
IDestinationVerifierFeeManager(s_feeManager).setFeeRecipients(donConfigId, recipientAddressesAndWeights);
}

// push the DonConfig
s_donConfigs.push(DonConfig(donConfigId, f, true, activationTime));

emit ConfigSet(donConfigId, signers, f, recipientAddressesAndWeights);
emit ConfigSet(donConfigId, signers, f, recipientAddressesAndWeights, uint16(donConfigLength));
}

/// @inheritdoc IDestinationVerifier
function setFeeManager(address feeManager) external override onlyOwner {
if (
!IERC165(feeManager).supportsInterface(IDestinationFeeManager.processFee.selector) ||
!IERC165(feeManager).supportsInterface(IDestinationFeeManager.processFeeBulk.selector) ||
!IERC165(feeManager).supportsInterface(IDestinationFeeManager.setFeeRecipients.selector)
) revert FeeManagerInvalid();
if (!IERC165(feeManager).supportsInterface(type(IDestinationVerifierFeeManager).interfaceId))
revert FeeManagerInvalid();

address oldFeeManager = s_feeManager;
s_feeManager = feeManager;
Expand Down Expand Up @@ -400,7 +416,7 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
_;
}

modifier checkValidProxy() {
modifier onlyProxy() {
if (address(i_verifierProxy) != msg.sender) {
revert AccessForbidden();
}
Expand All @@ -416,19 +432,12 @@ contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVer
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
interfaceId == this.verify.selector ||
interfaceId == this.verifyBulk.selector ||
interfaceId == this.s_accessController.selector ||
interfaceId == this.s_feeManager.selector ||
interfaceId == this.setConfig.selector ||
interfaceId == this.setConfigWithActivationTime.selector ||
interfaceId == this.setFeeManager.selector ||
interfaceId == this.setAccessController.selector ||
interfaceId == this.setConfigActive.selector;
interfaceId == type(IDestinationVerifier).interfaceId ||
interfaceId == type(IDestinationVerifierProxyVerifier).interfaceId;
}

/// @inheritdoc TypeAndVersionInterface
function typeAndVersion() external pure override returns (string memory) {
return "DestinationVerifier 1.0.0";
return "DestinationVerifier 0.4.0";
}
}
Loading

0 comments on commit df43633

Please sign in to comment.