forked from Certora/aave-v3-origin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add RevenueSplitter, add RevenueSplitter config to batch deploy…
…ments (aave-dao#37) * feat: add RevenueSplitter, add RevenueSplitter config to batch deployments * feat: add native currency split, add tests * chore: run lint * feat: add ReentrancyGuard to RevenueSplitter * chore: add test for splitNativeFund with smart contract wallet recipient that does NOT have fallback function * chore: fix assert message with correct recipient * chore: run linter * chore: add specs to IRevenueSplitter interface * chore: rephrase spec * chore: move config.incentivesProxy input logic into separate PR 'feat/reuse-rewards-controller' * chore: change license of RevenueSplitter.sol to BUSL-1.1 --------- Co-authored-by: kartojal <[email protected]>
- Loading branch information
Showing
13 changed files
with
675 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol'; | ||
|
||
interface IRevenueSplitterErrors { | ||
error InvalidPercentSplit(); | ||
} | ||
|
||
/// @title IRevenueSplitter | ||
/// @notice Interface for RevenueSplitter contract | ||
/// @dev The `RevenueSplitter` is a state-less non-upgradeable contract that supports 2 recipients (A and B), and defines the percentage split of the recipient A, with a value between 1 and 99_99. | ||
/// The `RevenueSplitter` contract must be attached to the `AaveV3ConfigEngine` as `treasury`, making new listings to use `RevenueSplitter` as treasury (instead of `Collector` ) at the `AToken` initialization, making all revenue managed by ATokens redirected to the RevenueSplitter contract. | ||
/// Once parties want to share their revenue, anyone can call `function splitRevenue(IERC20[] memory tokens)` to check the accrued ERC20 balance inside this contract, and split the amounts between the two recipients. | ||
/// It also supports split of native currency via `function splitNativeRevenue() external`, in case the instance receives native currency. | ||
/// | ||
/// Warning: For recipients, you can use any address, but preferable to use `Collector`, a Safe smart contract multisig or a smart contract that can handle both ERC20 and native transfers, to prevent balances to be locked. | ||
interface IRevenueSplitter is IRevenueSplitterErrors { | ||
/// @notice Split token balances in RevenueSplitter and transfer between two recipients | ||
/// @param tokens List of tokens to check balance and split amounts | ||
/// @dev Specs: | ||
/// - Does not revert if token balance is zero (no-op). | ||
/// - Rounds in favor of RECIPIENT_B (1 wei round). | ||
/// - Anyone can call this function anytime. | ||
/// - This method will always send ERC20 tokens to recipients, even if the recipients does NOT support the ERC20 interface. At deployment time is recommended to ensure both recipients can handle ERC20 and native transfers via e2e tests. | ||
function splitRevenue(IERC20[] memory tokens) external; | ||
|
||
/// @notice Split native currency in RevenueSplitter and transfer between two recipients | ||
/// @dev Specs: | ||
/// - Does not revert if native balance is zero (no-op) | ||
/// - Rounds in favor of RECIPIENT_B (1 wei round). | ||
/// - Anyone can call this function anytime. | ||
/// - This method will always send native currency to recipients, and does NOT revert if one or both recipients doesn't support handling native currency. At deployment time is recommended to ensure both recipients can handle ERC20 and native transfers via e2e tests. | ||
/// - If one recipient can not receive native currency, repeatedly calling the function will rescue/drain the funds of the second recipient (50% per call), allowing manual recovery of funds. | ||
function splitNativeRevenue() external; | ||
|
||
function RECIPIENT_A() external view returns (address payable); | ||
|
||
function RECIPIENT_B() external view returns (address payable); | ||
|
||
/// @dev Percentage of the split that goes to RECIPIENT_A, the diff goes to RECIPIENT_B, from 1 to 99_99 | ||
function SPLIT_PERCENTAGE_RECIPIENT_A() external view returns (uint16); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.19; | ||
|
||
import {IRevenueSplitter} from './IRevenueSplitter.sol'; | ||
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol'; | ||
import {GPv2SafeERC20} from 'aave-v3-core/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol'; | ||
import {PercentageMath} from 'aave-v3-core/contracts/protocol/libraries/math/PercentageMath.sol'; | ||
import {ReentrancyGuard} from 'aave-v3-periphery/contracts/dependencies/openzeppelin/ReentrancyGuard.sol'; | ||
|
||
/** | ||
* @title RevenueSplitter | ||
* @author Catapulta | ||
* @dev This periphery contract is responsible for splitting funds between two recipients. | ||
* Replace COLLECTOR in ATokens or Debt Tokens with RevenueSplitter, and them set COLLECTORs as recipients. | ||
*/ | ||
contract RevenueSplitter is IRevenueSplitter, ReentrancyGuard { | ||
using GPv2SafeERC20 for IERC20; | ||
using PercentageMath for uint256; | ||
|
||
address payable public immutable RECIPIENT_A; | ||
address payable public immutable RECIPIENT_B; | ||
|
||
uint16 public immutable SPLIT_PERCENTAGE_RECIPIENT_A; | ||
|
||
constructor(address recipientA, address recipientB, uint16 splitPercentageRecipientA) { | ||
if ( | ||
splitPercentageRecipientA == 0 || | ||
splitPercentageRecipientA >= PercentageMath.PERCENTAGE_FACTOR | ||
) { | ||
revert InvalidPercentSplit(); | ||
} | ||
RECIPIENT_A = payable(recipientA); | ||
RECIPIENT_B = payable(recipientB); | ||
SPLIT_PERCENTAGE_RECIPIENT_A = splitPercentageRecipientA; | ||
} | ||
|
||
/// @inheritdoc IRevenueSplitter | ||
function splitRevenue(IERC20[] memory tokens) external nonReentrant { | ||
for (uint8 x; x < tokens.length; ++x) { | ||
uint256 balance = tokens[x].balanceOf(address(this)); | ||
|
||
if (balance == 0) { | ||
continue; | ||
} | ||
|
||
uint256 amount_A = balance.percentMul(SPLIT_PERCENTAGE_RECIPIENT_A); | ||
uint256 amount_B = balance - amount_A; | ||
|
||
tokens[x].safeTransfer(RECIPIENT_A, amount_A); | ||
tokens[x].safeTransfer(RECIPIENT_B, amount_B); | ||
} | ||
} | ||
|
||
/// @inheritdoc IRevenueSplitter | ||
function splitNativeRevenue() external nonReentrant { | ||
uint256 balance = address(this).balance; | ||
|
||
if (balance == 0) { | ||
return; | ||
} | ||
|
||
uint256 amount_A = balance.percentMul(SPLIT_PERCENTAGE_RECIPIENT_A); | ||
uint256 amount_B = balance - amount_A; | ||
|
||
// Do not revert if fails to send to RECIPIENT_A or RECIPIENT_B, to prevent one recipient from blocking the other | ||
// if recipient does not accept native currency via fallback function or receive. | ||
// This can also be used as a manual recovery mechanism in case of an account does not support receiving native currency. | ||
RECIPIENT_A.call{value: amount_A}(''); | ||
RECIPIENT_B.call{value: amount_B}(''); | ||
} | ||
|
||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.