From dc27501a08001d145287b028b09ddb03ed759a32 Mon Sep 17 00:00:00 2001 From: 0xchin Date: Tue, 19 Nov 2024 01:01:58 -0300 Subject: [PATCH] test: add deploy script tests --- remappings.txt | 1 + script/Deploy.sol | 48 +++- test/integration/Grateful.t.sol | 330 ++++++++++++++++----------- test/integration/IntegrationBase.sol | 164 ++++++------- 4 files changed, 310 insertions(+), 233 deletions(-) diff --git a/remappings.txt b/remappings.txt index 6583dcd..d3b71e3 100644 --- a/remappings.txt +++ b/remappings.txt @@ -6,4 +6,5 @@ yield-daddy/=node_modules/yield-daddy/src solmate/=node_modules/solmate/src contracts/=src/contracts +script/=script interfaces/=src/interfaces diff --git a/script/Deploy.sol b/script/Deploy.sol index dfe5c08..95bfb65 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -24,15 +24,39 @@ contract Deploy is Script { error UnsupportedChain(); + // Public variables to store deployed contracts + Grateful public grateful; + mapping(address => AaveV3Vault) public vaults; + function getDeploymentParams( uint256 chainId ) internal pure returns (DeploymentParams memory params) { if (chainId == 1) { // Mainnet - address[] memory _tokens = new address[](1); - _tokens[0] = address(0x5fd84259d66Cd46123540766Be93DFE6D43130D7); + address[] memory _tokens = new address[](3); + _tokens[0] = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); // USDC + _tokens[1] = address(0xdAC17F958D2ee523a2206206994597C13D831ec7); // USDT + _tokens[2] = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); // DAI - VaultDeploymentParams[] memory _vaults; + VaultDeploymentParams[] memory _vaults = new VaultDeploymentParams[](3); + + _vaults[0] = VaultDeploymentParams({ + token: address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48), // USDC + aToken: address(0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c), // aUSDC + rewardsController: address(0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb) // Rewards Controller + }); + + _vaults[1] = VaultDeploymentParams({ + token: address(0xdAC17F958D2ee523a2206206994597C13D831ec7), // USDT + aToken: address(0x23878914EFE38d27C4D67Ab83ed1b93A74D4086a), // aUSDT + rewardsController: address(0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb) // Rewards Controller + }); + + _vaults[2] = VaultDeploymentParams({ + token: address(0x6B175474E89094C44Da98b954EedeAC495271d0F), // DAI + aToken: address(0x018008bfb33d285247A21d44E50697654f754e63), // aDAI + rewardsController: address(0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb) // Rewards Controller + }); params = DeploymentParams({ tokens: _tokens, @@ -98,10 +122,10 @@ contract Deploy is Script { function run() public { DeploymentParams memory _params = getDeploymentParams(block.chainid); - vm.startBroadcast(); + /* vm.startBroadcast(); */ // Deploy Grateful contract - Grateful _grateful = new Grateful(_params.tokens, _params.aavePool, _params.initialFee); + grateful = new Grateful(_params.tokens, _params.aavePool, _params.initialFee); // Deploy vaults and add them to Grateful uint256 vaultsLength = _params.vaults.length; @@ -113,21 +137,23 @@ contract Deploy is Script { ERC20(vaultParams.token), ERC20(vaultParams.aToken), _params.aavePool, - _grateful.owner(), // rewardRecipient_ (set to desired address) + grateful.owner(), // rewardRecipient_ (set to desired address) IRewardsController(vaultParams.rewardsController), - address(_grateful) // newOwner + address(grateful) // newOwner ); // Add the vault to Grateful - _grateful.addVault(vaultParams.token, address(vault)); + grateful.addVault(vaultParams.token, address(vault)); + + vaults[vaultParams.token] = vault; } // Deploy TestToken (if needed) - TestToken _testToken = new TestToken("Test Token", "TEST", 18); + /* TestToken _testToken = new TestToken("Test Token", "TEST", 18); */ // Add TestToken to Grateful (if needed) - _grateful.addToken(address(_testToken)); + /* grateful.addToken(address(_testToken)); */ - vm.stopBroadcast(); + /* vm.stopBroadcast(); */ } } diff --git a/test/integration/Grateful.t.sol b/test/integration/Grateful.t.sol index 6478d0b..0b8c7e9 100644 --- a/test/integration/Grateful.t.sol +++ b/test/integration/Grateful.t.sol @@ -1,145 +1,203 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {OneTime} from "contracts/OneTime.sol"; import {IntegrationBase} from "test/integration/IntegrationBase.sol"; contract IntegrationGreeter is IntegrationBase { + using SafeERC20 for IERC20; + /*////////////////////////////////////////////////////////////// - TESTS + TESTS //////////////////////////////////////////////////////////////*/ // Tests for Standard Payments function test_Payment() public { - _approveAndPay(_user, _merchant, _AMOUNT_USDC, _NOT_YIELDING_FUNDS); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; + + _approveAndPay(_user, _merchant, tokenAddr, amount, _NOT_YIELDING_FUNDS); - assertEq( - _usdc.balanceOf(_merchant), _grateful.applyFee(_merchant, _AMOUNT_USDC), "Merchant balance mismatch after payment" - ); + uint256 expectedMerchantBalance = _grateful.applyFee(_merchant, amount); + assertEq( + IERC20(tokenAddr).balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch after payment")) + ); + } } function test_PaymentYieldingFunds() public { - // Capture owner's initial balance before payment - uint256 ownerInitialBalance = _usdc.balanceOf(_owner); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; - _approveAndPay(_user, _merchant, _AMOUNT_USDC, _YIELDING_FUNDS); + IERC20 token = IERC20(tokenAddr); - // Advance time to accrue yield - vm.warp(block.timestamp + 1 days); + // Capture owner's initial balance before payment + uint256 ownerInitialBalance = token.balanceOf(_owner); - // Calculate profit before withdrawal - uint256 profit = _grateful.calculateProfit(_merchant, address(_usdc)); + _approveAndPay(_user, _merchant, tokenAddr, amount, _YIELDING_FUNDS); - // Merchant withdraws funds - vm.prank(_merchant); - _grateful.withdraw(address(_usdc)); + // Advance time to accrue yield + vm.warp(block.timestamp + 1 days); - // Calculate performance fee after withdrawal - uint256 performanceFee = _grateful.calculatePerformanceFee(profit); + // Calculate profit before withdrawal + uint256 profit = _grateful.calculateProfit(_merchant, tokenAddr); - uint256 initialDeposit = _grateful.applyFee(_merchant, _AMOUNT_USDC); - uint256 expectedMerchantBalance = initialDeposit + profit - performanceFee; + // Merchant withdraws funds + vm.prank(_merchant); + _grateful.withdraw(tokenAddr); - // Verify merchant's balance - assertEq(_usdc.balanceOf(_merchant), expectedMerchantBalance, "Merchant balance mismatch after withdrawal"); + // Calculate performance fee after withdrawal + uint256 performanceFee = _grateful.calculatePerformanceFee(profit); - // Verify owner's balance - uint256 ownerFinalBalance = _usdc.balanceOf(_owner); - uint256 initialFee = _AMOUNT_USDC - initialDeposit; - uint256 ownerExpectedBalanceIncrease = initialFee + performanceFee; + uint256 initialDeposit = _grateful.applyFee(_merchant, amount); + uint256 expectedMerchantBalance = initialDeposit + profit - performanceFee; - assertEq( - ownerFinalBalance - ownerInitialBalance, - ownerExpectedBalanceIncrease, - "Owner did not receive correct performance fee" - ); + // Verify merchant's balance + assertEq( + token.balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch after withdrawal")) + ); + + // Verify owner's balance + uint256 ownerFinalBalance = token.balanceOf(_owner); + uint256 initialFee = amount - initialDeposit; + uint256 ownerExpectedBalanceIncrease = initialFee + performanceFee; + + assertEq( + ownerFinalBalance - ownerInitialBalance, + ownerExpectedBalanceIncrease, + string(abi.encodePacked(symbol, ": Owner did not receive correct performance fee")) + ); + } } // Tests for One-Time Payments function test_OneTimePayment() public { - _setupAndExecuteOneTimePayment(_user, _merchant, _AMOUNT_USDC, _PAYMENT_SALT, _NOT_YIELDING_FUNDS); - - // Merchant receives the payment - assertEq( - _usdc.balanceOf(_merchant), - _grateful.applyFee(_merchant, _AMOUNT_USDC), - "Merchant balance mismatch after one-time payment" - ); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; + + _setupAndExecuteOneTimePayment(_user, _merchant, tokenAddr, amount, _PAYMENT_SALT, _NOT_YIELDING_FUNDS); + + // Merchant receives the payment + uint256 expectedMerchantBalance = _grateful.applyFee(_merchant, amount); + assertEq( + IERC20(tokenAddr).balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch after one-time payment")) + ); + } } function test_OneTimePaymentYieldingFunds() public { - // Capture owner's initial balance before payment - uint256 ownerInitialBalance = _usdc.balanceOf(_owner); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; + + IERC20 token = IERC20(tokenAddr); + + // Capture owner's initial balance before payment + uint256 ownerInitialBalance = token.balanceOf(_owner); - // Setup one-time payment with yielding funds - _setupAndExecuteOneTimePayment(_user, _merchant, _AMOUNT_USDC, _PAYMENT_SALT, _YIELDING_FUNDS); + // Setup one-time payment with yielding funds + _setupAndExecuteOneTimePayment(_user, _merchant, tokenAddr, amount, _PAYMENT_SALT, _YIELDING_FUNDS); - // Advance time to accrue yield - vm.warp(block.timestamp + 1 days); + // Advance time to accrue yield + vm.warp(block.timestamp + 1 days); - // Calculate profit before withdrawal - uint256 profit = _grateful.calculateProfit(_merchant, address(_usdc)); + // Calculate profit before withdrawal + uint256 profit = _grateful.calculateProfit(_merchant, tokenAddr); - // Merchant withdraws funds - vm.prank(_merchant); - _grateful.withdraw(address(_usdc)); + // Merchant withdraws funds + vm.prank(_merchant); + _grateful.withdraw(tokenAddr); - // Calculate performance fee after withdrawal - uint256 performanceFee = _grateful.calculatePerformanceFee(profit); + // Calculate performance fee after withdrawal + uint256 performanceFee = _grateful.calculatePerformanceFee(profit); - uint256 initialDeposit = _grateful.applyFee(_merchant, _AMOUNT_USDC); - uint256 expectedMerchantBalance = initialDeposit + profit - performanceFee; + uint256 initialDeposit = _grateful.applyFee(_merchant, amount); + uint256 expectedMerchantBalance = initialDeposit + profit - performanceFee; - // Verify merchant's balance - assertEq(_usdc.balanceOf(_merchant), expectedMerchantBalance, "Merchant balance mismatch after withdrawal"); + // Verify merchant's balance + assertEq( + token.balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch after withdrawal")) + ); - // Verify owner's balance - uint256 ownerFinalBalance = _usdc.balanceOf(_owner); - uint256 initialFee = _AMOUNT_USDC - initialDeposit; - uint256 ownerExpectedBalanceIncrease = initialFee + performanceFee; + // Verify owner's balance + uint256 ownerFinalBalance = token.balanceOf(_owner); + uint256 initialFee = amount - initialDeposit; + uint256 ownerExpectedBalanceIncrease = initialFee + performanceFee; - assertEq( - ownerFinalBalance - ownerInitialBalance, - ownerExpectedBalanceIncrease, - "Owner did not receive correct performance fee" - ); + assertEq( + ownerFinalBalance - ownerInitialBalance, + ownerExpectedBalanceIncrease, + string(abi.encodePacked(symbol, ": Owner did not receive correct performance fee")) + ); + } } function test_OverpaidOneTimePayment() public { - uint256 paymentId = _grateful.calculateId(_user, _merchant, address(_usdc), _AMOUNT_USDC); - address precomputed = address( - _grateful.computeOneTimeAddress(_merchant, _tokens, _AMOUNT_USDC, _PAYMENT_SALT, paymentId, _NOT_YIELDING_FUNDS) - ); - - // Payer sends double the amount - deal(address(_usdc), _user, _AMOUNT_USDC * 2); - vm.prank(_user); - _usdc.transfer(precomputed, _AMOUNT_USDC * 2); - - vm.prank(_gratefulAutomation); - OneTime _oneTime = _grateful.createOneTimePayment( - _merchant, _tokens, _AMOUNT_USDC, _PAYMENT_SALT, paymentId, _NOT_YIELDING_FUNDS, precomputed - ); - - // Merchant receives the correct amount - assertEq( - _usdc.balanceOf(_merchant), - _grateful.applyFee(_merchant, _AMOUNT_USDC), - "Merchant balance mismatch after overpaid one-time payment" - ); - - // Verify excess funds are in the OneTime contract - assertEq( - _usdc.balanceOf(address(_oneTime)), _AMOUNT_USDC, "Unexpected balance in OneTime contract after overpayment" - ); - - // Rescue funds - uint256 prevPayerBalance = _usdc.balanceOf(_user); - vm.prank(_owner); - _oneTime.rescueFunds(_usdc, _user, _AMOUNT_USDC); - - // Verify payer's balance after rescuing funds - assertEq(_usdc.balanceOf(_user), prevPayerBalance + _AMOUNT_USDC, "Payer balance mismatch after rescuing funds"); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; + + uint256 paymentId = _grateful.calculateId(_user, _merchant, tokenAddr, amount); + address precomputed = address( + _grateful.computeOneTimeAddress(_merchant, _tokens, amount, _PAYMENT_SALT, paymentId, _NOT_YIELDING_FUNDS) + ); + + // Payer sends double the amount + deal(tokenAddr, _user, amount * 2); + vm.prank(_user); + IERC20 token = IERC20(tokenAddr); + token.safeTransfer(precomputed, amount * 2); + + vm.prank(_gratefulAutomation); + OneTime _oneTime = _grateful.createOneTimePayment( + _merchant, _tokens, amount, _PAYMENT_SALT, paymentId, _NOT_YIELDING_FUNDS, precomputed + ); + + // Merchant receives the correct amount + uint256 expectedMerchantBalance = _grateful.applyFee(_merchant, amount); + assertEq( + token.balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch after overpaid one-time payment")) + ); + + // Verify excess funds are in the OneTime contract + assertEq( + token.balanceOf(address(_oneTime)), + amount, + string(abi.encodePacked(symbol, ": Unexpected balance in OneTime contract after overpayment")) + ); + + // Rescue funds + uint256 prevPayerBalance = token.balanceOf(_user); + vm.prank(_owner); + _oneTime.rescueFunds(token, _user, amount); + + // Verify payer's balance after rescuing funds + assertEq( + token.balanceOf(_user), + prevPayerBalance + amount, + string(abi.encodePacked(symbol, ": Payer balance mismatch after rescuing funds")) + ); + } } function test_PaymentWithCustomFee() public { @@ -148,42 +206,48 @@ contract IntegrationGreeter is IntegrationBase { customFees[1] = 0; // 0% customFees[2] = _FEE; // Default fee after unsetting custom fee - uint256 expectedOwnerBalance = 0; - uint256 expectedMerchantBalance = 0; - - for (uint256 i = 0; i < customFees.length; i++) { - // Set custom fee - vm.prank(_owner); - if (i < 2) { - _grateful.setCustomFee(customFees[i], _merchant); - } else { - _grateful.unsetCustomFee(_merchant); + for (uint256 i = 0; i < _tokens.length; i++) { + address tokenAddr = _tokens[i]; + string memory symbol = _tokenSymbols[tokenAddr]; + uint256 amount = _tokenAmounts[tokenAddr]; + + uint256 expectedOwnerBalance = 0; + uint256 expectedMerchantBalance = 0; + + for (uint256 j = 0; j < customFees.length; j++) { + // Set custom fee + vm.prank(_owner); + if (j < 2) { + _grateful.setCustomFee(customFees[j], _merchant); + } else { + _grateful.unsetCustomFee(_merchant); + } + + // Advance time to prevent payment ID collision + vm.warp(block.timestamp + 1); + + // Process payment + _approveAndPay(_user, _merchant, tokenAddr, amount, _NOT_YIELDING_FUNDS); + + // Calculate expected amounts + uint256 feeAmount = (amount * customFees[j]) / 10_000; + uint256 merchantAmount = amount - feeAmount; + + expectedOwnerBalance += feeAmount; + expectedMerchantBalance += merchantAmount; + + // Verify balances + assertEq( + IERC20(tokenAddr).balanceOf(_merchant), + expectedMerchantBalance, + string(abi.encodePacked(symbol, ": Merchant balance mismatch at iteration ", j)) + ); + assertEq( + IERC20(tokenAddr).balanceOf(_owner), + expectedOwnerBalance, + string(abi.encodePacked(symbol, ": Owner balance mismatch at iteration ", j)) + ); } - - // Advance time to prevent payment ID collision - vm.warp(block.timestamp + 1); - - // Process payment - _approveAndPay(_user, _merchant, _AMOUNT_USDC, _NOT_YIELDING_FUNDS); - - // Calculate expected amounts - uint256 feeAmount = (_AMOUNT_USDC * customFees[i]) / 10_000; - uint256 merchantAmount = _AMOUNT_USDC - feeAmount; - - expectedOwnerBalance += feeAmount; - expectedMerchantBalance += merchantAmount; - - // Verify balances - assertEq( - _usdc.balanceOf(_merchant), - expectedMerchantBalance, - string(abi.encodePacked("Merchant balance mismatch at iteration ", i)) - ); - assertEq( - _usdc.balanceOf(_owner), - expectedOwnerBalance, - string(abi.encodePacked("Owner balance mismatch at iteration ", i)) - ); } } } diff --git a/test/integration/IntegrationBase.sol b/test/integration/IntegrationBase.sol index a7262ba..9d2034b 100644 --- a/test/integration/IntegrationBase.sol +++ b/test/integration/IntegrationBase.sol @@ -2,30 +2,39 @@ pragma solidity 0.8.26; import {Grateful, IGrateful} from "contracts/Grateful.sol"; + import {Test} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; +import {Deploy} from "script/Deploy.sol"; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {AaveV3Vault} from "contracts/vaults/AaveV3Vault.sol"; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IPool, IRewardsController} from "yield-daddy/aave-v3/AaveV3ERC4626.sol"; -contract IntegrationBase is Test { +interface IERC20Symbol { + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); +} + +contract IntegrationBase is Test, Deploy { + using SafeERC20 for IERC20; + /*////////////////////////////////////////////////////////////// - CONSTANTS + CONSTANTS //////////////////////////////////////////////////////////////*/ + string internal constant _FORKED_NETWORK = "mainnet"; uint256 internal constant _FORK_BLOCK = 18_920_905; - uint256 internal constant _AMOUNT_USDC = 10 * 10 ** 6; // 10 USDC - uint256 internal constant _AMOUNT_DAI = 10 * 10 ** 18; // 10 DAI - uint256 internal constant _SUBSCRIPTION_PLAN_ID = 0; uint256 internal constant _FEE = 100; // 1% fee uint256 internal constant _PAYMENT_SALT = 4; // Salt for computing payment addresses bool internal constant _YIELDING_FUNDS = true; bool internal constant _NOT_YIELDING_FUNDS = false; /*////////////////////////////////////////////////////////////// - ADDRESSES + ADDRESSES //////////////////////////////////////////////////////////////*/ // EOAs @@ -34,120 +43,97 @@ contract IntegrationBase is Test { address internal _owner = makeAddr("owner"); address internal _gratefulAutomation = makeAddr("gratefulAutomation"); - // Tokens - IERC20 internal _usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); - IERC20 internal _usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); - IERC20 internal _dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); - - // Constructor args + // Tokens array address[] internal _tokens; - address internal _aUsdc = 0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c; - address internal _aUsdt = 0x23878914EFE38d27C4D67Ab83ed1b93A74D4086a; - address internal _aDai = 0x018008bfb33d285247A21d44E50697654f754e63; - address internal _rewardsController = 0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb; - IPool internal _aavePool = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2); - // Grateful contracts + // Token symbols + mapping(address => string) internal _tokenSymbols; + + // Amounts per token + mapping(address => uint256) internal _tokenAmounts; + + // Grateful contract IGrateful internal _grateful; - AaveV3Vault internal _usdcVault; - AaveV3Vault internal _usdtVault; - AaveV3Vault internal _daiVault; /*////////////////////////////////////////////////////////////// - SETUP FUNCTION + SETUP FUNCTION //////////////////////////////////////////////////////////////*/ function setUp() public { + // Use fork block from deployment parameters + vm.createSelectFork(vm.rpcUrl(_FORKED_NETWORK), _FORK_BLOCK); vm.startPrank(_owner); - vm.createSelectFork(vm.rpcUrl("mainnet"), _FORK_BLOCK); - - _tokens = new address[](3); - _tokens[0] = address(_usdc); - _tokens[1] = address(_usdt); - _tokens[2] = address(_dai); - - _grateful = new Grateful(_tokens, _aavePool, _FEE); - - _usdcVault = new AaveV3Vault( - ERC20(address(_usdc)), - ERC20(_aUsdc), - _aavePool, - address(0), - IRewardsController(_rewardsController), - address(_grateful) - ); - _daiVault = new AaveV3Vault( - ERC20(address(_dai)), - ERC20(_aDai), - _aavePool, - address(0), - IRewardsController(_rewardsController), - address(_grateful) - ); - _usdtVault = new AaveV3Vault( - ERC20(address(_usdt)), - ERC20(_aUsdt), - _aavePool, - address(0), - IRewardsController(_rewardsController), - address(_grateful) - ); + + // Get deployment parameters + DeploymentParams memory params = getDeploymentParams(block.chainid); + + // Copy tokens to storage variable _tokens + uint256 tokensLength = params.tokens.length; + _tokens = new address[](tokensLength); + for (uint256 i = 0; i < tokensLength; i++) { + _tokens[i] = params.tokens[i]; + } + + // Run deployment script + run(); + + // Access the deployed contracts + _grateful = grateful; + + // Get token symbols and label tokens and vaults + for (uint256 i = 0; i < tokensLength; i++) { + address tokenAddr = _tokens[i]; + IERC20Symbol token = IERC20Symbol(tokenAddr); + + string memory symbol = token.symbol(); + _tokenSymbols[tokenAddr] = symbol; + + // Label the token + vm.label(tokenAddr, symbol); + + // Label the vault + AaveV3Vault vault = vaults[tokenAddr]; + vm.label(address(vault), string(abi.encodePacked(symbol, " Vault"))); + + // Set amount per token (e.g., 10 tokens) + uint8 decimals = token.decimals(); + uint256 amount = 10 * (10 ** decimals); + _tokenAmounts[tokenAddr] = amount; + } vm.label(address(_grateful), "Grateful"); - vm.label(address(_usdcVault), "USDC Vault"); - vm.label(address(_daiVault), "DAI Vault"); - vm.label(address(_usdtVault), "USDT Vault"); - _grateful.addVault(address(_usdc), address(_usdcVault)); - _grateful.addVault(address(_usdt), address(_usdtVault)); - _grateful.addVault(address(_dai), address(_daiVault)); vm.stopPrank(); } /*////////////////////////////////////////////////////////////// - HELPER FUNCTIONS + HELPER FUNCTIONS //////////////////////////////////////////////////////////////*/ - function _approveAndPay(address payer, address merchant, uint256 amount, bool yieldFunds) internal { - uint256 paymentId = _grateful.calculateId(payer, merchant, address(_usdc), amount); - deal(address(_usdc), payer, amount); + function _approveAndPay(address payer, address merchant, address tokenAddr, uint256 amount, bool yieldFunds) internal { + uint256 paymentId = _grateful.calculateId(payer, merchant, tokenAddr, amount); + deal(tokenAddr, payer, amount); vm.startPrank(payer); - _usdc.approve(address(_grateful), amount); - _grateful.pay(merchant, address(_usdc), amount, paymentId, yieldFunds); + IERC20 token = IERC20(tokenAddr); + token.forceApprove(address(_grateful), amount); + _grateful.pay(merchant, tokenAddr, amount, paymentId, yieldFunds); vm.stopPrank(); } - function _calculateExpectedMerchantBalance( - uint256 initialDeposit, - uint256 profit, - uint256 performanceFeeRate - ) internal pure returns (uint256) { - uint256 performanceFee = (profit * performanceFeeRate) / 10_000; - uint256 totalAssets = initialDeposit + profit; - return totalAssets - performanceFee; - } - - function _getOwnerBalanceIncrease(uint256 initialFee, uint256 performanceFee) internal pure returns (uint256) { - return initialFee + performanceFee; - } - - function _captureBalances() internal view returns (uint256 ownerBalance, uint256 merchantBalance) { - ownerBalance = _usdc.balanceOf(_owner); - merchantBalance = _usdc.balanceOf(_merchant); - } - function _setupAndExecuteOneTimePayment( address payer, address merchant, + address tokenAddr, uint256 amount, uint256 salt, bool yieldFunds ) internal returns (uint256 paymentId, address precomputed) { - deal(address(_usdc), payer, amount); - paymentId = _grateful.calculateId(payer, merchant, address(_usdc), amount); + deal(tokenAddr, payer, amount); + paymentId = _grateful.calculateId(payer, merchant, tokenAddr, amount); precomputed = address(_grateful.computeOneTimeAddress(merchant, _tokens, amount, salt, paymentId, yieldFunds)); vm.prank(payer); - _usdc.transfer(precomputed, amount); + IERC20 token = IERC20(tokenAddr); + token.safeTransfer(precomputed, amount); vm.prank(_gratefulAutomation); _grateful.createOneTimePayment(merchant, _tokens, amount, salt, paymentId, yieldFunds, precomputed); }