Contrat
Contrat
0x7e94a24e40…639525d745
0x7e94a24e4084c4fee2562b9d0b906f639525d745
Solde WTG
0 WTG
≈ 0,00 FCFA (@ 23,45 FCFA/WTG)
Avoirs en tokens
0 token
≈ 0,00 FCFA
Plus d'infos
Transactions envoyées0
Dernière activitéil y a 2 sem.
Première activitéil y a 2 sem.
Financé par
—
Code du contrat
✓ VérifiéWintgVerifyingPaymaster · Solidity v0.8.20+commit.a1b79de6 · optimiseur activé (200 runs) · licence MIT
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import { PackedUserOperation, IEntryPoint, IPaymaster, packValidationData } from "./interfaces.sol";
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function balanceOf(address) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
}
abstract contract BasePaymaster is IPaymaster {
IEntryPoint public immutable entryPoint;
address public owner;
modifier onlyEntryPoint() {
require(msg.sender == address(entryPoint), "Paymaster: not EntryPoint");
_;
}
modifier onlyOwner() {
require(msg.sender == owner, "Paymaster: not owner");
_;
}
constructor(address entryPoint_, address owner_) {
entryPoint = IEntryPoint(entryPoint_);
owner = owner_;
}
function deposit() external payable {
entryPoint.depositTo{ value: msg.value }(address(this));
}
function getDeposit() external view returns (uint256) {
return entryPoint.balanceOf(address(this));
}
function withdrawTo(address payable to, uint256 amount) external onlyOwner {
entryPoint.withdrawTo(to, amount);
}
receive() external payable {
entryPoint.depositTo{ value: msg.value }(address(this));
}
}
contract WintgVerifyingPaymaster is BasePaymaster {
using ECDSA for bytes32;
address public verifyingSigner;
event SignerUpdated(address indexed signer);
constructor(address entryPoint_, address owner_, address signer_) BasePaymaster(entryPoint_, owner_) {
verifyingSigner = signer_;
}
function setSigner(address s) external onlyOwner {
verifyingSigner = s;
emit SignerUpdated(s);
}
function getHash(PackedUserOperation calldata op, uint48 validUntil, uint48 validAfter)
public
view
returns (bytes32)
{
return keccak256(
abi.encode(
op.sender,
op.nonce,
keccak256(op.initCode),
keccak256(op.callData),
op.accountGasLimits,
op.preVerificationGas,
op.gasFees,
block.chainid,
address(this),
validUntil,
validAfter
)
);
}
function validatePaymasterUserOp(PackedUserOperation calldata op, bytes32, uint256)
external
view
override
onlyEntryPoint
returns (bytes memory context, uint256 validationData)
{
bytes calldata pd = op.paymasterAndData;
uint48 validUntil = uint48(bytes6(pd[52:58]));
uint48 validAfter = uint48(bytes6(pd[58:64]));
bytes calldata sig = pd[64:];
bytes32 h = MessageHashUtils.toEthSignedMessageHash(getHash(op, validUntil, validAfter));
bool ok = ECDSA.recover(h, sig) == verifyingSigner;
return ("", packValidationData(!ok, validUntil, validAfter));
}
function postOp(PostOpMode, bytes calldata, uint256, uint256) external override onlyEntryPoint {
}
}
contract WintgTokenPaymaster is BasePaymaster {
mapping(address => uint256) public tokenPerWtg;
address public treasury;
event TokenSet(address indexed token, uint256 perWtg);
event GasPaidInToken(address indexed user, address indexed token, uint256 tokenAmount, uint256 wtgGasCost);
constructor(address entryPoint_, address owner_, address treasury_) BasePaymaster(entryPoint_, owner_) {
treasury = treasury_;
}
function setToken(address token, uint256 perWtg) external onlyOwner {
tokenPerWtg[token] = perWtg;
emit TokenSet(token, perWtg);
}
function setTreasury(address t) external onlyOwner {
treasury = t;
}
function _tokenAmount(address token, uint256 wtgCost) internal view returns (uint256) {
return (wtgCost * tokenPerWtg[token]) / 1e18;
}
function validatePaymasterUserOp(PackedUserOperation calldata op, bytes32, uint256 maxCost)
external
view
override
onlyEntryPoint
returns (bytes memory context, uint256 validationData)
{
address token = address(bytes20(op.paymasterAndData[52:72]));
require(tokenPerWtg[token] > 0, "TokenPaymaster: token not supported");
uint256 maxTokenCost = _tokenAmount(token, maxCost);
require(IERC20(token).balanceOf(op.sender) >= maxTokenCost, "TokenPaymaster: token balance");
require(IERC20(token).allowance(op.sender, address(this)) >= maxTokenCost, "TokenPaymaster: token allowance");
return (abi.encode(op.sender, token), 0);
}
function postOp(PostOpMode, bytes calldata context, uint256 actualGasCost, uint256)
external
override
onlyEntryPoint
{
(address user, address token) = abi.decode(context, (address, address));
uint256 tokenAmount = _tokenAmount(token, actualGasCost);
if (tokenAmount > 0) {
require(IERC20(token).transferFrom(user, treasury, tokenAmount), "TokenPaymaster: charge failed");
emit GasPaidInToken(user, token, tokenAmount, actualGasCost);
}
}
}
[
{
"type": "constructor",
"inputs": [
{
"name": "entryPoint_",
"type": "address",
"internalType": "address"
},
{
"name": "owner_",
"type": "address",
"internalType": "address"
},
{
"name": "signer_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "receive",
"stateMutability": "payable"
},
{
"type": "function",
"name": "deposit",
"inputs": [],
"outputs": [],
"stateMutability": "payable"
},
{
"type": "function",
"name": "entryPoint",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IEntryPoint"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getDeposit",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getHash",
"inputs": [
{
"name": "op",
"type": "tuple",
"internalType": "struct PackedUserOperation",
"components": [
{
"name": "sender",
"type": "address",
"internalType": "address"
},
{
"name": "nonce",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "initCode",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "callData",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "accountGasLimits",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "preVerificationGas",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "gasFees",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "paymasterAndData",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
}
]
},
{
"name": "validUntil",
"type": "uint48",
"internalType": "uint48"
},
{
"name": "validAfter",
"type": "uint48",
"internalType": "uint48"
}
],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "owner",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "postOp",
"inputs": [
{
"name": "",
"type": "uint8",
"internalType": "enum IPaymaster.PostOpMode"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "setSigner",
"inputs": [
{
"name": "s",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "validatePaymasterUserOp",
"inputs": [
{
"name": "op",
"type": "tuple",
"internalType": "struct PackedUserOperation",
"components": [
{
"name": "sender",
"type": "address",
"internalType": "address"
},
{
"name": "nonce",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "initCode",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "callData",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "accountGasLimits",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "preVerificationGas",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "gasFees",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "paymasterAndData",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
}
]
},
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "context",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "validationData",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "verifyingSigner",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "withdrawTo",
"inputs": [
{
"name": "to",
"type": "address",
"internalType": "address payable"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "SignerUpdated",
"inputs": [
{
"name": "signer",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"type": "error",
"name": "ECDSAInvalidSignature",
"inputs": []
},
{
"type": "error",
"name": "ECDSAInvalidSignatureLength",
"inputs": [
{
"name": "length",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "ECDSAInvalidSignatureS",
"inputs": [
{
"name": "s",
"type": "bytes32",
"internalType": "bytes32"
}
]
}
]
Aucun transfert de token.