Contract
Contract✓ Verified (full match)via Sourcify- Native balance
- —
- Transactions
- 0 sent · 15,069 received
- Token transfers
- 6,312
- First seen
- · block 10,388,203
- Last seen
- · block 10,832,739
Counts and history cover indexed blocks 10,388,153 onward — earlier activity isn't indexed yet.
- Contract name
- NoxaRouter
- Compiler
- v0.8.20+commit.a1b79de6
- Language
- solidity
- Optimizer
- enabled · 200 runs
- EVM version
- compiler default
- Verified
- 2026-07-15 15:13:34 UTC · via Sourcify · full match
Source code1 file
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title NoxaRouter
* @notice Прокси для торговли на Uniswap V3 (Robinhood L2).
* Автоматически берёт роялти при buy/sell.
*
* Uniswap V3 Router : 0xCaf681a66D020601342297493863E78C959E5cb2
* WETH : 0x0bd7d308f8e1639fab988df18a8011f41eacad73
* Pool fee : 10000 (1%)
*/
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
interface IWETH {
function deposit() external payable;
function withdraw(uint256 wad) external;
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
interface IUniswapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params)
external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params)
external payable returns (uint256 amountIn);
function multicall(uint256 deadline, bytes[] calldata data)
external payable returns (bytes[] memory);
function wrapETH(uint256 value) external payable;
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;
}
interface IUniswapV3Factory {
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);
}
interface IUniswapV3PoolMinimal {
function liquidity() external view returns (uint128);
}
contract NoxaRouter {
uint256 public constant BPS_DENOM = 10_000;
uint256 public constant MAX_ROYALTY_BPS = 1_000;
uint24 public constant POOL_FEE = 10000;
// Same Uniswap V3 factory the seller/sniper bots already read pools
// from off-chain (FACTORY_ADDR in noxa_seller.py / noxa_sniper.py).
address public constant FACTORY = 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA;
address public owner;
address public pendingOwner;
address public immutable UNI_ROUTER;
address public immutable WETH;
address public immutable ROYALTY_ADDR;
uint256 public buyRoyaltyBps;
uint256 public sellRoyaltyBps;
event Buy(
address indexed token, address indexed buyer,
uint256 ethIn, uint256 royaltyEth, uint256 tokensOut
);
event BuyExact(
address indexed token, address indexed buyer,
uint256 ethSpent, uint256 royaltyEth, uint256 tokensOut, uint256 refundedEth
);
event Sell(
address indexed token, address indexed seller,
uint256 tokensIn, uint256 ethOut, uint256 royaltyEth
);
event RoyaltyUpdated(uint256 newBuyBps, uint256 newSellBps);
event OwnershipTransferred(address indexed old, address indexed new_);
error Unauthorized();
error InvalidRoyalty();
error TransferFailed();
error ZeroAmount();
error SwapFailed();
error InsufficientOutput();
error RebuyTooSoon();
error TradingNotOpen();
error InsufficientRoyaltyBuffer();
// Anti-flood: minimum seconds between two successful buys of the SAME
// token by the SAME address through this router. Checked FIRST, before
// any royalty transfer / WETH wrap / Uniswap call — a flood bot sending
// many sequential-nonce buys only needs ONE to land; every later tx
// from the same sender for the same token should die here as cheaply
// as possible instead of burning gas on the full swap path.
uint256 public rebuyCooldownSecs = 3;
mapping(address => mapping(address => uint256)) public lastBuyAt; // buyer => token => timestamp
modifier onlyOwner() {
if (msg.sender != owner) revert Unauthorized();
_;
}
function setRebuyCooldown(uint256 secs_) external onlyOwner {
rebuyCooldownSecs = secs_;
}
/// @dev "Trading open" here is NOT a fixed block offset — the actual
/// launch platform creates the pool / adds liquidity off-chain some
/// random ~2-30s after the token deploy tx, so any block-count-based
/// guess (e.g. a token's own launchBlock() getter) tells us nothing
/// real. The only thing that's actually true on-chain is: does the
/// pool exist yet, and does it have liquidity. Two cheap staticcalls
/// (factory + pool), still a small fraction of the gas the full
/// wrap+approve+swap path burns only to revert deep inside the swap.
function _tradingOpen(address tokenAddress) internal view returns (bool) {
address pool = IUniswapV3Factory(FACTORY).getPool(tokenAddress, WETH, POOL_FEE);
if (pool == address(0)) return false;
try IUniswapV3PoolMinimal(pool).liquidity() returns (uint128 liq) {
return liq > 0;
} catch {
return false;
}
}
constructor(
address uniRouter_,
address weth_,
address royaltyAddr_,
uint256 buyBps_,
uint256 sellBps_
) {
require(uniRouter_ != address(0), "zero router");
require(weth_ != address(0), "zero weth");
require(royaltyAddr_ != address(0), "zero royalty");
require(buyBps_ <= MAX_ROYALTY_BPS, "buy royalty too high");
require(sellBps_ <= MAX_ROYALTY_BPS, "sell royalty too high");
owner = msg.sender;
UNI_ROUTER = uniRouter_;
WETH = weth_;
ROYALTY_ADDR = royaltyAddr_;
buyRoyaltyBps = buyBps_;
sellRoyaltyBps = sellBps_;
// Approve WETH to Uniswap Router for swaps
IERC20(weth_).approve(uniRouter_, type(uint256).max);
}
/// @param tokenAddress токен, который покупаем
/// @param amountOutMinimum минимальное кол-во токенов, которое согласны получить
/// (защита от проскальзывания / sandwich-атак). Считайте off-chain
/// через quote + допустимый slippage, например quote * 99 / 100.
function buy(address tokenAddress, uint256 amountOutMinimum)
external
payable
returns (uint256 tokensOut)
{
if (msg.value == 0) revert ZeroAmount();
if (rebuyCooldownSecs > 0) {
uint256 last = lastBuyAt[msg.sender][tokenAddress];
if (last != 0 && block.timestamp - last < rebuyCooldownSecs) revert RebuyTooSoon();
lastBuyAt[msg.sender][tokenAddress] = block.timestamp;
}
if (!_tradingOpen(tokenAddress)) revert TradingNotOpen();
uint256 royalty = (msg.value * buyRoyaltyBps) / BPS_DENOM;
uint256 swapEth = msg.value - royalty;
if (royalty > 0) {
(bool royaltyOk,) = ROYALTY_ADDR.call{value: royalty}("");
if (!royaltyOk) revert TransferFailed();
}
// Wrap ETH to WETH directly (sends to this contract)
IWETH(WETH).deposit{value: swapEth}();
// Ensure Uniswap router can pull our WETH
(bool wethApproveOk,) = WETH.call(
abi.encodeWithSignature("approve(address,uint256)", UNI_ROUTER, type(uint256).max)
);
if (!wethApproveOk) revert TransferFailed();
// Swap WETH -> Token with recipient = msg.sender (not this contract).
// This bypasses per-address pool-buy limits (maxTxBps / maxWalletBps)
// in tokens like PonsLauncherToken, because the pool-to-recipient
// transfer credits _restrictedPoolBuys[msg.sender] individually
// instead of accumulating on the router address.
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(IUniswapRouter.exactInputSingle.selector,
IUniswapRouter.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: tokenAddress,
fee: POOL_FEE,
recipient: msg.sender,
amountIn: swapEth,
amountOutMinimum: amountOutMinimum,
sqrtPriceLimitX96: 0
})
);
uint256 deadline = block.timestamp + 600;
bytes[] memory result = IUniswapRouter(UNI_ROUTER).multicall(deadline, data);
tokensOut = abi.decode(result[0], (uint256));
if (tokensOut == 0) revert SwapFailed();
if (tokensOut < amountOutMinimum) revert InsufficientOutput();
emit Buy(tokenAddress, msg.sender, msg.value, royalty, tokensOut);
}
/// @notice Покупает РОВНО amountOut токенов. msg.value — это потолок
/// (сколько эфира вы готовы потратить), а не точная сумма: шлите
/// с запасом на проскальзывание (например, quote * 101 / 100).
/// Всё, что реально не ушло в своп, возвращается вам ЭФИРОМ,
/// royalty при этом берётся с фактически потраченной суммы, а не
/// со всего msg.value.
/// Нужно, когда площадка (Noxa fi, первый час торгов) ограничивает
/// РАЗМЕР одной покупки в токенах (например, 20_000_000) — так
/// получаем ровно лимит за одну транзакцию.
/// @param tokenAddress токен, который покупаем
/// @param amountOut точное количество токенов, которое хотим получить
function buyExact(address tokenAddress, uint256 amountOut)
external
payable
returns (uint256 ethSpent)
{
if (msg.value == 0) revert ZeroAmount();
if (amountOut == 0) revert ZeroAmount();
if (rebuyCooldownSecs > 0) {
uint256 last = lastBuyAt[msg.sender][tokenAddress];
if (last != 0 && block.timestamp - last < rebuyCooldownSecs) revert RebuyTooSoon();
lastBuyAt[msg.sender][tokenAddress] = block.timestamp;
}
if (!_tradingOpen(tokenAddress)) revert TradingNotOpen();
// Wrap the FULL msg.value — royalty is carved out afterwards, from the
// actual swap cost, so it doesn't overcharge on the slippage buffer.
IWETH(WETH).deposit{value: msg.value}();
(bool wethApproveOk,) = WETH.call(
abi.encodeWithSignature("approve(address,uint256)", UNI_ROUTER, type(uint256).max)
);
if (!wethApproveOk) revert TransferFailed();
// recipient = msg.sender to bypass per-address pool-buy limits
// (see buy() comment for details)
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(IUniswapRouter.exactOutputSingle.selector,
IUniswapRouter.ExactOutputSingleParams({
tokenIn: WETH,
tokenOut: tokenAddress,
fee: POOL_FEE,
recipient: msg.sender,
amountOut: amountOut,
amountInMaximum: msg.value,
sqrtPriceLimitX96: 0
})
);
uint256 deadline = block.timestamp + 600;
bytes[] memory result = IUniswapRouter(UNI_ROUTER).multicall(deadline, data);
uint256 amountIn = abi.decode(result[0], (uint256));
if (amountIn == 0) revert SwapFailed();
uint256 royalty = (amountIn * buyRoyaltyBps) / BPS_DENOM;
uint256 leftoverWeth = msg.value - amountIn;
if (leftoverWeth < royalty) revert InsufficientRoyaltyBuffer();
uint256 refund = leftoverWeth - royalty;
ethSpent = amountIn + royalty;
if (leftoverWeth > 0) {
IWETH(WETH).withdraw(leftoverWeth);
}
if (royalty > 0) {
(bool royaltyOk,) = ROYALTY_ADDR.call{value: royalty}("");
if (!royaltyOk) revert TransferFailed();
}
if (refund > 0) {
(bool refundOk,) = msg.sender.call{value: refund}("");
if (!refundOk) revert TransferFailed();
}
emit BuyExact(tokenAddress, msg.sender, ethSpent, royalty, amountOut, refund);
}
/// @param tokenAddress токен, который продаём
/// @param tokenAmount сколько токенов продаём
/// @param amountOutMinimum минимальное кол-во ETH (в виде WETH), которое согласны
/// получить со свопа, ДО вычета royalty
function sell(address tokenAddress, uint256 tokenAmount, uint256 amountOutMinimum)
external
returns (uint256 ethReceived)
{
if (tokenAmount == 0) revert ZeroAmount();
bool pullOk = IERC20(tokenAddress).transferFrom(msg.sender, address(this), tokenAmount);
if (!pullOk) revert TransferFailed();
IERC20(tokenAddress).approve(UNI_ROUTER, tokenAmount);
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(IUniswapRouter.exactInputSingle.selector,
IUniswapRouter.ExactInputSingleParams({
tokenIn: tokenAddress,
tokenOut: WETH,
fee: POOL_FEE,
recipient: address(this),
amountIn: tokenAmount,
amountOutMinimum: amountOutMinimum,
sqrtPriceLimitX96: 0
})
);
uint256 deadline = block.timestamp + 600;
IUniswapRouter(UNI_ROUTER).multicall(deadline, data);
// Unwrap WETH via Uniswap Router: transfer WETH to router, then unwrapWETH9
uint256 wethBal = IERC20(WETH).balanceOf(address(this));
if (wethBal > 0) {
IERC20(WETH).transfer(UNI_ROUTER, wethBal);
bytes[] memory unwrapData = new bytes[](1);
unwrapData[0] = abi.encodeWithSelector(IUniswapRouter.unwrapWETH9.selector, 0, address(this));
IUniswapRouter(UNI_ROUTER).multicall(block.timestamp + 600, unwrapData);
}
uint256 ethBalance = address(this).balance;
uint256 royalty = (ethBalance * sellRoyaltyBps) / BPS_DENOM;
ethReceived = ethBalance - royalty;
if (royalty > 0) {
(bool royaltyOk,) = ROYALTY_ADDR.call{value: royalty}("");
if (!royaltyOk) revert TransferFailed();
}
(bool sendOk,) = msg.sender.call{value: ethReceived}("");
if (!sendOk) revert TransferFailed();
emit Sell(tokenAddress, msg.sender, tokenAmount, ethReceived, royalty);
}
function setRoyalty(uint256 buyBps_, uint256 sellBps_) external onlyOwner {
if (buyBps_ > MAX_ROYALTY_BPS || sellBps_ > MAX_ROYALTY_BPS)
revert InvalidRoyalty();
buyRoyaltyBps = buyBps_;
sellRoyaltyBps = sellBps_;
emit RoyaltyUpdated(buyBps_, sellBps_);
}
function transferOwnership(address newOwner) external onlyOwner {
pendingOwner = newOwner;
}
function acceptOwnership() external {
require(msg.sender == pendingOwner, "not pending");
emit OwnershipTransferred(owner, msg.sender);
owner = msg.sender;
pendingOwner = address(0);
}
function rescueETH(uint256 amount) external onlyOwner {
(bool ok,) = owner.call{value: amount}("");
require(ok, "rescue failed");
}
function rescueERC20(address token, uint256 amount) external onlyOwner {
IERC20(token).transfer(owner, amount);
}
function rescueWETH() external onlyOwner {
uint256 wethBal = IERC20(WETH).balanceOf(address(this));
if (wethBal > 0) {
IWETH(WETH).withdraw(wethBal);
(bool ok,) = owner.call{value: wethBal}("");
require(ok, "rescue failed");
}
}
function buyTotalEth(uint256 ethAmount) external view returns (uint256) {
return ethAmount + (ethAmount * buyRoyaltyBps) / BPS_DENOM;
}
function sellNetEth(uint256 grossEth) external view returns (uint256) {
return grossEth - (grossEth * sellRoyaltyBps) / BPS_DENOM;
}
receive() external payable {}
}
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "uniRouter_",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "address",
"name": "royaltyAddr_",
"type": "address"
},
{
"internalType": "uint256",
"name": "buyBps_",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "sellBps_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "InsufficientOutput",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientRoyaltyBuffer",
"type": "error"
},
{
"inputs": [],
"name": "InvalidRoyalty",
"type": "error"
},
{
"inputs": [],
"name": "RebuyTooSoon",
"type": "error"
},
{
"inputs": [],
"name": "SwapFailed",
"type": "error"
},
{
"inputs": [],
"name": "TradingNotOpen",
"type": "error"
},
{
"inputs": [],
"name": "TransferFailed",
"type": "error"
},
{
"inputs": [],
"name": "Unauthorized",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAmount",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethIn",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "royaltyEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensOut",
"type": "uint256"
}
],
"name": "Buy",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethSpent",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "royaltyEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensOut",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "refundedEth",
"type": "uint256"
}
],
"name": "BuyExact",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "old",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "new_",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newBuyBps",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newSellBps",
"type": "uint256"
}
],
"name": "RoyaltyUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensIn",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethOut",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "royaltyEth",
"type": "uint256"
}
],
"name": "Sell",
"type": "event"
},
{
"inputs": [],
"name": "BPS_DENOM",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "FACTORY",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_ROYALTY_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "POOL_FEE",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ROYALTY_ADDR",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UNI_ROUTER",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "WETH",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountOutMinimum",
"type": "uint256"
}
],
"name": "buy",
"outputs": [
{
"internalType": "uint256",
"name": "tokensOut",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"name": "buyExact",
"outputs": [
{
"internalType": "uint256",
"name": "ethSpent",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "buyRoyaltyBps",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "ethAmount",
"type": "uint256"
}
],
"name": "buyTotalEth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "lastBuyAt",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "rebuyCooldownSecs",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "rescueERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "rescueETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "rescueWETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountOutMinimum",
"type": "uint256"
}
],
"name": "sell",
"outputs": [
{
"internalType": "uint256",
"name": "ethReceived",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "grossEth",
"type": "uint256"
}
],
"name": "sellNetEth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "sellRoyaltyBps",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "secs_",
"type": "uint256"
}
],
"name": "setRebuyCooldown",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "buyBps_",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "sellBps_",
"type": "uint256"
}
],
"name": "setRoyalty",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Bytecode hash 0x40a28d1f85e1487efe07f6df368b2497fd0f888a37033b7354d197dca93ce436