GasSponsoredAccount7702

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/eth/eip7702.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.30;

interface IERC20Like {
    function transfer(address to, uint256 value) external returns (bool);

    function balanceOf(address owner) external view returns (uint256);
}

library SafeERC20 {
    function safeTransfer(IERC20Like token, address to, uint256 value) internal {
        (bool success, bytes memory data) =
                                address(token).call(abi.encodeWithSelector(token.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "SafeERC20:TRANSFER_FAIL");
    }
}

interface IGlobalConfig {
    // flags and fee
    function globalPaused() external view returns (bool);

    function enforceExactNet() external view returns (bool);

    function useTokenAllowlist() external view returns (bool);

    function feeRecipient() external view returns (address);

    function allowAdminSweep() external view returns (bool);

    // allowlists
    function isSponsorAllowed(address who) external view returns (bool);

    function isTokenAllowed(address token) external view returns (bool);

    function getAllSponsors() external view returns (address[] memory);

    function getAllTokens() external view returns (address[] memory);
}

contract GasSponsoredAccount7702 {
    using SafeERC20 for IERC20Like;

    // immutable global config
    IGlobalConfig public immutable GLOBAL_CONFIG;

    constructor(address globalConfig_) {
        require(globalConfig_ != address(0), "GlobalConfigZero");
        GLOBAL_CONFIG = IGlobalConfig(globalConfig_);
    }

    // ===== Constants =====
    bytes4 private constant _MAGIC_BYTES32 = 0x1626ba7e; // EIP-1271
    bytes4 private constant _MAGIC_BYTES = 0x20c13b0b; // isValidSignature(bytes)

    // ===== Events =====
    event GaslessTransferExecuted(
        address indexed account,
        address indexed sponsor,
        address token,
        address to,
        uint256 grossAmount,
        uint256 feeAmount,
        uint256 netAmount,
        address feeRecipient,
        uint256 nonce,
        bytes32 digest,
        bytes32 indexed id
    );
    event TokenSwept(address indexed token, address indexed to, uint256 amount, uint256 nonce, bytes32 digest);
    event ETHSwept(address indexed to, uint256 amount, uint256 nonce, bytes32 digest);

    // ===== Storage (EIP-7201 style custom slot) =====
    bytes32 private constant _ACCOUNT_STORAGE_SLOT =
    bytes32(uint256(keccak256("allscale.7702.storage")) - 1);

    struct AccountStorage {
        // nonces
        uint256 opNonce;
        uint256 adminNonce;
        // reentrancy guard (0 = unlocked, 1 = locked)
        uint256 reentrancyGuard;
        // EIP-712 cache
        bytes32 cachedDomainSeparator;
        uint256 cachedChainId;
        address cachedThis;
        // id anti-replay
        mapping(bytes32 => bool) usedId;
    }

    function _getAccountStorage() private pure returns (AccountStorage storage s) {
        bytes32 slot = _ACCOUNT_STORAGE_SLOT;
        assembly ("memory-safe") {s.slot := slot}
    }

    // ===== Modifiers =====
    modifier nonReentrant() {
        AccountStorage storage s = _getAccountStorage();
        require(s.reentrancyGuard == 0, "REENTRANCY");
        s.reentrancyGuard = 1;
        _;
        s.reentrancyGuard = 0;
    }

    modifier nonPaused() {
        require(!GLOBAL_CONFIG.globalPaused(), "PAUSED");
        _;
    }

    receive() external payable {}

    fallback() external payable {}

    // ===== EIP-712 =====
    string private constant _NAME = "AllScaleEIP7702";
    string private constant _VERSION = "1";
    bytes32 private constant _EIP712_DOMAIN_TYPEHASH =
    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    function _domainSeparator() internal returns (bytes32) {
        AccountStorage storage s = _getAccountStorage();
        if (s.cachedChainId == block.chainid && s.cachedThis == address(this) && s.cachedDomainSeparator != bytes32(0)) {
            return s.cachedDomainSeparator;
        }
        bytes32 ds = keccak256(
            abi.encode(
                _EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(_NAME)),
                keccak256(bytes(_VERSION)),
                block.chainid,
                address(this)
            )
        );
        s.cachedChainId = block.chainid;
        s.cachedThis = address(this);
        s.cachedDomainSeparator = ds;
        return ds;
    }

    /// 非 view(要缓存到存储里)
    function domainSeparator() external returns (bytes32) {
        return _domainSeparator();
    }

    // ---- Typed data typehashes(完整字符串,去掉省略号)----
    bytes32 private constant TRANSFER_TYPEHASH = keccak256(
        "GaslessTransfer(address sponsor,address token,address to,uint256 amount,uint256 feeAmount,uint256 deadline,uint256 nonce,bytes32 id)"
    );
    bytes32 private constant SWEEP_TOKEN_TYPEHASH = keccak256(
        "SweepToken(address token,address to,uint256 amount,uint256 nonce,uint256 deadline)"
    );
    bytes32 private constant SWEEP_ETH_TYPEHASH = keccak256(
        "SweepETH(address to,uint256 amount,uint256 nonce,uint256 deadline)"
    );

    // ===== Views =====
    function getOpNonce() external view returns (uint256) {return _getAccountStorage().opNonce;}

    function getNonce() external view returns (uint256) {return _getAccountStorage().adminNonce;}

    // ===== EIP-1271 (optional) =====
    function isValidSignature(bytes32 hash, bytes memory sig) external pure returns (bytes4) {
        return hash != bytes32(0) && sig.length != 0 ? _MAGIC_BYTES32 : bytes4(0);
    }

    function isValidSignature(bytes memory data, bytes memory sig) external pure returns (bytes4) {
        return data.length != 0 && sig.length != 0 ? _MAGIC_BYTES : bytes4(0);
    }

    // ===== Internal helpers =====
    function _hashTypedDataV4(bytes32 structHash) internal returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), structHash));
    }

    function _recover(bytes32 digest, bytes memory signature) internal pure returns (address) {
        bytes32 r;
        bytes32 s;
        uint8 v;
        if (signature.length == 65) {
            assembly ("memory-safe") {
                r := mload(add(signature, 32))
                s := mload(add(signature, 64))
                v := byte(0, mload(add(signature, 96)))
            }
        } else if (signature.length == 64) {
            assembly ("memory-safe") {
                r := mload(add(signature, 32))
                s := mload(add(signature, 64))
            }
            v = uint8((uint256(s) >> 255) + 27);
            s = bytes32(uint256(s) & ((1 << 255) - 1));
        } else {
            revert("BAD_SIG_LEN");
        }
        require(v == 27 || v == 28, "BAD_V");
        address signer = ecrecover(digest, v, r, s);
        require(signer != address(0), "ECRECOVER_ZERO");
        return signer;
    }

    function _requireDeadline(uint256 deadline) internal view {
        require(deadline >= block.timestamp, "EXPIRED");
    }

    function _verifyAndBumpOp(bytes32 structHash, bytes calldata signature) internal returns (bytes32 digest, uint256 usedNonce) {
        AccountStorage storage s = _getAccountStorage();
        usedNonce = s.opNonce;
        digest = _hashTypedDataV4(structHash);
        address signer = _recover(digest, signature);
        require(signer == address(this), "BadSigner");
        unchecked {s.opNonce = usedNonce + 1;}
    }

    function _verifyAndBumpAdmin(bytes32 structHash, bytes calldata signature) internal returns (bytes32) {
        bytes32 digest = _hashTypedDataV4(structHash);
        address signer = _recover(digest, signature);
        require(signer == address(this), "BadSigner");
        AccountStorage storage s = _getAccountStorage();
        unchecked {s.adminNonce += 1;}
        return digest;
    }

    function _transferExactNet(IERC20Like token, address to, uint256 sendAmount) internal {
        uint256 beforeBal = token.balanceOf(to);
        (bool ok, bytes memory data) =
                                address(token).call(abi.encodeWithSelector(token.transfer.selector, to, sendAmount));
        require(ok && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAIL");
        uint256 delta = token.balanceOf(to) - beforeBal;
        require(delta == sendAmount, "NET_MISMATCH");
    }

    // ===== Business entry (global-config driven) =====
    function gaslessTransfer(
        address token,
        address to,
        uint256 amount,
        uint256 feeAmount,
        uint256 deadline,
        bytes32 id,
        bytes calldata signature
    ) external nonReentrant nonPaused {
        require(amount > 0, "ZeroAmount");
        require(token != address(0) && to != address(0), "ZeroAddr");
        require(address(token).code.length > 0, "TokenNotContract");
        require(feeAmount <= amount, "FeeGTAmount");
        _requireDeadline(deadline);

        // Sponsor allowlist
        require(GLOBAL_CONFIG.isSponsorAllowed(msg.sender), "SPONSOR_DENY");

        // Optional token allowlist
        if (GLOBAL_CONFIG.useTokenAllowlist()) {
            require(GLOBAL_CONFIG.isTokenAllowed(token), "TOKEN_DENY");
        }

        // id anti-replay
        AccountStorage storage s = _getAccountStorage();
        require(!s.usedId[id], "ID_USED");
        s.usedId[id] = true;

        // Verify signature & bump opNonce
        (bytes32 digest, uint256 usedNonce) = _verifyAndBumpOp(
            keccak256(
                abi.encode(
                    TRANSFER_TYPEHASH,
                    msg.sender,
                    token,
                    to,
                    amount,
                    feeAmount,
                    deadline,
                    s.opNonce,
                    id
                )
            ),
            signature
        );

        // Transfers
        IERC20Like t = IERC20Like(token);
        address feeRecvForEvent = GLOBAL_CONFIG.feeRecipient();
        require(feeRecvForEvent != address(0), "FEE_ZERO");

        if (feeAmount > 0) {
            if (GLOBAL_CONFIG.enforceExactNet()) {
                _transferExactNet(t, feeRecvForEvent, feeAmount);
            } else {
                t.safeTransfer(feeRecvForEvent, feeAmount);
            }
        }

        uint256 net = amount - feeAmount;
        if (GLOBAL_CONFIG.enforceExactNet()) {
            _transferExactNet(t, to, net);
        } else {
            t.safeTransfer(to, net);
        }

        emit GaslessTransferExecuted(
            address(this), msg.sender, token, to, amount, feeAmount, net, feeRecvForEvent, usedNonce, digest, id
        );
    }

    // ===== Admin sweeps (受 GlobalConfig.allowAdminSweep 控制,且同样严格校验) =====

    function sweepToken(address token, address to, uint256 amount, uint256 deadline, bytes calldata signature)
    external nonReentrant nonPaused
    {
        require(GLOBAL_CONFIG.allowAdminSweep(), "ADMIN_SWEEP_OFF");
        require(token != address(0) && to != address(0), "ZeroAddr");
        require(address(token).code.length > 0, "TokenNotContract");
        _requireDeadline(deadline);

        AccountStorage storage s = _getAccountStorage();
        uint256 used = s.adminNonce;

        bytes32 digest = _verifyAndBumpAdmin(
            keccak256(abi.encode(SWEEP_TOKEN_TYPEHASH, token, to, amount, used, deadline)), signature
        );

        IERC20Like(token).safeTransfer(to, amount);
        emit TokenSwept(token, to, amount, used, digest);
    }

    function sweepETH(address to, uint256 amount, uint256 deadline, bytes calldata signature)
    external nonReentrant nonPaused
    {
        require(GLOBAL_CONFIG.allowAdminSweep(), "ADMIN_SWEEP_OFF");
        require(to != address(0), "ZeroAddr");
        _requireDeadline(deadline);

        AccountStorage storage s = _getAccountStorage();
        uint256 used = s.adminNonce;
        bytes32 digest = _verifyAndBumpAdmin(
            keccak256(abi.encode(SWEEP_ETH_TYPEHASH, to, amount, used, deadline)), signature
        );
        (bool ok,) = to.call{value: amount}("");
        require(ok, "ETH_SEND_FAIL");
        emit ETHSwept(to, amount, used, digest);
    }
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "viaIR": true,
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Factory|addr:0x3f6b45a2ff7b012531cc2cf4c7d2849d9a1df333|verified:true|block:23679753|tx:0x0864f206d0d5e5c149f320bd213c822dd7b05ea7b38689ec21acefabe459244c|first_check:1761728675

Submitted on: 2025-10-29 10:04:35

Comments

Log in to comment.

No comments yet.