Contrat

Contrat
0x7e94a24e40…639525d745

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"
            }
        ]
    }
]
HashMéthodeBlocÂgeDeÀMontantFrais
0x1bdb0d7bd4… Envelopper WTG 32 270 il y a 2 sem. 0x835164…ee75cc ENTR. 0x7e94a2…25d745 2000 WTG
≈ 46 899,96 FCFA
0.00011033 WTG
Aucun transfert de token.
Tx parenteTypeDeÀValeur
0x1bdb0d7b…0afee0 appel 0x7e94a2…25d745 0x45df02…35bd59 2000 WTG
≈ 46 899,96 FCFA