Skip to content

Commit

Permalink
feat: add fees feature
Browse files Browse the repository at this point in the history
  • Loading branch information
0xChin committed Sep 6, 2024
1 parent 15aca03 commit db36e40
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ SEPOLIA_DEPLOYER_PK=
OPTIMISM_SEPOLIA_RPC=https://opt-sepolia.g.alchemy.com/v2/YNob1yS6fZux6Fs44VAybG3JXP4k8QgN
OPTIMISM_SEPOLIA_DEPLOYER_PK=<deployer-pk>

VIRTUAL_OPTIMISM_RPC=
TENDERLY_ACCESS_KEY=
TENDERLY_VERIFIER_URL=

ETHERSCAN_API_KEY=ZIGN5Y8QXYQ5SH17D4RA2YQWNM2DP62S89
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ optimism-sepolia = "${OPTIMISM_SEPOLIA_RPC}"
mainnet = { key = "${ETHERSCAN_API_KEY}", chain = "mainnet" }
sepolia = { key = "${ETHERSCAN_API_KEY}", chain = "sepolia" }
optimism-sepolia = { key = "${ETHERSCAN_API_KEY}", chain = "optimism-sepolia" }
arbitrum-sepolia = { key = "${ARBITRUM_ETHERSCAN_API_KEY}", chain = "arbitrum-sepolia" }
unknown_chain = { key = "${TENDERLY_ACCESS_KEY}", chain = 4924, url = "${VIRTUAL_OPTIMISM_RPC}/verify/etherscan" }
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
"build": "forge build",
"build:optimized": "FOUNDRY_PROFILE=optimized forge build",
"coverage": "forge coverage --report summary --report lcov --match-path 'test/unit/*'",
"deploy:arbitrum-sepolia": "bash -c 'source .env && forge script Deploy -vvvvv --rpc-url $ARBITRUM_SEPOLIA_RPC --broadcast --chain arbitrum-sepolia --private-key $ARBITRUM_SEPOLIA_DEPLOYER_PK --verify --verifier blockscout --verifier-url https://arbitrum-sepolia.blockscout.com/api/'",
"deploy:mainnet": "bash -c 'source .env && forge script Deploy -vvvvv --rpc-url $MAINNET_RPC --broadcast --chain mainnet --private-key $MAINNET_DEPLOYER_PK'",
"deploy:optimism-sepolia": "bash -c 'source .env && forge script Deploy -vvvvv --rpc-url $OPTIMISM_SEPOLIA_RPC --broadcast --chain optimism-sepolia --private-key $OPTIMISM_SEPOLIA_DEPLOYER_PK --verify --verifier blockscout --verifier-url https://optimism-sepolia.blockscout.com/api/'",
"deploy:sepolia": "bash -c 'source .env && forge script Deploy -vvvvv --rpc-url $SEPOLIA_RPC --broadcast --chain sepolia --private-key $SEPOLIA_DEPLOYER_PK'",
"deploy:v-optimism": "bash -c 'source .env && forge script Deploy -vvvvv --rpc-url $VIRTUAL_OPTIMISM_RPC --broadcast --private-key $OPTIMISM_DEPLOYER_PK --verify'",
"lint:check": "yarn lint:sol-tests && yarn lint:sol-logic && forge fmt --check",
"lint:fix": "sort-package-json && forge fmt && yarn lint:sol-tests --fix && yarn lint:sol-logic --fix",
"lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js",
Expand Down
21 changes: 19 additions & 2 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,28 @@ contract Deploy is Script {
address[] memory _tokens = new address[](1);
_tokens[0] = address(0x5fd84259d66Cd46123540766Be93DFE6D43130D7);

address[] memory _tokensOptimismSepolia = new address[](2);
_tokensOptimismSepolia[0] = address(0x7F5c764cBc14f9669B88837ca1490cCa17c31607);
_tokensOptimismSepolia[1] = address(0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1);

address[] memory _tokensArbitrumSepolia = new address[](1);
_tokensArbitrumSepolia[0] = address(
0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d // usdc
);

// Mainnet
_deploymentParams[1] = DeploymentParams(_tokens, IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2));

// Optimism Sepolia
_deploymentParams[11_155_420] = DeploymentParams(_tokens, IPool(0xb50201558B00496A145fE76f7424749556E326D8));

// V-Optimism
_deploymentParams[4924] =
DeploymentParams(_tokensOptimismSepolia, IPool(0x794a61358D6845594F94dc1DB02A252b5b4814aD));

// Arbitrum
_deploymentParams[421_614] =
DeploymentParams(_tokensArbitrumSepolia, IPool(0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff));
}

function run() public {
Expand All @@ -34,10 +51,10 @@ contract Deploy is Script {
Grateful _grateful = new Grateful(_params.tokens, _params.aavePool);
AaveV3Vault _vault = new AaveV3Vault(
ERC20(_params.tokens[0]),
ERC20(0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c),
ERC20(0x460b97BD498E1157530AEb3086301d5225b91216),
_params.aavePool,
address(0),
IRewardsController(0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb),
IRewardsController(0x3A203B14CF8749a1e3b7314c6c49004B77Ee667A),
address(_grateful)
);
_grateful.addVault(_params.tokens[0], address(_vault));
Expand Down
17 changes: 14 additions & 3 deletions src/contracts/Grateful.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ contract Grateful is IGrateful, Ownable2Step {
// @inheritdoc IGrateful
uint256 public subscriptionCount;

// @inheritdoc IGrateful
uint256 public fee;

modifier onlyWhenTokenWhitelisted(address _token) {
if (!tokensWhitelisted[_token]) {
revert Grateful_TokenNotWhitelisted();
Expand Down Expand Up @@ -205,6 +208,11 @@ contract Grateful is IGrateful, Ownable2Step {
yieldingFunds[msg.sender] = !yieldingFunds[msg.sender];
}

function applyFee(uint256 amount) public view returns (uint256) {
uint256 fee = (amount * 100) / 10_000;
return amount - fee;
}

/**
* @notice Processes a payment
* @param _sender Address of the sender
Expand All @@ -222,20 +230,23 @@ contract Grateful is IGrateful, Ownable2Step {
uint256 _paymentId,
uint256 _subscriptionId
) internal {
uint256 amountWithFee = applyFee(_amount);
if (yieldingFunds[_merchant]) {
AaveV3ERC4626 vault = vaults[_token];
if (address(vault) == address(0)) {
revert Grateful_VaultNotSet();
}
IERC20(_token).transferFrom(_sender, address(this), _amount);
uint256 _shares = vault.deposit(_amount, address(this));
IERC20(_token).transferFrom(_sender, address(this), amountWithFee);
uint256 _shares = vault.deposit(amountWithFee, address(this));
shares[_merchant][_token] += _shares;
} else {
if (!IERC20(_token).transferFrom(_sender, _merchant, _amount)) {
if (!IERC20(_token).transferFrom(_sender, _merchant, amountWithFee)) {
revert Grateful_TransferFailed();
}
}

IERC20(_token).transferFrom(_sender, owner(), _amount - amountWithFee);

emit PaymentProcessed(_sender, _merchant, _token, _amount, yieldingFunds[_merchant], _paymentId, _subscriptionId);
}
}
11 changes: 11 additions & 0 deletions src/interfaces/IGrateful.sol
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ interface IGrateful {
*/
function subscriptionCount() external view returns (uint256 _subscriptionCount);

/**
* @notice Returns the fee applied to the payments
* @return _fee Fee applied to the payments
*/
function fee() external view returns (uint256);

/*///////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -250,4 +256,9 @@ interface IGrateful {
address _token,
uint256 _amount
) external view returns (uint256);

/// @notice Applies the fee to an amount
/// @param amount Amount of the token
/// @return amountWithFee Amount of the token with the fee applied
function applyFee(uint256 amount) external view returns (uint256);
}
10 changes: 5 additions & 5 deletions test/integration/Grateful.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract IntegrationGreeter is IntegrationBase {
);
vm.stopPrank();

assertEq(_usdc.balanceOf(_merchant), _amount);
assertEq(_usdc.balanceOf(_merchant), _grateful.applyFee(_amount));
}

function test_PaymentYieldingFunds() public {
Expand All @@ -35,7 +35,7 @@ contract IntegrationGreeter is IntegrationBase {
vm.prank(_merchant);
_grateful.withdraw(address(_usdc));

assertGt(_usdc.balanceOf(_merchant), _amount);
assertGt(_usdc.balanceOf(_merchant), _grateful.applyFee(_amount));
}

function test_Subscription() public {
Expand All @@ -45,7 +45,7 @@ contract IntegrationGreeter is IntegrationBase {
vm.stopPrank();

// When subscription is created, a initial payment is made
assertEq(_usdc.balanceOf(_merchant), _amount);
assertEq(_usdc.balanceOf(_merchant), _grateful.applyFee(_amount));

// Shouldn't be able to process the subscription before 30 days have passed
vm.expectRevert(IGrateful.Grateful_TooEarlyForNextPayment.selector);
Expand All @@ -56,7 +56,7 @@ contract IntegrationGreeter is IntegrationBase {

_grateful.processSubscription(subscriptionId);

assertEq(_usdc.balanceOf(_merchant), _amount * 2);
assertEq(_usdc.balanceOf(_merchant), _grateful.applyFee(_amount) * 2);

// Should revert if the payments amount has been reached

Expand All @@ -83,6 +83,6 @@ contract IntegrationGreeter is IntegrationBase {
_grateful.createOneTimePayment(_merchant, address(_usdc), _amount, 4, paymentId, precomputed);

// Merchant receives the payment
assertEq(_usdc.balanceOf(_merchant), _amount);
assertEq(_usdc.balanceOf(_merchant), _grateful.applyFee(_amount));
}
}

0 comments on commit db36e40

Please sign in to comment.