Skip to main content
PulseScanner.io

Address

0x3be75c97b18d97125444fd503e79b25be475a3b8
Current Holdings
$438.92
TXs sent
0
First Active
2026-06-01
block 26,677,144
Last Active
today
block 27,521,538
Funded By
0x8042…27d7

Net worth historyi

585 snapshots · to block 27,521,087coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchPMINTSwapFeeRoutersolc 0.8.20+commit.a1b79de6runtime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/*
    PMINTSwapFeeRouter
    ==================
*/

interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function approve(address spender, uint256 value) external returns (bool);
}

contract PMINTSwapFeeRouter {
    address public constant NATIVE = address(0);
    uint256 public constant BPS_BASE = 10000;
    uint256 public constant MAX_FEE_BPS = 100; // 1 percent hard ceiling, owner can never exceed

    address public owner;
    address public feeWallet;
    uint256 public feeBps = 30; // 0.3 percent
    mapping(address => bool) public allowedRouter;

    uint256 private _lock = 1;

    event SwapExecuted(address indexed user, address tokenIn, address router, uint256 amountIn, uint256 amountSwapped, uint256 feeAmount);
    event RouterSet(address indexed router, bool allowed);
    event FeeWalletSet(address indexed wallet);
    event FeeBpsSet(uint256 bps);
    event OwnerSet(address indexed owner);

    modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; }
    modifier nonReentrant() { require(_lock == 1, "reentrant"); _lock = 2; _; _lock = 1; }

    constructor(address _feeWallet, address[] memory _routers) {
        require(_feeWallet != address(0), "fee wallet zero");
        owner = msg.sender;
        feeWallet = _feeWallet;
        emit OwnerSet(msg.sender);
        emit FeeWalletSet(_feeWallet);
        for (uint256 i = 0; i < _routers.length; i++) {
            require(_routers[i] != address(0), "router zero");
            allowedRouter[_routers[i]] = true;
            emit RouterSet(_routers[i], true);
        }
    }

    // ----------------------------- swap -----------------------------
    // tokenIn  : input token, or address(0) for native PLS
    // amountIn : total the user spends (must equal msg.value when native)
    // router   : the venue to call, must be allowlisted (PulseX or Piteas)
    // data     : swap calldata built by the frontend for (amountIn - fee),
    //            with the output recipient set to the user
    function swap(
        address tokenIn,
        uint256 amountIn,
        address router,
        bytes calldata data
    ) external payable nonReentrant {
        require(allowedRouter[router], "router not allowed");
        require(amountIn > 0, "amount zero");

        uint256 fee = (amountIn * feeBps) / BPS_BASE;
        uint256 netIn = amountIn - fee;
        require(netIn > 0, "net zero");

        if (tokenIn == NATIVE) {
            require(msg.value == amountIn, "bad msg.value");
            if (fee > 0) _sendNative(feeWallet, fee);
            (bool ok, ) = router.call{value: netIn}(data);
            require(ok, "router call failed");
        } else {
            require(msg.value == 0, "native not expected");
            _safeTransferFrom(tokenIn, msg.sender, address(this), amountIn);
            if (fee > 0) _safeTransfer(tokenIn, feeWallet, fee);
            _safeApprove(tokenIn, router, 0);
            _safeApprove(tokenIn, router, netIn);
            (bool ok, ) = router.call(data);
            require(ok, "router call failed");
            _safeApprove(tokenIn, router, 0);
        }

        emit SwapExecuted(msg.sender, tokenIn, router, amountIn, netIn, fee);
    }

    // ------------------- admin (renounce to freeze) -------------------
    function setOwner(address o) external onlyOwner { owner = o; emit OwnerSet(o); }
    function renounceOwnership() external onlyOwner { owner = address(0); emit OwnerSet(address(0)); }
    function setFeeWallet(address w) external onlyOwner { require(w != address(0), "zero"); feeWallet = w; emit FeeWalletSet(w); }
    function setFeeBps(uint256 b) external onlyOwner { require(b <= MAX_FEE_BPS, "fee too high"); feeBps = b; emit FeeBpsSet(b); }
    function setRouter(address r, bool ok) external onlyOwner { require(r != address(0), "zero"); allowedRouter[r] = ok; emit RouterSet(r, ok); }

    // ---- rescue (config only owner power; nothing sits here in normal use) ----
    function rescue(address token, address to, uint256 amount) external onlyOwner {
        require(to != address(0), "zero");
        if (token == NATIVE) _sendNative(to, amount);
        else _safeTransfer(token, to, amount);
    }

    // ----------------------------- helpers -----------------------------
    function _sendNative(address to, uint256 amount) internal {
        (bool ok, ) = to.call{value: amount}("");
        require(ok, "native send failed");
    }
    function _safeTransfer(address token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(IERC20.transfer.selector, to, value));
    }
    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
    }
    function _safeApprove(address token, address spender, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(IERC20.approve.selector, spender, value));
    }
    function _callOptionalReturn(address token, bytes memory data) internal {
        (bool ok, bytes memory ret) = token.call(data);
        require(ok && (ret.length == 0 || abi.decode(ret, (bool))), "erc20 op failed");
    }

    receive() external payable {}
}