账户
0x36...d9e0
0x36...d9e0

0x36...d9e0

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.25+commit.b61c2a91
语言
Solidity
合同源代码
文件 1 的 1:Light.sol
/**
 *Submitted for verification at goerli.basescan.org on 2023-11-16
*/

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        _status = _NOT_ENTERED;
    }

    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

abstract contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor() {
        _transferOwnership(msg.sender);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract Light is Ownable, ReentrancyGuard {

    struct Seat {
        address owner;
        uint256 totalReward;
        uint256 currentReward;
        address layer1Address;
        uint256 deadline;
        uint256 subjectETHBalance;
        uint256 totalSupply;
        mapping (address => uint256) balanceOf;
        mapping (uint256 => uint256) claimedBitMap;
    }

    struct TradeEvent {
        uint256 eventIndex;
        uint256 ts;
        address trader;
        address subject;
        bool isBuy;
        uint256 buyAmount;
        uint256 ethAmount;
        uint256 traderBalance;
        uint256 supply;
    }

    struct ClaimEvent {
        uint256 eventIndex;
        uint256 ts;
        address sender;
        address subject;
        uint256 claimedIndex;
        uint256 reward;
    }

    struct SubjectRewardSetEvent {
        uint256 eventIndex;
        uint256 ts;
        bytes32 subject;
        address owner;
        uint256 snapshotReward;
        uint256 rewardPercent;
        uint256 totalReward;
    }

    address public protocolFeeTo;
    uint256 public tradeIndex;
    uint256 public bindIndex;
    uint256 public prizeIndex;
    uint256 public claimIndex;
    uint256 public protocolFeePercent;
    uint256 public subjectFeePercent;
    address[] public signers;
    mapping (address => bool) public authorized;
    mapping (address => uint256) public indexes;
    mapping (address => Seat) public seats;

    event SignerAdded(address sender, address account);
    event SignerRemoved(address sender, address account);
    event BindSubject(uint256 eventIndex, uint256 ts, address layer1Address, address owner);
    event RewardClaimed(ClaimEvent claimEvent);
    event SubjectRewardSet(SubjectRewardSetEvent rewardEvent);
    event Trade(TradeEvent tradeEvent);

    constructor() {
        protocolFeeTo = msg.sender;
        protocolFeePercent = 0.05 ether; // 5%
        subjectFeePercent = 0.05 ether; // 5%

        uint256 chainId;
        assembly {
            chainId := chainid()
        }
    }

    struct TradeParameters {
        uint256 value;
        uint256 price;
        uint256 protocolFee;
        uint256 subjectFee;
        bool success;
    }

    function buySeat(
        address layer1Address,
        uint256 amount
    ) external payable nonReentrant {
        TradeParameters memory params;
        Seat storage seat = seats[layer1Address];
        params.price = getPrice(seat.totalSupply, amount);
        params.protocolFee = params.price * protocolFeePercent / 1 ether;
        params.subjectFee = params.price * subjectFeePercent / 1 ether;
        params.value = params.price + params.protocolFee + params.subjectFee;
        require(msg.value >= params.value, "Insufficient payment");
        seat.balanceOf[msg.sender] += amount;
        seat.totalSupply += amount;

        if (seat.owner == address(0)) {
            seat.subjectETHBalance += params.subjectFee;
        } else {
            (params.success, ) = seat.owner.call{value: params.subjectFee}(new bytes(0));
            require(params.success, "Unable to send funds");
        }
        (params.success, ) = protocolFeeTo.call{value: params.protocolFee}(new bytes(0));
        require(params.success, "Unable to send funds");

        emit Trade(TradeEvent({
            eventIndex: tradeIndex++,
            ts: block.timestamp,
            trader: msg.sender,
            subject: layer1Address,
            isBuy: true,
            buyAmount: amount,
            ethAmount: params.price,
            traderBalance: seat.balanceOf[msg.sender],
            supply: seat.totalSupply
        }));
    }

    function sellSeat(
        address layer1Address,
        uint256 amount
    ) external nonReentrant {
        TradeParameters memory params;
        Seat storage seat = seats[layer1Address];
        require(seat.balanceOf[msg.sender] >= amount, "Insufficient seats");
        params.price = getPrice(seat.totalSupply - amount, amount);
        params.protocolFee = params.price * protocolFeePercent / 1 ether;
        params.subjectFee = params.price * subjectFeePercent / 1 ether;
        params.value = params.price - params.protocolFee - params.subjectFee;
        seat.balanceOf[msg.sender] -= amount;
        seat.totalSupply -= amount;
        if (seat.owner == address(0)) {
            seat.subjectETHBalance += params.subjectFee;
        } else {
            (params.success, ) = seat.owner.call{value: params.subjectFee}(new bytes(0));
            require(params.success, "Unable to send funds");
        }
        (params.success, ) = msg.sender.call{value: params.value}(new bytes(0));
        require(params.success, "Unable to send funds");
        (params.success, ) = protocolFeeTo.call{value: params.protocolFee}(new bytes(0));
        require(params.success, "Unable to send funds");

        emit Trade(TradeEvent({
            eventIndex: tradeIndex++,
            ts: block.timestamp,
            trader: msg.sender,
            subject: layer1Address,
            isBuy: false,
            buyAmount: amount,
            ethAmount: params.price,
            traderBalance: seat.balanceOf[msg.sender],
            supply: seat.totalSupply
        }));
    }

    function bindSubjectAndClaim(
        address layer1Address,
        address owner
    ) external onlyOwner {
        // recover(buildBindSeparator(subject, owner), v, r, s);
        Seat storage vp = seats[layer1Address];
        if (vp.owner == address(0)) {
            vp.owner = owner;
            emit BindSubject(bindIndex++, block.timestamp, layer1Address, owner);
        }
        if (vp.subjectETHBalance > 0) {
            uint256 balance = vp.subjectETHBalance;
            vp.subjectETHBalance = 0;
            (bool success, ) = owner.call{value: balance}(new bytes(0));
            require(success, "Unable to send funds");
            emit RewardClaimed(ClaimEvent({
                eventIndex: claimIndex++,
                ts: block.timestamp,
                sender: owner,
                subject: layer1Address,
                claimedIndex: 0,
                reward: balance
            }));
        }
    }

    function setProtocolFeeTo(address feeTo) external onlyOwner {
        protocolFeeTo = feeTo;
    }

    function setProtocolFeePercent(uint256 feePercent) external onlyOwner {
        protocolFeePercent = feePercent;
    }

    function setSubjectFeePercent(uint256 feePercent) external onlyOwner {
        subjectFeePercent = feePercent;
    }

    function getPrice(uint256 supply, uint256 amount) public pure returns (uint256) {
        uint256 sum1 = supply * (supply + 1) * (2 * supply + 1) / 6;
        uint256 sum2 = (supply + amount) * (supply + 1 + amount) * (2 * (supply + amount) + 1) / 6;
        uint256 summation = sum2 - sum1;
        return summation * 1 ether / 54321;
    }

    function getBuyPrice(address layer1Address, uint256 amount) public view returns (uint256) {
        return getPrice(seats[layer1Address].totalSupply, amount);
    }

    function getSellPrice(address layer1Address, uint256 amount) public view returns (uint256) {
        return getPrice(seats[layer1Address].totalSupply - amount, amount);
    }

    function getBuyPriceAfterFee(address layer1Address, uint256 amount) public view returns (uint256) {
        uint256 price = getBuyPrice(layer1Address, amount);
        uint256 protocolFee = price * protocolFeePercent / 1 ether;
        uint256 subjectFee = price * subjectFeePercent / 1 ether;
        return price + protocolFee + subjectFee;
    }

    function getSellPriceAfterFee(address layer1Address, uint256 amount) public view returns (uint256) {
        uint256 price = getSellPrice(layer1Address, amount);
        uint256 protocolFee = price * protocolFeePercent / 1 ether;
        uint256 subjectFee = price * subjectFeePercent / 1 ether;
        return price - protocolFee - subjectFee;
    }

    function getSubjectOwner(address layer1Address) public view returns (address) {
        return seats[layer1Address].owner;
    }

    function getSubjectETHBalance(address layer1Address) public view returns (uint256) {
        return seats[layer1Address].subjectETHBalance;
    }

    function getSubjectSupply(address layer1Address) public view returns (uint256) {
        return seats[layer1Address].totalSupply;
    }

    function getSubjectBalanceOf(address layer1Address, address account) public view returns (uint256) {
        return seats[layer1Address].balanceOf[account];
    }

    function getSubjectTotalReward(address layer1Address) public view returns (uint256) {
        return seats[layer1Address].totalReward;
    }

    function getSubjectCurrentReward(address layer1Address) public view returns (uint256) {
        return seats[layer1Address].currentReward;
    }

    function getLightStatus(address layer1Address) public view returns (bool) {
        Seat storage vp = seats[layer1Address];
        if (vp.owner == address(0)) {
            return false;
        } else {
            return true;
        }
    }

    function getSubjectDeadline(address layer1Address) public view returns (uint256) {
        return seats[layer1Address].deadline;
    }
}
设置
{
  "compilationTarget": {
    "Light.sol": "Light"
  },
  "evmVersion": "cancun",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"eventIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"},{"indexed":false,"internalType":"address","name":"layer1Address","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"BindSubject","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"eventIndex","type":"uint256"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"subject","type":"address"},{"internalType":"uint256","name":"claimedIndex","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"indexed":false,"internalType":"struct Light.ClaimEvent","name":"claimEvent","type":"tuple"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SignerRemoved","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"eventIndex","type":"uint256"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"bytes32","name":"subject","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"snapshotReward","type":"uint256"},{"internalType":"uint256","name":"rewardPercent","type":"uint256"},{"internalType":"uint256","name":"totalReward","type":"uint256"}],"indexed":false,"internalType":"struct Light.SubjectRewardSetEvent","name":"rewardEvent","type":"tuple"}],"name":"SubjectRewardSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"eventIndex","type":"uint256"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"subject","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"traderBalance","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"}],"indexed":false,"internalType":"struct Light.TradeEvent","name":"tradeEvent","type":"tuple"}],"name":"Trade","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bindIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"bindSubjectAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"buySeat","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyPriceAfterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getLightStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getSellPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getSellPriceAfterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getSubjectBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectCurrentReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectETHBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"}],"name":"getSubjectTotalReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"indexes","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":"prizeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"seats","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"totalReward","type":"uint256"},{"internalType":"uint256","name":"currentReward","type":"uint256"},{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"subjectETHBalance","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"layer1Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sellSeat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feePercent","type":"uint256"}],"name":"setProtocolFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeTo","type":"address"}],"name":"setProtocolFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feePercent","type":"uint256"}],"name":"setSubjectFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"signers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"subjectFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]