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

Add global discount #14137

Merged
merged 3 commits into from
Aug 20, 2024
Merged
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
25 changes: 24 additions & 1 deletion contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ contract DestinationFeeManager is IDestinationFeeManager, IDestinationVerifierFe
/// @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 @@ -289,9 +292,14 @@ contract DestinationFeeManager is IDestinationFeeManager, IDestinationVerifierFe
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 Down Expand Up @@ -345,6 +353,21 @@ contract DestinationFeeManager is IDestinationFeeManager, IDestinationVerifierFe
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ interface IDestinationFeeManager is IERC165 {
*/
function updateSubscriberDiscount(address subscriber, bytes32 feedId, address token, uint64 discount) external;

/**
* @notice Adds a subscriber to the fee manager
* @param subscriber address of the subscriber
* @param token token to apply the discount to
* @param discount discount to be applied to the fee
*/
function updateSubscriberGlobalDiscount(address subscriber, address token, uint64 discount) external;

/**
* @notice Withdraws any native or LINK rewards to the owner address
* @param assetAddress address of the asset to withdraw
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ contract BaseDestinationFeeManagerTest is Test {
changePrank(originalAddr);
}

function setSubscriberGlobalDiscount(address subscriber, address token, uint256 discount, address sender) public {
//record the current address and switch to the recipient
address originalAddr = msg.sender;
changePrank(sender);

//set the discount
feeManager.updateSubscriberGlobalDiscount(subscriber, token, uint64(discount));

//change back to the original address
changePrank(originalAddr);
}

function setNativeSurcharge(uint256 surcharge, address sender) public {
//record the current address and switch to the recipient
address originalAddr = msg.sender;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,4 +603,118 @@ contract DestinationFeeManagerProcessFeeTest is BaseDestinationFeeManagerTest {
//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);
}

function test_GlobalDiscountWithNative() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR / 2, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);
}

function test_GlobalDiscountWithLink() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(link), FEE_SCALAR / 2, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);
}

function test_GlobalDiscountWithNativeAndLink() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR / 2, ADMIN);
setSubscriberGlobalDiscount(USER, address(link), FEE_SCALAR / 2, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);
}

function test_GlobalDiscountIsOverridenByIndividualDiscountNative() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR / 2, ADMIN);
setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 4, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 4);
}

function test_GlobalDiscountIsOverridenByIndividualDiscountLink() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(link), FEE_SCALAR / 2, ADMIN);
setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 4, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 4);
}

function test_GlobalDiscountIsUpdatedAfterBeingSetToZeroLink() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(link), FEE_SCALAR / 2, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);

//set the global discount to zero
setSubscriberGlobalDiscount(USER, address(link), 0, ADMIN);

//get the discount applied
discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);

//fee should be zero
assertEq(discount, 0);
}

function test_GlobalDiscountIsUpdatedAfterBeingSetToZeroNative() public {
//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR / 2, ADMIN);

//get the discount applied
uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);

//fee should be half the default
assertEq(discount, FEE_SCALAR / 2);

//set the global discount to zero
setSubscriberGlobalDiscount(USER, address(native), 0, ADMIN);

//get the discount applied
discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);

//fee should be zero
assertEq(discount, 0);
}

function test_GlobalDiscountCantBeSetToMoreThanMaximum() public {
//should revert with invalid discount
vm.expectRevert(INVALID_DISCOUNT_ERROR);

//set the global discount to 101%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR + 1, ADMIN);
}

function test_onlyOwnerCanSetGlobalDiscount() public {
//should revert with unauthorized
vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR);

//set the global discount to 50%
setSubscriberGlobalDiscount(USER, address(native), FEE_SCALAR / 2, USER);
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading