Contract Name:
DYLIPaymaster
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./IPaymaster.sol";
contract DYLIPaymaster is IPaymaster {
address constant BOOTLOADER = address(0x8001);
address public owner;
mapping(address => bool) public whitelistedContracts;
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
constructor() {
owner = msg.sender;
}
function validateAndPayForPaymasterTransaction(
bytes32,
bytes32,
Transaction calldata _transaction
) external payable returns (bytes4 magic, bytes memory context) {
require(
msg.sender == BOOTLOADER,
"Only the Bootloader can call this function"
);
require(
whitelistedContracts[address(uint160(_transaction.to))],
"Transaction not from a whitelisted contract"
);
context = "";
magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC;
uint requiredETH = _transaction.gasLimit * _transaction.maxFeePerGas;
(bool success, ) = BOOTLOADER.call{value: requiredETH}("");
require(success, "Bootloader call failed");
}
function addWhitelistedContract(address _contract) external onlyOwner {
require(_contract != address(0), "Invalid address");
whitelistedContracts[_contract] = true;
}
function removeWhitelistedContract(address _contract) external onlyOwner {
require(_contract != address(0), "Invalid address");
whitelistedContracts[_contract] = false;
}
function withdraw(address payable _to, uint256 _amount) external onlyOwner {
require(_to != address(0), "Invalid address");
require(_amount <= address(this).balance, "Insufficient balance");
(bool success, ) = _to.call{value: _amount}("");
require(success, "Withdraw failed");
}
receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./Transaction.sol";
enum ExecutionResult {
Revert,
Success
}
bytes4 constant PAYMASTER_VALIDATION_SUCCESS_MAGIC = IPaymaster
.validateAndPayForPaymasterTransaction
.selector;
interface IPaymaster {
/// @dev Called by the bootloader to verify that the paymaster agrees to pay for the
/// fee for the transaction. This transaction should also send the necessary amount of funds onto the bootloader
/// address.
/// @param _txHash The hash of the transaction
/// @param _suggestedSignedHash The hash of the transaction that is signed by an EOA
/// @param _transaction The transaction itself.
/// @return magic The value that should be equal to the signature of the validateAndPayForPaymasterTransaction
/// if the paymaster agrees to pay for the transaction.
/// @return context The "context" of the transaction: an array of bytes of length at most 1024 bytes, which will be
/// passed to the `postTransaction` method of the account.
/// @dev The developer should strive to preserve as many steps as possible both for valid
/// and invalid transactions as this very method is also used during the gas fee estimation
/// (without some of the necessary data, e.g. signature).
function validateAndPayForPaymasterTransaction(
bytes32 _txHash,
bytes32 _suggestedSignedHash,
Transaction calldata _transaction
) external payable returns (bytes4 magic, bytes memory context);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/// @notice Structure used to represent a zkSync transaction.
struct Transaction {
// The type of the transaction.
uint256 txType;
// The caller.
uint256 from;
// The callee.
uint256 to;
// The gasLimit to pass with the transaction.
// It has the same meaning as Ethereum's gasLimit.
uint256 gasLimit;
// The maximum amount of gas the user is willing to pay for a byte of pubdata.
uint256 gasPerPubdataByteLimit;
// The maximum fee per gas that the user is willing to pay.
// It is akin to EIP1559's maxFeePerGas.
uint256 maxFeePerGas;
// The maximum priority fee per gas that the user is willing to pay.
// It is akin to EIP1559's maxPriorityFeePerGas.
uint256 maxPriorityFeePerGas;
// The transaction's paymaster. If there is no paymaster, it is equal to 0.
uint256 paymaster;
// The nonce of the transaction.
uint256 nonce;
// The value to pass with the transaction.
uint256 value;
// In the future, we might want to add some
// new fields to the struct. The `txData` struct
// is to be passed to account and any changes to its structure
// would mean a breaking change to these accounts. In order to prevent this,
// we should keep some fields as "reserved".
// It is also recommended that their length is fixed, since
// it would allow easier proof integration (in case we will need
// some special circuit for preprocessing transactions).
uint256[4] reserved;
// The transaction's calldata.
bytes data;
// The signature of the transaction.
bytes signature;
// The properly formatted hashes of bytecodes that must be published on L1
// with the inclusion of this transaction. Note, that a bytecode has been published
// before, the user won't pay fees for its republishing.
bytes32[] factoryDeps;
// The input to the paymaster.
bytes paymasterInput;
// Reserved dynamic type for the future use-case. Using it should be avoided,
// But it is still here, just in case we want to enable some additional functionality.
bytes reservedDynamic;
}