Skip to content

Commit

Permalink
fixing
Browse files Browse the repository at this point in the history
  • Loading branch information
Filipp Makarov authored and Filipp Makarov committed Nov 21, 2024
1 parent 04580de commit 9e72580
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 15 deletions.
25 changes: 21 additions & 4 deletions contracts/token/BiconomyTokenPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,14 @@ contract BiconomyTokenPaymaster is

// deduct max penalty from the token amount we pass to the postOp
// so we don't refund it at postOp
context = abi.encode(userOp.sender, tokenAddress, tokenAmount-((maxPenalty*tokenPrice*externalPriceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)), tokenPrice, externalPriceMarkup, userOpHash);
context = abi.encode(
userOp.sender,
tokenAddress,
tokenAmount-((maxPenalty*tokenPrice*externalPriceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)),
tokenPrice,
externalPriceMarkup,
userOpHash
);
validationData = _packValidationData(false, validUntil, validAfter);
} else if (mode == PaymasterMode.INDEPENDENT) {
// Use only oracles for the token specified in modeSpecificData
Expand All @@ -528,12 +535,14 @@ contract BiconomyTokenPaymaster is
// Get address for token used to pay
address tokenAddress = modeSpecificData.parseIndependentModeSpecificData();
uint256 tokenPrice = _getPrice(tokenAddress);

console2.log("tokenPrice in validation phase", tokenPrice);

if(tokenPrice == 0) {
revert TokenNotSupported();
}
uint256 tokenAmount;

// TODO: Account for penalties here
{
// Calculate token amount to precharge
uint256 maxFeePerGas = UserOperationLib.unpackMaxFeePerGas(userOp);
Expand All @@ -545,7 +554,14 @@ contract BiconomyTokenPaymaster is
SafeTransferLib.safeTransferFrom(tokenAddress, userOp.sender, address(this), tokenAmount);

context =
abi.encode(userOp.sender, tokenAddress, tokenAmount-((maxPenalty*tokenPrice*independentPriceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)), tokenPrice, independentPriceMarkup, userOpHash);
abi.encode(
userOp.sender,
tokenAddress,
tokenAmount-((maxPenalty*tokenPrice*independentPriceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)),
tokenPrice,
independentPriceMarkup,
userOpHash
);
validationData = 0; // Validation success and price is valid indefinetly
}
}
Expand Down Expand Up @@ -576,6 +592,8 @@ contract BiconomyTokenPaymaster is
bytes32 userOpHash
) = abi.decode(context, (address, address, uint256, uint256, uint32, bytes32));

console2.log("unaccountedGas", unaccountedGas);

// Calculate the actual cost in tokens based on the actual gas cost and the token price
uint256 actualTokenAmount = (
(actualGasCost + (unaccountedGas * actualUserOpFeePerGas)) * appliedPriceMarkup * tokenPrice
Expand All @@ -587,7 +605,6 @@ contract BiconomyTokenPaymaster is
emit TokensRefunded(userOpSender, tokenAddress, refundAmount, userOpHash);
}

// Todo: Review events and what we need to emit.
emit PaidGasInTokens(
userOpSender, tokenAddress, actualGasCost, actualTokenAmount, appliedPriceMarkup, tokenPrice, userOpHash
);
Expand Down
25 changes: 18 additions & 7 deletions test/base/TestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,6 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors {
}

// Note: Token paymaster could also get into stack deep issues.
// TODO: Refactor to reduce stack depth
/// @notice Generates and signs the paymaster data for a user operation.
/// @dev This function prepares the `paymasterAndData` field for a `PackedUserOperation` with the correct signature.
/// @param userOp The user operation to be signed.
Expand Down Expand Up @@ -409,6 +408,15 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors {
) * 10 * userOp.unpackMaxFeePerGas() / 100;
}

function getRealPenalty(PackedUserOperation calldata userOp, uint256 gasValue, uint256 gasPrice) public pure returns (uint256) {
uint256 gasLimit = uint128(uint256(userOp.accountGasLimits))
+ uint128(bytes16(userOp.paymasterAndData[_PAYMASTER_POSTOP_GAS_OFFSET:_PAYMASTER_DATA_OFFSET]));

uint256 penalty = (gasLimit - gasValue) * 10 * gasPrice / 100;
console2.log("penalty in tests", penalty);
return penalty;
}

// Note: can pack values into one struct
function calculateAndAssertAdjustments(
BiconomySponsorshipPaymaster bicoPaymaster,
Expand Down Expand Up @@ -449,7 +457,8 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors {
uint256 initialPaymasterTokenBalance,
uint256 tokenPrice,
uint32 priceMarkup,
uint256 maxPenalty
uint256 maxPenalty,
uint256 realPenalty
)
internal
view
Expand All @@ -471,14 +480,16 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors {
console2.log("gasCollectedInERC20ByPaymaster", gasCollectedInERC20ByPaymaster);
console2.log("maxPenalty", maxPenalty);
console2.log("totalGasFeePaid", totalGasFeePaid);
console2.log(uint256(1226028000000) + uint256(1794876000000));

uint256 gasPaidBySAInNativeTokens = gasPaidBySAInERC20 * 1e18 / tokenPrice;

// Review we will also need to update premium numbers in below if there is premium: multiply by 1e6 / premium
assertGt(gasPaidBySAInERC20 * 1e18 / tokenPrice, BUNDLER.addr.balance - initialBundlerBalance);
assertGt(gasPaidBySAInNativeTokens, BUNDLER.addr.balance - initialBundlerBalance);

// Ensure that max 2% difference between total gas paid + the adjustment premium and gas paid by smart account (ERC20 charge * token gas price) (from
// Todo
// assertApproxEqRel(totalGasFeePaid + actualPriceMarkup + maxPenalty, gasPaidByDapp, 0.02e18);
// Ensure that max 4% difference between what is should have been charged and what was charged
// this difference comes from difference of postop gas and estimated postop gas (paymaster.unaccountedGas)
// and from estimation of real penalty which is not emitted by EP :(
assertApproxEqRel(totalGasFeePaid + maxPenalty - realPenalty, gasPaidBySAInNativeTokens, 0.04e18);
}

function _toSingletonArray(address addr) internal pure returns (address[] memory) {
Expand Down
7 changes: 6 additions & 1 deletion test/unit/concrete/TestTokenPaymaster.Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ contract TestTokenPaymasterBase is TestBase {
vm.expectEmit(true, true, false, false, address(tokenPaymaster));
emit IBiconomyTokenPaymaster.PaidGasInTokens(address(ALICE_ACCOUNT), address(usdc), 0, 0, 1e6, 0, bytes32(0));

uint256 customGasPrice = 3e6;
startPrank(BUNDLER.addr);
vm.txGasPrice(customGasPrice);
uint256 gasValue = gasleft();
ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr));
gasValue = gasValue - gasleft();
stopPrank();

calculateAndAssertAdjustmentsForTokenPaymaster(
Expand All @@ -132,7 +136,8 @@ contract TestTokenPaymasterBase is TestBase {
initialPaymasterTokenBalance,
2624042830,
100000,
this.getMaxPenalty(ops[0]));
this.getMaxPenalty(ops[0]),
this.getRealPenalty(ops[0], gasValue, customGasPrice));
}

// test to make a swap.
Expand Down
13 changes: 10 additions & 3 deletions test/unit/concrete/TestTokenPaymaster.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ contract TestTokenPaymaster is TestBase {
MockToken public testToken;
MockToken public testToken2;
MockOracle public tokenOracle;
uint256 public customGasPrice;

function setUp() public {
setupPaymasterTestEnvironment();

uint256 customGasPrice = 3e6;
customGasPrice = 3e6;
vm.txGasPrice(customGasPrice);

// Deploy mock oracles and tokens
Expand Down Expand Up @@ -453,7 +454,9 @@ contract TestTokenPaymaster is TestBase {

// Execute the operation
startPrank(BUNDLER.addr);
uint256 gasValue = gasleft();
ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr));
gasValue = gasValue - gasleft();
stopPrank();

calculateAndAssertAdjustmentsForTokenPaymaster(
Expand All @@ -465,7 +468,8 @@ contract TestTokenPaymaster is TestBase {
initialPaymasterTokenBalance,
1e18, // tokenPrice
100000,
this.getMaxPenalty(ops[0]));
this.getMaxPenalty(ops[0]),
this.getRealPenalty(ops[0], gasValue, customGasPrice));
}

function test_Success_TokenPaymaster_IndependentMode_WithoutPremium() external {
Expand Down Expand Up @@ -508,7 +512,9 @@ contract TestTokenPaymaster is TestBase {
emit IBiconomyTokenPaymaster.PaidGasInTokens(address(ALICE_ACCOUNT), address(testToken), 0, 0, 1e6, 0, bytes32(0));

startPrank(BUNDLER.addr);
uint256 gasValue = gasleft();
ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr));
gasValue = gasValue - gasleft();
stopPrank();

calculateAndAssertAdjustmentsForTokenPaymaster(
Expand All @@ -520,6 +526,7 @@ contract TestTokenPaymaster is TestBase {
initialPaymasterTokenBalance,
1e18, // tokenPrice
100000,
this.getMaxPenalty(ops[0]));
this.getMaxPenalty(ops[0]),
this.getRealPenalty(ops[0], gasValue, customGasPrice));
}
}

0 comments on commit 9e72580

Please sign in to comment.