Skip to content

Commit

Permalink
fix: add null addresses checks in creditGasFees (#302)
Browse files Browse the repository at this point in the history
  • Loading branch information
nvtaveras committed Dec 1, 2023
1 parent 3c4bf8d commit e6fd126
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 11 deletions.
32 changes: 25 additions & 7 deletions contracts/tokens/StableTokenV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ contract StableTokenV2 is ERC20PermitUpgradeable, IStableTokenV2, CalledByVm {
* @param value The amount of balance to reserve
* @dev Note that this function is called by the protocol when paying for tx fees in this
* currency. After the tx is executed, gas is refunded to the sender and credited to the
* various tx fee recipients via a call to `creditGasFees`. Note too that the events emitted
* by `creditGasFees` reflect the *net* gas fee payments for the transaction.
* various tx fee recipients via a call to `creditGasFees`.
*/
function debitGasFees(address from, uint256 value) external onlyVm {
_burn(from, value);
Expand All @@ -278,8 +277,7 @@ contract StableTokenV2 is ERC20PermitUpgradeable, IStableTokenV2, CalledByVm {
* @param gatewayFee Gateway fee
* @dev Note that this function is called by the protocol when paying for tx fees in this
* currency. Before the tx is executed, gas is debited from the sender via a call to
* `debitGasFees`. Note too that the events emitted by `creditGasFees` reflect the *net* gas fee
* payments for the transaction.
* `debitGasFees`.
*/
function creditGasFees(
address from,
Expand All @@ -291,9 +289,29 @@ contract StableTokenV2 is ERC20PermitUpgradeable, IStableTokenV2, CalledByVm {
uint256 gatewayFee,
uint256 baseTxFee
) external onlyVm {
uint256 amountToBurn;
_mint(from, refund + tipTxFee + gatewayFee + baseTxFee);
_transfer(from, feeRecipient, tipTxFee);
_transfer(from, gatewayFeeRecipient, gatewayFee);
_transfer(from, communityFund, baseTxFee);

if (feeRecipient != address(0)) {
_transfer(from, feeRecipient, tipTxFee);
} else if (tipTxFee > 0) {
amountToBurn += tipTxFee;
}

if (gatewayFeeRecipient != address(0)) {
_transfer(from, gatewayFeeRecipient, gatewayFee);
} else if (gatewayFee > 0) {
amountToBurn += gatewayFee;
}

if (communityFund != address(0)) {
_transfer(from, communityFund, baseTxFee);
} else if (baseTxFee > 0) {
amountToBurn += baseTxFee;
}

if (amountToBurn > 0) {
_burn(from, amountToBurn);
}
}
}
122 changes: 118 additions & 4 deletions test/tokens/StableTokenV2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { StableTokenV2 } from "contracts/tokens/StableTokenV2.sol";

contract StableTokenV2Test is BaseTest {
event TransferComment(string comment);
event Transfer(address indexed from, address indexed to, uint256 value);

bytes32 private constant _PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
Expand All @@ -30,7 +31,7 @@ contract StableTokenV2Test is BaseTest {

address feeRecipient = address(0x3001);
address gatewayFeeRecipient = address(0x3002);
address conmunityFund = address(0x3003);
address communityFund = address(0x3003);

StableTokenV2 private token;

Expand Down Expand Up @@ -163,21 +164,22 @@ contract StableTokenV2Test is BaseTest {

function test_creditGasFees_whenCallerNotVM_shouldRevert() public {
vm.expectRevert("Only VM can call");
token.creditGasFees(holder0, feeRecipient, gatewayFeeRecipient, conmunityFund, 25, 25, 25, 25);
token.creditGasFees(holder0, feeRecipient, gatewayFeeRecipient, communityFund, 25, 25, 25, 25);
}

function test_creditGasFees_whenCalledByVm_shouldCreditFees() public {
uint256 refund = 20;
uint256 tipTxFee = 30;
uint256 gatewayFee = 10;
uint256 baseTxFee = 40;
uint256 tokenSupplyBefore = token.totalSupply();

vm.prank(address(0));
token.creditGasFees(
holder0,
feeRecipient,
gatewayFeeRecipient,
conmunityFund,
communityFund,
refund,
tipTxFee,
gatewayFee,
Expand All @@ -187,7 +189,119 @@ contract StableTokenV2Test is BaseTest {
assertEq(token.balanceOf(holder0), 1000 + refund);
assertEq(token.balanceOf(feeRecipient), tipTxFee);
assertEq(token.balanceOf(gatewayFeeRecipient), gatewayFee);
assertEq(token.balanceOf(conmunityFund), baseTxFee);
assertEq(token.balanceOf(communityFund), baseTxFee);
assertEq(token.totalSupply(), tokenSupplyBefore + refund + tipTxFee + gatewayFee + baseTxFee);
}

function test_creditGasFees_whenCalledByVm_with0xFeeRecipient_shouldBurnTipTxFee() public {
uint256 refund = 20;
uint256 tipTxFee = 30;
uint256 gatewayFee = 10;
uint256 baseTxFee = 40;
uint256 holder0InitialBalance = token.balanceOf(holder0);
uint256 tokenSupplyBefore = token.totalSupply();
uint256 newlyMinted = refund + tipTxFee + gatewayFee + baseTxFee;

vm.prank(address(0));
token.creditGasFees(
holder0,
address(0),
gatewayFeeRecipient,
communityFund,
refund,
tipTxFee,
gatewayFee,
baseTxFee
);

assertEq(token.balanceOf(holder0), holder0InitialBalance + refund);
assertEq(token.balanceOf(feeRecipient), 0);
assertEq(token.balanceOf(gatewayFeeRecipient), gatewayFee);
assertEq(token.balanceOf(communityFund), baseTxFee);
assertEq(token.totalSupply(), tokenSupplyBefore + newlyMinted - tipTxFee);
}

function test_creditGasFees_whenCalledByVm_with0xGatewayFeeRecipient_shouldBurnGateWayFee() public {
uint256 refund = 20;
uint256 tipTxFee = 30;
uint256 gatewayFee = 10;
uint256 baseTxFee = 40;
uint256 holder0InitialBalance = token.balanceOf(holder0);
uint256 tokenSupplyBefore = token.totalSupply();
uint256 newlyMinted = refund + tipTxFee + gatewayFee + baseTxFee;

vm.prank(address(0));
token.creditGasFees(holder0, feeRecipient, address(0), communityFund, refund, tipTxFee, gatewayFee, baseTxFee);

assertEq(token.balanceOf(holder0), holder0InitialBalance + refund);
assertEq(token.balanceOf(feeRecipient), tipTxFee);
assertEq(token.balanceOf(gatewayFeeRecipient), 0);
assertEq(token.balanceOf(communityFund), baseTxFee);
assertEq(token.totalSupply(), tokenSupplyBefore + newlyMinted - gatewayFee);
}

function test_creditGasFees_whenCalledByVm_with0xCommunityFund_shouldBurnBaseTxFee() public {
uint256 refund = 20;
uint256 tipTxFee = 30;
uint256 gatewayFee = 10;
uint256 baseTxFee = 40;
uint256 holder0InitialBalance = token.balanceOf(holder0);
uint256 tokenSupplyBefore = token.totalSupply();
uint256 newlyMinted = refund + tipTxFee + gatewayFee + baseTxFee;

vm.prank(address(0));
token.creditGasFees(
holder0,
feeRecipient,
gatewayFeeRecipient,
address(0),
refund,
tipTxFee,
gatewayFee,
baseTxFee
);

assertEq(token.balanceOf(holder0), holder0InitialBalance + refund);
assertEq(token.balanceOf(feeRecipient), tipTxFee);
assertEq(token.balanceOf(gatewayFeeRecipient), gatewayFee);
assertEq(token.balanceOf(communityFund), 0);
assertEq(token.totalSupply(), tokenSupplyBefore + newlyMinted - baseTxFee);
}

function test_creditGasFees_whenCalledByVm_withMultiple0xRecipients_shouldBurnTheirRespectiveFees() public {
uint256 refund = 20;
uint256 tipTxFee = 30;
uint256 gatewayFee = 10;
uint256 baseTxFee = 40;
uint256 holder0InitialBalance = token.balanceOf(holder0);
uint256 tokenSupplyBefore0 = token.totalSupply();
uint256 newlyMinted0 = refund + tipTxFee + gatewayFee + baseTxFee;

vm.prank(address(0));
// gateWayFeeRecipient and communityFund both 0x
token.creditGasFees(holder0, feeRecipient, address(0), address(0), refund, tipTxFee, gatewayFee, baseTxFee);

assertEq(token.balanceOf(holder0), holder0InitialBalance + refund);
assertEq(token.balanceOf(feeRecipient), tipTxFee);
assertEq(token.balanceOf(gatewayFeeRecipient), 0);
assertEq(token.balanceOf(communityFund), 0);
assertEq(token.totalSupply(), tokenSupplyBefore0 + newlyMinted0 - gatewayFee - baseTxFee);

// case with both feeRecipient and communityFund both 0x
uint256 holder1InitialBalance = token.balanceOf(holder1);
uint256 feeRecipientBalance = token.balanceOf(feeRecipient);
uint256 gatewayFeeRecipientBalance = token.balanceOf(gatewayFeeRecipient);
uint256 communityFundBalance = token.balanceOf(communityFund);
uint256 tokenSupplyBefore1 = token.totalSupply();
uint256 newlyMinted1 = refund + tipTxFee + gatewayFee + baseTxFee;
vm.prank(address(0));
token.creditGasFees(holder1, address(0), gatewayFeeRecipient, address(0), refund, tipTxFee, gatewayFee, baseTxFee);

assertEq(token.balanceOf(holder1), holder1InitialBalance + refund);
assertEq(token.balanceOf(feeRecipient), feeRecipientBalance);
assertEq(token.balanceOf(gatewayFeeRecipient), gatewayFeeRecipientBalance + gatewayFee);
assertEq(token.balanceOf(communityFund), communityFundBalance);
assertEq(token.totalSupply(), tokenSupplyBefore1 + newlyMinted1 - tipTxFee - baseTxFee);
}

function buildTypedDataHash(
Expand Down

0 comments on commit e6fd126

Please sign in to comment.