Contrat
Contrat
0x0ed2b9b6de…88eb79243d
0x0ed2b9b6de058c88e925f59a0aa73188eb79243d
Solde WTG
0 WTG
≈ 0,00 FCFA (@ 17,65 FCFA/WTG)
Avoirs en tokens
0 token
≈ 0,00 FCFA
Plus d'infos
Transactions envoyées1
Dernière activitéil y a 1 j
Première activitéil y a 1 j
Financé par
—
Code du contrat
✓ VérifiéWintgTokenPaymaster · 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": "treasury_",
"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": "owner",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "postOp",
"inputs": [
{
"name": "",
"type": "uint8",
"internalType": "enum IPaymaster.PostOpMode"
},
{
"name": "context",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "actualGasCost",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "setToken",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "perWtg",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "setTreasury",
"inputs": [
{
"name": "t",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "tokenPerWtg",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "treasury",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"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": "maxCost",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "context",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "validationData",
"type": "uint256",
"internalType": "uint256"
}
],
"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": "GasPaidInToken",
"inputs": [
{
"name": "user",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "tokenAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "wtgGasCost",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "TokenSet",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "perWtg",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
}
]
0x60406080815260049081361015610027575b5050361561001d575f80fd5b610025610922565b005b5f91823560e01c918263205c28781461080857826352b7512c146104df57826361d027b3146104b657826378bf2b53146104475782637c627b21146102715782638da5cb5b146102495782639dcce6f514610211578263b0d691fe146101cd578263c399ec88146101175750508063d0e30db0146101005763f0f44260146100af5780610011565b346100fd5760203660031901126100fd576100c86108ae565b81546001600160a01b0391906100e19083163314610995565b166bffffffffffffffffffffffff60a01b600254161760025580f35b80fd5b50806003193601126100fd57610114610922565b80f35b8390346101c957816003193601126101c95780516370a0823160e01b815230938101939093526020836024817f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd596001600160a01b03165afa9182156101be5791610186575b6020925051908152f35b90506020823d82116101b6575b816101a060209383610900565b810103126101b257602091519061017c565b5f80fd5b3d9150610193565b9051903d90823e3d90fd5b5080fd5b8390346101c957816003193601126101c957517f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd596001600160a01b03168152602090f35b8390346101c95760203660031901126101c95760209181906001600160a01b036102396108ae565b1681526001845220549051908152f35b8390346101c957816003193601126101c957905490516001600160a01b039091168152602090f35b9091503461044357608036600319011261044357600382351015610443576024359067ffffffffffffffff80831161043f573660238401121561043f578284013590811161043f57820136602482011161043f576001600160a01b03906044359083908590610303337f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd598716146109d8565b031261043b578180610323604461031c602489016108c4565b97016108c4565b95169416946103328287610a38565b928361033c578780f35b60025416908451916323b872dd60e01b83528682840152602483015283604483015260209182816064818c8c5af19081156104315789916103f7575b50156103b6575083519283528201527fca1e232344ead66146cfc03ad6c3051ab81f825588475f435ba7ec3e613b42de9190a35f8080808080808780f35b60649185519162461bcd60e51b8352820152601d60248201527f546f6b656e5061796d61737465723a20636861726765206661696c65640000006044820152fd5b90508281813d831161042a575b61040e8183610900565b8101031261042657518015158103610426575f610378565b8880fd5b503d610404565b86513d8b823e3d90fd5b8580fd5b8480fd5b8280fd5b8390346101c957806003193601126101c9577fe2e037187b134bfff9cda71fddec1c201b00ba7a552335543243c138faebccce60206104846108ae565b8454602435916001600160a01b03916104a09083163314610995565b169384865260018352818187205551908152a280f35b8390346101c957816003193601126101c95760025490516001600160a01b039091168152602090f35b83346100fd576060916003199183833601126100fd5784359267ffffffffffffffff808511610443578487019161012086360391820112610804576001600160a01b0395610550337f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd598916146109d8565b60e4810135916022190182121561043f57019087820135908111610804578036036024830113610804576048116104435760580135851c958683526020946001865284842054156107b5576105a760443589610a38565b906105b184610a24565b86516370a0823160e01b815291168382015286816024818c5afa908115610737579082918691610784575b501061074157610620866105ef85610a24565b8751636eb1769f60e11b81526001600160a01b03909116858201908152306020820152909283918291604090910190565b03818c5afa90811561073757859161070a575b50106106c757508584846106478894610a24565b81516001600160a01b039182168482019081529190941660208201528390604001039061067c601f1992838101865285610900565b80519586938285528551809386015281955b8387106106af5750849550818784601f969701015285015201168101030190f35b8681018201518988018901529581019588955061068e565b835162461bcd60e51b8152908101859052601f60248201527f546f6b656e5061796d61737465723a20746f6b656e20616c6c6f77616e6365006044820152606490fd5b90508681813d8311610730575b6107218183610900565b810103126101b2575189610633565b503d610717565b86513d87823e3d90fd5b845162461bcd60e51b8152808301879052601d60248201527f546f6b656e5061796d61737465723a20746f6b656e2062616c616e63650000006044820152606490fd5b809250888092503d83116107ae575b61079d8183610900565b810103126101b2578190518a6105dc565b503d610793565b845162461bcd60e51b8152808301879052602360248201527f546f6b656e5061796d61737465723a20746f6b656e206e6f7420737570706f726044820152621d195960ea1b6064820152608490fd5b8380fd5b90915034610443578060031936011261044357826108246108ae565b81546001600160a01b03919061083d9083163314610995565b817f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd591690813b1561080457836044928651978895869463040b850f60e31b8652169084015260243560248401525af19081156108a5575061089c575080f35b610114906108d8565b513d84823e3d90fd5b600435906001600160a01b03821682036101b257565b35906001600160a01b03821682036101b257565b67ffffffffffffffff81116108ec57604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176108ec57604052565b7f00000000000000000000000045df020e5bf15908c4c5fde61d2787ba5335bd596001600160a01b0316803b156101b2575f6024916040519283809263b760faf960e01b825230600483015234905af1801561098a5761097f5750565b610988906108d8565b565b6040513d5f823e3d90fd5b1561099c57565b60405162461bcd60e51b81526020600482015260146024820152732830bcb6b0b9ba32b91d103737ba1037bbb732b960611b6044820152606490fd5b156109df57565b60405162461bcd60e51b815260206004820152601960248201527f5061796d61737465723a206e6f7420456e747279506f696e74000000000000006044820152606490fd5b356001600160a01b03811681036101b25790565b6001600160a01b03165f908152600160205260409020548181029180159083049091141715610a6f57670de0b6b3a7640000900490565b634e487b7160e01b5f52601160045260245ffdfea2646970667358221220504234245fc3fd22870ce2d721ebca63a3d9b82edb0f45610f36836db828ae9764736f6c63430008140033
Aucun transfert de token.