StakedNET

0xb773ec2c326b7f98a5a83fc098825492f020a4c7

Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
2,736 bytes
ABI entries
29
13 read · 5 write
License
none

Contract information

Address
0xb773ec2c326b7f98a5a83fc098825492f020a4c7
Chain
Robinhood Chain (4663)
Compiler
v0.8.30+commit.73712a01
Optimization
Enabled
Creation tx
0x6090b037e0…af15325858

Token

Name
Staked NET
Symbol
sNET
Decimals
9
Holders
249

Read contract (13)

allowance(address, address)uint256
balanceForGons(uint256)uint256
balanceOf(address)uint256
circulatingSupply()uint256
decimals()uint8
gonsForBalance(uint256)uint256
gonsPerFragment()uint256
index()uint256
name()string
staking()address
symbol()string
totalSupply()uint256
wired()bool

Events (3)

ApprovalLogRebaseTransfer

ABI

[
  {
    "inputs": [],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyWired",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotDeployer",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotStaking",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotWired",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "epoch",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "rebaseAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      }
    ],
    "name": "LogRebase",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "gons",
        "type": "uint256"
      }
    ],
    "name": "balanceForGons",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "circulatingSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "gonsForBalance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "gonsPerFragment",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "index",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "profit",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "epoch",
        "type": "uint256"
      }
    ],
    "name": "rebase",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "staking",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "staking_",
        "type": "address"
      }
    ],
    "name": "wire",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "wired",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.24;

import {IsNET} from "./interfaces/IsNET.sol";
import {Constants} from "./Constants.sol";
import {Wired} from "./abstract/Wired.sol";

/// @title StakedNET (sNET) — rebasing staked token
/// @notice OHM v1 gons model (specs/mechanism.md §3): TOTAL_GONS is fixed and
///         rebases scale gonsPerFragment. The Staking contract holds the
///         non-circulating inventory; user-held ("circulating") fragments
///         grow by exactly the rebase profit in aggregate, keeping the
///         NET ⇄ sNET peg (invariant §6.5).
contract StakedNET is IsNET, Wired {
    error NotStaking();
    error InsufficientBalance();
    error InsufficientAllowance();

    string public constant name = "Staked NET";
    string public constant symbol = "sNET";
    uint8 public constant decimals = 9;

    /// @dev Inventory ceiling: 5B whole NET of fragments. The RFV hard cap
    ///      binds supply far below this in any realistic path.
    uint256 private constant INITIAL_FRAGMENTS = 5_000_000_000e9;
    uint256 private constant TOTAL_GONS =
        type(uint256).max - (type(uint256).max % INITIAL_FRAGMENTS);
    uint256 private constant MAX_SUPPLY = type(uint128).max;

    address public staking;

    uint256 private _totalSupply;
    uint256 public gonsPerFragment;
    uint256 private _indexGons;
    mapping(address => uint256) private _gonBalances;
    mapping(address => mapping(address => uint256)) public allowance;

    constructor() {
        _totalSupply = INITIAL_FRAGMENTS;
        gonsPerFragment = TOTAL_GONS / INITIAL_FRAGMENTS;
    }

    /// @notice One-time wiring: assigns the full inventory to Staking and
    ///         pins the index base at 1.0 (1e9).
    function wire(address staking_) external wiring {
        staking = _nonZero(staking_);
        _gonBalances[staking_] = TOTAL_GONS;
        _indexGons = Constants.NET_UNIT * gonsPerFragment;
        emit Transfer(address(0), staking_, INITIAL_FRAGMENTS);
    }

    // ── Views ──

    function totalSupply() external view returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view returns (uint256) {
        return _gonBalances[account] / gonsPerFragment;
    }

    /// @notice User-held fragments (everything outside the Staking inventory).
    function circulatingSupply() public view returns (uint256) {
        return _totalSupply - balanceOf(staking);
    }

    /// @inheritdoc IsNET
    function index() external view returns (uint256) {
        return _indexGons / gonsPerFragment;
    }

    function gonsForBalance(uint256 amount) external view returns (uint256) {
        return amount * gonsPerFragment;
    }

    function balanceForGons(uint256 gons) external view returns (uint256) {
        return gons / gonsPerFragment;
    }

    // ── Rebase ──

    /// @inheritdoc IsNET
    function rebase(uint256 profit, uint256 epoch) external returns (uint256) {
        _checkWired();
        if (msg.sender != staking) revert NotStaking();
        uint256 circulating = circulatingSupply();
        if (profit == 0 || circulating == 0) {
            emit LogRebase(epoch, 0, _indexGons / gonsPerFragment);
            return _totalSupply;
        }
        // Scale total supply so circulating fragments grow by exactly
        // `profit` in aggregate (inventory scales proportionally).
        uint256 rebaseAmount = profit * _totalSupply / circulating;
        uint256 newSupply = _totalSupply + rebaseAmount;
        if (newSupply > MAX_SUPPLY) newSupply = MAX_SUPPLY;
        _totalSupply = newSupply;
        gonsPerFragment = TOTAL_GONS / newSupply;
        emit LogRebase(epoch, rebaseAmount, _indexGons / gonsPerFragment);
        return newSupply;
    }

    // ── ERC-20 (gon-based) ──

    function approve(address spender, uint256 value) external returns (bool) {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        if (allowed != type(uint256).max) {
            if (allowed < value) revert InsufficientAllowance();
            unchecked {
                allowance[from][msg.sender] = allowed - value;
            }
        }
        _transfer(from, to, value);
        return true;
    }

    function _transfer(address from, address to, uint256 value) internal {
        if (to == address(0)) revert ZeroAddress();
        uint256 gons = value * gonsPerFragment;
        uint256 fromGons = _gonBalances[from];
        if (fromGons < gons) revert InsufficientBalance();
        unchecked {
            _gonBalances[from] = fromGons - gons;
        }
        _gonBalances[to] += gons;
        emit Transfer(from, to, value);
    }
}
Chain explorer5114msChain node83ms