Skip to content

Commit

Permalink
Cleanup comments
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFirekeeper committed Feb 15, 2024
1 parent 68ce6b7 commit 838d074
Showing 1 changed file with 55 additions and 14 deletions.
69 changes: 55 additions & 14 deletions contracts/prebuilts/account/paymaster/SimpleERC20Paymaster.sol
Original file line number Diff line number Diff line change
@@ -1,59 +1,99 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

/// @author thirdweb

// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/

// ====== External imports ======
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeTransferLib } from "../utils/SafeTransferLib.sol";

import "../utils/BasePaymaster.sol";
// ========== Internal imports ==========
import { SafeTransferLib } from "../utils/SafeTransferLib.sol";
import { BasePaymaster } from "../utils/BasePaymaster.sol";

/**
* @title SimpleERC20Paymaster
* @dev This contract allows UserOps to be sponsored with a fixed amount of ERC20 tokens instead of the native chain currency.
* It inherits from the BasePaymaster contract and implements specific logic to handle ERC20 payments for transactions.
*/
contract SimpleERC20Paymaster is BasePaymaster {
using UserOperationLib for UserOperation;
using SafeERC20 for IERC20;

IERC20 public token;
uint256 public tokenPricePerOp;
IERC20 public token; // The ERC20 token used for payment
uint256 public tokenPricePerOp; // The price per operation in the specified ERC20 tokens (in wei)

/**
* @dev Emitted when a user operation is successfully sponsored, indicating the actual token cost and gas cost.
*/
event UserOperationSponsored(address indexed user, uint256 actualTokenNeeded, uint256 actualGasCost);

/**
* @dev Initializes the paymaster contract with the entry point, token, and price per operation.
* @param _entryPoint The entry point contract address for handling operations.
* @param _token The ERC20 token address used for payments.
* @param _tokenPricePerOp The cost per operation in tokens.
*/
constructor(IEntryPoint _entryPoint, IERC20 _token, uint256 _tokenPricePerOp) BasePaymaster(_entryPoint) {
token = _token;
tokenPricePerOp = _tokenPricePerOp;
}

/**
* @dev Allows the contract owner to update the token price per operation.
* @param _tokenPricePerOp The new price per operation in tokens.
*/
function setTokenPricePerOp(uint256 _tokenPricePerOp) external onlyOwner {
tokenPricePerOp = _tokenPricePerOp;
}

/**
* @dev Withdraws ERC20 tokens from the contract to a specified address, callable only by the contract owner.
* @param to The address to which the tokens will be transferred.
* @param amount The amount of tokens to transfer.
*/
function withdrawToken(address to, uint256 amount) external onlyOwner {
SafeTransferLib.safeTransfer(address(token), to, amount);
}

/**
* @dev Validates the paymaster user operation before execution, ensuring sufficient payment and proper data format.
* @param userOp The user operation to validate.
* @param context Additional context for validation (unused).
* @param validationData Additional data for validation (unused).
* @return context A bytes array for the operation context.
* @return validationResult The result of the validation, 0 if successful.
*/
function _validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32,
uint256
) internal override returns (bytes memory context, uint256 validationResult) {
unchecked {
uint256 cachedTokenPrice = tokenPricePerOp;
require(cachedTokenPrice != 0, "SPM : price not set");
require(cachedTokenPrice != 0, "SPM: price not set");
uint256 length = userOp.paymasterAndData.length - 20;
// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf is the mask for the last 6 bits 011111 which mean length should be 100000(32) || 000000(0)
require(
length & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf == 0,
"SPM : invalid data length"
"SPM: invalid data length"
);
// NOTE: we assumed that nativeAsset's decimals is 18
if (length == 32) {
require(
cachedTokenPrice <= uint256(bytes32(userOp.paymasterAndData[20:52])),
"SPM : token amount too high"
"SPM: token amount too high"
);
}
SafeTransferLib.safeTransferFrom(address(token), userOp.sender, address(this), cachedTokenPrice);
context = abi.encodePacked(cachedTokenPrice, userOp.sender);
// No return here since validationData == 0 and we have context saved in memory
validationResult = 0;
return (abi.encodePacked(cachedTokenPrice, userOp.sender), 0);
}
}

Expand All @@ -64,19 +104,20 @@ contract SimpleERC20Paymaster is BasePaymaster {
/// @param actualGasCost The actual gas cost of the transaction.
function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override {
if (mode == PostOpMode.postOpReverted) {
return; // Do nothing here to not revert the whole bundle and harm reputation
return; // If operation reverted, do nothing to avoid affecting bundle reputation
}
unchecked {
uint256 actualTokenNeeded = tokenPricePerOp;
// Refund excess tokens if more were provided than needed
if (uint256(bytes32(context[0:32])) > actualTokenNeeded) {
// If the initially provided token amount is greater than the actual amount needed, refund the difference
SafeTransferLib.safeTransfer(
address(token),
address(bytes20(context[32:52])),
uint256(bytes32(context[0:32])) - actualTokenNeeded
);
} // If the token amount is not greater than the actual amount needed, no refund occurs

// Emit an event indicating the user operation was sponsored
emit UserOperationSponsored(address(bytes20(context[32:52])), actualTokenNeeded, actualGasCost);
}
}
Expand Down

0 comments on commit 838d074

Please sign in to comment.