Skip to content

Commit

Permalink
Add global discount
Browse files Browse the repository at this point in the history
  • Loading branch information
Fletch153 committed Aug 16, 2024
1 parent 2cf1664 commit 7858e3f
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 1 deletion.
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);
}
}

0 comments on commit 7858e3f

Please sign in to comment.