ETH Price: $3,093.70 (-2.17%)

Contract

0xC6781ee67Cc92569a7790D95D3A55750f221f6F3

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GmBoost

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import {IFeeManager} from "./IFeeManager.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

/// @title GmBoost - Per-user GM contract (clone) that accepts ETH, splits value,
///         forwards platform share immediately, and accrues owner share for withdrawal.
/// @author GmBoost Team
/// @notice Deploy via Factory as an ERC-1167 minimal proxy pointing to this implementation.
contract GmBoost is ReentrancyGuard {
    // -------------------------- Custom Errors --------------------------
    error AlreadyInitialized();
    error ZeroAddress();
    error NotOwner();
    error InsufficientEth();
    error TransferFailed();
    error UnauthorizedCaller();
    error NothingToWithdraw();

    // ---------------------------- Storage ------------------------------
    /// @notice The user who owns this GM contract.
    address public owner;
    /// @notice Address of FeeManager providing config.
    address public feeManager;
    /// @notice Factory that deployed this implementation.
    address public immutable FACTORY;
    uint16 private constant _BPS_DENOMINATOR = 10_000;
    bool private _initialized;   // One-time initializer guard

    // ---------------------------- Events -------------------------------
    /// @notice Emitted whenever a GM is sent on-chain.
    /// @param sender        The caller who sent the GM (pays msg.value)
    /// @param value         The total ETH sent with the call (tips included)
    /// @param requiredWei   The required minimum at the time of call (from FeeManager)
    /// @param platformShare The amount forwarded to the platform treasury
    /// @param ownerShare    The amount retained in this contract for the owner
    event OnChainGM(
        address indexed sender,
        uint256 value,
        uint256 requiredWei,
        uint256 platformShare,
        uint256 ownerShare
    ); // solhint-disable-line gas-indexed-events

    /// @notice Emitted when owner withdraws accumulated funds
    /// @param owner Address of the owner who withdrew
    /// @param amount Amount withdrawn in wei
    event OwnerWithdrawn(address indexed owner, uint256 amount); // solhint-disable-line gas-indexed-events

    // -------------------------- Constructor ----------------------------
    /// @notice Locks the implementation contract and records the factory address.
    /// @dev Clones use their own storage, so this only affects the implementation.
    ///      The factory address is used to authorize clone initialization.
    /// @param factory_ The address of the GmBoostFactory that will create clones
    constructor(address factory_) {
        if (factory_ == address(0)) revert ZeroAddress();
        _initialized = true;
        FACTORY = factory_;
    }

    // --------------------------- Initializer ---------------------------
    /// @notice Must be called exactly once by the Factory right after cloning.
    /// @dev Custom initialization guard (equivalent to OpenZeppelin Initializable):
    ///      - Implementation locked in constructor (prevents initialization attack on implementation)
    ///      - _initialized flag prevents double initialization on clones
    ///      - Factory-only authorization provides ADDITIONAL protection beyond standard OZ pattern
    ///      - Only the factory can initialize clones to prevent unauthorized deployments
    ///        that could bypass deployment fees or use malicious FeeManager contracts
    ///      - No external dependencies, lower gas costs than inherited Initializable
    /// @param owner_ Address of the contract owner
    /// @param feeManager_ Address of the FeeManager contract
    function initialize(address owner_, address feeManager_) external {
        if (msg.sender != FACTORY) revert UnauthorizedCaller();
        if (_initialized) revert AlreadyInitialized();
        if (owner_ == address(0) || feeManager_ == address(0)) revert ZeroAddress();
        owner = owner_;
        feeManager = feeManager_;
        _initialized = true;
    }

    // --------------------------- Core Logic ----------------------------
    /// @notice Send a GM. Requires at least the configured ETH fee; tips allowed.
    /// @dev No reentrancy guard needed - follows CEI pattern strictly:
    ///      1. Checks (fee validation)
    ///      2. Effects (state is already finalized before external call)
    ///      3. Interactions (external call to feeRecipient)
    ///      Reentrancy cannot exploit as no state writes occur after the call.
    /// Splits full msg.value into platformShare (forwarded now) and ownerShare (retained).
    function onChainGM() external payable {
        // 1) Read config from FeeManager (single STATICCALL)
        (uint256 requiredWei, uint16 ownerShareBps, address feeRecipient) =
            IFeeManager(feeManager).getConfig();

        // Extra safety: feeRecipient should never be zero (guarded in FeeManager) but validate here
        if (feeRecipient == address(0)) revert ZeroAddress();

        // 2) Enforce minimum fee (tips allowed)
        if (msg.value < requiredWei) revert InsufficientEth();

        // 3) Compute split
        //    ownerShare = floor(msg.value * bps / 10_000)
        uint256 ownerShare = (msg.value * ownerShareBps) / _BPS_DENOMINATOR;
        uint256 platformShare = msg.value - ownerShare;

        // 4) Forward platform share now (single external call)
        if (platformShare != 0) {
            // Safe: feeRecipient from FeeManager (Safe multisig controlled, not user input)
            // CEI pattern enforced, explicit success check, no state writes after external call
            (bool ok, ) = payable(feeRecipient).call{value: platformShare}("");
            if (!ok) revert TransferFailed();
        }

        // 5) Owner share is intentionally left in this contract (no transfer here)

        // 6) Emit event (transparent on-chain receipt)
        emit OnChainGM(msg.sender, msg.value, requiredWei, platformShare, ownerShare);
    }

    /// @notice Owner withdraws entire accrued balance (pull model).
    function withdrawOwner() external nonReentrant {
        if (msg.sender != owner) revert NotOwner();
        uint256 bal = address(this).balance;
        if (bal == 0) revert NothingToWithdraw();
        // Safe: owner withdrawing to self (onlyOwner check above, nonReentrant guard on function)
        // ReentrancyGuard + owner validation + balance check before external call
        (bool ok, ) = payable(owner).call{value: bal}("");
        if (!ok) revert TransferFailed();
        emit OwnerWithdrawn(owner, bal);
    }

    // ------------------------- Receive Fallback ------------------------
    /// @notice Accepts ETH sent directly (counted toward owner's balance).
    receive() external payable {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

/// @title IFeeManager - Interface for reading the current GM payout/fee config
/// @author GmBoost Team
/// @notice Exposes read-only accessors for GM fee and deployment settings.
interface IFeeManager {
    /// @notice Returns the current configuration used by GM contracts.
    /// @return ethFeeWei  The minimum ETH required to call onChainGM (tips allowed).
    /// @return ownerShareBps  The owner's share in basis points (0..10_000).
    /// @return feeRecipient  The platform treasury receiving the platform share.
    function getConfig()
        external
        view
        returns (uint256 ethFeeWei, uint16 ownerShareBps, address feeRecipient);

    /// @notice Returns deployment configuration used by the Factory.
    /// @return deployFeeWei  The ETH fee required to deploy a GM contract (tips allowed).
    /// @return feeRecipient  The platform treasury receiving deployment fees.
    function getDeployConfig()
        external
        view
        returns (uint256 deployFeeWei, address feeRecipient);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"factory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InsufficientEth","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requiredWei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"platformShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ownerShare","type":"uint256"}],"name":"OnChainGM","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OwnerWithdrawn","type":"event"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"feeManager_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onChainGM","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a060405234801561001057600080fd5b5060405161072f38038061072f83398101604081905261002f9161007f565b60016000556001600160a01b03811661005b5760405163d92e233d60e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a01b1790556001600160a01b03166080526100af565b60006020828403121561009157600080fd5b81516001600160a01b03811681146100a857600080fd5b9392505050565b60805161065f6100d0600039600081816077015261013f015261065f6000f3fe6080604052600436106100595760003560e01c80632dd3100014610065578063485cc955146100b55780635011b71c146100d75780638da5cb5b146100df578063d0fb0203146100ff578063e8cc00ad1461011f57600080fd5b3661006057005b600080fd5b34801561007157600080fd5b506100997f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c157600080fd5b506100d56100d036600461053e565b610134565b005b6100d561021d565b3480156100eb57600080fd5b50600154610099906001600160a01b031681565b34801561010b57600080fd5b50600254610099906001600160a01b031681565b34801561012b57600080fd5b506100d56103e2565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461017d57604051635c427cd960e01b815260040160405180910390fd5b600254600160a01b900460ff16156101a75760405162dc149f60e41b815260040160405180910390fd5b6001600160a01b03821615806101c457506001600160a01b038116155b156101e25760405163d92e233d60e01b815260040160405180910390fd5b600180546001600160a01b039384166001600160a01b0319909116179055600280546001600160a81b0319169190921617600160a01b179055565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663c3f909d46040518163ffffffff1660e01b8152600401606060405180830381865afa158015610275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102999190610577565b919450925090506001600160a01b0381166102c75760405163d92e233d60e01b815260040160405180910390fd5b823410156102e85760405163500d4efb60e11b815260040160405180910390fd5b60006127106102fb61ffff8516346105d7565b61030591906105f4565b905060006103138234610616565b90508015610391576000836001600160a01b03168260405160006040518083038185875af1925050503d8060008114610368576040519150601f19603f3d011682016040523d82523d6000602084013e61036d565b606091505b505090508061038f576040516312171d8360e31b815260040160405180910390fd5b505b60408051348152602081018790529081018290526060810183905233907fe7fa94cf55633341e4ae28c596bf2261087dce60c581d58b36602e04b1904e249060800160405180910390a25050505050565b6103ea6104fc565b6001546001600160a01b03163314610415576040516330cd747160e01b815260040160405180910390fd5b47600081900361043857604051630686827b60e51b815260040160405180910390fd5b6001546040516000916001600160a01b03169083908381818185875af1925050503d8060008114610485576040519150601f19603f3d011682016040523d82523d6000602084013e61048a565b606091505b50509050806104ac576040516312171d8360e31b815260040160405180910390fd5b6001546040518381526001600160a01b03909116907f7f36cb738e7e0427042dc19669b1186fd858a03b8e699e089a4306ab78a160cb9060200160405180910390a250506104fa6001600055565b565b60026000540361051f57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6001600160a01b038116811461053b57600080fd5b50565b6000806040838503121561055157600080fd5b823561055c81610526565b9150602083013561056c81610526565b809150509250929050565b60008060006060848603121561058c57600080fd5b83519250602084015161ffff811681146105a557600080fd5b60408501519092506105b681610526565b809150509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105ee576105ee6105c1565b92915050565b60008261061157634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156105ee576105ee6105c156fea2646970667358221220a4cba231d075efacbdbf3bf601040f59b5d7c279a80e53a5c6ca0241b7cc420364736f6c634300081e0033000000000000000000000000129674a91cbc4582e0dce1465665b1abf21a6f7b

Deployed Bytecode

0x6080604052600436106100595760003560e01c80632dd3100014610065578063485cc955146100b55780635011b71c146100d75780638da5cb5b146100df578063d0fb0203146100ff578063e8cc00ad1461011f57600080fd5b3661006057005b600080fd5b34801561007157600080fd5b506100997f000000000000000000000000129674a91cbc4582e0dce1465665b1abf21a6f7b81565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c157600080fd5b506100d56100d036600461053e565b610134565b005b6100d561021d565b3480156100eb57600080fd5b50600154610099906001600160a01b031681565b34801561010b57600080fd5b50600254610099906001600160a01b031681565b34801561012b57600080fd5b506100d56103e2565b336001600160a01b037f000000000000000000000000129674a91cbc4582e0dce1465665b1abf21a6f7b161461017d57604051635c427cd960e01b815260040160405180910390fd5b600254600160a01b900460ff16156101a75760405162dc149f60e41b815260040160405180910390fd5b6001600160a01b03821615806101c457506001600160a01b038116155b156101e25760405163d92e233d60e01b815260040160405180910390fd5b600180546001600160a01b039384166001600160a01b0319909116179055600280546001600160a81b0319169190921617600160a01b179055565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663c3f909d46040518163ffffffff1660e01b8152600401606060405180830381865afa158015610275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102999190610577565b919450925090506001600160a01b0381166102c75760405163d92e233d60e01b815260040160405180910390fd5b823410156102e85760405163500d4efb60e11b815260040160405180910390fd5b60006127106102fb61ffff8516346105d7565b61030591906105f4565b905060006103138234610616565b90508015610391576000836001600160a01b03168260405160006040518083038185875af1925050503d8060008114610368576040519150601f19603f3d011682016040523d82523d6000602084013e61036d565b606091505b505090508061038f576040516312171d8360e31b815260040160405180910390fd5b505b60408051348152602081018790529081018290526060810183905233907fe7fa94cf55633341e4ae28c596bf2261087dce60c581d58b36602e04b1904e249060800160405180910390a25050505050565b6103ea6104fc565b6001546001600160a01b03163314610415576040516330cd747160e01b815260040160405180910390fd5b47600081900361043857604051630686827b60e51b815260040160405180910390fd5b6001546040516000916001600160a01b03169083908381818185875af1925050503d8060008114610485576040519150601f19603f3d011682016040523d82523d6000602084013e61048a565b606091505b50509050806104ac576040516312171d8360e31b815260040160405180910390fd5b6001546040518381526001600160a01b03909116907f7f36cb738e7e0427042dc19669b1186fd858a03b8e699e089a4306ab78a160cb9060200160405180910390a250506104fa6001600055565b565b60026000540361051f57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6001600160a01b038116811461053b57600080fd5b50565b6000806040838503121561055157600080fd5b823561055c81610526565b9150602083013561056c81610526565b809150509250929050565b60008060006060848603121561058c57600080fd5b83519250602084015161ffff811681146105a557600080fd5b60408501519092506105b681610526565b809150509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105ee576105ee6105c1565b92915050565b60008261061157634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156105ee576105ee6105c156fea2646970667358221220a4cba231d075efacbdbf3bf601040f59b5d7c279a80e53a5c6ca0241b7cc420364736f6c634300081e0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000129674a91cbc4582e0dce1465665b1abf21a6f7b

-----Decoded View---------------
Arg [0] : factory_ (address): 0x129674A91Cbc4582e0dce1465665B1Abf21a6F7B

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000129674a91cbc4582e0dce1465665b1abf21a6f7b


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.