Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GmBoost
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Loading...
Loading
Loading...
Loading
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.