Contrat

Contrat
0x0ed2b9b6de…88eb79243d

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
HashMéthodeBlocÂgeDeÀMontantFrais
0x8c3e01cab4… Envelopper WTG 32 272 il y a 1 j 0x835164…ee75cc ENTR. 0x0ed2b9…79243d 2000 WTG
≈ 35 295,10 FCFA
0.00011034 WTG
0x7b9d8c805a… Appel contrat 32 269 il y a 1 j 0x835164…ee75cc ENTR. 0x0ed2b9…79243d 0.00009539 WTG
Aucun transfert de token.
Tx parenteTypeDeÀValeur
0x8c3e01ca…b4c768 appel 0x0ed2b9…79243d 0x45df02…35bd59 2000 WTG
≈ 35 295,10 FCFA