Merge remote-tracking branch 'build/master' into class-v6-invention
This commit is contained in:
commit
da2a06e4b6
122 changed files with 16385 additions and 587 deletions
26
.forgejo/issue_template/grant.md
Normal file
26
.forgejo/issue_template/grant.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
name: Grant application
|
||||
about: Apply for an Igneum grant: tooling, a reference app, infrastructure or research, paid in IGN on delivery
|
||||
title: "Grant: "
|
||||
labels: grant
|
||||
---
|
||||
|
||||
<!-- Read igneum.network/grants first. A short application is fine; the definition of done is the part that matters. -->
|
||||
|
||||
## What you will build
|
||||
|
||||
<!-- One paragraph. Name the tier: tooling, reference app, infrastructure, research. -->
|
||||
|
||||
## What done looks like
|
||||
|
||||
<!-- What runs where on the public testnet, and what a reviewer can click or call to see it working. -->
|
||||
|
||||
## Your public work
|
||||
|
||||
<!-- A repository, a package, a paper, a deployed thing. Links. -->
|
||||
|
||||
## How to reach you
|
||||
|
||||
<!-- An email, a Discord handle, or this issue. -->
|
||||
|
||||
<!-- Devnet and testnet coins have no value. No amount, price or date is promised. Not legal advice. -->
|
||||
18
contracts/bridge/foundry.toml
Normal file
18
contracts/bridge/foundry.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[profile.default]
|
||||
src = "src"
|
||||
test = "test"
|
||||
script = "script"
|
||||
out = "out"
|
||||
libs = []
|
||||
solc_version = "0.8.28"
|
||||
# The verifier calls the BLS12-381 precompiles of EIP-2537 (live on Sepolia and mainnet since Pectra), so the test EVM
|
||||
# runs the Osaka rules, the fork Sepolia is on (EIP-7883 modexp pricing counts here).
|
||||
evm_version = "osaka"
|
||||
optimizer = true
|
||||
optimizer_runs = 200
|
||||
via_ir = true
|
||||
fs_permissions = [{ access = "read", path = "./test/vectors" }, { access = "read-write", path = "./deploy-out.json" }]
|
||||
auto_detect_remappings = false
|
||||
|
||||
[rpc_endpoints]
|
||||
sepolia = "https://ethereum-sepolia-rpc.publicnode.com"
|
||||
46
contracts/bridge/script/Deploy.s.sol
Normal file
46
contracts/bridge/script/Deploy.s.sol
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
import {IgneumCertificateVerifier} from "../src/IgneumCertificateVerifier.sol";
|
||||
|
||||
/// Deploys the verifier on Sepolia from BRIDGE_DEPLOYER_KEY (environment, never printed), installs the voter table
|
||||
/// from the vectors file named in BRIDGE_TABLE_JSON (a gen.mjs output: keys, weights, index, chain_id) and, when the
|
||||
/// file carries a certificate (bitmap, signature), submits it, so the contract records one checkpoint final from the start.
|
||||
///
|
||||
/// BRIDGE_TABLE_JSON=test/vectors/chain.json forge script script/Deploy.s.sol:Deploy --rpc-url sepolia --broadcast --sig "run()"
|
||||
contract Deploy {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("BRIDGE_DEPLOYER_KEY");
|
||||
string memory j = vm.readFile(vm.envOr("BRIDGE_TABLE_JSON", "test/vectors/chain.json"));
|
||||
bytes[] memory keys = vm.parseJsonBytesArray(j, ".keys");
|
||||
uint256[] memory w = vm.parseJsonUintArray(j, ".weights");
|
||||
bytes memory packed;
|
||||
uint64[] memory weights = new uint64[](w.length);
|
||||
for (uint256 i = 0; i < keys.length; i++) {
|
||||
packed = abi.encodePacked(packed, keys[i]);
|
||||
weights[i] = uint64(w[i]);
|
||||
}
|
||||
uint64 index = uint64(vm.parseJsonUint(j, ".index"));
|
||||
|
||||
vm.startBroadcast(key);
|
||||
IgneumCertificateVerifier v = new IgneumCertificateVerifier(vm.parseJsonString(j, ".chain_id"));
|
||||
v.installTable(index, packed, weights);
|
||||
bool hasCert = vm.keyExistsJson(j, ".bitmap");
|
||||
if (hasCert) {
|
||||
v.submitCertificate(index, vm.parseJsonBytes32(j, ".checkpoint"), vm.parseJsonBytes(j, ".bitmap"), vm.parseJsonBytes(j, ".signature"));
|
||||
}
|
||||
vm.stopBroadcast();
|
||||
|
||||
vm.writeFile(
|
||||
"deploy-out.json",
|
||||
string.concat(
|
||||
"{\n \"IgneumCertificateVerifier\": \"", vm.toString(address(v)), "\",\n \"chain_id\": \"", vm.parseJsonString(j, ".chain_id"),
|
||||
"\",\n \"table_index\": ", vm.toString(uint256(index)), ",\n \"voters\": ", vm.toString(keys.length), ",\n \"table_id\": \"",
|
||||
vm.toString(v.tableId()), "\",\n \"final_checkpoint\": \"", hasCert ? vm.toString(vm.parseJsonBytes32(j, ".checkpoint")) : "none yet", "\"\n}\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
22
contracts/bridge/script/Send.s.sol
Normal file
22
contracts/bridge/script/Send.s.sol
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
|
||||
/// Sends SEND_WEI of the chain's coin from the key in BRIDGE_DEPLOYER_KEY to SEND_TO (Sepolia test ETH between the
|
||||
/// lanes' throwaway deployers). The key is read from the environment and never printed.
|
||||
///
|
||||
/// SEND_TO=0x.. SEND_WEI=20000000000000000 forge script script/Send.s.sol:Send --rpc-url sepolia --broadcast --sig "run()"
|
||||
contract Send {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("BRIDGE_DEPLOYER_KEY");
|
||||
address to = vm.envAddress("SEND_TO");
|
||||
uint256 wei_ = vm.envUint("SEND_WEI");
|
||||
vm.startBroadcast(key);
|
||||
(bool ok,) = to.call{value: wei_}("");
|
||||
require(ok, "send failed");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
113
contracts/bridge/src/BLS12381.sol
Normal file
113
contracts/bridge/src/BLS12381.sol
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// BLS12-381 through the EIP-2537 precompiles (Ethereum mainnet and Sepolia since Pectra): the hash-to-curve of
|
||||
/// RFC 9380 (BLS12381G2_XMD:SHA-256_SSWU_RO_) with the caller's domain separation tag, public-key aggregation in G1
|
||||
/// and the two-pairing check of a "minimal public key" signature (keys in G1, signatures in G2), the scheme of
|
||||
/// Igneum's finality votes (consensus/core/src/finality.rs, blst "min_pk").
|
||||
///
|
||||
/// Encodings are the precompiles' own: a field element is 64 bytes (16 zero bytes then the 48-byte big-endian
|
||||
/// value), a G1 point 128 bytes (x, y), a G2 point 256 bytes (x.c0, x.c1, y.c0, y.c1). Compressed chain forms
|
||||
/// (48-byte keys, 96-byte signatures) are decompressed off chain by the submitter; the pairing precompile refuses
|
||||
/// a point off the curve or outside the prime-order subgroup, so a wrong decompression fails the check.
|
||||
library BLS12381 {
|
||||
address internal constant G1ADD = address(0x0b);
|
||||
address internal constant G2ADD = address(0x0d);
|
||||
address internal constant PAIRING = address(0x0f);
|
||||
address internal constant MAP_FP2_TO_G2 = address(0x11);
|
||||
address internal constant MODEXP = address(0x05);
|
||||
|
||||
uint256 internal constant G1_LEN = 128;
|
||||
uint256 internal constant G2_LEN = 256;
|
||||
|
||||
/// The field modulus p, big-endian, 48 bytes (the modexp precompile's modulus).
|
||||
bytes internal constant P = hex"1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab";
|
||||
|
||||
/// The G1 generator with its y negated (p - y), in the 128-byte encoding, for the pairing check
|
||||
/// e(pk, H(m)) * e(-G1, sig) == 1.
|
||||
bytes internal constant NEG_G1 =
|
||||
hex"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"
|
||||
hex"00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca";
|
||||
|
||||
error PrecompileFailed(address which);
|
||||
error BadLength(string what);
|
||||
|
||||
// ---- hash to curve ----
|
||||
|
||||
/// expand_message_xmd with SHA-256 (RFC 9380 section 5.3.1) to `len` bytes; len at most 255 * 32.
|
||||
function expandMessageXmd(bytes memory msg_, bytes memory dst, uint256 len) internal pure returns (bytes memory out) {
|
||||
require(dst.length <= 255, "BLS: DST too long");
|
||||
uint256 ell = (len + 31) / 32;
|
||||
require(ell <= 255 && len > 0, "BLS: bad length");
|
||||
bytes memory dstPrime = abi.encodePacked(dst, uint8(dst.length));
|
||||
bytes32 b0 = sha256(abi.encodePacked(new bytes(64), msg_, uint16(len), uint8(0), dstPrime));
|
||||
bytes32 bi = sha256(abi.encodePacked(b0, uint8(1), dstPrime));
|
||||
out = new bytes(ell * 32);
|
||||
assembly {
|
||||
mstore(add(out, 32), bi)
|
||||
}
|
||||
for (uint256 i = 2; i <= ell; i++) {
|
||||
bi = sha256(abi.encodePacked(b0 ^ bi, uint8(i), dstPrime));
|
||||
assembly {
|
||||
mstore(add(add(out, 32), mul(sub(i, 1), 32)), bi)
|
||||
}
|
||||
}
|
||||
assembly {
|
||||
mstore(out, len)
|
||||
}
|
||||
}
|
||||
|
||||
/// A 64-byte big-endian integer reduced mod p and returned in the precompiles' 64-byte field encoding.
|
||||
function reduce64(bytes memory chunk, uint256 offset) internal view returns (bytes memory fe) {
|
||||
require(chunk.length >= offset + 64, "BLS: chunk");
|
||||
bytes memory base = new bytes(64);
|
||||
for (uint256 i = 0; i < 64; i++) {
|
||||
base[i] = chunk[offset + i];
|
||||
}
|
||||
// modexp(base^1 mod p): lengths 64, 1, 48
|
||||
bytes memory input = abi.encodePacked(uint256(64), uint256(1), uint256(48), base, uint8(1), P);
|
||||
(bool ok, bytes memory r) = MODEXP.staticcall(input);
|
||||
if (!ok || r.length != 48) revert PrecompileFailed(MODEXP);
|
||||
fe = abi.encodePacked(bytes16(0), r);
|
||||
}
|
||||
|
||||
/// hash_to_curve for G2: two field elements of Fp2 from a 256-byte expansion, each mapped by the precompile
|
||||
/// (which clears the cofactor), then added.
|
||||
function hashToG2(bytes memory msg_, bytes memory dst) internal view returns (bytes memory point) {
|
||||
bytes memory u = expandMessageXmd(msg_, dst, 256);
|
||||
bytes memory q0 = mapFp2ToG2(abi.encodePacked(reduce64(u, 0), reduce64(u, 64)));
|
||||
bytes memory q1 = mapFp2ToG2(abi.encodePacked(reduce64(u, 128), reduce64(u, 192)));
|
||||
point = g2Add(q0, q1);
|
||||
}
|
||||
|
||||
function mapFp2ToG2(bytes memory fp2) internal view returns (bytes memory point) {
|
||||
if (fp2.length != 128) revert BadLength("fp2");
|
||||
(bool ok, bytes memory r) = MAP_FP2_TO_G2.staticcall(fp2);
|
||||
if (!ok || r.length != G2_LEN) revert PrecompileFailed(MAP_FP2_TO_G2);
|
||||
point = r;
|
||||
}
|
||||
|
||||
// ---- group operations ----
|
||||
|
||||
function g1Add(bytes memory a, bytes memory b) internal view returns (bytes memory c) {
|
||||
if (a.length != G1_LEN || b.length != G1_LEN) revert BadLength("g1");
|
||||
(bool ok, bytes memory r) = G1ADD.staticcall(abi.encodePacked(a, b));
|
||||
if (!ok || r.length != G1_LEN) revert PrecompileFailed(G1ADD);
|
||||
c = r;
|
||||
}
|
||||
|
||||
function g2Add(bytes memory a, bytes memory b) internal view returns (bytes memory c) {
|
||||
if (a.length != G2_LEN || b.length != G2_LEN) revert BadLength("g2");
|
||||
(bool ok, bytes memory r) = G2ADD.staticcall(abi.encodePacked(a, b));
|
||||
if (!ok || r.length != G2_LEN) revert PrecompileFailed(G2ADD);
|
||||
c = r;
|
||||
}
|
||||
|
||||
/// e(pk, hm) * e(-G1, sig) == 1, which holds exactly when sig = sk * hm for pk = sk * G1.
|
||||
function verifyMinPk(bytes memory pk, bytes memory hm, bytes memory sig) internal view returns (bool) {
|
||||
if (pk.length != G1_LEN || hm.length != G2_LEN || sig.length != G2_LEN) revert BadLength("pairing");
|
||||
(bool ok, bytes memory r) = PAIRING.staticcall(abi.encodePacked(pk, hm, NEG_G1, sig));
|
||||
if (!ok || r.length != 32) return false;
|
||||
return abi.decode(r, (uint256)) == 1;
|
||||
}
|
||||
}
|
||||
155
contracts/bridge/src/IgneumCertificateVerifier.sol
Normal file
155
contracts/bridge/src/IgneumCertificateVerifier.sol
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {BLS12381} from "./BLS12381.sol";
|
||||
import {MerklePatricia} from "./MerklePatricia.sol";
|
||||
|
||||
interface IIgneumCertificateVerifier {
|
||||
function chainId() external view returns (string memory);
|
||||
function tableId() external view returns (bytes32);
|
||||
function verifyCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature)
|
||||
external
|
||||
view
|
||||
returns (bool ok, uint256 signedWeight, uint256 totalWeight);
|
||||
function submitCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature) external;
|
||||
function finalCheckpoint(uint64 index) external view returns (bytes32);
|
||||
function isFinal(bytes32 checkpoint) external view returns (bool);
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] calldata proof)
|
||||
external
|
||||
pure
|
||||
returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash);
|
||||
}
|
||||
|
||||
/// The Igneum light-client bridge primitive on Ethereum: verifies a Devnet 3 finality certificate (the aggregate
|
||||
/// BLS signature of the canonical voter list over the vote message, under the 2/3-of-total-weight rule) against an
|
||||
/// installed voter table, records the checkpoint hashes it proved final, and verifies an Ethereum-shape account
|
||||
/// proof against a state root. What it proves and what it does not: docs/bridge/light-client-bridge.md.
|
||||
///
|
||||
/// Devnet 3, test tokens, no value.
|
||||
contract IgneumCertificateVerifier is IIgneumCertificateVerifier {
|
||||
using MerklePatricia for bytes32;
|
||||
|
||||
string public constant VOTE_PREFIX = "igneum-vote-v1/";
|
||||
bytes public constant DST_VOTE = "IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
|
||||
|
||||
string private _chainId;
|
||||
address public owner;
|
||||
|
||||
/// The canonical voter list at the installed checkpoint index: 128-byte G1 keys in the node's canonical order
|
||||
/// (sorted by key hash, every key above dust and not stripped) and their weights (blue blocks in the window).
|
||||
bytes[] private _keys;
|
||||
uint64[] private _weights;
|
||||
uint256 public totalWeight;
|
||||
uint64 public tableIndex;
|
||||
bytes32 public override tableId;
|
||||
|
||||
mapping(uint64 => bytes32) public override finalCheckpoint;
|
||||
mapping(bytes32 => bool) public override isFinal;
|
||||
|
||||
event TableInstalled(uint64 indexed atIndex, uint256 voters, uint256 totalWeight, bytes32 tableId);
|
||||
event CheckpointFinal(uint64 indexed index, bytes32 checkpoint, uint256 signedWeight, uint256 totalWeight, uint256 signers);
|
||||
|
||||
error NotOwner();
|
||||
error NoTable();
|
||||
error BadCertificate(string why);
|
||||
|
||||
constructor(string memory chainId_) {
|
||||
_chainId = chainId_;
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function chainId() external view override returns (string memory) {
|
||||
return _chainId;
|
||||
}
|
||||
|
||||
function voterCount() external view returns (uint256) {
|
||||
return _keys.length;
|
||||
}
|
||||
|
||||
function voter(uint256 i) external view returns (bytes memory key, uint64 weight) {
|
||||
return (_keys[i], _weights[i]);
|
||||
}
|
||||
|
||||
/// Installs the voter table read from a Devnet 3 node (igneum_getFinalityWeights at `atIndex`): `keys` is the
|
||||
/// concatenation of 128-byte uncompressed G1 keys in canonical order, `weights` their weights. The table is a
|
||||
/// trusted input of this first version (see the doc); only the installer may replace it.
|
||||
function installTable(uint64 atIndex, bytes calldata keys, uint64[] calldata weights) external {
|
||||
if (msg.sender != owner) revert NotOwner();
|
||||
if (keys.length != weights.length * BLS12381.G1_LEN || weights.length == 0) revert BadCertificate("table shape");
|
||||
delete _keys;
|
||||
delete _weights;
|
||||
uint256 total;
|
||||
for (uint256 i = 0; i < weights.length; i++) {
|
||||
_keys.push(keys[i * BLS12381.G1_LEN:(i + 1) * BLS12381.G1_LEN]);
|
||||
_weights.push(weights[i]);
|
||||
total += weights[i];
|
||||
}
|
||||
totalWeight = total;
|
||||
tableIndex = atIndex;
|
||||
tableId = keccak256(abi.encodePacked(atIndex, keys, abi.encodePacked(weights)));
|
||||
emit TableInstalled(atIndex, weights.length, total, tableId);
|
||||
}
|
||||
|
||||
/// The bytes every voter signs for (index, checkpoint): "igneum-vote-v1/" chain_id 0x00 index_le64 checkpoint.
|
||||
function voteMessage(uint64 index, bytes32 checkpoint) public view returns (bytes memory) {
|
||||
return abi.encodePacked(VOTE_PREFIX, _chainId, bytes1(0), le64(index), checkpoint);
|
||||
}
|
||||
|
||||
function verifyCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature)
|
||||
public
|
||||
view
|
||||
override
|
||||
returns (bool ok, uint256 signedWeight, uint256 totalWeight_)
|
||||
{
|
||||
uint256 n = _keys.length;
|
||||
if (n == 0) revert NoTable();
|
||||
if (bitmap.length != (n + 7) / 8) revert BadCertificate("bitmap length");
|
||||
if (signature.length != BLS12381.G2_LEN) revert BadCertificate("signature length");
|
||||
bytes memory agg;
|
||||
uint256 signers;
|
||||
for (uint256 p = 0; p < n; p++) {
|
||||
if (uint8(bitmap[p >> 3]) & uint8(1 << (p & 7)) == 0) continue;
|
||||
signedWeight += _weights[p];
|
||||
signers++;
|
||||
agg = agg.length == 0 ? _keys[p] : BLS12381.g1Add(agg, _keys[p]);
|
||||
}
|
||||
totalWeight_ = totalWeight;
|
||||
if (signers == 0) return (false, 0, totalWeight_);
|
||||
// the rule decided 4 October 2026: signed weight at least two thirds of the whole window's weight
|
||||
if (3 * signedWeight < 2 * totalWeight_) return (false, signedWeight, totalWeight_);
|
||||
bytes memory hm = BLS12381.hashToG2(voteMessage(index, checkpoint), DST_VOTE);
|
||||
ok = BLS12381.verifyMinPk(agg, hm, signature);
|
||||
}
|
||||
|
||||
function submitCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature) external override {
|
||||
(bool ok, uint256 signed, uint256 total) = verifyCertificate(index, checkpoint, bitmap, signature);
|
||||
if (!ok) revert BadCertificate("certificate does not verify");
|
||||
bytes32 known = finalCheckpoint[index];
|
||||
if (known != bytes32(0) && known != checkpoint) revert BadCertificate("a different checkpoint is final at this index");
|
||||
finalCheckpoint[index] = checkpoint;
|
||||
isFinal[checkpoint] = true;
|
||||
uint256 signers;
|
||||
for (uint256 p = 0; p < _keys.length; p++) {
|
||||
if (uint8(bitmap[p >> 3]) & uint8(1 << (p & 7)) != 0) signers++;
|
||||
}
|
||||
emit CheckpointFinal(index, checkpoint, signed, total, signers);
|
||||
}
|
||||
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] calldata proof)
|
||||
external
|
||||
pure
|
||||
override
|
||||
returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash)
|
||||
{
|
||||
MerklePatricia.Account memory a = MerklePatricia.verifyAccount(stateRoot, account, proof);
|
||||
return (a.exists, a.nonce, a.balance, a.storageRoot, a.codeHash);
|
||||
}
|
||||
|
||||
function le64(uint64 v) internal pure returns (bytes8 out) {
|
||||
uint64 r;
|
||||
for (uint256 i = 0; i < 8; i++) {
|
||||
r = (r << 8) | ((v >> (8 * i)) & 0xff);
|
||||
}
|
||||
out = bytes8(r);
|
||||
}
|
||||
}
|
||||
214
contracts/bridge/src/MerklePatricia.sol
Normal file
214
contracts/bridge/src/MerklePatricia.sol
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// An Ethereum account proof (the eth_getProof shape) checked against a state root: the keccak-keyed Merkle
|
||||
/// Patricia trie of reth's layout, which Igneum's executor uses for its stateRoot (igneum/exec/src/state.rs,
|
||||
/// alloy_trie::root::state_root over keccak256(address) keys and RLP(nonce, balance, storageRoot, codeHash)
|
||||
/// values). A proof is the list of RLP nodes from the root to the account's leaf, or to the branch or leaf that
|
||||
/// shows the account absent.
|
||||
library MerklePatricia {
|
||||
struct Account {
|
||||
bool exists;
|
||||
uint256 nonce;
|
||||
uint256 balance;
|
||||
bytes32 storageRoot;
|
||||
bytes32 codeHash;
|
||||
}
|
||||
|
||||
error BadProof(string why);
|
||||
|
||||
/// Verifies `proof` for `account` under `stateRoot`; reverts when a node does not hash to its reference or
|
||||
/// the path is malformed, returns exists=false when the trie shows no such account.
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] memory proof) internal pure returns (Account memory out) {
|
||||
bytes memory value = verifyPath(stateRoot, abi.encodePacked(keccak256(abi.encodePacked(account))), proof);
|
||||
if (value.length == 0) return out;
|
||||
(uint256 off, uint256 len, bool isList) = decode(value, 0);
|
||||
if (!isList) revert BadProof("account value is not a list");
|
||||
uint256 end = off + len;
|
||||
uint256 p = off;
|
||||
(uint256 o1, uint256 l1,) = decode(value, p);
|
||||
out.nonce = toUint(value, o1, l1);
|
||||
p = o1 + l1;
|
||||
(uint256 o2, uint256 l2,) = decode(value, p);
|
||||
out.balance = toUint(value, o2, l2);
|
||||
p = o2 + l2;
|
||||
(uint256 o3, uint256 l3,) = decode(value, p);
|
||||
if (l3 != 32) revert BadProof("storage root length");
|
||||
out.storageRoot = toBytes32(value, o3);
|
||||
p = o3 + l3;
|
||||
(uint256 o4, uint256 l4,) = decode(value, p);
|
||||
if (l4 != 32) revert BadProof("code hash length");
|
||||
out.codeHash = toBytes32(value, o4);
|
||||
if (o4 + l4 != end) revert BadProof("account value has extra fields");
|
||||
out.exists = true;
|
||||
}
|
||||
|
||||
/// Walks the proof for `key` (32 bytes, hashed already) from `root`; returns the value found, or empty bytes
|
||||
/// when the trie proves the key absent.
|
||||
function verifyPath(bytes32 root, bytes memory key, bytes[] memory proof) internal pure returns (bytes memory value) {
|
||||
bytes memory nibbles = toNibbles(key);
|
||||
uint256 pos = 0;
|
||||
bytes32 want = root;
|
||||
bytes memory embedded;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
bytes memory node = proof[i];
|
||||
if (embedded.length != 0) {
|
||||
if (keccak256(node) != keccak256(embedded)) revert BadProof("embedded node mismatch");
|
||||
embedded = "";
|
||||
} else if (keccak256(node) != want) {
|
||||
revert BadProof("node hash mismatch");
|
||||
}
|
||||
(uint256 off, uint256 len, bool isList) = decode(node, 0);
|
||||
if (!isList) revert BadProof("node is not a list");
|
||||
uint256 count = itemCount(node, off, len);
|
||||
if (count == 17) {
|
||||
if (pos == nibbles.length) {
|
||||
// the branch's own value slot
|
||||
(uint256 vo, uint256 vl,) = itemAt(node, off, 16);
|
||||
return slice(node, vo, vl);
|
||||
}
|
||||
uint8 nib = uint8(nibbles[pos]);
|
||||
(uint256 co, uint256 cl, bool clist) = itemAt(node, off, nib);
|
||||
if (cl == 0 && !clist) return ""; // empty slot: the key is absent
|
||||
pos++;
|
||||
if (clist) {
|
||||
embedded = slice(node, co - headerLen(node, co, cl, true), cl + headerLen(node, co, cl, true));
|
||||
} else {
|
||||
if (cl != 32) revert BadProof("child reference length");
|
||||
want = toBytes32(node, co);
|
||||
}
|
||||
} else if (count == 2) {
|
||||
(uint256 po, uint256 pl,) = itemAt(node, off, 0);
|
||||
(bytes memory path, bool isLeaf) = decodePath(slice(node, po, pl));
|
||||
if (!matches(nibbles, pos, path)) return ""; // diverging path: the key is absent
|
||||
pos += path.length;
|
||||
(uint256 vo, uint256 vl, bool vlist) = itemAt(node, off, 1);
|
||||
if (isLeaf) {
|
||||
if (pos != nibbles.length) revert BadProof("leaf before the key's end");
|
||||
return slice(node, vo, vl);
|
||||
}
|
||||
if (vlist) {
|
||||
embedded = slice(node, vo - headerLen(node, vo, vl, true), vl + headerLen(node, vo, vl, true));
|
||||
} else {
|
||||
if (vl != 32) revert BadProof("extension reference length");
|
||||
want = toBytes32(node, vo);
|
||||
}
|
||||
} else {
|
||||
revert BadProof("node arity");
|
||||
}
|
||||
}
|
||||
revert BadProof("proof ends before the key");
|
||||
}
|
||||
|
||||
// ---- paths ----
|
||||
|
||||
function toNibbles(bytes memory key) internal pure returns (bytes memory n) {
|
||||
n = new bytes(key.length * 2);
|
||||
for (uint256 i = 0; i < key.length; i++) {
|
||||
n[2 * i] = bytes1(uint8(key[i]) >> 4);
|
||||
n[2 * i + 1] = bytes1(uint8(key[i]) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-prefix decoding of a leaf or extension path.
|
||||
function decodePath(bytes memory hp) internal pure returns (bytes memory path, bool isLeaf) {
|
||||
if (hp.length == 0) revert BadProof("empty path");
|
||||
uint8 flag = uint8(hp[0]) >> 4;
|
||||
isLeaf = flag >= 2;
|
||||
bool odd = flag % 2 == 1;
|
||||
uint256 n = (hp.length - 1) * 2 + (odd ? 1 : 0);
|
||||
path = new bytes(n);
|
||||
uint256 w = 0;
|
||||
if (odd) path[w++] = bytes1(uint8(hp[0]) & 0x0f);
|
||||
for (uint256 i = 1; i < hp.length; i++) {
|
||||
path[w++] = bytes1(uint8(hp[i]) >> 4);
|
||||
path[w++] = bytes1(uint8(hp[i]) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
function matches(bytes memory nibbles, uint256 pos, bytes memory path) internal pure returns (bool) {
|
||||
if (pos + path.length > nibbles.length) return false;
|
||||
for (uint256 i = 0; i < path.length; i++) {
|
||||
if (nibbles[pos + i] != path[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- RLP ----
|
||||
|
||||
/// The item at `p`: the offset of its payload, the payload length and whether it is a list.
|
||||
function decode(bytes memory b, uint256 p) internal pure returns (uint256 off, uint256 len, bool isList) {
|
||||
if (p >= b.length) revert BadProof("rlp out of range");
|
||||
uint8 first = uint8(b[p]);
|
||||
if (first < 0x80) return (p, 1, false);
|
||||
if (first < 0xb8) return (p + 1, first - 0x80, false);
|
||||
if (first < 0xc0) {
|
||||
uint256 n = first - 0xb7;
|
||||
return (p + 1 + n, readLen(b, p + 1, n), false);
|
||||
}
|
||||
if (first < 0xf8) return (p + 1, first - 0xc0, true);
|
||||
uint256 m = first - 0xf7;
|
||||
return (p + 1 + m, readLen(b, p + 1, m), true);
|
||||
}
|
||||
|
||||
function headerLen(bytes memory b, uint256 off, uint256 len, bool isList) private pure returns (uint256) {
|
||||
// the header length of an item whose payload starts at off: single bytes under 0x80 have none
|
||||
if (!isList && len == 1 && uint8(b[off]) < 0x80) return 0;
|
||||
if (len < 56) return 1;
|
||||
uint256 n = 0;
|
||||
uint256 l = len;
|
||||
while (l > 0) {
|
||||
n++;
|
||||
l >>= 8;
|
||||
}
|
||||
return 1 + n;
|
||||
}
|
||||
|
||||
function readLen(bytes memory b, uint256 p, uint256 n) private pure returns (uint256 len) {
|
||||
if (n == 0 || n > 32 || p + n > b.length) revert BadProof("rlp length");
|
||||
for (uint256 i = 0; i < n; i++) {
|
||||
len = (len << 8) | uint8(b[p + i]);
|
||||
}
|
||||
}
|
||||
|
||||
function itemCount(bytes memory b, uint256 off, uint256 len) private pure returns (uint256 n) {
|
||||
uint256 p = off;
|
||||
uint256 end = off + len;
|
||||
while (p < end) {
|
||||
(uint256 o, uint256 l,) = decode(b, p);
|
||||
p = o + l;
|
||||
n++;
|
||||
}
|
||||
if (p != end) revert BadProof("rlp list overrun");
|
||||
}
|
||||
|
||||
function itemAt(bytes memory b, uint256 off, uint256 index) private pure returns (uint256 o, uint256 l, bool isList) {
|
||||
uint256 p = off;
|
||||
for (uint256 i = 0; ; i++) {
|
||||
(o, l, isList) = decode(b, p);
|
||||
if (i == index) return (o, l, isList);
|
||||
p = o + l;
|
||||
}
|
||||
}
|
||||
|
||||
function toUint(bytes memory b, uint256 off, uint256 len) private pure returns (uint256 v) {
|
||||
if (len > 32) revert BadProof("integer too long");
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
v = (v << 8) | uint8(b[off + i]);
|
||||
}
|
||||
}
|
||||
|
||||
function toBytes32(bytes memory b, uint256 off) private pure returns (bytes32 v) {
|
||||
assembly {
|
||||
v := mload(add(add(b, 32), off))
|
||||
}
|
||||
}
|
||||
|
||||
function slice(bytes memory b, uint256 off, uint256 len) private pure returns (bytes memory out) {
|
||||
if (off + len > b.length) revert BadProof("slice out of range");
|
||||
out = new bytes(len);
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
out[i] = b[off + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
144
contracts/bridge/test/Verifier.t.sol
Normal file
144
contracts/bridge/test/Verifier.t.sol
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "./Vm.sol";
|
||||
import {IgneumCertificateVerifier} from "../src/IgneumCertificateVerifier.sol";
|
||||
import {BLS12381} from "../src/BLS12381.sol";
|
||||
|
||||
/// The verifier on Foundry's Prague EVM (the EIP-2537 precompiles): the synthetic vectors made by
|
||||
/// test/vectors/gen.mjs (five keys, a certificate by four of them, a small account trie) and, when present, a real
|
||||
/// certificate from the chain (test/vectors/chain.json, as /api/checkpoint serves it, decompressed by gen.mjs).
|
||||
contract VerifierTest {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
string json;
|
||||
IgneumCertificateVerifier v;
|
||||
|
||||
function setUp() public {
|
||||
json = vm.readFile("test/vectors/synthetic.json");
|
||||
v = new IgneumCertificateVerifier(vm.parseJsonString(json, ".chain_id"));
|
||||
_install(v, json);
|
||||
}
|
||||
|
||||
function _install(IgneumCertificateVerifier target, string memory j) internal {
|
||||
bytes[] memory keys = vm.parseJsonBytesArray(j, ".keys");
|
||||
uint256[] memory w = vm.parseJsonUintArray(j, ".weights");
|
||||
bytes memory packed;
|
||||
uint64[] memory weights = new uint64[](w.length);
|
||||
for (uint256 i = 0; i < keys.length; i++) {
|
||||
packed = abi.encodePacked(packed, keys[i]);
|
||||
weights[i] = uint64(w[i]);
|
||||
}
|
||||
target.installTable(uint64(vm.parseJsonUint(j, ".index")), packed, weights);
|
||||
}
|
||||
|
||||
function test_vote_message_matches_the_node() public view {
|
||||
bytes memory want = vm.parseJsonBytes(json, ".vote_message");
|
||||
bytes memory got = v.voteMessage(uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"));
|
||||
require(keccak256(want) == keccak256(got), "vote message");
|
||||
}
|
||||
|
||||
function test_expand_message_xmd_known_answer() public view {
|
||||
// RFC 9380 appendix K.1 (expand_message_xmd with SHA-256, DST "QUUX-V01-CS02-with-expander-SHA256-128"): the
|
||||
// empty message at 32 bytes is the appendix's own first answer; the "abc" at 128 bytes answer comes from noble
|
||||
bytes memory dst = bytes(vm.parseJsonString(json, ".xmd_dst"));
|
||||
bytes memory out = BLS12381.expandMessageXmd("", dst, 32);
|
||||
require(keccak256(out) == keccak256(hex"68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"), "xmd 32 (RFC)");
|
||||
require(keccak256(out) == keccak256(vm.parseJsonBytes(json, ".xmd_empty_32")), "xmd 32 (noble)");
|
||||
bytes memory out2 = BLS12381.expandMessageXmd("abc", dst, 128);
|
||||
require(keccak256(out2) == keccak256(vm.parseJsonBytes(json, ".xmd_abc_128")), "xmd 128 (noble)");
|
||||
}
|
||||
|
||||
function test_certificate_verifies() public view {
|
||||
(bool ok, uint256 signed, uint256 total) = v.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"), vm.parseJsonBytes(json, ".bitmap"), vm.parseJsonBytes(json, ".signature")
|
||||
);
|
||||
require(ok, "certificate");
|
||||
require(signed == vm.parseJsonUint(json, ".signed_weight") && total == vm.parseJsonUint(json, ".total_weight"), "weights");
|
||||
}
|
||||
|
||||
function test_certificate_under_two_thirds_is_refused() public view {
|
||||
(bool ok, uint256 signed,) = v.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"), vm.parseJsonBytes(json, ".weak_bitmap"), vm.parseJsonBytes(json, ".weak_signature")
|
||||
);
|
||||
require(!ok && signed * 3 < vm.parseJsonUint(json, ".total_weight") * 2, "weak certificate accepted");
|
||||
}
|
||||
|
||||
function test_wrong_checkpoint_or_index_fails() public view {
|
||||
bytes32 cp = vm.parseJsonBytes32(json, ".checkpoint");
|
||||
uint64 index = uint64(vm.parseJsonUint(json, ".index"));
|
||||
bytes memory bm = vm.parseJsonBytes(json, ".bitmap");
|
||||
bytes memory sig = vm.parseJsonBytes(json, ".signature");
|
||||
(bool ok1,,) = v.verifyCertificate(index, cp ^ bytes32(uint256(1)), bm, sig);
|
||||
(bool ok2,,) = v.verifyCertificate(index + 1, cp, bm, sig);
|
||||
require(!ok1 && !ok2, "forged certificate accepted");
|
||||
// the right signers' weight with a bitmap naming a different signer set does not match the signature
|
||||
bytes memory other = vm.parseJsonBytes(json, ".weak_bitmap");
|
||||
other[0] = bytes1(uint8(other[0]) | 0x1f);
|
||||
(bool ok3,,) = v.verifyCertificate(index, cp, other, sig);
|
||||
require(!ok3, "wrong signer set accepted");
|
||||
}
|
||||
|
||||
function test_submit_records_the_checkpoint() public {
|
||||
bytes32 cp = vm.parseJsonBytes32(json, ".checkpoint");
|
||||
uint64 index = uint64(vm.parseJsonUint(json, ".index"));
|
||||
v.submitCertificate(index, cp, vm.parseJsonBytes(json, ".bitmap"), vm.parseJsonBytes(json, ".signature"));
|
||||
require(v.isFinal(cp) && v.finalCheckpoint(index) == cp, "not recorded");
|
||||
vm.expectRevert(abi.encodeWithSelector(IgneumCertificateVerifier.BadCertificate.selector, "certificate does not verify"));
|
||||
v.submitCertificate(index, cp, vm.parseJsonBytes(json, ".weak_bitmap"), vm.parseJsonBytes(json, ".weak_signature"));
|
||||
}
|
||||
|
||||
function test_account_proof_present_and_absent() public view {
|
||||
bytes32 root = vm.parseJsonBytes32(json, ".state_root");
|
||||
(bool exists, uint256 nonce, uint256 balance, bytes32 sroot, bytes32 chash) =
|
||||
v.verifyAccount(root, vm.parseJsonAddress(json, ".account"), vm.parseJsonBytesArray(json, ".account_proof"));
|
||||
require(exists, "account absent");
|
||||
require(nonce == vm.parseJsonUint(json, ".account_nonce") && balance == vm.parseJsonUint(json, ".account_balance"), "account fields");
|
||||
require(sroot == vm.parseJsonBytes32(json, ".account_storage_root") && chash == vm.parseJsonBytes32(json, ".account_code_hash"), "account roots");
|
||||
(bool exists2,,,,) = v.verifyAccount(root, vm.parseJsonAddress(json, ".absent_account"), vm.parseJsonBytesArray(json, ".absent_proof"));
|
||||
require(!exists2, "absent account present");
|
||||
}
|
||||
|
||||
function test_account_proof_against_a_wrong_root_reverts() public {
|
||||
bytes32 root = vm.parseJsonBytes32(json, ".state_root") ^ bytes32(uint256(1));
|
||||
bytes[] memory proof = vm.parseJsonBytesArray(json, ".account_proof");
|
||||
address a = vm.parseJsonAddress(json, ".account");
|
||||
vm.expectRevert(abi.encodeWithSelector(bytes4(keccak256("BadProof(string)")), "node hash mismatch"));
|
||||
v.verifyAccount(root, a, proof);
|
||||
}
|
||||
|
||||
/// A certificate the chain actually carried (test/vectors/chain.json; skipped when the file is absent).
|
||||
function test_chain_certificate_verifies() public {
|
||||
string memory j;
|
||||
try vm.readFile("test/vectors/chain.json") returns (string memory s) {
|
||||
j = s;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
IgneumCertificateVerifier c = new IgneumCertificateVerifier(vm.parseJsonString(j, ".chain_id"));
|
||||
_install(c, j);
|
||||
(bool ok, uint256 signed, uint256 total) = c.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(j, ".index")), vm.parseJsonBytes32(j, ".checkpoint"), vm.parseJsonBytes(j, ".bitmap"), vm.parseJsonBytes(j, ".signature")
|
||||
);
|
||||
require(signed == vm.parseJsonUint(j, ".signed_weight") && total == vm.parseJsonUint(j, ".total_weight"), "chain weights");
|
||||
require(ok, "the chain's certificate does not verify");
|
||||
}
|
||||
|
||||
/// One Devnet 3 account under a real Devnet 3 state root (test/vectors/dn3-account.json from a node's eth_getProof;
|
||||
/// skipped when the file is absent). The root is the chain's own; the link from a certified checkpoint to that root
|
||||
/// is the gap the doc names.
|
||||
function test_devnet3_account_balance_proven() public {
|
||||
string memory j;
|
||||
try vm.readFile("test/vectors/dn3-account.json") returns (string memory s) {
|
||||
j = s;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
(bool exists, uint256 nonce, uint256 balance, bytes32 sroot, bytes32 chash) = v.verifyAccount(
|
||||
vm.parseJsonBytes32(j, ".state_root"), vm.parseJsonAddress(j, ".account"), vm.parseJsonBytesArray(j, ".account_proof")
|
||||
);
|
||||
require(exists, "the Devnet 3 account is absent under its root");
|
||||
require(nonce == vm.parseJsonUint(j, ".account_nonce") && balance == vm.parseJsonUint(j, ".account_balance"), "Devnet 3 account fields");
|
||||
require(sroot == vm.parseJsonBytes32(j, ".account_storage_root") && chash == vm.parseJsonBytes32(j, ".account_code_hash"), "Devnet 3 account roots");
|
||||
}
|
||||
}
|
||||
34
contracts/bridge/test/Vm.sol
Normal file
34
contracts/bridge/test/Vm.sol
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// The Foundry cheatcodes this project uses, declared here so the tree needs no remote dependency.
|
||||
interface Vm {
|
||||
function startBroadcast(uint256 privateKey) external;
|
||||
function stopBroadcast() external;
|
||||
function envUint(string calldata name) external view returns (uint256);
|
||||
function envAddress(string calldata name) external view returns (address);
|
||||
function envOr(string calldata name, string calldata defaultValue) external view returns (string memory);
|
||||
function toString(address value) external pure returns (string memory);
|
||||
function toString(uint256 value) external pure returns (string memory);
|
||||
function toString(bytes32 value) external pure returns (string memory);
|
||||
function toString(bytes calldata value) external pure returns (string memory);
|
||||
function readFile(string calldata path) external view returns (string memory);
|
||||
function writeFile(string calldata path, string calldata data) external;
|
||||
function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);
|
||||
function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);
|
||||
function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);
|
||||
function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);
|
||||
function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);
|
||||
function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);
|
||||
function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);
|
||||
function keyExistsJson(string calldata json, string calldata key) external view returns (bool);
|
||||
function deal(address who, uint256 newBalance) external;
|
||||
function prank(address msgSender) external;
|
||||
function startPrank(address msgSender) external;
|
||||
function stopPrank() external;
|
||||
function warp(uint256 newTimestamp) external;
|
||||
function expectRevert(bytes calldata revertData) external;
|
||||
function addr(uint256 privateKey) external pure returns (address);
|
||||
}
|
||||
|
||||
address constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
|
||||
9
contracts/bridge/test/vectors/.gitignore
vendored
Normal file
9
contracts/bridge/test/vectors/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
node_modules
|
||||
synthetic.json
|
||||
chain.json
|
||||
checkpoint-live.json
|
||||
checkpoint-dn3.json
|
||||
weights-dn3.json
|
||||
checkpoints-dn3.json
|
||||
dn3-table.json
|
||||
dn3-account.json
|
||||
116
contracts/bridge/test/vectors/gen.mjs
Normal file
116
contracts/bridge/test/vectors/gen.mjs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// Test vectors for the Igneum certificate verifier. Two sources:
|
||||
// node gen.mjs synthetic > synthetic.json five vote keys made here (noble BLS12-381), a certificate signed by four
|
||||
// of them over the Devnet 3 vote message, a small account trie with proofs
|
||||
// node gen.mjs table <weights.json> > dn3-table.json the voter table alone from a node's igneum_getFinalityWeights answer
|
||||
// (voters in the canonical order: sorted by key hash; weight = blocks)
|
||||
// node gen.mjs account <getProof.json> <stateRoot> <blockNumber> > dn3-account.json an eth_getProof answer from a Devnet 3
|
||||
// node (the reference-apps lane's reader) as the suite's real-root account vector
|
||||
// node gen.mjs chain <checkpoint.json> > dn3.json a real certificate as igneum.network/api/checkpoint?source=dn3 serves it:
|
||||
// the voter table and the aggregate signature decompressed to the
|
||||
// precompiles' encodings (the verifier checks the same bytes the node signed)
|
||||
// Encodings: field element 64 bytes (16 zero bytes then 48), G1 128 bytes, G2 256 bytes (x.c0, x.c1, y.c0, y.c1).
|
||||
// The DST and the vote message follow consensus/core/src/finality.rs and site/verify/core.js.
|
||||
import { bls12_381 } from '@noble/curves/bls12-381';
|
||||
import { expand_message_xmd } from '@noble/curves/abstract/hash-to-curve';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const DST = 'IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_';
|
||||
const CHAIN_ID = 'igneum-devnet-3';
|
||||
const te = new TextEncoder();
|
||||
const hex = b => '0x' + Array.from(b, x => x.toString(16).padStart(2, '0')).join('');
|
||||
const unhex = h => Uint8Array.from(Buffer.from(h.replace(/^0x/, ''), 'hex'));
|
||||
const be = (n, len) => { const out = new Uint8Array(len); let v = BigInt(n); for (let i = len - 1; i >= 0; i--) { out[i] = Number(v & 0xffn); v >>= 8n; } return out; };
|
||||
const fe = n => { const out = new Uint8Array(64); out.set(be(n, 48), 16); return out; };
|
||||
const concat = parts => { const n = parts.reduce((a, p) => a + p.length, 0); const out = new Uint8Array(n); let o = 0; for (const p of parts) { out.set(p, o); o += p.length; } return out; };
|
||||
const u64le = n => { const out = new Uint8Array(8); let v = BigInt(n); for (let i = 0; i < 8; i++) { out[i] = Number(v & 0xffn); v >>= 8n; } return out; };
|
||||
|
||||
const G1 = bls12_381.G1.ProjectivePoint, G2 = bls12_381.G2.ProjectivePoint;
|
||||
function g1Enc(p) { const a = p.toAffine(); return concat([fe(a.x), fe(a.y)]); }
|
||||
function g2Enc(p) { const a = p.toAffine(); return concat([fe(a.x.c0), fe(a.x.c1), fe(a.y.c0), fe(a.y.c1)]); }
|
||||
function voteMessage(index, checkpointHex) { return concat([te.encode('igneum-vote-v1/' + CHAIN_ID), new Uint8Array([0]), u64le(index), unhex(checkpointHex)]); }
|
||||
function bitmapOf(positions, n) { const bm = new Uint8Array(Math.ceil(n / 8)); for (const p of positions) bm[p >> 3] |= 1 << (p & 7); return bm; }
|
||||
|
||||
async function synthetic() {
|
||||
const sks = [1, 2, 3, 4, 5].map(i => { const s = new Uint8Array(32); s[31] = i; s[0] = 0x11 * i; return bls12_381.utils.randomPrivateKey ? bls12_381.G1.normPrivateKeyToScalar(s) : s; });
|
||||
const keys = sks.map(sk => G1.BASE.multiply(sk));
|
||||
const weights = [100, 250, 400, 300, 150];
|
||||
const index = 1234, checkpoint = '0x' + 'ab'.repeat(32);
|
||||
const msg = voteMessage(index, checkpoint);
|
||||
const hm = bls12_381.G2.hashToCurve(msg, { DST });
|
||||
const signers = [0, 1, 2, 3]; // 1,050 of 1,200: above two thirds
|
||||
const weakSigners = [0, 2, 4]; // 650 of 1,200: under two thirds
|
||||
const sign = who => who.map(i => hm.multiply(sks[i])).reduce((a, b) => a.add(b));
|
||||
const sig = sign(signers), weak = sign(weakSigners);
|
||||
// the account trie: three accounts, proofs for one present and one absent
|
||||
const { Trie } = require('@ethereumjs/trie');
|
||||
const { RLP } = require('@ethereumjs/rlp');
|
||||
const { keccak256 } = require('ethereum-cryptography/keccak');
|
||||
const trie = new Trie({ useKeyHashing: true });
|
||||
const accounts = [
|
||||
{ address: '0x07dd4dbca5c1a66755af28bacca1d901a2d209aa', nonce: 7n, balance: 999174011168718479514n, storageRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' },
|
||||
{ address: '0x9a6fa842c4e58a87aef1f3ad15233d99283002b7', nonce: 1n, balance: 0n, storageRoot: '0x' + '11'.repeat(32), codeHash: '0x' + '22'.repeat(32) },
|
||||
{ address: '0x53fe98022c2ac26d5d721457fb1c374b4d56144b', nonce: 3n, balance: 2580n * 10n ** 18n, storageRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' },
|
||||
];
|
||||
for (const a of accounts) {
|
||||
const v = RLP.encode([a.nonce === 0n ? new Uint8Array() : be(a.nonce, Math.ceil(a.nonce.toString(2).length / 8)), a.balance === 0n ? new Uint8Array() : be(a.balance, Math.ceil(a.balance.toString(2).length / 8)), unhex(a.storageRoot), unhex(a.codeHash)]);
|
||||
await trie.put(unhex(a.address), v);
|
||||
}
|
||||
const root = hex(trie.root());
|
||||
const proofFor = async addr => (await trie.createProof(unhex(addr))).map(hex);
|
||||
const absent = '0x000000000000000000000000000000000000dead';
|
||||
return {
|
||||
chain_id: CHAIN_ID, dst: DST, index, checkpoint,
|
||||
keys: keys.map(k => hex(g1Enc(k))), weights, total_weight: weights.reduce((a, b) => a + b, 0),
|
||||
bitmap: hex(bitmapOf(signers, keys.length)), signature: hex(g2Enc(sig)), signed_weight: signers.reduce((a, i) => a + weights[i], 0),
|
||||
weak_bitmap: hex(bitmapOf(weakSigners, keys.length)), weak_signature: hex(g2Enc(weak)),
|
||||
vote_message: hex(msg),
|
||||
// RFC 9380 expand_message_xmd(SHA-256) answers, computed by noble, for the Solidity port's own check
|
||||
xmd_dst: 'QUUX-V01-CS02-with-expander-SHA256-128',
|
||||
xmd_abc_128: hex(expand_message_xmd(te.encode('abc'), te.encode('QUUX-V01-CS02-with-expander-SHA256-128'), 128, sha256)),
|
||||
xmd_empty_32: hex(expand_message_xmd(new Uint8Array(), te.encode('QUUX-V01-CS02-with-expander-SHA256-128'), 32, sha256)),
|
||||
state_root: root,
|
||||
account: accounts[0].address, account_nonce: accounts[0].nonce.toString(), account_balance: accounts[0].balance.toString(),
|
||||
account_storage_root: accounts[0].storageRoot, account_code_hash: accounts[0].codeHash,
|
||||
account_proof: await proofFor(accounts[0].address),
|
||||
absent_account: absent, absent_proof: await proofFor(absent),
|
||||
};
|
||||
}
|
||||
|
||||
function chain(file) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const voters = d.voters.map(v => ({ key: hex(g1Enc(G1.fromHex(v.pubkey_hex.replace(/^0x/, '')))), weight: Math.round(Number(v.weight)) }));
|
||||
const sig = G2.fromHex(d.certificate.aggregate_signature_hex.replace(/^0x/, ''));
|
||||
const positions = []; const bm = unhex(d.certificate.bitmap_hex);
|
||||
for (let p = 0; p < voters.length; p++) if (bm[p >> 3] & (1 << (p & 7))) positions.push(p);
|
||||
return {
|
||||
source: d.source, chain_id: d.chain_id, dst: DST, index: d.index, checkpoint: '0x' + d.hash,
|
||||
keys: voters.map(v => v.key), weights: voters.map(v => v.weight), total_weight: voters.reduce((a, v) => a + v.weight, 0),
|
||||
bitmap: '0x' + d.certificate.bitmap_hex, signature: hex(g2Enc(sig)), signed_weight: positions.reduce((a, p) => a + voters[p].weight, 0),
|
||||
signers: positions.length, voters_at_index: d.voters_at_index, stored_at: d.stored_at,
|
||||
};
|
||||
}
|
||||
|
||||
function table(file) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const r = d.result || d;
|
||||
const voters = r.keys.filter(k => k.voter === true || k.voter === 'True').map(k => ({ keyHash: String(k.keyHash).replace(/^0x/, ''), key: hex(g1Enc(G1.fromHex(String(k.pubkey).replace(/^0x/, '')))), weight: Number(BigInt(k.blocks)) }));
|
||||
voters.sort((a, b) => (a.keyHash < b.keyHash ? -1 : a.keyHash > b.keyHash ? 1 : 0));
|
||||
const total = voters.reduce((a, v) => a + v.weight, 0);
|
||||
return { chain_id: process.env.IGNEUM_CHAIN_ID || CHAIN_ID, dst: DST, index: Number(BigInt(r.checkpointIndex)), checkpoint_at_index: '0x' + String(r.checkpointHash).replace(/^0x/, ''), keys: voters.map(v => v.key), weights: voters.map(v => v.weight), total_weight: total, total_weight_node: Number(BigInt(r.totalWeight)), voters: voters.length };
|
||||
}
|
||||
|
||||
function account(file, stateRoot, blockNumber) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const r = d.result || d;
|
||||
return { chain_id: CHAIN_ID, state_root: stateRoot, block_number: Number(blockNumber), account: r.address, account_nonce: BigInt(r.nonce).toString(), account_balance: BigInt(r.balance).toString(), account_storage_root: r.storageHash, account_code_hash: r.codeHash, account_proof: r.accountProof };
|
||||
}
|
||||
|
||||
const mode = process.argv[2];
|
||||
if (mode === 'synthetic') synthetic().then(v => console.log(JSON.stringify(v, null, 1)));
|
||||
else if (mode === 'chain') console.log(JSON.stringify(chain(process.argv[3]), null, 1));
|
||||
else if (mode === 'table') console.log(JSON.stringify(table(process.argv[3]), null, 1));
|
||||
else if (mode === 'account') console.log(JSON.stringify(account(process.argv[3], process.argv[4], process.argv[5]), null, 1));
|
||||
else { console.error('usage: gen.mjs synthetic | table <weights.json> | account <getProof.json> <stateRoot> <blockNumber> | chain <checkpoint.json>'); process.exit(2); }
|
||||
232
docs/analysis/class-v6/family-gate.md
Normal file
232
docs/analysis/class-v6/family-gate.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
# Class v6, the family gate: how a parameter family is cryptanalysed as a family
|
||||
|
||||
Research lane D of the class v6 rotating-family design, under the Counter ASIC coordinator. First cut 8 October 2026, 11:0x to 17:00 BST (the deliverable clock); the full report by 09:00 BST on 9 October. Branch `class-v6-family-gate` (this document) and the harness branch `family-gate-v5` (the class v5 crate at 8f481459 plus the census harness, never a chain path). Internal research, not an independent review; nothing here touches a served number, the devnet or the testnet object; no consensus code this week. Every figure carries its source: a lane report on the mirror, a log on a box, or an arithmetic step shown in the text. Figures from memory are labelled approximate.
|
||||
|
||||
The question. Class v6 (the founder's word at 11:1x BST, 8 October 2026) draws per era the parameters a release used to fix (layer 1), lets the dataset track the chain state (layer 2), rotates instruction families by height (layer 3) and generalises the acceptance floor and the uniformity test to each era's draw with a redraw on failure (layer 4). A chip is then built against a FAMILY of hashes, not one hash. The in-house pass of 7 October and the attack board F1 to F10 bounded ONE member of the family (class v4 sub-version 3 at 017e7037 and class v5 at 1c420786). This document says how the family is bounded: what the space is, how many eras must be drawn to say anything about the worst era, which tests the chain runs itself on every era and epoch, what the offline board looks like over the testnet period, what a published proof of testing contains, and what the whole apparatus cannot see.
|
||||
|
||||
## 0. One page
|
||||
|
||||
| Item | The line |
|
||||
|---|---|
|
||||
| The space (section 1) | Seven drawn axes with a tested band each: the mixer multiplier `m` in {4, 8, 16} (8 and 4 measured on cards and the verifier; 16 the verifier's open row), the ten non-load op weights within B points of table 1.4.2 with shuffle and mulhi never raised (B = 2 proposed in spec 1.13.1, B = 4 the research lane's proposal), the read width in {1, 4} words (w16 measured 5 October, w64 excluded), the shadow block shape in {64, 128, 256} instructions at 6,912 per iteration (measured 6 October), the shadow placement fixed at the whole block after instruction 63 (the per-load placement is a known-failed corner: 1.4 percent acceptance, 42 of 64 seeds exhausting 32 attempts), the program length N by the ladder's signal inside rungs 0 to 2 (rung 3 inadmissible by F6), and the existing era draws (the stride `M`, the rotation `R` in 1..31, the interleave, the per-site windows). The day key (ROT, MUL, RC) is drawn daily under the AP-F4-1 redraw rule |
|
||||
| Which tests depend on which axis (section 1.3) | The acceptance rule and every index statistic ((c''), (c'''), the bucket bound, the bit-bias read, the attempts census) run on the closed-form dataset and never see `m`: the mixer axis is bounded per family by adv-mixer-3's rows and F4, not per era. The width axis changes the index space of every site ((c'')'s expectation `E_s` must divide the window by the width, a spec change the harness carries). The shape and weight axes change the draw's stream and so every per-era statistic |
|
||||
| The sampling bound (section 2) | With `n` eras drawn from the chain's own distribution and every one passing a per-era test, the fraction of eras that would fail it is under `3/n` at 95 percent confidence (the rule of three; Wilks 1941 for the order-statistic form): 190 eras bound the failing fraction at 1 in 64 (one era in 32 years of 180-day eras), 3,067 at 2^-10. The bound is on the TESTED property only; the union bound over the per-era tests' own false-pass rates gives the family's false-pass rate, and each test's false-pass rate is itself a rule-of-three number on its known-failed cases (the (c''') floor refused 9 of 9 live hot sets, so its miss rate on that class is under 0.33 at 95 percent: nine cases bound nothing tighter) |
|
||||
| The per-era tests (section 3) | Three rings. Ring A, the chain runs per era at the cut, microseconds: the structural redraw rules (the band membership of every draw, the day-key cost rule, the product-bias rotation class recorded). Ring B, the chain runs per epoch, seconds: the acceptance rule generalised to the family's shape ((a) (b) (a') (c) (c') (c'') (c''') plus the two next-class tests, the per-site largest-256-item-bucket bound and the index-bit bias read, on the same 2^20 pass). Ring C, the gate runs offline per drawn era, box-hours: the F8-form census at 2^24 on 64 seeds, the attempts census, the exhaustion count. Each row carries its known-failed shape and its clean-seed cost so the redraw is priced |
|
||||
| The board (section 4) | F1 to F10 and the nine lanes classified per-era, per-family or chain-run, with the harness taking the era draw as an input; the proof of testing is one JSON record per drawn era (the draw, the object, the binary, the seeds, every verdict with its statistic, threshold and log sha256, the core-seconds) and one family summary (eras per stratum, the worst era per test, the refuse rate per band, the bound's arithmetic) |
|
||||
| The honest line (section 5) | The gate sees what its tests see. It does not see the diffuse era-stride class below the bit-bias read's resolution (a bias under 0.3 percent at 2^20), a mechanism that lives in a joint corner no stratum names, a mixer weakness below adv-mixer-3's bands, or an era whose draw sits in the untested 1 in 64. A GPU-like chip loses nothing on any era; what a corner buys it is a per-era hot set bounded at 1.002x (the floor) or 1.0024x (the diffuse class), or, at `m = 4`, a mixer with 2 applications of measured margin instead of 6 |
|
||||
| Running now (section 6) | The harness `family_gate_era_census` on build-1 from 11:16 BST: one drawn era per seed, every family parameter from the era's own stream, the chain draw through the real rule keyed on the family's shape, one TSV row per era with the (c'') ratio, the bucket ratio, the bit bias and the attempts; the base control (`v5_attempts_census`, the shipped draw) beside it. The coverage table in section 6 is filled from the logs at 16:xx BST |
|
||||
|
||||
## 1. The parameter space
|
||||
|
||||
### 1.1 The axes, their bands and the margin each band was read from
|
||||
|
||||
| Axis | Band proposed for the draw | What fixed the band (the measured rows) | The tested margin inside the band | Known-failed corner, named |
|
||||
|---|---|---|---|---|
|
||||
| Mixer multiplier `m` (applications per round, `LoadClass::mixer_mult`; 72 per item at `m = 8`, 8 between dependent reads) | {4, 8, 16}; the research lane's outline; this lane's reading: {8} plus {4} as a corner, {16} only after the verifier row | x4 and x8 measured (`docs/plans/mixer-x4.md` section 6.4: 1.92 and 2.79 ms per unit on a loaded M5 Max core; the daily build 42 ms at x8 on the 5090, measured); x16 estimated at about 3.7 ms per unit on the M5 Max core and 9 ms on a 2019-class core (chip-model-v3 section 3 item 1), against the 10 ms verifier gate | adv-mixer-3 (`report-mixer-3.md`, "The round margin, stated"): no statistic survives 2 of the 8 keyed applications between reads at bands 0.0015 (Q2, 2^24 states), 0.00026 (2^27), 0.00018 (Q2b, 2^28); SAT solved at k = 1 in 137 s and timed out at k = 2, 3, 4; two real days and eight random days agree. So at `m = 8` 6 of 8 applications are margin; at `m = 4` the same rows leave 2 of 4; at `m = 16` 14 of 16 | None measured. The corner is `m = 4` by margin and `m = 16` by the verifier; the all-ROT-equal day key is the day-level corner (rejected by the AP-F4-1 rule) |
|
||||
| Op-mix weights (the ten non-load families, sum 75) | Each weight within B points of table 1.4.2 (add 12, xor 10, mul 8, mad 8, shfl 8, rotl 7, sub 6, mulhi 6, rotr 6, or 4), renormalised by largest remainder; shfl and mulhi never raised; B = 2 (spec 1.13.1, proposed) or B = 4 (the research lane) | The microbench (`counter-asic-4-research.md` 15.1a, the 5090 alone, 8 October): pJ per counted op at the stock clock and the 1,300 MHz lock: arx 11.3 / 6.2, mul 13.9 / 8.3, mulhi 39.6 / 21.0, prmt 22.3 / 11.5, lop3 24.1 / 13.0, shfl 55.8 / 29.4; the shuffle is 4.9x the add, so a draw that raises shfl raises the card's premium per instruction with no better `k` for a chip (15.1b). F7's era census: the op-weight corners (15 to 31 of 75) read 1.0x against the GPU, 0 memory effect | The acceptance's rejection rate moves with the lossy share: at the table 0.68 per candidate ((a') 83.5 percent of rejections; adv-accept row 90, 20,000 seeds); the F7 census at B = 2 read every corner clean for the chip; nothing was measured at B = 4 before today (section 6) | The lossy corner: or, mul and mulhi all at +B. It raises (a') rejections and so the attempts per seed; the exhaustion bound `r^256` is the number to read there (section 3, ring C) |
|
||||
| Read width `W` (words per load) | {1, 4} | `docs/plans/read-width.md` (5 October): w16 within the rules (5090 139.8 against 136.1 MH/s, 9070 XT 17.90 against 18.15, M5 Max within 1 percent); w64 bandwidth-bound (5090 share 0.58, 71.9 MH/s): out; the per-load mixes out on the 5 percent spread rule | The acceptance runs unchanged on aligned addresses (read-width.md section 2), but (c'') and (c''') read a site's distinct ALIGNED indices against `E_s = N - N^2 / 2W_s`: at `W = 4` the index space is `W_s / 4`, so the expectation must follow or every width-4 program reads 0.976 at a quarter window and is refused by the 0.98 floor. The harness divides the window by the width (`site_window_words`); the spec line is owed | `W = 16` (w64): excluded by measurement, never in the band |
|
||||
| Shadow block shape (instructions per block, passes per iteration) | {64 x 108, 128 x 54, 256 x 27}: 6,912 shadow instructions per iteration at rung 0 | 64-instruction blocks ran 2.5 to 3.5 percent faster than 256 on the 5090 and the M5 Max (6 October, measured); 1,024 cost the M5 Max 17 percent (out) | F1's shadow redundancy bound (3.0 percent of peephole-removable instructions, the v5 generator's `SHADOW_REMOVABLE_MAX_PERMILLE`) was set from F1's census at 256 instructions; the removable fraction per block is a property of the block's length, so the fraction must be re-read at 64 and 128 (a per-family row). The acceptance's (a') fixpoint and the shadow's execution in (c) take any length | The per-load placement (16 sub-blocks of 16 after each load): dead as a chain class (`counter-asic-4-research.md` 20.2a-close): 22 of 1,621 candidates accepted, 42 of 64 seeds exhaust 32 attempts, candidate 0 carries index bit 0 set in 40 of 1,024 addresses at site 0 (z 29.5). The placement axis therefore has ONE value in the band |
|
||||
| Program length `N` (counted ops per hash) | Not drawn: the ladder's signal (rungs 0 to 2); the research lane's outline keeps it so | F6: the worst of 10^5 class v4 programs 8.708 ms on the half-core proxy, so N about 300,000 fits under 10 ms (rung 2 admissible, rung 3 not); the M5 Max loses 3.3 to 10 points across the band (measured ladder) | The verifier's worst case was censused at rung 0 only; a draw inside the ladder needs the 10^5-program worst case at the top rung (per-family row) | Rung 3 (inadmissible by F6) |
|
||||
| Era stride and interleave (`M` odd, `R` in 1..31, `pos` four ascending bit positions, the fold rotations, the per-site windows `k_off`, `o`) | As spec 1.13.1 draws them today | F7's 2^24 era census (stride bijective, R, pos, M uniform, no class over 1.1x); adv-cache-2 section 2.3: the same 32 base programs read 2 of 32 with a site over 1.04x under `R = 29` and 16 of 32 under drawn eras (8 over 1.2x, worst 1.75x), because `rotl(x * M, R)` places a product's biased low bits (P(bit 0) = 1/4) at address bits R and up, inside the 28-bit index unless R is 29 or 30; at D = 29 only R = 30 and 31 cut bit 0 | The whole 64-seed F8 census is a census over drawn eras (each f8 seed carries its own era), so the per-era uniformity verdicts of sub-version 3 and class v5 (60 of 64 and 61 of 64 under 1.2x) already sample this axis; the devnet's clean reading at R = 29 is the accident, the drawn-era figure the chain's | R in 1..27 with a product as the last writer of a load's source (sub-class A); the warp-uniform mulhi source (sub-class B, 1 in 16,000 warps) |
|
||||
| Dataset size `D` (layer 2) | 2^28 words today, 2^29 at the 2 GiB genesis step, growing on the 1.13.3 schedule with the state as a floor | The acceptance's closed form is pinned at D = 28 (`ACCEPT_DATASET_LOG2`); the live dataset is larger; the stand-in gap measured at 0.0004 under D = 28 (adv-accept Q2, 54 programs) | Unmeasured at D = 29: which R values hide the product bits changes with D, and the window cap `min(k_off, D - 26)` changes the per-site windows | D at a value where the acceptance's D = 28 windows and the live windows disagree: the stand-in gap row of ring C |
|
||||
| Day key (ROT x 8, MUL x 16, RC x 16, drawn daily from the day seed) | As spec 1.8.4, under the AP-F4-1 redraw rule in class v5 (cost A at most 205 rejected, k >= 1, the eight ROT equal rejected) | F4 and adv-mixer-2: 0 of 2^24 days over 1.1x on both metrics with the rule (8ca66afa); 5.69e-4 of days over 1.1x on LUT area without it, 15 days a century, worst 28 April 2050 at 1.113x | The rule is per day and chain-run; it does not depend on `m` (the cost is per application) | Day 29,337 (redrawn under the rule); the planted mul1all and mulnaf days fire |
|
||||
|
||||
### 1.2 The joint space and what a draw covers
|
||||
|
||||
Counting the discrete axes alone: 3 (m) x 2 (W) x 3 (shape) x the weight perturbations ((2B + 1)^10 before the caps: about 9.8 million at B = 2, 3.5 billion at B = 4) x 31 (R) x 2^31 (M) x 1,820 (pos) x 31^6 (the fold rotations). The space is of order 2^80 before the per-site windows, which are per program. No census walks it. What a census can do is (i) draw eras from the chain's own distribution (the era stream over random `E_n`) and bound the fraction of eras that fail a test (section 2.1), and (ii) pin the axes that carry a KNOWN mechanism at their corner and draw the rest (section 2.3), so a mechanism that depends on one named axis is read at its worst value. A mechanism that depends on a joint corner nobody named is in the honest line (section 5).
|
||||
|
||||
### 1.3 Which tests see which axis
|
||||
|
||||
| Test | `m` | weights | `W` | shape | N | era stride, windows | D | day key |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| The acceptance rule and the index statistics ((c''), (c'''), bucket, bit bias), on the closed form | no (the mixer never runs) | yes (the stream) | yes (the index space) | yes (the stream, the shadow's execution) | yes (the shadow's passes) | yes (`load_index`) | no (D = 28 pinned) | no |
|
||||
| The attempts census and the exhaustion bound | no | yes | yes | yes | yes | yes | no | no |
|
||||
| The F8-form census at 2^24 on the live dataset | yes (the item words) | yes | yes | yes | yes | yes | yes | yes |
|
||||
| adv-mixer-3's distinguisher rows, F2, F4, adv-mixer-2 | yes | no | no | no | no | no | no | yes |
|
||||
| F6 verifier worst case | yes | yes | yes | yes | yes | no | yes (the fill) | no |
|
||||
| F1 shadow redundancy | no | yes | no | yes | yes | no | no | no |
|
||||
| F3, adv-cache, adv-cache-3 (the chained cache) | no (the cache fill is ChaCha12) | no | no | no | no | no | yes (the cache doublings) | yes |
|
||||
| F7 era census | no | yes (the perturbation) | yes | no | no | yes | no | no |
|
||||
| F5 chip model, F10 ladder | the band's top | the band's dearest mix | yes | no | the ladder | no | yes | no |
|
||||
|
||||
Reading: the per-era statistical tests are blind to `m` by construction, so the mixer is a per-FAMILY axis with three values and is closed by re-running adv-mixer-3's ladder and F4 at `m = 4` and `m = 16` (section 4), not by drawing eras. The weights, the width and the shape are per-era axes and are what the drawn-era census of section 6 walks.
|
||||
|
||||
## 2. The sampling bound
|
||||
|
||||
### 2.1 Zero failures in `n` eras (the rule of three, Wilks)
|
||||
|
||||
Let a per-era test have a fixed verdict per era and let `p` be the fraction of the family's eras (under the chain's own draw) that fail it. If `n` eras drawn independently from that draw all pass, then with confidence `1 - alpha`, `p <= eps` where `(1 - eps)^n = alpha`, that is `n >= ln(alpha) / ln(1 - eps)`, about `3 / eps` at 95 percent and `4.6 / eps` at 99 percent (Hanley and Lippman-Hand 1983; Wilks 1941 gives the same arithmetic as the one-sided nonparametric tolerance limit on the worst order statistic). The table, with the era length of layer 3 (180 days) turned into years:
|
||||
|
||||
| `eps` (the failing fraction bounded) | One failing era expected every | `n` at 95 percent | `n` at 99 percent |
|
||||
|---|---|---|---|
|
||||
| 1/16 | 8 years | 45 | 70 |
|
||||
| 1/64 | 32 years | 190 | 293 |
|
||||
| 1/256 | 126 years | 766 | 1,177 |
|
||||
| 2^-10 | 505 years | 3,067 | 4,713 |
|
||||
| 2^-20 | the F4 and F7 gate's fraction | 3.1 million | 4.8 million |
|
||||
|
||||
What this buys and does not. The F4 and F7 gates ask "no class with gain over 1.1x at a fraction over 2^-20" and reach it by censusing 2^24 draws of a CHEAP statistic (microseconds per day key or era seed). A per-era test that costs box-hours (the F8 census at 2^24) can be run on hundreds of eras, so it bounds the failing fraction at the 1/64 to 1/256 class, never 2^-20. That is why layer 4 puts the tests on the chain: a per-era test the chain runs on EVERY era (ring A) or every epoch (ring B) needs no sampling bound at all; the offline census (ring C) is then a check on the chain-run tests' calibration (their clean refuse rate and their known-failed firing per stratum), and a reading of the one statistic the chain cannot afford, the live-dataset census.
|
||||
|
||||
### 2.2 The union bound over the per-era tests
|
||||
|
||||
Let the chain run tests `T_1 .. T_k` on every era or epoch, and let `delta_i` be the probability that `T_i` passes an era (or program) that carries the failure class `T_i` exists for. The family's false-pass rate on the union of those classes is at most `sum delta_i`. Each `delta_i` is itself bounded by the rule of three on the test's known-failed cases: a test that fired on `f` of `f` known-failed cases has `delta_i <= 3 / f` at 95 percent. The numbers today:
|
||||
|
||||
| Test | Known-failed cases it fired on | `delta` at 95 percent | Source |
|
||||
|---|---|---|---|
|
||||
| (c''') floor at 0.995 on the few-item hot-set class | 9 of 9 live hot sets refused (minimum sites 0.9809 to 0.9919), both single-item programs refused | under 0.33 | adv-accept, "the floor's final tally", 01:13 BST 8 October; class-v5 section 14 |
|
||||
| (c'') floor at 0.98 on the low-entropy band | 5 of 5 (p23, p18, p19, p15, p56) | under 0.60 | attack-pass-2026-10.md, sub-version 3 |
|
||||
| (a') freshness on the lineage-visible constant class | 11 of 11 (sub-version 1's eleven seeds under 1.2x on sub-version 3) | under 0.27 | attack-pass-2026-10.md, the sub-version 1 table |
|
||||
| The bucket bound (in sigma of the bucket's expectation at 2^20) on the quarter-bit class | 4 of 4 would be caught (p4, p8, p10, p34: largest bucket 3.1x to 5.6x at narrow windows, +17 to +37 sigma), not yet wired as a rule | under 0.75 once wired; the clean spread is measured in section 6 | the hash lane's attribution, 09:46 BST 8 October |
|
||||
| The index-bit bias read on the product class | 3 of 3 named sites (Devnet 3 site 0 at P(bit 0) = 0.25; era-drawn-28 site 15 at 0.778; the per-load candidate 0 at z 29.5), and 7 of 7 in the 16-era smoke run at 130 to 511 sigma | under 0.30 on ten cases; but the read is a record, not a refusal (section 3.2) | adv-cache-2 2.3; counter-asic-4-research.md 20.2a; section 6 |
|
||||
| The day-key cost rule | the planted mul1all and mulnaf days, day 29,337 | 0 of 2^24 days over 1.1x after the rule (a census, not a case count) | f4-weakday.md, 8ca66afa |
|
||||
|
||||
Reading: the per-test miss rates are bounded by HANDFULS of known cases, so the union bound today is a loose number (the sum exceeds 1). The way to tighten it is not more eras but more known-failed cases per test, which the adversarial sweeps supply cheaply: adv-accept's tail holds 22 programs beyond the 1.2x gate of 37 measured live, and the drawn-era census of adv-cache-2 holds 19 biased sites of 1,056. A test with 60 fired cases has `delta` under 0.05; with 300, under 0.01. The proof of testing (section 4.3) therefore carries, per test, the count of known-failed cases it fired on, and that count is the number a reader checks first.
|
||||
|
||||
### 2.3 Stratified draws over the corners
|
||||
|
||||
The axes with a known mechanism and their corner values: `m` in {4, 16} (margin, verifier), weights at the lossy cap (or, mul, mulhi at +B) and at the table, `W` in {1, 4}, shape in {64, 256}, R in {1..27} against {28..31} (the product-bias class visible or hidden; at D = 29 the hidden set is {30, 31}), the windows forced to quarter (`k_off = 2` at every site, the F8 tail class), D in {28, 29}. That is 2 x 2 x 2 x 2 x 2 x 2 x 2 = 128 corner cells for the per-era statistics (the mixer cells are per-family rows), plus the random stratum (every axis drawn). The plan: at least 8 eras per cell for the cheap ring-B statistics (1,024 eras, about 2 core-hours each at the (c''') cost, 2,000 core-hours, 64 box-hours of 32-core slots) and the random stratum at 3,000 eras (the 2^-10 line of 2.1 at 95 percent for the ring-B tests, 6,000 core-hours, 190 box-hours); the live-dataset census at 2^24 on 64 seeds for 24 corner representatives and 64 random eras (88 eras at 45 to 95 core-hours each, about 6,000 core-hours, 190 box-hours). About 450 box-hours in all, 2 to 3 days of both boxes at the 88-core pool, inside the testnet period by a wide margin. Section 6 records what has run.
|
||||
|
||||
## 3. The per-era automatic tests (layer 4)
|
||||
|
||||
The three rings. A test's ring says who runs it and what a failure costs.
|
||||
|
||||
| Ring | Who runs it, when | Cost per run | What a failure does |
|
||||
|---|---|---|---|
|
||||
| A: structural, per era | every node at the era cut, on the drawn parameters | microseconds | the era stream's next block of draws is consumed (a redraw), up to a cap, then the base table (the class v4 values) as the last resort, so the draw is total and no consensus path panics (the AP-F8-2 shape) |
|
||||
| B: the acceptance, per epoch | every node at the epoch draw, on each candidate | about 2.2 s per chosen candidate on one box core at 2^20 (the (c'') pass), plus 0.3 s for the 64-unit parts; the two next-class tests ride the same 2^20 pass | the next attempt, as today; the cap 256 and the last resort unchanged |
|
||||
| C: offline, per drawn era | the family gate on the boxes, before the testnet and through it | box-hours | a finding against the family's band (a band narrowed, a rule added), never a chain event |
|
||||
|
||||
### 3.1 Ring A: the structural rules the chain runs per era
|
||||
|
||||
| Rule | Draw it reads | Known-failed shape | Clean refuse rate | Source |
|
||||
|---|---|---|---|---|
|
||||
| Band membership: `m` in the band, `W` in the allowed set, the shape in the set, every weight within B of the table with shfl and mulhi at or under their base, the sum 75 | the layer-1 draws | a draw outside the band (a unit test) | 0 by construction (the draw is bounded) | spec 1.13.1's form |
|
||||
| The day-key cost rule (AP-F4-1, class v5) | ROT, MUL | mul1all, mulnaf, day 29,337 | 6.1e-4 per day | f4-weakday.md 6.7 to 8; 8ca66afa |
|
||||
| The rotation class recorded: whether R leaves a product's low bits inside the index at the era's D | R, D | none (a record, not a refusal: restricting R to {29, 30} would cut the interleave's entropy from 31 to 2 values; the value-level test of ring B is the catch) | 0 | adv-cache-2 2.3 |
|
||||
| The weights' lossy share bound: or + mul + mulhi at most the table's 18 plus B, so the exhaustion bound `r^256` stays under 1e-18 (r under 0.85) | weights | the lossy corner of section 6 if its `r` reads over 0.85 | 0 by construction | row 90 (r = 0.681 at the table) and section 6 |
|
||||
|
||||
### 3.2 Ring B: the acceptance rule generalised to the family, per epoch
|
||||
|
||||
| Part | Generalisation | Known-failed shape (fires today) | Clean refuse rate (the cost) | Per-candidate cost |
|
||||
|---|---|---|---|---|
|
||||
| (a) (b) | unchanged | the class v2 census vectors (22, 37, 51) | 11.6 and 3.0 percent of rejections | microseconds |
|
||||
| (a') the freshness fixpoint over base then shadow | keyed on the family's shape (`is_family_shape`: shadow in {64, 128, 256} at 6,912 per iteration, `m` in {4, 8, 16}, the mix one-hot on the drawn width) in place of the one class v4 shape, in the draw's source rule and the acceptance alike | sub-version 1's eleven seeds | 83.5 percent of rejections (57.5 percent of candidates) | microseconds |
|
||||
| (c) the dynamic test with the shadow executed | the interpreter already runs any block length, any pass count and any width (the fold) | p23 at attempt 1 (the shared-operand idiom) | 0.9 percent | about 3 ms (64 units) |
|
||||
| (c') saturated sources | unchanged | the forced-saturation plant | 0.05 percent | in (c) |
|
||||
| (c'') the distinct-index ratio at 0.98 | `E_s = N - N^2 / (2 W_s / W)`: the window divided by the width | p15, p18, p19, p56 | 1.1 percent | 2.2 s at 2^20 |
|
||||
| (c''') the hot-item floor at 0.995 | the same `E_s`; the floor's clean spread re-read per stratum (section 6): a fixed 0.995 under a spread that moves with the shape or the width is either a liveness cost or a miss | seed 100767 (0.9919) and the nine live hot sets | 2.435 percent of accepted class v4 programs, +0.045 on the mean attempt | in the (c'') pass |
|
||||
| The per-site largest-256-item-bucket bound (NEW, the F8 tail's catch) | the largest count over a site's 4,096-word buckets in its window against `N / (W_s / 4096)`, in SIGMA of the bucket's expectation (`(max - E) / sqrt(E)`), refused above a band set from the clean spread. The ratio alone cannot carry the bound: a clean full-window site's largest of 65,536 Poisson(16) buckets reads 2.1x at +4.4 sigma, a quarter-window site's largest of 16,384 Poisson(64) buckets 1.5x at +4 sigma (the 16-era smoke run read ratios 2.2 to 2.4 on clean sites); the four tail seeds' 3.1x to 5.6x at narrow windows are +17 to +37 sigma | p4, p8, p10, p34 | measured in section 6 (the columns `bucket_z_max`, `bucket_win`) | one linear pass over the (c'') indices |
|
||||
| The index-bit bias read (NEW, adv-cache-2's value-level test) | per site, the one-count of each free index bit (bits above the width's alignment and below the window's cut) over the 2^20 evaluations, in sigma (`sigma = sqrt(N) / 2 = 512`); a 6-sigma band is a bias of 0.3 percent at 2^20 (the product law's bit 0 at 25 percent reads z about 512, bit 1 at 3/8 z 256, bit 3 at 3.1 percent z 64, bit 6 at 0.4 percent z 8, bit 7 at 0.2 percent z 4: passes). MEASURED on the first 16 drawn eras (11:21 BST, section 6): 7 of 16 accepted programs carry one site with a bias of 130 to 511 sigma at address bit R or R + 1 (the era's rotation), the era-stride class exactly, on programs (c''') passes at 0.9954 to 1.0000; the 9 others read under 3.8 sigma. So as a REFUSAL the read would redraw about 40 percent of epochs; its right use is as a record per era plus the structural lever (fold the product's low bits in `load_index` before the rotation, a next-class item), and the chip price is stated in section 5 | Devnet 3 site 0, era-drawn-28 site 15, the per-load candidate 0; and now the 7 of 16 | 7 of 16 at 6 sigma (a refusal is not the form); 0 of 16 at a 600-sigma band | one pass over the indices, 28 bit tests each |
|
||||
| The cap and the last resort | unchanged at 256; the last resort's own verdict is adv-accept-3's finding 1 (9 percent of last-resort programs fail (a)); the family keeps the open fix (continue past 256 until one passes) | the reject-everything mirror | 0 reached in 1.02 x 10^6 seeds | n/a |
|
||||
|
||||
### 3.3 Ring C: the offline tests per drawn era
|
||||
|
||||
| Test | What it reads | Known-failed shape | Clean cost per era | Sample needed for its own verdict |
|
||||
|---|---|---|---|---|
|
||||
| The attempts census (row 90's form) | every candidate of each seed's chain draw through the real rule; `r` per candidate, the parts' shares, the attempt histogram, `P(exhaust) = r^256`, 0 at the cap | the forced-exhaust plant (hits the cap, prints the last resort); the per-load class (r about 0.98) | 1,000 seeds: 202 s on 23 threads at the table (1.3 core-hours); about 5 core-seconds per accepted program with (c''') | 1,000 seeds per stratum reads `r` to 0.01 |
|
||||
| The F8-form uniformity census at 2^24 on the live dataset | the item histogram against the window model (the program's own 16 draws under the era's windows at the era's D), the top 0.1 percent within 1.2x, the hot-set test `X_f >= f`, the 6-sigma largest bucket, the per-site attribution | quarter-lines, half-lines, const-item (the plants); p31 (29.27x), p23 (4.82x) | 42 to 95 core-minutes per seed at 2^24 (the two halves of 32 on build-2 took 41 to 46 minutes at 30 to 32 cores; the 64 seeds of sub-version 3 took 69 minutes of the box); 64 seeds about 45 to 100 core-hours | 64 seeds per era bound the fraction of epochs over 1.2x at 3/64 (4.7 percent) at 95 percent: a calibration of ring B, not a hot-set hunt (adv-accept's sweep found 9 hot sets in 796,042 draws, 1e-5, every one refused by the floor) |
|
||||
| The stand-in gap at the era's D | the (c'') and bucket statistics on the closed form at D = 28 against the live dataset at the era's D on the same programs | none yet (the gap read 0.0004 at D = 28; a D where the windows disagree is the plant to build) | one 2^24 run per program, about 1 core-hour; 54 programs per era class | per D value, not per era |
|
||||
| The exhaustion count at scale | 10^4 to 10^5 chain-shaped seeds per stratum | the per-load class | 1.45 s per seed (F9's chain path): 4 core-hours per 10^4 | 10^5 per lossy corner reads the past-31 tail |
|
||||
|
||||
## 4. The board over the testnet period
|
||||
|
||||
### 4.1 F1 to F10 and the nine lanes, classified
|
||||
|
||||
| Row | Harness input | Class | Per what | Cost per run | Note |
|
||||
|---|---|---|---|---|---|
|
||||
| F1 shadow redundancy | the shape (block length, passes) | per family | each of the three shapes | 10^4 programs at 5 core-seconds each (the (c''') draw): 14 core-hours; 10^5: 140 | the 3.0 percent `SHADOW_REMOVABLE_MAX_PERMILLE` re-read per shape |
|
||||
| F2, adv-mixer, adv-mixer-3 (the round margin) | `m`, the day | per family | `m` in {4, 16} on 10 days each | index census 2^32 t about 7 core-hours per k per day; sac at 2^24 similar; SAT 1 core-hour per k | at `m = 4` the gate "no distinguisher beyond 2 of m" leaves 2 of 4 |
|
||||
| F3, adv-cache, adv-cache-3 (the chained cache) | the cache log2 (layer 2's doublings) | per family | each cache size step | minutes (the closure search), the curve by arithmetic | the fill is not drawn |
|
||||
| F4, adv-mixer-2 (the weak day) | `m`, the day key | per family and chain-run per day | 2^24 days per `m` | 379 s on 12 cores (1.3 core-hours) | the rule is chain-run; the census is its calibration |
|
||||
| F5 chip model | the band's top (`m = 16`, the dearest mix, `W = 4`, rung 2) | per family | once per band | minutes | the premium row per corner |
|
||||
| F6 verifier worst case | `m`, shape, `W`, N, the fill at D | per family | the top corner (`m = 16`, rung 2, `W = 4`) | 10^5 programs timed on the half-core proxy: about 100 core-hours | the x16 row decides whether 16 enters the band |
|
||||
| F7 era census | the era draw with the layer-1 draws added | per family | 2^24 era seeds | minutes | stride bijective, R, pos, M, the weights' corners uniform |
|
||||
| F8 uniformity | the era (every axis) | per era (ring C) and chain-run per epoch (ring B) | 64 seeds per drawn era | 45 to 100 core-hours | section 3.3 |
|
||||
| F9 acceptance edges, grinding, exhaustion | the era | per era (the exhaustion count) and per family (the 5090 grinding row) | 10^4 seeds per stratum | 4 core-hours | the GPU row once per band |
|
||||
| F10 ladder monotonicity | N | per family | once | the fast-time harness, minutes | unchanged by the draws |
|
||||
| adv-cache-2 (hot set, era stride) | the era | per era | 32 drawn programs at 2^23 | 0.7 core-hours per program | the value-level read is ring B now |
|
||||
| adv-accept, adv-accept-2, adv-accept-3 | the era | per era (the sweep and the attempts census) and per family (the A6000 header row) | as the attempts census | as above | the last-resort fix is the family's |
|
||||
|
||||
### 4.2 The testnet period as the window
|
||||
|
||||
Before the first miner: the per-family rows at the corners (F1 at three shapes, the mixer ladder at `m = 4` and 16, F4 per `m`, F6 at the top corner, F7 with the new draws), and the ring-C census on the corner cells and the random stratum of section 2.3. Through the period: every era the chain actually draws is a drawn era of the census (the chain's own eras are the best sample, the one the rule of three speaks about), so the F8-form census at 2^24 runs on each live era within its first day, and the attempts census on each; a live era that fails ring C is a finding against the band, filed and priced, never a chain event (the chain's ring-A and ring-B tests already passed it). The board's verdict at the end of the period: the count of live eras drawn and passed, the corner cells drawn and passed, the worst reading per test, the refuse rate per stratum, and the bound's arithmetic from those counts.
|
||||
|
||||
### 4.3 The proof of testing (the published format)
|
||||
|
||||
One JSON record per drawn era, in `docs/analysis/class-v6/gate-records/<family-id>/<stratum>/<era-label>.json`, the shape of `docs/plans/counter-asic-3-gate/*.json`:
|
||||
|
||||
```
|
||||
{ "family": { "id": "<sha256 of the genesis band table>", "spec": "docs/spec/01-lottery-hash.md@<commit>", "object": "igneum-pow@<commit>" },
|
||||
"era": { "label": "igneum-family-gate/era/<k>", "stratum": "random | lossy-cap | w4 | shape64 | ...",
|
||||
"draw": { "m": 8, "weights": [12,10,8,8,8,7,6,6,6,4], "width_words": 1, "shape": [256, 27], "R": 17, "M": "0x9ad30d99", "pos": [0,2,12,13] } },
|
||||
"harness": { "binary": "<sha256 of the pinned copy>", "box": "igneum-build-1", "lease": "<the lease line>", "started": "<UTC>", "ended": "<UTC>", "core_seconds": 7210 },
|
||||
"tests": [ { "name": "attempts-census", "seeds": "igneum-family-gate/program/<k>/epoch/0..999", "r": 0.681, "parts": {"a_prime": 0.835, ...}, "max_attempt": 28, "exhausted": 0, "verdict": "PASS", "log": "<path>", "log_sha256": "<hex>" },
|
||||
{ "name": "c3-floor", "floor": 0.995, "min_ratio": 0.9962, "min_site": 6, "verdict": "PASS", ... },
|
||||
{ "name": "bucket-bound", "bound": 2.0, "max_ratio": 1.31, "verdict": "PASS", ... },
|
||||
{ "name": "bit-bias", "band_sigma": 6, "max_z": 2.4, "verdict": "PASS", ... },
|
||||
{ "name": "f8-census-2e24", "seeds": 64, "over_1.2x": 2, "worst": 1.38, "hot_sets": 0, "verdict": "PASS", "known_failed_fired": ["quarter-lines", "const-item"], ... } ],
|
||||
"label": "internal research, not an independent review" }
|
||||
```
|
||||
|
||||
And one family summary per board cut, `docs/analysis/class-v6/gate-records/<family-id>/summary.md`: eras drawn per stratum; per test the count passed, the worst reading, the refuse rate, the known-failed cases fired (the count that bounds `delta`); the rule-of-three line per test (`3 / n` at 95 percent); the union bound's sum; the box-hours; the list of corner cells not reached. A reader checks the record by re-running one era from its label with the pinned binary; every number in the summary is a count over the records.
|
||||
|
||||
## 5. The honest line
|
||||
|
||||
What the family gate cannot see, and how a chip would use it.
|
||||
|
||||
| Blind spot | Why the gate misses it | What a chip gets from it | Bound today |
|
||||
|---|---|---|---|
|
||||
| The era-stride class, measured today at the bit level on 7 of 16 drawn eras (section 3.2): not diffuse, a 25 percent bias on ONE address bit (bit R, the product's bit 0 through `rotl(x * M, R)`) at one site, on programs every floor passes | the (c''') floor reads distinct counts, which a one-bit bias barely moves (0.9954 to 1.0000 on the seven); the bit read sees it at 130 to 511 sigma but refusing it would redraw about 40 percent of epochs; the class is structural (`load_index`'s form and the weights' products), so the catch is a next-class change to the address form, not a per-era floor | a store holding the favoured half of that site's window (128 MiB at D = 28) serves 75 percent of that site's reads instead of 50: 25 percent of 1/16 of a hash's reads, about 1.6 percent of reads at f = 1/2 from one site in about 40 percent of eras (arithmetic on the measured bias); the honest partial-store curve already costs 1.26x the ops at f = 1/2 (adv-cache-2 Q4), so the f = 1 verdict stands; the top-0.1-percent reading of the ledger (1.0024x) was the same class seen through the coarser instrument | the per-era record (ring A names the rotation class; ring B logs the bit read); the structural fix is the family's first owed item for the research lane |
|
||||
| A joint corner no stratum names | the 128 cells pin the axes with a KNOWN mechanism; a mechanism that needs, say, a particular `M` with a particular weight table and a particular shape is reached only by the random stratum, which bounds its fraction at 3/n | one era (180 days) of whatever the corner is worth, at most once per occurrence | 1/64 to 1/256 of eras untested at 95 percent (section 2.1); the chain-run rings catch the known shapes on every era |
|
||||
| The mixer below adv-mixer-3's bands | biases under 0.00018 (Q2b), correlations under 0.00073 with multi-bit masks, differentials under 2^-19, any structure a SAT model of 2 or more applications would expose; at `m = 4` the measured margin is 2 applications | a shortcut that saves applications against the 9,360 ops per item; none found at any k | the round margin, stated; `m = 4` is the corner that spends 4 of the 6 measured spare applications |
|
||||
| The verifier at `m = 16` and rung 2 on a 2019-class core | unmeasured (an estimate of 9 ms against the 10 ms gate) | nothing for a chip; a node tier retired if the corner is drawn | the row is owed before 16 enters the band |
|
||||
| The acceptance's stand-in at D = 28 against a live D = 29 | the windows cap `min(k_off, D - 26)` and the rotation's cut set move with D; the gap is measured at D = 28 only | a per-site concentration the closed form does not reproduce | 0.0004 at D = 28; unmeasured at 29 (ring C row) |
|
||||
| The union bound's own looseness | the per-test miss rates rest on 3 to 11 known-failed cases each (section 2.2), so the family's false-pass rate is not yet a number under 1 | nothing new; the bound is on what the gate claims, not on the hash | fixed by cases, not eras: 60 fired cases per test for `delta` under 0.05 |
|
||||
| The last-resort program | 9 percent of last-resort programs fail (a) and are handed out unchecked; a lossy-corner era that raised `r` toward 0.95 would reach it at 2e-6 per epoch | a program that re-reads one address in two loads of the same hash | ring A's lossy-share bound keeps `r` under 0.85 (`r^256` under 1e-18); the fix (continue past 256) is owed to the rule's owner |
|
||||
| The era redraw's own grindability | a ring-A redraw consumes the stream's next block, so an adversary who could steer `E_n` could steer which block is used; the era VDF of F7 (517 s on the fastest prover, 259x the window) closes the steering of `E_n` itself | nothing beyond F7's bound | F7 (a) PASS with the VDF in the node |
|
||||
|
||||
A GPU-like chip (the `f = 1` stored-dataset chip with a programmable core, chip-model-v3 section 5) loses nothing on any era of the family: every drawn parameter is firmware to it, and what the family costs it is the core sized for the band's top (the research lane's USD 30 to 60 per chip, modelled). The family gate's job is therefore not to defeat that chip (the identity of the research file's section 2 says the per-joule edge is the card's own idle, 2.1x at `k = 1`) but to make sure no drawn era hands ANY chip more than the one hash did: a per-era hot set, a per-era mixer shortcut, a per-era verifier miss. Everything in this document is a bound on that increment, and the increments found so far are 1.002x and 1.0024x.
|
||||
|
||||
## 6. Running now, and the coverage measured
|
||||
|
||||
Started 11:1x BST, 8 October 2026, on igneum-build-1 under `lease pool` (class measure, owner class-v6-family-gate), the scripts under `/srv/builds/_adv-family-gate/` (fg-setup.sh, fg-build.sh, fg-census.sh), every binary run from a pinned copy under `bin/<tag>/` with its sha256 (AP-H2's rule), logs and TSV rows under `logs/`, copies of the finished logs land under `docs/analysis/class-v6/logs/` on this branch with the full report.
|
||||
|
||||
| Run | What | Where | State |
|
||||
|---|---|---|---|
|
||||
| base | `v5_attempts_census` (the shipped class v5 draw: shape 256 x 27, `m = 8`, `W = 1`, the table weights) over f8-label seeds 1,000 to 11,000, each seed its own drawn era (M, R, pos, windows) | build-1, 24 cores, binary 4bec799c (8f481459 unmodified) | running from 11:16 BST |
|
||||
| fg1 random | `family_gate_era_census` with every axis drawn (shape in {64, 128, 256}, `m` in {4, 8, 16} recorded, `W` over {1, 4}, weights at B = 4 with shfl and mulhi never raised) | build-1 | the harness built at 11:2x BST; the smoke run and the chunks follow |
|
||||
| fg1 corners | the same harness pinned per cell: `IGNEUM_FG_LOSSY_CAP`, `IGNEUM_FG_WIDTH=4`, `IGNEUM_FG_SHAPE=64`, the combinations | build-1, build-3, build-4 as the pool frees | queued |
|
||||
|
||||
The coverage table (filled from the TSV rows at 16:xx BST for the 17:00 cut; the full read at 09:00 BST tomorrow):
|
||||
|
||||
| Stratum | Eras drawn | `r` per candidate | Mean attempt, max | Exhausted | min (c'') ratio (the worst era) | Under 0.995 (the (c''') refuse rate on the accepted draw) | Largest bucket ratio (worst era, site) | Largest bit bias in sigma (worst era, site, bit) |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| base (shipped draw) | pending | | | | | | | |
|
||||
| random (every axis drawn) | pending | | | | | | | |
|
||||
| lossy cap | pending | | | | | | | |
|
||||
| W = 4 | pending | | | | | | | |
|
||||
| shape 64 | pending | | | | | | | |
|
||||
|
||||
## 7. Owed by 09:00 BST on 9 October (the full report)
|
||||
|
||||
1. The coverage table of section 6 filled from the logs, with the per-stratum refuse rates and the union-bound arithmetic on the measured numbers, and the TSV rows and logs under `docs/analysis/class-v6/logs/`.
|
||||
2. The clean spread of the bucket ratio and the bit bias per stratum, so the two new ring-B tests get a bound and a clean refuse rate (not a guess).
|
||||
3. The lossy-corner `r` against the 0.85 line, and the exhaustion count at 10^4 seeds on that corner.
|
||||
4. The width-4 reading of (c'') and (c''') with the divided expectation, and the spec line for 1.4.6.5.
|
||||
5. The mixer rows at `m = 4` and 16 (adv-mixer-3's index and sac at k = 2 on two days; the SAT at k = 2) as the per-family corner rows, if the boxes have the cores after the other lanes' jobs arrive; else the plan with its hours.
|
||||
6. The F8-form census at 2^24 on 64 seeds of one lossy-cap era and one width-4 era, the first ring-C rows on the family (about 2 box-hours each).
|
||||
7. The gate-record JSON written for every era of the census from the TSV (the format of 4.3), and the summary.
|
||||
|
||||
## 8. Sources
|
||||
|
||||
In-tree (the mirror's master and lane branches at 8 October 2026, 11:00 BST): `docs/plans/cryptanalysis/in-house-pass.md` (sections 13 and 14, the nine lanes' close); `docs/analysis/attack-pass-2026-10.md` (F1 to F10; the sub-version 1, 2 and 3 re-gate tables; the tail attribution of 8 October, 09:40 to 09:46 BST); `docs/analysis/cryptanalysis/report-mixer-3.md` on branch adv-mixer-3 at 981bfff2 (the round margin); `docs/analysis/cryptanalysis/report-chained-cache-2.md` on adv-cache-2 at bfc3746c (section 2.3, the era-stride table); `docs/analysis/cryptanalysis/report-acceptance-rule-3.md` on adv-accept-3 at 7826d2b2 (Q1, Q1b); `docs/analysis/cryptanalysis/report-acceptance-rule.md` on adv-accept at 8f188e5a (row 90, the floor's tally, gap-deep); `docs/spec/01-lottery-hash.md` 1.4.6, 1.4.7, 1.8.4, 1.13; `docs/design/class-v5-stored-state.md` on class-v5 at 8f481459 (sections 11 and 14) and `docs/design/class-v5-harness/` (v5-attempts-census-1000.log, v5-census-4600-0.log); `docs/plans/counter-asic-3-status.md` section 7c; `docs/plans/read-width.md`; `docs/analysis/counter-asic-4-research.md` on counter-asic-4 at 7a133d76 (15.1a, 15.1b, 20.2a, 20.2b, 20.3); `docs/design/class-v6-rotating-family.md` on the same branch (the outline).
|
||||
|
||||
Public, read 8 October 2026:
|
||||
|
||||
- Hanley, J. A. and Lippman-Hand, A., "If nothing goes wrong, is everything all right? Interpreting zero numerators", JAMA 249(13), 1743 to 1745, 1983; the rule of three as a one-sided 95 percent bound 3/n on a binomial rate with zero events in n trials: https://en.wikipedia.org/wiki/Rule_of_three_(statistics)
|
||||
- Wilks, S. S., "Determination of Sample Sizes for Setting Tolerance Limits", Annals of Mathematical Statistics 12(1), 91 to 96, 1941; the nonparametric tolerance limit on the extreme order statistic, the same arithmetic as 2.1: https://www.projecteuclid.org/euclid.aoms/1177700380
|
||||
- Böhme, M., "STADS: Software Testing as Species Discovery", ACM TOSEM 27(2), 2018; the Good-Turing estimate `f_1 / n` of the discovery probability as the residual-risk bound of a testing campaign with no finding (the fuzzing-coverage view of section 2): https://arxiv.org/abs/1803.02130
|
||||
- OSTIF, "Four audits of RandomX for Monero and Arweave have been completed: results" (2019; Trail of Bits, X41 D-SEC, Kudelski Security, Quarkslab; no critical finding; the one-round AES diffusion and the BLAKE2 rows): https://ostif.org/four-audits-of-randomx-for-monero-and-arweave-have-been-completed-results/
|
||||
- Quarkslab, "Security audit of Monero RandomX" (2019; the "alternative configurations" caveat: the audits bounded the shipped configuration, which is the single-member reading this document generalises): https://blog.quarkslab.com/security-audit-of-monero-randomx.html
|
||||
- Least Authority, ProgPoW algorithm audit (final report 9 September 2019; the Ethereum Cat Herders, the Ethereum Foundation and Bitfly as clients): https://leastauthority.com/blog/2019/09/09/
|
||||
- The hardware audit of ProgPoW (Bob Rao, 2019; "works well against conventional ASIC strategies", the memory-intensive threat kept open), as reported: https://criptonoticias.com/mineria/desarrolladores-ethereum-presentan-resultados-auditoria-progpow
|
||||
|
|
@ -234,6 +234,39 @@ The arithmetic that binds. A chip's memory is bought by the board, and today's p
|
|||
|
||||
So layer 2 as a rate "tracking chain state" ages out fixed-memory silicon only if the dataset grows faster than a chip generation's memory headroom, and every rate that does that retires the honest small cards first by the same table. The E3 is the only case in the record where a growth rule beat a chip, and it beat a chip that had under-provisioned memory by a factor the card fleet also hit (4 GB). The rule that would hurt the f = 1 chip is one that keeps the dataset above what one board of commodity DRAM holds at the chip's price point, and that rule is unaffordable for the honest fleet. The honest reading: layer 2 is the right lever class (the memory is the one parameter a stored-dataset chip cannot read as firmware), and its value is set by the floor and the ceiling, not by the tracking: a floor keeps the dataset above every SRAM die (class B stays closed: 2 GiB is 1,000 mm^2 of SRAM even at N5), and a ceiling keeps it under the honest tiers' memory. Between those two lines the chip's board holds whatever the card holds, and the growth rate changes nothing for it. What "tracking chain state" adds over the fixed schedule is governance (no release decides the size) and the class v5 link (the dataset is built from the state, so the size follows the state's record count naturally); it is not an anti-chip rate. Resolved by the synthesis lane (11:2x UK, `docs/design/class-v6-rotating-family.md` section 7b on `counter-asic-4`): layer 2's rule carries a per-year ceiling as its first constant, the fixed schedule's power-of-two step for that year, so the chain's state can bring a step forward and never add one; "retires cards before chips" is recorded as the reason the ceiling exists. Under that rule the table above is the ceiling's own schedule, and the honest 8 GB tier's year-12 line stands whatever the state does. What this file adds for the record: if the chain's state grew the way Ethereum's did (approximate, from memory: the account and storage state passed 100 GB in its eighth year), a dataset tracking it with no ceiling would have outgrown every consumer card inside the first decade; the ceiling is what makes layer 2 a governance rule and not a fleet-retirement rule.
|
||||
|
||||
### 4.2a One schedule, priced (main's ask of 11:2x UK, for the 20:00 reading)
|
||||
|
||||
Main asked for one dataset-floor schedule priced per tier and against the chips, so the 20:00 reading carries a decision: 6 GiB at the v6 epoch, 10 GiB two years on, 14 GiB at four years, each step by height like a class epoch, the schedule a consensus field. The method is `card-lifetime-2026-10-05.md`'s: a card's room for the dataset is its usable memory (75 percent of card memory, the standing rule "the whole working set under 6 GB on an 8 GB card"; 50 percent of Apple unified memory) less the non-dataset working set (best: 32 KiB scratch, the cache freed after the build, 254 to 479 MiB by tier; worst: 128 KiB scratch, the cache resident, 600 to 1,500 MiB). The population is the bench table's measured cards (`site/miner-bench.json`, 8 October 2026: 32 distinct consumer cards, one Apple part, eight datacentre parts); the fleet's own card census is not a file this lane could find and is owed, so the shares below are by count of distinct measured cards, not by hashrate.
|
||||
|
||||
**What the memory arithmetic says about main's three steps.** A step fits a tier when the dataset plus the working set is under the tier's usable memory.
|
||||
|
||||
| Step | 8 GB (usable 6,144 MiB) | 10 GB (7,680) | 11 GB (8,448) | 12 GB (9,216) | 16 GB (12,288) | Apple 16 GB unified (8,192) | 24 GB (18,432) | 32 GB (24,576) |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| 6 GiB (6,144 MiB) | **does not fit the rule**: 6,398 best, 6,744 worst, 78 to 82 percent of the card; fits only if the budget rule moves to about 85 percent (a headless rig with no display) | fits (6,404 best, 63 percent) | fits | fits | fits | fits (6,432 MiB, 79 percent of its usable half) | fits | fits |
|
||||
| 10 GiB (10,240 MiB) | out | out | out | **out**: 10,506 best, 10,888 worst, 86 to 89 percent | fits (10,518, 64 percent) | out | fits | fits |
|
||||
| 14 GiB (14,336 MiB) | out | out | out | out | **out**: 14,614 best, 15,032 worst, 89 to 92 percent | out | fits (14,752, 60 percent) | fits |
|
||||
|
||||
So main's schedule as stated retires, under the standing budget rule: at 6 GiB the 6 GB tier and, unless the rule is loosened to about 85 percent, the 8 GB tier (22 percent of the measured consumer cards: the RTX 3070, 3070 Ti, 3060 Ti, 4060, 4060 Ti 8 GB, 5060, 2070 Super) on day one; at 10 GiB the 10, 11 and 12 GB tiers and Apple 16 GB (another 31 percent: the RTX 3080, 1080 Ti, 2080 Ti, 4070, 4070 Ti, 4070 Super, 5070, 3080 Ti, 3060, Arc B580) at year 2; at 14 GiB the 16 GB tier (28 percent: the RTX 5060 Ti, 5070 Ti, 5080, 4080, 4080 Super, 4070 Ti Super, 4060 Ti 16 GB, RX 9070 XT, RTX A4000) at year 4, leaving 24 GB and above (16 percent of the measured consumer cards, plus every datacentre part). That is not the tier order main's note describes, so the schedule that drops the tiers in that order is priced beside it:
|
||||
|
||||
| Step | Dataset | Year | Who falls off (share of the 32 measured consumer cards) | Who holds, and at what share of card memory (best / worst) |
|
||||
|---|---|---|---|---|
|
||||
| v6 epoch | 5.5 GiB (5,632 MiB) | 0 | the 6 GB tier (RTX 2060: 3 percent) | 8 GB at 72 / 76 percent (the worst case one point over the rule); 10 GB 77 percent; Apple 16 GB unified at 72 percent; everything larger |
|
||||
| +2 years | 8 GiB (8,192 MiB) | 2 | the 8 GB tier (22 percent), the 10 GB RTX 3080 (3 percent: 8,452 of 7,680), Apple 16 GB unified (8,480 of 8,192) | 11 GB at 100 percent of usable (the 1080 Ti and 2080 Ti: out in practice, 6 percent); 12 GB at 69 / 72 percent; 16 GB; 24 GB; 32 GB; Apple 32 GB at 52 percent of its usable half |
|
||||
| +4 years | 11 GiB (11,264 MiB) | 4 | the 12 GB tier (22 percent) | 16 GB at 70 / 73 percent; 24 GB at 48 percent; 32 GB; Apple 32 GB at 71 percent of its usable half |
|
||||
| the fixed schedule's own steps beyond | 16 GiB | the year the state brings it forward, else year 28 | the 16 GB tier (28 percent); Apple 32 GB | 24 GB at 68 percent; 32 GB |
|
||||
|
||||
Reading, per tier, in the form main asked for (the year each falls off, and the share of today's measured cards that is): on the priced schedule the 6 GB tier falls at the v6 epoch (3 percent), the 8 GB tier and the 10 GB RTX 3080 and the Apple 16 GB laptop at year 2 (25 percent of the consumer cards plus the base Apple laptop), the 11 GB Pascal and Turing parts in practice at year 2 (6 percent), the 12 GB tier at year 4 (22 percent), the 16 GB tier at the 16 GiB step (28 percent), and 24 GB and above hold through every step priced. On main's schedule as stated the same tiers fall two years earlier each, and the 8 GB tier falls on day one unless the 75 percent rule moves. Either way this is the fleet-retirement rule the ceiling exists to bound (section 4.2): a step every two years retires a quarter of today's measured consumer cards each time.
|
||||
|
||||
**Against the chips, with the number.** Three chips, by what the step does to each:
|
||||
|
||||
| Chip | What a step costs it | The number |
|
||||
|---|---|---|
|
||||
| The hybrid-bonded DRAM chip sized at launch (the Jasminer X4's shape: DRAM dies bonded to the logic at tapeout, 5 GB per unit in 2021; the E3's shape in commodity form, 4 GB of DDR3 soldered to the board) | its memory is fixed at tapeout, so it dies at the first step it cannot carry, as the E3 did 20 to 27 months after shipping. On main's schedule a chip sized to the 6 GiB floor with 8 GB of bonded DRAM dies at the 10 GiB step (year 2); on the priced schedule a chip sized to 5.5 GiB with 8 GB dies at the 8 GiB step (year 2); a chip sized with 16 GB holds through year 4 on both and dies at the 16 GiB step. But the schedule is a consensus field read at genesis, so a maker sizes to the step it wants to survive: the X4's 5 GB was Ethash's DAG plus a year, chosen off a public schedule; the E3 died because its memory was sized to the CARD FLEET's limit, not to the schedule | kills only the chip that under-sizes; sizing to 16 GB costs the X4 shape about 3x its 2021 memory die area (approximate) and the E3 shape USD 160 more of GDDR7 (8 x USD 20, chip-model-v3 5.1) on a USD 470 part |
|
||||
| The f = 1 GDDR7 chip on a board (the record's class C; 16 x 2 GB devices, 32 GB) | nothing until the dataset passes 32 GB: every step priced here fits its board; a bigger step buys more devices at USD 20 per 2 GB | USD 0 per step through 16 GiB; its 5.1x per joule and USD 2.8 per MH/s stand at every step |
|
||||
| The SRAM store (the f = 0 recompute chip holding the cache on die) | the dataset's size costs it nothing (it derives every item); the CACHE's doubling under option C costs it capex only: 128 mm^2 and USD 46 per good die at 256 MiB, 255 mm^2 and USD 111 at 512 MiB (year 4 on the fixed schedule, or the year the state brings the doubling forward), 510 mm^2 and USD 306 at 1 GiB; and the mirror's size is what forces it onto a 7 nm or better node (the 5 October file, section 2.5) | USD 46 to 111 per die at the year-4 doubling; its edge stays 0.92x at the op budget and 1.86x per joule (`chip-model-v3.md` 5.4), unmoved by the dataset's steps |
|
||||
|
||||
The honest sentence for the 20:00 reading: the dataset-floor schedule is a fleet-retirement rule with a chip tax of USD 0 to 160 per unit on the chips that matter (classes C and B), and it kills only a chip whose maker ignores a public consensus field; the one precedent of a growth rule killing a chip (the E3) is a precedent of a maker sizing to the fleet, not to the schedule. If the schedule is adopted, the 75 percent budget rule and the 6 GiB floor cannot both stand for the 8 GB tier; 5.5 GiB keeps the 8 GB card inside the rule in the best case and one point over in the worst, and the headless-rig reading (about 85 percent) is what makes 6 GiB fit. The fleet's hashrate-weighted census is owed before the share column is read as a hashrate share.
|
||||
|
||||
### 4.3 Layer 3: scheduled family epochs by height, every 180 days, no release
|
||||
|
||||
What is declared: a new instruction family goes live on a height schedule, every 180 days by default, with no release (the reserve of spec 1.13.2, ordered at genesis). The record of scheduled change against chips:
|
||||
|
|
|
|||
122
docs/bridge/light-client-bridge.md
Normal file
122
docs/bridge/light-client-bridge.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# The light-client bridge primitive (Devnet 3 to Ethereum Sepolia), 8 October 2026
|
||||
|
||||
Devnet 3, test tokens, no value. This is a design plus one working contract. It moves nothing. It proves two things on
|
||||
Sepolia and states, below, what it does not prove.
|
||||
|
||||
## What exists
|
||||
|
||||
| Piece | Where | What it does |
|
||||
|---|---|---|
|
||||
| The verifier contract | `contracts/bridge/src/IgneumCertificateVerifier.sol`, deployed on Sepolia (address in `docs/contracts/sepolia.json`) | holds a Devnet 3 voter table; verifies a finality certificate against it and records the checkpoint hash as final; verifies an Ethereum account proof against a state root |
|
||||
| BLS12-381 | `contracts/bridge/src/BLS12381.sol` | hash-to-curve for G2 (RFC 9380, the node's DST), key aggregation in G1, the two-pairing check, all through the EIP-2537 precompiles |
|
||||
| The account proof | `contracts/bridge/src/MerklePatricia.sol` | walks an eth_getProof-shaped proof (RLP nodes, hex-prefix paths, embedded children) to the account's RLP value or to its absence |
|
||||
| The suite | `contracts/bridge/test/Verifier.t.sol`, vectors from `test/vectors/gen.mjs` | 9 tests on Foundry's Prague EVM: the vote message byte for byte, RFC 9380 expand_message_xmd answers, a certificate by four of five made-up keys, one under two thirds refused, forged index and checkpoint refused, the recorded checkpoint, an account present and an account absent under one root, a wrong root refused, and one certificate the chain actually carried |
|
||||
| The vectors | `gen.mjs synthetic`, `gen.mjs table <weights.json>`, `gen.mjs chain <checkpoint.json>` | made-up keys and a three-account trie; the Devnet 3 voter table from a node's `igneum_getFinalityWeights`; a real certificate as `/api/checkpoint` serves it, keys and signature decompressed to the precompiles' encodings |
|
||||
|
||||
The suite ran green on build-3 (9 of 9) before the deploy; the Sepolia address and the deploy transactions are in
|
||||
`docs/contracts/sepolia.json`.
|
||||
|
||||
## What the certificate check proves
|
||||
|
||||
A certificate is `(index, checkpoint hash, bitmap, aggregate signature)` as `consensus/core/src/finality.rs` writes it
|
||||
into a block's coinbase (`Certificate::write`: index_le64, checkpoint, voter_count_le32, bitmap_len_le32, bitmap,
|
||||
signature, aggregator, aggregator proof). The contract takes the first four fields; the signature is the 96-byte G2
|
||||
point decompressed off chain to the precompiles' 256-byte form (a wrong decompression is a point the pairing
|
||||
precompile refuses).
|
||||
|
||||
The contract holds a voter table installed by its deployer: the canonical voter list at one checkpoint index (every
|
||||
key above dust and not stripped, sorted by key hash, as the node's `igneum_getFinalityWeights` reports it), each key a
|
||||
128-byte uncompressed G1 point, each weight the key's blue blocks in the 30-day window. `tableId` is the keccak of
|
||||
`(index, keys, weights)`.
|
||||
|
||||
`verifyCertificate(index, checkpoint, bitmap, signature)` holds exactly when:
|
||||
|
||||
1. bit `p` of the bitmap names voter `p` of the table, and the sum of the named voters' weights is at least two thirds
|
||||
of the table's total weight (the rule decided 4 October 2026: lock = 2/3 of all 30-day weight; stricter than the
|
||||
17/30 floor plus 2/3 of active that the node line still carries, so every certificate the node locks under the new
|
||||
rule passes here and some the old rule locked would not);
|
||||
2. the aggregate of the named keys (G1 additions) verifies the signature over the vote message
|
||||
`"igneum-vote-v1/" || chain_id || 0x00 || index_le64 || checkpoint` under the domain separation tag
|
||||
`IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_`, with `chain_id` the string the contract was built with
|
||||
(`igneum-devnet-3`): e(aggregate key, H(message)) * e(-G1, signature) = 1.
|
||||
|
||||
So a recorded `finalCheckpoint(index)` means: the keys in the installed table that hold at least two thirds of that
|
||||
table's weight signed this checkpoint hash at this index on this chain id. That is the finality rule's own statement,
|
||||
checked with the node's own bytes, by a contract on another chain.
|
||||
|
||||
Measured on the test EVM: a 29-voter table costs about 5.3 million gas to install; a certificate with 12 signers
|
||||
verifies in about 3.9 million gas (the pairing and the two map-to-curve calls dominate; a G1 addition per signer is
|
||||
375 gas). On Sepolia at a 1 gwei tip that is under 0.01 ETH per certificate.
|
||||
|
||||
## What the account proof proves
|
||||
|
||||
`verifyAccount(stateRoot, account, proof)` walks an Ethereum account proof (the `eth_getProof` shape: RLP nodes from
|
||||
the root, keys hashed with keccak, the hex-prefix leaf and extension paths, children by hash or embedded when under 32
|
||||
bytes) and returns the account's nonce, balance, storage root and code hash, or `exists = false` when the trie shows the
|
||||
account absent. This is the trie Igneum's executor commits to: `igneum/exec/src/state.rs` computes `stateRoot` with
|
||||
`alloy_trie::root::state_root` over `keccak256(address)` and `RLP(nonce, balance, storage_root, code_hash)`, EIP-161
|
||||
empty accounts left out, reth's layout, the same as Ethereum's.
|
||||
|
||||
So a verified account proof means: under this state root, this account has these fields.
|
||||
|
||||
## What is NOT proven, in order of weight
|
||||
|
||||
1. **The link from a certified checkpoint to a state root.** Nothing the contract verifies ties a checkpoint hash to an
|
||||
EVM state root. The Kaspa-shaped header the voters sign has no execution root (its `utxo_commitment` is the UTXO
|
||||
multiset, `accepted_id_merkle_root` the accepted transaction ids); the executor runs behind consensus as a follower
|
||||
and the EVM block hash is the DAG block hash, not a hash of the EVM header. The binding that exists today is in the
|
||||
coinbase of later blocks: the IGNS segment record (`BlockStatement.post_root` for its last chain block, signed by
|
||||
the aggregator's vote key) and the proof records (`ProofRecord.statement` = keccak of a `ShardOutput` carrying
|
||||
`pre_root` and `post_root`, signed by the prover's vote key), both under the carrier block's `hash_merkle_root`. A
|
||||
carried record that fails a node's native veto is ignored rather than faulting the block, so even that binding
|
||||
rests on the aggregator's and prover's keys and on the nodes' native check, not on a header field. Today a caller
|
||||
gives the verifier a state root as a stated input beside a verified certificate; the contract does not know they
|
||||
belong together. The reference-apps lane's oracle verifies the coinbase path (BLAKE2b header hash, the merkle
|
||||
branch, the record parse) on Sepolia and shares this verifier for the certificate; the two together are the full
|
||||
chain once the record's signature check lands there.
|
||||
2. **The voter table itself.** The table is installed by the deployer from a node's `igneum_getFinalityWeights` read:
|
||||
the keys, their canonical order (sorted by `BLAKE2b-256("IgneumVoteKeyHash", key)`, which the contract does not
|
||||
recompute: no BLAKE2b on chain today) and their weights are trusted. A wrong table makes a wrong verdict in both
|
||||
directions. A light client proper tracks the table from the chain: every weight is a count of blue blocks whose
|
||||
headers name the key, so the table follows from headers; and the node's `FinalityWeights` RPC reports the table at
|
||||
the certificate's own index (`voters_at_index`). The next step is a table update that takes a certified checkpoint
|
||||
plus the headers between locks, the shape `/api/checkpoint` already serves to the browser verifier
|
||||
(`site/verify/core.js` checks exactly that path, in JavaScript).
|
||||
3. **The checkpoint index is a number the submitter gives.** The contract records one hash per index and refuses a
|
||||
second, but it does not know the chain's current index; an old certificate at an old index verifies for ever
|
||||
against the table it was signed under. A consumer should read `finalCheckpoint` at an index it already knows from
|
||||
the chain, not treat the newest recorded index as the chain's tip.
|
||||
4. **Equivocation and stripping.** The node strips a key's weight for 30 days on equivocation evidence. The installed
|
||||
table carries the stripping as of its read and nothing after it.
|
||||
5. **Proof of work, the DAG order, execution correctness.** None of it is checked here. The certificate's claim is the
|
||||
voters' signature, and the voters are the miners who proved their blocks; the ZK proofs of execution (the shard
|
||||
proofs the records name) are verified by the nodes, not by this contract. A proof-carrying bridge (the chain's SP1
|
||||
shard proofs verified on Ethereum) is the design's end state and is not today's primitive.
|
||||
6. **The state root's age and the account's current balance.** An account proof says what the balance was under that
|
||||
root; the root is one block's. Nothing here prevents a stale root from being presented.
|
||||
|
||||
## How one balance gets proven on Sepolia today, and what each step rests on
|
||||
|
||||
| Step | Source | Rests on |
|
||||
|---|---|---|
|
||||
| the voter table at index N | a Devnet 3 node's `igneum_getFinalityWeights` | the node, the installer (trusted today) |
|
||||
| the certificate for checkpoint C at index N | `/api/checkpoint?source=dn3` (the observer's `dn3_live_certificates`, the bytes a block carried) | verified on chain: the signature and the two-thirds rule |
|
||||
| the state root R of chain block B | `eth_getBlockByNumber` on Devnet 3 | stated, not proven against C (gap 1) |
|
||||
| the account proof for A under R | `eth_getProof` on the reference-apps lane's reader node (fork branch light-apps-node, the Devnet 3 pin plus a read-only RPC) | verified on chain against R |
|
||||
|
||||
The test `test_account_proof_present_and_absent` proves the account under a made-up root; the Devnet 3 account
|
||||
proof against a real root goes into the suite as `test/vectors/dn3-account.json` the moment the reader node serves
|
||||
`eth_getProof` (the proof shape is Ethereum's, so the contract needs no change).
|
||||
|
||||
## The design from here
|
||||
|
||||
1. The header path on chain: BLAKE2b-256 through the EIP-152 precompile for the keyed header hash and the key hashes,
|
||||
the merkle branch to the coinbase, the segment and proof records parsed from the coinbase payload. This closes gap 1
|
||||
and lets the contract recompute canonical order (gap 2's order).
|
||||
2. The table update from certified headers: weights counted from the blue blocks between two locks, so the table
|
||||
follows the chain instead of an installer. This closes gap 2.
|
||||
3. A tip rule: the contract keeps the highest index it has recorded and a consumer reads only at or below it; the
|
||||
relayer submits each lock as it lands (one transaction per 30-second checkpoint is affordable on Sepolia, not on
|
||||
mainnet; mainnet gets one certificate per epoch).
|
||||
4. The proof-carrying bridge: the shard proofs' aggregate verified on Ethereum (the prover network's own product),
|
||||
which replaces trust in the native veto with a verified execution root.
|
||||
16
docs/build/README.md
vendored
Normal file
16
docs/build/README.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# docs/build: the builder programme
|
||||
|
||||
8 October 2026. These files are the source of the developer pages on igneum.network; `site/build.mjs` renders two of them as pages and the rest are read here.
|
||||
|
||||
| File | Serves |
|
||||
|---|---|
|
||||
| `build.md` | [igneum.network/build](https://igneum.network/build): what is different (built to prove every block, a lock in minutes, nothing to stake, the EVM unchanged), the chain ids and endpoints, the wallet, the explorer, the faucet, the five-minute contract, the browser verifier |
|
||||
| `grants.md` | [igneum.network/grants](https://igneum.network/grants): the tiers, what a grant is, how to apply, the review, the honest lines |
|
||||
| `first-contract.md`, `first-contract-test.sh` | the walkthrough and the script that runs it end to end on Devnet 3 from a build box; the PASS line is the test record |
|
||||
| `rpc.md` | the JSON-RPC method list as the node serves it, read from a Devnet 3 node, with the probe |
|
||||
| `faucet.md` | the Devnet 3 faucet: rules, where it runs, how it is funded |
|
||||
| `verify-a-block.md` | the in-browser checkpoint verifier, twelve lines |
|
||||
|
||||
The faucet service is `infra/build-server/faucet/`. The grant application template is `.forgejo/issue_template/grant.md`.
|
||||
|
||||
Served-text rules (the site audit reads every page before it lands): no em dashes, short sentences, one to three points per block, nothing that reads as an offer, a price or a promise of value; devnet and testnet coins have no value; no amount, price or date is promised.
|
||||
88
docs/build/build.md
vendored
Normal file
88
docs/build/build.md
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Build on Igneum
|
||||
|
||||
This file is the source of [igneum.network/build](https://igneum.network/build). The site build renders it as the page. The other files in this directory are the walkthrough, the RPC list, the faucet, the verifier and the grants.
|
||||
|
||||
## What is different
|
||||
|
||||
**Every block is built to be proven.** A chain block carries a zero-knowledge proof of its execution. The miners are the provers: the same cards that find blocks prove them, in shards. On Devnet 3 a share of blocks carries a proof today; the live page shows the share and the lag, and the design target at launch is under a minute. Full nodes execute every block themselves, so a bad proof is a light-client problem and never a chain split.
|
||||
|
||||
**A lock in minutes, not an hour of confirmations.** Miners sign a checkpoint every 30 seconds. When two thirds of the mining weight of the last 30 days have signed, the checkpoint is locked. Weight is blocks mined, nothing else. The lock lands in about two minutes. The [litepaper](/litepaper) has the rule.
|
||||
|
||||
**Nothing to stake.** No validator set, no delegation, no slashing, no bonded class above the miners. Finality comes from mining weight alone. Nobody holds a key that the chain depends on.
|
||||
|
||||
**The EVM you already know.** Solidity deploys unchanged. Standard JSON-RPC, EIP-1559 transactions, the chain id in the signature, `cancun` as the EVM version. Gas has two dimensions on Igneum, execution and proving, and the node folds the second into the price it quotes, so `eth_estimateGas` and `eth_gasPrice` work as they do on Ethereum.
|
||||
|
||||
## Networks
|
||||
|
||||
| | Devnet 3 | Testnet | Mainnet |
|
||||
|---|---|---|---|
|
||||
| Chain id | 4463 (`0x116f`) | 4462 (`0x116e`) | 4461 (`0x116d`) |
|
||||
| Network id | `igneum-devnet-3` | `igneum-testnet-1` | not started |
|
||||
| RPC | `https://rpc.devnet.igneum.network` (a node you run serves `http://127.0.0.1:26790`) | `https://rpc.testnet.igneum.network` (answers; nothing mines there yet, so a transaction waits) | none |
|
||||
| Coins | no value, resets without notice | no value, resets with notice | not started |
|
||||
| Symbol, decimals | IGN, 18 | IGN, 18 | IGN, 18 |
|
||||
|
||||
Devnet 3 is where you build today. It is a developer network: it resets without notice and its coins have no value. Its public RPC takes the read methods, `eth_sendRawTransaction` and a wRPC websocket at `/ws`, at 20 requests a second per address. The public testnet exists, its RPC answers, and no blocks are being produced on it until it opens. Mainnet has no date. Devnet 3 answers chain id 4463 until its class v5 floor, then 4464.
|
||||
|
||||
## Endpoints and tools
|
||||
|
||||
- **Wallet.** Any Ethereum wallet. [Add Igneum to MetaMask](/metamask) with one click, or the [Igneum wallet](/wallet).
|
||||
- **Faucet.** [10 IGN of Devnet 3 coin](/faucet) per address per day. No account.
|
||||
- **Explorer.** [The explorer](/explorer) shows blocks, the DAG, miners and addresses. The EVM views, transactions and contracts, are being built and link from the same page as they land.
|
||||
- **Swap.** [The swap](/swap): test tokens on Devnet 3, every swap in a proven block.
|
||||
- **Source.** [git.igneum.network/igneum-network/igneum](https://git.igneum.network/igneum-network/igneum): the node, the miner, the site, and these pages under `docs/build/`.
|
||||
|
||||
## Your first contract in five minutes
|
||||
|
||||
With [Foundry](https://getfoundry.sh). Tested end to end on Devnet 3 on a build box; the full walkthrough with the expected output is [docs/build/first-contract.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/first-contract.md).
|
||||
|
||||
```
|
||||
curl -L https://foundry.paradigm.xyz | bash && foundryup
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast wallet new # an address and a private key, for the devnet only
|
||||
```
|
||||
|
||||
Paste the address into [the faucet](/faucet). Then:
|
||||
|
||||
```
|
||||
export PK=0x... # the private key cast printed
|
||||
cast balance $(cast wallet address $PK) --rpc-url $RPC --ether
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast
|
||||
```
|
||||
|
||||
`forge create` prints `Deployed to: 0x...`. Call it:
|
||||
|
||||
```
|
||||
cast send 0xDEPLOYED "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call 0xDEPLOYED "number()(uint256)" --rpc-url $RPC
|
||||
```
|
||||
|
||||
The call answers `1`. Paste the transaction hash into [the explorer](/explorer). Hardhat, ethers and viem work the same way: chain id 4463, the RPC above.
|
||||
|
||||
## The RPC the node serves
|
||||
|
||||
Read from a Devnet 3 node, not from a spec. `web3_clientVersion` answers `igneumd/2.1.0/execution-layer-v3`. The full list, served and not served, with the probe that produced it: [docs/build/rpc.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/rpc.md).
|
||||
|
||||
- **Served.** `eth_chainId`, `eth_blockNumber`, `eth_getBalance`, `eth_getTransactionCount`, `eth_getCode`, `eth_getStorageAt`, `eth_getBlockByNumber`, `eth_getBlockByHash`, `eth_getTransactionByHash`, `eth_getTransactionReceipt`, `eth_getBlockReceipts`, `eth_getLogs`, `eth_call`, `eth_estimateGas`, `eth_gasPrice`, `eth_maxPriorityFeePerGas`, `eth_feeHistory`, `eth_sendRawTransaction`, `eth_syncing`, `eth_accounts`, `net_version`, `net_peerCount`, `net_listening`, `web3_clientVersion`.
|
||||
- **Igneum's own.** `igneum_getExecStatus`, `igneum_getProvingStatus`, `igneum_getShardPlan`, `igneum_getProofRecords`, `igneum_getTransactionStatus`, `igneum_estimateGas`, `igneum_getBudgets` and the segment and proof calls. `igneum_estimateGas` returns both gas dimensions and whether a call exceeds the proving limit.
|
||||
- **Not served.** Filters and subscriptions (`eth_newFilter`, `eth_subscribe`), `txpool_*`, `debug_*`, `trace_*`, `eth_sendTransaction`, `eth_sign`, `eth_getProof`, the uncle calls. Poll `eth_blockNumber` and `eth_getLogs`. Sign on your side.
|
||||
|
||||
## Verify a block in your browser
|
||||
|
||||
The site ships a light client. Your browser fetches the latest certified checkpoint from `/api/checkpoint` and verifies the BLS aggregate signature, the voter weights and the header chain itself, in the tab. Nothing is trusted from the server but the data. The example, in twelve lines, is [docs/build/verify-a-block.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/verify-a-block.md); the live run is [verify/test.html](/verify/test.html), genuine and tampered cases side by side.
|
||||
|
||||
```
|
||||
import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified, r.signers, 'of', r.voters, 'voters', r.ms, 'ms');
|
||||
```
|
||||
|
||||
## Where to ask
|
||||
|
||||
- An issue on [the repository](https://git.igneum.network/igneum-network/igneum/issues).
|
||||
- [Discord](https://discord.gg/igneum), the builders channel.
|
||||
- [Grants](/grants) for tooling, reference apps, infrastructure and research.
|
||||
|
||||
Devnet and testnet coins have no value. Nothing on this page is an offer to sell anything.
|
||||
36
docs/build/faucet.md
vendored
Normal file
36
docs/build/faucet.md
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# The Devnet 3 faucet
|
||||
|
||||
[igneum.network/faucet](https://igneum.network/faucet) sends 10 IGN of Devnet 3 coin to an address. Once per address per day, once per connection per day. No account.
|
||||
|
||||
## What it is
|
||||
|
||||
- A small Node service on a build box, `infra/build-server/faucet/faucet.mjs`, behind Caddy at `faucet.igneum.network`. The page on igneum.network posts to it.
|
||||
- It signs a plain transfer with its own key and sends it to the Devnet 3 node on the same box by address (`FAUCET_RPC`), never chosen by chain id: Devnet 3 answers the same chain id as the shared devnet.
|
||||
- The key lives only in the service's environment file on that box. It is not in the repository and not on the site.
|
||||
|
||||
## The rules, as the code enforces them
|
||||
|
||||
| Rule | Value |
|
||||
|---|---|
|
||||
| Amount | 10 IGN per send; the code refuses to start with an amount over the 100 IGN cap |
|
||||
| Per address | one send per 24 hours |
|
||||
| Per connection | one send per 24 hours |
|
||||
| Per day, in total | 500 sends, then "come back tomorrow" |
|
||||
| What is stored | the address, the connection's IP, the transaction hash and the time, in a file on the box, for the 24-hour window |
|
||||
|
||||
The faucet's balance is refilled from the devnet's funder as it runs down. When it is empty the page says so and sends nothing.
|
||||
|
||||
## Devnet 3 coin
|
||||
|
||||
No value. Not for sale, not redeemable, not a claim on anything. The chain resets without notice and balances do not carry over. Mainnet starts from an empty genesis.
|
||||
|
||||
## Running it
|
||||
|
||||
```
|
||||
infra/build-server/faucet/faucet.sh install # dry run: what would be copied and started
|
||||
infra/build-server/faucet/faucet.sh install --go # copy the service, the unit and the Caddy block; start it
|
||||
infra/build-server/faucet/faucet.sh status # the unit, the balance, the sends in the last 24 hours
|
||||
node infra/build-server/faucet/faucet.mjs --self-test # the limiter: known-failed cases first
|
||||
```
|
||||
|
||||
The public testnet faucet is a separate thing: `site/api/faucet.mjs` is prepared for it and answers "not open yet" until the testnet starts.
|
||||
49
docs/build/first-contract-test.sh
vendored
Executable file
49
docs/build/first-contract-test.sh
vendored
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# The five-minute walkthrough (docs/build/first-contract.md), run end to end on a build box against a Devnet 3 node, so the
|
||||
# page is tested and not described. Runs where Foundry is installed (~/.foundry/bin); asks the faucet for the coins exactly
|
||||
# as a reader would, deploys Foundry's Counter, calls it, reads the receipt, prints one PASS line with the numbers.
|
||||
# RPC=http://127.0.0.1:27810 FAUCET=http://127.0.0.1:8790/api/faucet bash docs/build/first-contract-test.sh
|
||||
# Known-failed first: with RPC pointed at a closed port the script must print FAIL and exit 1 (--self-test).
|
||||
set -uo pipefail
|
||||
export PATH="$HOME/.foundry/bin:$PATH"
|
||||
RPC="${RPC:-https://rpc.devnet.igneum.network}"
|
||||
FAUCET="${FAUCET:-https://faucet.igneum.network/api/faucet}"
|
||||
t0=$(date +%s); now() { date -u +%H:%M:%SZ; }
|
||||
fail() { echo "FAIL $(now): $*"; exit 1; }
|
||||
if [ "${1:-}" = --self-test ]; then
|
||||
out=$(RPC=http://127.0.0.1:9 FAUCET=http://127.0.0.1:9/x bash "$0" 2>&1); rc=$?
|
||||
[ "$rc" = 1 ] && case "$out" in *FAIL*) echo "self-test passed: a closed RPC port reads FAIL, exit 1"; exit 0 ;; esac
|
||||
echo "self-test failed: rc=$rc out=$out"; exit 1
|
||||
fi
|
||||
command -v forge >/dev/null || fail "forge is not installed"
|
||||
cid=$(cast chain-id --rpc-url "$RPC" 2>/dev/null) || fail "no chain id from $RPC"
|
||||
[ "$cid" = 4463 ] || [ "$cid" = 4464 ] || fail "chain id $cid is not Devnet 3"
|
||||
work=$(mktemp -d); cd "$work" || fail "no scratch dir"
|
||||
# step 1: a key for the devnet only (never printed)
|
||||
w=$(cast wallet new 2>&1 | sed 's/\x1b\[[0-9;]*m//g') || fail "cast wallet new"
|
||||
PK=$(printf '%s\n' "$w" | sed -n 's/^Private key: *//p' | head -1); ME=$(printf '%s\n' "$w" | sed -n 's/^Address: *//p' | head -1)
|
||||
[ -n "$PK" ] && [ -n "$ME" ] || fail "cast wallet new printed no key"
|
||||
# step 2: the faucet, as a reader would
|
||||
f=$(curl -s -m 60 -X POST -H 'content-type: application/json' --data "{\"address\":\"$ME\"}" "$FAUCET") || fail "the faucet did not answer"
|
||||
case "$f" in *'"ok":true'*) ;; *) fail "the faucet refused: $f" ;; esac
|
||||
drip=$(printf '%s' "$f" | sed -n 's/.*"tx":"\(0x[0-9a-f]*\)".*/\1/p')
|
||||
for i in $(seq 1 60); do bal=$(cast balance "$ME" --rpc-url "$RPC" --ether 2>/dev/null); case "$bal" in 10.*|9.*) break ;; esac; sleep 1; done
|
||||
case "$bal" in 10.*|9.*) ;; *) fail "balance after the faucet: ${bal:-none}" ;; esac
|
||||
# step 3: deploy Foundry's template counter
|
||||
forge init counter --no-git >/dev/null 2>&1 || forge init counter >/dev/null 2>&1 || fail "forge init"
|
||||
cd counter || fail "no counter dir"
|
||||
out=$(forge create src/Counter.sol:Counter --rpc-url "$RPC" --private-key "$PK" --broadcast 2>&1) || fail "forge create: $(printf '%s' "$out" | tail -3)"
|
||||
C=$(printf '%s\n' "$out" | sed -n 's/^Deployed to: *//p' | head -1); deployTx=$(printf '%s\n' "$out" | sed -n 's/^Transaction hash: *//p' | head -1)
|
||||
[ -n "$C" ] || fail "no Deployed to line: $out"
|
||||
# step 4: call it
|
||||
cast send "$C" "increment()" --rpc-url "$RPC" --private-key "$PK" >/dev/null 2>&1 || fail "cast send increment"
|
||||
n=$(cast call "$C" "number()(uint256)" --rpc-url "$RPC" 2>/dev/null); [ "$n" = 1 ] || fail "number() after increment: $n"
|
||||
sendOut=$(cast send "$C" "setNumber(uint256)" 41 --rpc-url "$RPC" --private-key "$PK" 2>&1) || fail "cast send setNumber"
|
||||
txh=$(printf '%s\n' "$sendOut" | sed -n 's/^transactionHash *//p' | head -1)
|
||||
n=$(cast call "$C" "number()(uint256)" --rpc-url "$RPC" 2>/dev/null); [ "$n" = 41 ] || fail "number() after setNumber: $n"
|
||||
# step 5: the receipt
|
||||
st=$(cast receipt "${txh:-$deployTx}" --rpc-url "$RPC" 2>/dev/null | sed -n 's/^status *//p' | head -1)
|
||||
case "$st" in 1*|*success*) ;; *) fail "receipt status: $st" ;; esac
|
||||
blk=$(cast block-number --rpc-url "$RPC" 2>/dev/null)
|
||||
echo "PASS $(now): Devnet 3 chain id $cid, faucet drip $drip, deployed Counter at $C (tx $deployTx), increment then setNumber(41) read back 41, receipt status $st, block $blk, $(( $(date +%s) - t0 )) s end to end, Foundry $(forge --version 2>/dev/null | sed -n 's/^forge Version: *//p' | head -1)"
|
||||
cd / && rm -rf "$work"
|
||||
91
docs/build/first-contract.md
vendored
Normal file
91
docs/build/first-contract.md
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Your first contract on Devnet 3, in five minutes
|
||||
|
||||
With Foundry. Tested end to end on Devnet 3 from a build box on 8 October 2026; the pass line and the exact output are at the end. Hardhat, ethers and viem work the same way: chain id 4463 and the RPC below.
|
||||
|
||||
## 0. What you need
|
||||
|
||||
- Foundry: `curl -L https://foundry.paradigm.xyz | bash && foundryup`. About a minute.
|
||||
- The RPC. Devnet 3's public endpoint is `https://rpc.devnet.igneum.network`. A node you run yourself serves `http://127.0.0.1:26790`.
|
||||
- Nothing else. No account, no sign-up.
|
||||
|
||||
```
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast chain-id --rpc-url $RPC # 4463
|
||||
```
|
||||
|
||||
## 1. A key, for the devnet only
|
||||
|
||||
```
|
||||
cast wallet new
|
||||
```
|
||||
|
||||
It prints an address and a private key. Keep the key for this walkthrough and nothing else: devnet coins have no value and the chain resets without notice.
|
||||
|
||||
```
|
||||
export PK=0x... # the private key cast printed
|
||||
export ME=$(cast wallet address $PK)
|
||||
```
|
||||
|
||||
## 2. Coins from the faucet
|
||||
|
||||
Paste `$ME` into [igneum.network/faucet](https://igneum.network/faucet). It sends 10 IGN and shows the transaction hash. Once per address per day.
|
||||
|
||||
```
|
||||
cast balance $ME --rpc-url $RPC --ether # 10.000000000000000000
|
||||
```
|
||||
|
||||
## 3. Deploy
|
||||
|
||||
Foundry's template is a counter. Initialise it and deploy it as it is.
|
||||
|
||||
```
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```
|
||||
Deployer: 0x...
|
||||
Deployed to: 0x...
|
||||
Transaction hash: 0x...
|
||||
```
|
||||
|
||||
```
|
||||
export C=0x... # the Deployed to address
|
||||
```
|
||||
|
||||
## 4. Call it
|
||||
|
||||
```
|
||||
cast send $C "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call $C "number()(uint256)" --rpc-url $RPC # 1
|
||||
cast send $C "setNumber(uint256)" 41 --rpc-url $RPC --private-key $PK
|
||||
cast call $C "number()(uint256)" --rpc-url $RPC # 41
|
||||
```
|
||||
|
||||
`cast send` waits for the receipt. A block takes about a second.
|
||||
|
||||
## 5. See it
|
||||
|
||||
Paste the transaction hash into [igneum.network/explorer](https://igneum.network/explorer). The receipt is also one call away:
|
||||
|
||||
```
|
||||
cast receipt 0xTXHASH --rpc-url $RPC
|
||||
```
|
||||
|
||||
## What is different under the hood
|
||||
|
||||
- Gas has two dimensions, execution and proving. The node folds the second into the price it quotes, so `forge` and `cast` estimate and pay as on Ethereum. `igneum_estimateGas` shows both numbers and whether a call exceeds the proving limit.
|
||||
- Your transaction is in a block within about a second, proven tens of seconds later, and locked by miner signatures in about two minutes. `igneum_getTransactionStatus` reports each stage.
|
||||
- A transaction signed for another chain id is refused. EIP-155, EIP-1559 and legacy envelopes are accepted.
|
||||
|
||||
## The test record
|
||||
|
||||
Run on a build box against its own Devnet 3 node (the box that also fronts the public RPC and runs the faucet), with Foundry 1.8.5 and a fresh key, through `docs/build/first-contract-test.sh`. The pass line is appended below by the run.
|
||||
|
||||
```
|
||||
PASS 10:17:23Z: Devnet 3 chain id 4463, faucet drip 0x8620e9d894484e824e4ac33002946a00e2f75823ea6db0da0ad29f1af142e8f2, deployed Counter at 0x6345265C6Db0b3713eb6645d795d0B52FE0a4201 (tx 0xcf77b4822d51f3c60ecdf6d7dbbe67524d42071f06c76e1cf9b0511d64783574), increment then setNumber(41) read back 41, receipt status 1 (success), block 27055, 24 s end to end, Foundry 1.8.5
|
||||
```
|
||||
|
||||
Through the public endpoints, `https://rpc.devnet.igneum.network` and `https://faucet.igneum.network`, from the box: the first faucet drip and the first reader-path deploy on Devnet 3.
|
||||
46
docs/build/grants.md
vendored
Normal file
46
docs/build/grants.md
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Grants
|
||||
|
||||
This file is the source of [igneum.network/grants](https://igneum.network/grants).
|
||||
|
||||
## What a grant is
|
||||
|
||||
Grants are paid in IGN from the dev fee fund, on delivery. You propose a piece of work, it is accepted with a written definition of done, you build it, and it runs on the public testnet. Not a salary, not an advance, not an investment.
|
||||
|
||||
The money is the dev fee fund: the IGN that the Ember dev fee collects. Ember, the official miner, takes an optional 1% of a miner's rewards, in full view and off with one flag; that fee goes to Igneum Labs, the company that ships the software. The protocol itself carries no fee, no fund and no allocation, and no grant is paid from emission. [The dev fee](/dev-fee) has the mechanism.
|
||||
|
||||
## The tiers
|
||||
|
||||
| Tier | What fits |
|
||||
|---|---|
|
||||
| Tooling | SDK bindings, indexers, a Hardhat or Foundry plugin for the two gas dimensions, verification tooling, a light client in another language |
|
||||
| Reference apps | A token, a swap, a registry, a wallet integration, an app that uses `igneum_getTransactionStatus` and the lock the way it is meant to be used |
|
||||
| Infrastructure | RPC providers, archive nodes, seed nodes in new regions, pool software, an explorer back end |
|
||||
| Research | The lottery hash, the finality rule, the proving layer, the fee model; attacks on the public test vectors; measurements the project does not have |
|
||||
|
||||
A grant is sized by the work in front of it, not by a table. Two grants in the same tier can differ.
|
||||
|
||||
## How to apply
|
||||
|
||||
Open an issue on [git.igneum.network/igneum-network/igneum](https://git.igneum.network/igneum-network/igneum/issues/new?template=.forgejo%2Fissue_template%2Fgrant.md) and pick the Grant template. It asks for:
|
||||
|
||||
1. What you will build, in a paragraph, and which tier it is.
|
||||
2. What done looks like: what runs where, what a reviewer can click or call to see it working on the public testnet.
|
||||
3. Your public work: a repository, a package, a paper, a deployed thing.
|
||||
4. How you want to be reached.
|
||||
|
||||
A short issue is fine. The definition of done is the part that matters.
|
||||
|
||||
## The review
|
||||
|
||||
- Every Friday. Each open application gets one of three answers inside seven days: accepted with a definition of done, questions, or no with the reason.
|
||||
- Accepted work is tracked in its issue. The reviewer and the builder agree the definition of done there before any work starts.
|
||||
- Delivery is reviewed on the public testnet first. Payment follows the review, in the issue, in the open.
|
||||
|
||||
## The honest lines
|
||||
|
||||
- Devnet and testnet coins have no value. Before mainnet there is no IGN with value: a grant delivered on the testnet is recorded in its issue, and payment comes from the fund when the fund holds IGN. Nothing is promised about when, or whether, that is.
|
||||
- No amount, price or date is promised. The fund is what the dev fee collects, and it is zero today.
|
||||
- A grant is for work delivered, never for a user count, a listing, a post or a referral.
|
||||
- Igneum Labs may decline any application and may close the programme; what has been accepted and delivered is still paid.
|
||||
|
||||
Not legal advice.
|
||||
79
docs/build/rpc.md
vendored
Normal file
79
docs/build/rpc.md
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# The JSON-RPC a Devnet 3 node serves
|
||||
|
||||
Read from the node, not from a spec: every method below was sent to a Devnet 3 node on 8 October 2026 (`web3_clientVersion` answered `igneumd/2.1.0/execution-layer-v3`, `eth_chainId` `0x116f`, block 26,666) and sorted by what came back. A method the node does not know answers JSON-RPC error `-32601`. The probe is at the end; run it against your own node to refresh this file.
|
||||
|
||||
Transport: HTTP POST, JSON-RPC 2.0, one request per call, no batches tested. The public endpoint is `https://rpc.devnet.igneum.network`; a node you run serves `http://127.0.0.1:26790`. The DAG side of the node (blocks, the mempool, the vote table) speaks the Kaspa-style gRPC and wRPC on their own ports; the explorer and the observer use those, a contract developer needs only what is here.
|
||||
|
||||
## Served: the Ethereum set
|
||||
|
||||
| Method | Note |
|
||||
|---|---|
|
||||
| `web3_clientVersion` | `igneumd/<version>/execution-layer-v3` |
|
||||
| `net_version` | the chain id as a decimal string, `"4463"` |
|
||||
| `net_listening`, `net_peerCount` | |
|
||||
| `eth_chainId` | `0x116f` (4463) on Devnet 3; `0x1170` after its class v5 floor |
|
||||
| `eth_blockNumber` | the executed chain tip |
|
||||
| `eth_syncing` | `false` when the executor is at the tip |
|
||||
| `eth_mining` | `false` from the RPC's point of view: mining is the miner's, not the node's |
|
||||
| `eth_accounts` | always `[]`: the node holds no keys |
|
||||
| `eth_protocolVersion` | `0x41` |
|
||||
| `eth_gasPrice`, `eth_maxPriorityFeePerGas`, `eth_feeHistory` | EIP-1559 pricing; the proving dimension is folded into the quoted price |
|
||||
| `eth_getBalance`, `eth_getTransactionCount`, `eth_getCode`, `eth_getStorageAt` | by block tag or number |
|
||||
| `eth_getBlockByNumber`, `eth_getBlockByHash` | the EVM view of a chain block; `null` for an unknown hash |
|
||||
| `eth_getBlockTransactionCountByNumber` | |
|
||||
| `eth_getTransactionByHash`, `eth_getTransactionByBlockNumberAndIndex` | |
|
||||
| `eth_getTransactionReceipt`, `eth_getBlockReceipts` | |
|
||||
| `eth_getLogs` | by block range, address and topics |
|
||||
| `eth_call`, `eth_estimateGas` | as on Ethereum |
|
||||
| `eth_sendRawTransaction` | a signed EIP-155, EIP-1559 or legacy envelope; the chain id must match |
|
||||
|
||||
## Served: Igneum's own
|
||||
|
||||
| Method | What the answer carries (from the probe) |
|
||||
|---|---|
|
||||
| `igneum_getExecStatus` | the executed tip, a continuity break if any, what the executor is blocked on |
|
||||
| `igneum_getProvingStatus` | whether proving is active, its activation height, assignees per shard, the dust rule |
|
||||
| `igneum_getShardPlan` | a block's shard plan: the DAA score, eligible keys, the epoch seed, the assignments |
|
||||
| `igneum_getProofRecords` | the proof records a block carries and claims |
|
||||
| `igneum_getTransactionStatus` | per transaction: in the mempool, included in, executed, locked |
|
||||
| `igneum_estimateGas` | both gas dimensions, the base fee, and `exceedsProvingLimit` |
|
||||
| `igneum_getBudgets` | the proving budgets: backlog depth, the base fee, chain blocks |
|
||||
| `igneum_getAssignedShards` | the shards assigned to this node's prover |
|
||||
| `igneum_getSegment`, `igneum_getSegmentRecords`, `igneum_getSegmentStatement` | a segment's executed blocks, records and statement |
|
||||
| `igneum_getSegmentProofBytes`, `igneum_getProofBytes` | the proof bytes for a key hash (`keyHash` is required) |
|
||||
| `igneum_exportSegments` | a range of segments with their accounts |
|
||||
| `igneum_exportExecSnapshot` | writes a snapshot to a path on the node's own disk |
|
||||
| `igneum_submitProofRecord`, `igneum_submitSegmentRecord` | the prover's submissions; a record is required |
|
||||
|
||||
## Not served
|
||||
|
||||
Each of these answered `-32601` on 8 October 2026. Where a tool wants one, the note says what to do instead.
|
||||
|
||||
| Method | Instead |
|
||||
|---|---|
|
||||
| `eth_newFilter`, `eth_newBlockFilter`, `eth_newPendingTransactionFilter`, `eth_getFilterChanges`, `eth_getFilterLogs`, `eth_uninstallFilter` | poll `eth_blockNumber` and `eth_getLogs` |
|
||||
| `eth_subscribe`, `eth_unsubscribe` | no WebSocket subscriptions; poll |
|
||||
| `eth_sendTransaction`, `eth_sign`, `eth_signTransaction` | the node holds no keys; sign on your side and use `eth_sendRawTransaction` |
|
||||
| `eth_getProof` | not yet |
|
||||
| `eth_getTransactionByBlockHashAndIndex`, `eth_getBlockTransactionCountByHash` | use the by-number forms |
|
||||
| `eth_getUncleByBlockHashAndIndex`, `eth_getUncleByBlockNumberAndIndex`, `eth_getUncleCountByBlockHash`, `eth_getUncleCountByBlockNumber` | there are no uncles; the DAG's merged blocks are not EVM blocks |
|
||||
| `eth_createAccessList`, `eth_simulateV1`, `eth_blobBaseFee` | not yet; no blobs |
|
||||
| `eth_coinbase`, `eth_hashrate` | the miner's, not the node's |
|
||||
| `txpool_content`, `txpool_status` | `igneum_getTransactionStatus` for one transaction |
|
||||
| `debug_traceTransaction`, `debug_traceBlockByNumber`, `trace_block` | no tracing yet |
|
||||
| `web3_sha3` | hash on your side |
|
||||
|
||||
## The probe
|
||||
|
||||
Every method with a harmless argument; the verdict is `served`, `not-found` (`-32601`) or `error` (the node knows the method and refused the argument, which counts as served).
|
||||
|
||||
```
|
||||
URL=http://127.0.0.1:26790
|
||||
call() { curl -s -X POST -H 'content-type: application/json' \
|
||||
--data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$1\",\"params\":${2:-[]}}" "$URL"; }
|
||||
for m in web3_clientVersion eth_chainId eth_blockNumber eth_newFilter eth_subscribe; do
|
||||
printf '%-32s %s\n' "$m" "$(call $m | cut -c1-80)"
|
||||
done
|
||||
```
|
||||
|
||||
Devnet 3 resets without notice and its coins have no value.
|
||||
34
docs/build/verify-a-block.md
vendored
Normal file
34
docs/build/verify-a-block.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Verify a block in your browser
|
||||
|
||||
Igneum's finality is a certificate: miners sign a checkpoint every 30 seconds, and when two thirds of the 30-day mining weight have signed, it is locked. A browser can check that certificate by itself. The site ships the verifier: `site/verify/core.js` does the work, `site/verify/verify.js` fetches the data and calls it.
|
||||
|
||||
## Twelve lines
|
||||
|
||||
```
|
||||
<script type="module">
|
||||
import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified ? 'verified' : 'not verified', r.reason || '');
|
||||
console.log(`checkpoint ${r.index} on ${r.network}, block ${r.hash.slice(0, 12)}`);
|
||||
console.log(`${r.signers} of ${r.voters} voters signed`);
|
||||
console.log(`${(r.weight_fraction_total * 100).toFixed(1)}% of total weight`);
|
||||
console.log(`${r.headers_checked} headers checked in ${r.ms} ms`);
|
||||
</script>
|
||||
```
|
||||
|
||||
## What is checked, in the tab
|
||||
|
||||
1. The header chain from the previous locked checkpoint to this one: each header's hash is recomputed and each links to its parent.
|
||||
2. The voter table: each voter's key hash, and the weights the bitmap selects.
|
||||
3. The BLS aggregate signature over the checkpoint message, against the aggregated public keys of the signers, and that the signed weight reaches two thirds of the total.
|
||||
|
||||
Nothing is trusted from the server but the data itself. Change one bit of the signature, drop one signer from the bitmap, alter a header's nonce, and `verify` says `false` with the reason. The live run of exactly those cases is [igneum.network/verify/test.html](https://igneum.network/verify/test.html).
|
||||
|
||||
## The data
|
||||
|
||||
`GET /api/checkpoint` returns the latest certified checkpoint: the certificate as carried in a block, the voter list with public keys and weights, and the selected-chain headers from the previous lock. `?source=test` returns the finality test network's instead. Libraries, pinned: BLAKE2b from `@noble/hashes` 2.4.0 and BLS12-381 from `@noble/curves` 2.4.0, pure JavaScript.
|
||||
|
||||
## From a node
|
||||
|
||||
The same certificate is in the block that carries it, and `igneum_getProofRecords` returns a block's records. A light client that reads blocks from a node instead of the site's API verifies the same way; `core.js` has no dependency on the site.
|
||||
42
docs/contracts/sepolia.json
Normal file
42
docs/contracts/sepolia.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"network": "ethereum-sepolia",
|
||||
"chain_id": 11155111,
|
||||
"note": "The Igneum light-client bridge primitive: a verifier for Devnet 3 finality certificates and Ethereum account proofs. Devnet 3, test tokens, no value; Sepolia, test ether, no value. What it proves and what it does not: docs/bridge/light-client-bridge.md.",
|
||||
"rpc": "https://ethereum-sepolia-rpc.publicnode.com",
|
||||
"deployed_at": "2026-10-08T12:36:00Z",
|
||||
"deployer": "0x0C896A191D6b76c37d704454b35B2D61276b7471",
|
||||
"source": "contracts/bridge (Foundry, solc 0.8.28, evm_version osaka, via-IR, optimizer 200 runs)",
|
||||
"contracts": {
|
||||
"IgneumCertificateVerifier": {
|
||||
"address": "0xAf74f3F512081291D663Bb1d6b6d37E99e37D744",
|
||||
"create_tx": "0x55351cbbccda0f78311c22feb1174d99c5d8d9fe3488cb60ff8656f65007e079",
|
||||
"create_block": 11869731,
|
||||
"igneum_chain_id": "igneum-devnet-3",
|
||||
"table": {
|
||||
"tx": "0x6ec1045dbc0abe981944e9e15987089d3f0cdc2e8e467f688b7b0c63e907b26b",
|
||||
"block": 11869732,
|
||||
"index": 2127,
|
||||
"voters": 29,
|
||||
"total_weight": 7164,
|
||||
"table_id": "0xabfcc2bc54ca92ec506beee8a44dced17f15cf1e7c518a6221bf2819b0d1cbd6",
|
||||
"read_from": "igneum_getFinalityWeights on a Devnet 3 node at checkpoint index 2127 (hash 0xcb21b52c\u2026), 12:1x UTC 8 October 2026"
|
||||
},
|
||||
"final_checkpoints": [
|
||||
{
|
||||
"index": 2127,
|
||||
"checkpoint": "0xcb21b52c18654542e7e66af82898313282fd6881e44d01c448d3ba2bd1abd544",
|
||||
"tx": "0x569a62c155f2273bc2167afc137bc9a44bfe522bf21f7554500c2045add444fc",
|
||||
"block": 11869773,
|
||||
"gas_used": 765514,
|
||||
"signers": 17,
|
||||
"signed_weight_under_table": 4833,
|
||||
"total_weight": 7164,
|
||||
"source": "igneum.network/api/checkpoint?index=2127 (dn3_live_certificates), the bytes the chain carried; verified by eth_call before the send (true, 4833, 7164)"
|
||||
}
|
||||
],
|
||||
"interface": "IIgneumCertificateVerifier in contracts/bridge/src/IgneumCertificateVerifier.sol: chainId(), tableId(), verifyCertificate(uint64 index, bytes32 checkpoint, bytes bitmap, bytes signature) view returns (bool ok, uint256 signedWeight, uint256 totalWeight), submitCertificate(...), finalCheckpoint(uint64) view returns (bytes32), isFinal(bytes32) view returns (bool), verifyAccount(bytes32 stateRoot, address account, bytes[] proof) pure returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash)"
|
||||
}
|
||||
},
|
||||
"first_deploy_note": "A first creation at 0xD7dd375E14F92A4CE4782040325189e6d6E394b6 (tx 0x4db10565\u2026, block 11869633) ran out of gas at Foundry's Prague-spec estimate of 3,323,884; Sepolia runs Osaka pricing (EIP-7883 modexp), so the test EVM and the deploy now use osaka and the RPC's own estimate. That address holds no code.",
|
||||
"tests": "contracts/bridge/test/Verifier.t.sol: 9 of 9 green on build-3 (Foundry, osaka), 12:3x UTC 8 October 2026; the live contract verified and recorded Devnet 3 checkpoint 2127 at 12:5x UTC"
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml`
|
|||
| 15 | Every block is proven, with the proof landing within about a minute at launch | Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate | implemented | repo `d7e1f89` (GPU proof), `e01a3cc`, `292e800`, `eedd136` (`proving/igneum-prove`: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6 | `proving/windows-wsl2` (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; `igneum-prove-host --mode block` on `proving/fixtures/`; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards" | First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture `block-78-increment` (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in `docs/benchmarks/proving-e2e.md`. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on PC 2 in 34 s, verified on the Mac in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind `proving_v1_activation_daa` (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one | none yet |
|
||||
| 16 | A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves) | Litepaper Proving ("The proving budget"); roadmap gate 2 | designed | spec 5.1 (Target), 7.6 (`S_p` provisional, 7,500,000 pgas = `B_p` / 4) | `PROVE-SHARD.bat` on the RTX 5090 (pending); the end-to-end standard in `docs/benchmarks/proving-e2e.md`; bench-log "proving: devnet v4 shards" | Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional `S_p` is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card | none yet |
|
||||
| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/cryptanalysis/in-house-pass.md` (the internal adversarial pass) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026). | none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), whose floor reading is in (measured, 8 October 2026; ledger AP-F8-1 and AP-F8-6): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test, and no outside review has run yet |
|
||||
| 18 | The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet |
|
||||
| 18 | The chip resistance measurements: the program is latency-bound (dependent reads spread over the whole dataset), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache; measured 8 October 2026: the distinct-index floor holds at 0.995 on every accepted program, about half of epochs carry one load site with a biased address bit at the era's stride rotation, priced at about 1.6 percent of a hash's reads to a chip storing half the dataset and nothing to one storing all of it (`docs/analysis/class-v6/family-gate.md`, lane D; adv-cache-2's `report-chained-cache-2.md` section 2.3 on its branch; ledger AP-F8-7) | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet |
|
||||
| 19 | The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors | Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page | tested by the team | ca2-mixer 1ab8b21 (`tests/mixer.rs`, `tests/scratch.rs`), ca2-era 78c0ee4, ca2-soundness a465881 (`docs/analysis/scratch-soundness.md`), `igneum-pow/tests/packs.rs` | The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card | Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (PC 1 job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing) | none yet |
|
||||
| 20 | No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%) | Homepage stats and Economics tiles; litepaper Supply, Economics | implemented | repo `6ac80a3`; fork "igneum-node devnet v0"; `consensus/core/src/igneum.rs`, `coinbase.rs` | `cargo test -p kaspa-consensus-core igneum` (8 pass: subsidy table, ramp, split, cap) and `cargo test -p kaspa-consensus coinbase` (8 pass); `igneum-miner inspect 40`; bench-log "igneum-node devnet v0" | Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the `igneum-proving-pool-v0` output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened | none yet |
|
||||
| 21 | The proving pool's 20% reaches shard provers and aggregators | Litepaper Economics; homepage "20% provers" | tested by the team | spec 5.3; `proving/igneum-prove` carries the prover's payout address in every shard proof (ledger P12) | None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (`proving.rs shard_payouts`, the carrying segment pays the first valid record per shard its part of the segment's pool credit) | The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (`sim/economy`, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to PC 2's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid") | none yet |
|
||||
|
|
|
|||
|
|
@ -706,7 +706,7 @@ Evidence: litepaper "For miners", hardware paragraph. Wording: overclaims list,
|
|||
### C2. vs Monero: "no chip in seven years" is not proof
|
||||
"Absence of a public RandomX ASIC is not evidence one cannot exist. Monero is also a small prize."
|
||||
|
||||
Status: Conceded, stated; reopened as conceded (7 October 2026, morning, X36): the X9 never shipped, so Monero's record is again seven years without a shipped chip, and the concession stands as first written; the litepaper says so in the same sentences.
|
||||
Status: Conceded, stated; corrected (8 October 2026, lane A's history): Monero's record is about seven years with one shipped chip, the Antminer X5 at 1.46x per joule over a desktop CPU, not seven years without one; the concession stands and the litepaper's sentences say so (`docs/analysis/class-v6/history.md` 2.3). Was: Conceded, stated; reopened as conceded (7 October 2026, morning, X36): the X9 never shipped, so Monero's record is again seven years without a shipped chip, and the concession stands as first written; the litepaper says so in the same sentences.
|
||||
|
||||
Status: Conceded, stated (7 October 2026, morning): the one-screen home page is back on the owner's word, so this row is stated on `site/litepaper.html` only; the sentence there is unchanged and the text check lists it under the litepaper.
|
||||
|
||||
|
|
@ -2298,7 +2298,7 @@ Evidence: `site/litepaper.html`; `docs/plans/testnet-go.md`; X31, X32.
|
|||
### X34. RandomX described as chip-free
|
||||
"The home page said the random program 'has kept chips off Monero since 2019', the litepaper said Monero ran on RandomX 'with no chip publicly shipped' and spoke of 'Monero's seven years without a public chip'. Bitmain's Antminer X9, a RandomX chip, ships from July 2026 (1 MH/s at 2,472 W, about USD 5,600; monero-project/monero issue 10270), and RandomX 2.0 shipped on 25 March 2026. Every sentence that said or implied RandomX is chip-free, or that Monero's approach has held, was wrong."
|
||||
|
||||
Status: Fixed, stated; corrected (7 October 2026, morning, X36): the X9 never shipped. Bitmain opened pre-orders on 26 December 2025 and withdrew the product in mid-May 2026 before any unit was delivered; every sentence below that had it shipping now states that, and RandomX stands as a technique no chip has yet shipped against. The sentences in this row are the history.
|
||||
Status: Fixed, stated; corrected again (8 October 2026, lane A's history, `docs/analysis/class-v6/history.md` 2.3): one chip did ship against RandomX, Bitmain's Antminer X5 (announced 27 August 2023, shipped September 2023), a board of RISC-V chips at 1.46x per joule over a Ryzen 9 7950X, on silicon SChernykh believes mined privately from about 2021; RandomX v2 was released on 25 March 2026 with its mainnet activation pending (PR 10038); the X9 was withdrawn in mid-May 2026 with zero units. Every served sentence that said "no chip shipped" or "seven years without a shipped chip" now carries the X5 and the v2 release (litepaper precedents row, the chip-model paragraph, the vs RandomX section and its track-record row; /claims and /randomx follow from it); the X36 sentence on the X9 stands. Was: Fixed, stated; corrected (7 October 2026, morning, X36): the X9 never shipped. Bitmain opened pre-orders on 26 December 2025 and withdrew the product in mid-May 2026 before any unit was delivered; every sentence below that had it shipping now states that, and RandomX stands as a technique no chip has yet shipped against. The sentences in this row are the history.
|
||||
|
||||
Status: Fixed, stated (7 October 2026, morning): the one-screen home page carries no RandomX sentence, so the corrected wording stands on `site/litepaper.html` (four sentences and the table row); the text check lists them there.
|
||||
|
||||
|
|
@ -2528,6 +2528,15 @@ Evidence: `docs/analysis/cryptanalysis/report-acceptance-rule-3.md` sections 6.2
|
|||
|
||||
The three genesis fields of `docs/analysis/mission/mission.md` section 2.8, built on the node fork branch `genesis-forward` (from release-0.3.19-node dc141409) and the repo branch `genesis-forward`; the design and the gates in `docs/design/genesis-forward.md`. Every switch is never on the devnet (its digest c562d70e... does not move); the testnet genesis sets all three (the testnet lane re-pins and re-digests).
|
||||
|
||||
### AP-F8-7. The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit
|
||||
"The served text says every hash is a chain of random reads over the dataset. Measured at the acceptance rule's own 2^20 sample over 4,900 drawn eras (lane D's family harness, 8 October 2026) and in adv-cache-2's drawn-program reading the night before: the reads are spread over the whole dataset and the distinct-index floor holds at 0.995 on every accepted program, but 52 to 58 percent of accepted programs in every stratum carry one load site whose address bit R (the era's stride rotation), R+1 or R+2 is biased over 6 sigma, a third over 100 sigma, the worst z 1,024: a product's bit 0 at P = 1/4 landing on an address bit."
|
||||
|
||||
Status: Open, priced: 1.6 percent at f = 1/2, nothing at f = 1; the served sentence corrected 8 October 2026 (the site audit lane, by main's word): the litepaper's lead reads "dependent reads spread over a multi-gigabyte dataset", the "chain of random reads" sentence carries the measured clause after it, evidence row 18 states the measurement with its sources. The disposition is class v6 layer 1's rule: fold the product's low bits before the rotation so no era lands a biased bit on an address bit, with the bias test as its guard (`docs/analysis/class-v6/family-gate.md`).
|
||||
|
||||
Answer: Correct as a measurement and bounded as a gain. The favoured half of one site's window serves 75 instead of 50 percent of that site's reads, 25 percent of 1/16 of a hash's reads, about 1.6 percent, to a chip storing half the dataset; a chip storing all of it gains nothing (the f = 1 verdict unchanged, and the partial store already costs 1.26x the ops). The sentence that said "random" now says what was measured.
|
||||
|
||||
Evidence: `docs/analysis/class-v6/family-gate.md` (lane D, the index-bit bias read, 8 October 2026); adv-cache-2's `docs/analysis/cryptanalysis/report-chained-cache-2.md` section 2.3 (branch adv-cache-2); `site/litepaper.html` Mining; `docs/evidence.md` row 18.
|
||||
|
||||
### GF1. A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point
|
||||
"When a quantum computer comes, every BLS vote key is forged and the chain has no way to change the scheme without a fork of the kind you say you never need."
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate check fails when the two drift. One row per item: the claim or criticism, its status, what was done, and the evidence. Internal identifiers, times of day and team-member names are left out on purpose; the full ledger is published with the repository.
|
||||
|
||||
193 items. By status: Conceded, stated 52; Fixed 31; Decided 22; Fixed on a branch, pending merge 14; Answered by design 9; Answered with evidence 6; Fixed, stated 4; Closed by rule 3; Open 3; Spec fixed 2; Answered by design, with a correction to our own text 1; Answered with evidence, stated 1; Answered by design for finality, Conceded for the lottery 1; Conceded, implemented, stated 1; Rule implemented and measured; launch month simulated 1; Answered by design, with the concession stated 1; Conceded, stated in the litepaper and the design doc 1; Answered with evidence at 1 block/s 1; Conceded, stated in the simulation report 1; Answered by design, with the dependency conceded. Update 7… 1; Conceded, stated in the litepaper, with the dial explained 1; Closed by spec 1; Conceded by decision, stated in the design doc 1; Answered by design, with the founder's edge conceded 1; Answered by design, with a metrics caveat 1; Closed by removal, 3 October 2026 1; Conceded, stated in the litepaper 1; Conceded, stated in the design doc 1; Measured on the live node line, and the overlay does NOT… 1; Conceded, stated in the simulation 1; Conceded in part, labelled, stated 1; Fixed in the node 1; Answered with evidence for the largest body the rules allow 1; Fixed in the proving code 1; Fixed in the spec 1; Rule fixed 1; Rule written 1; Fixed, logged 1; Answered with evidence for the test half 1; Fixed in the node and shipped, rule not yet activated on… 1; Simulation half run 1; Answered with evidence for all four 1; Written 1; Designed 1; Fixed and confirmed 1; Rolled out 1; Conceded by decision 1; Conceded, scheduled, stated 1; Conceded, contained by rule, stated 1; Fixed on a branch and verified locally 1; Answered with evidence and stated 1; Answered with evidence for PC 2 1; Answered by design and with evidence 1; Fixed, stated; restated 1; Fixed, stated; restated further 1; Fixed in part, finding bounded, stated 1; Fixed as a genesis lever, measurement owed 1.
|
||||
194 items. By status: Conceded, stated 52; Fixed 31; Decided 22; Fixed on a branch, pending merge 14; Answered by design 9; Answered with evidence 6; Fixed, stated 4; Closed by rule 3; Open 3; Spec fixed 2; Answered by design, with a correction to our own text 1; Answered with evidence, stated 1; Answered by design for finality, Conceded for the lottery 1; Conceded, implemented, stated 1; Rule implemented and measured; launch month simulated 1; Answered by design, with the concession stated 1; Conceded, stated in the litepaper and the design doc 1; Answered with evidence at 1 block/s 1; Conceded, stated in the simulation report 1; Answered by design, with the dependency conceded. Update 7… 1; Conceded, stated in the litepaper, with the dial explained 1; Closed by spec 1; Conceded by decision, stated in the design doc 1; Answered by design, with the founder's edge conceded 1; Answered by design, with a metrics caveat 1; Closed by removal, 3 October 2026 1; Conceded, stated in the litepaper 1; Conceded, stated in the design doc 1; Measured on the live node line, and the overlay does NOT… 1; Conceded, stated in the simulation 1; Conceded in part, labelled, stated 1; Fixed in the node 1; Answered with evidence for the largest body the rules allow 1; Fixed in the proving code 1; Fixed in the spec 1; Rule fixed 1; Rule written 1; Fixed, logged 1; Answered with evidence for the test half 1; Fixed in the node and shipped, rule not yet activated on… 1; Simulation half run 1; Answered with evidence for all four 1; Written 1; Designed 1; Fixed and confirmed 1; Rolled out 1; Conceded by decision 1; Conceded, scheduled, stated 1; Conceded, contained by rule, stated 1; Fixed on a branch and verified locally 1; Answered with evidence and stated 1; Answered with evidence for PC 2 1; Answered by design and with evidence 1; Fixed, stated; restated 1; Fixed, stated; restated further 1; Fixed in part, finding bounded, stated 1; Open, priced 1; Fixed as a genesis lever, measurement owed 1.
|
||||
|
||||
| Id | Claim or criticism | Status | What was done | Evidence |
|
||||
|---|---|---|---|---|
|
||||
|
|
@ -195,6 +195,7 @@ Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate
|
|||
| AP-F8-1 | A load whose source was last written by `or`, `mul` or `mulhi` makes a cross-hash hot set | Fixed in part, finding bounded, stated | Class v4 sub-version 3 (igneum-pow a commit, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under… | [docs/analysis/ca3-v4-uniform.md](../docs/analysis/ca3-v4-uniform.md) |
|
||||
| AP-F8-4 | The program id's derivation text omitted generator 4's sub-version suffix (interoperability, documentation; no object change) | Fixed | The id and its printed derivation come from one byte recipe (`generator::IdRecipe`, `program_id_recipe`, `program_id_class_recipe`, `Program::program_id_derivation`), so the two cannot drift; the emitter prints that… | [igneum-pow/tests/derivation.rs](../igneum-pow/tests/derivation.rs) |
|
||||
| AP-F8-5 | The public specification did not describe the shipped acceptance rule (documentary; no object change) | Spec fixed | Sections 1.4.3 and 1.4.6 of `docs/spec/01-lottery-hash.md` rewritten to the shipped rule at igneum-pow a commit with every constant named and every order of operations stated (1.4.3: the two per-register states of the… | [docs/analysis/cryptanalysis/report-acceptance-rule-3.md](../docs/analysis/cryptanalysis/report-acceptance-rule-3.md) |
|
||||
| AP-F8-7 | The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit | Open, priced | 1.6 percent at f = 1/2, nothing at f = 1; the served sentence corrected 8 October 2026 (the site the team, by the team's word): the litepaper's lead reads "dependent reads spread over a multi-gigabyte dataset", the… | [docs/analysis/class-v6/family-gate.md](../docs/analysis/class-v6/family-gate.md) |
|
||||
| GF1 | A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point | Fixed | The byte costs nothing now and a fork later. | none named |
|
||||
| GF2 | A vote key cannot move: a miner who changes keys re-earns 30 days of weight, and so does the post-quantum migration | Fixed | The successor inherits the window, not a fresh one, so a key rotation costs no weight and the migration of GF1 is one item per key. | none named |
|
||||
| GF3 | A 256 MB on-chip cache makes the lottery hash 2 to 3x cheaper for the card that has it, and the cache size is a constant | Fixed as a genesis lever, measurement owed | Consumer LLC is 96 to 128 MB today and datacentre 256 MB (`chip-model-v3`, approximate), so the shortcut is a datacentre card's today and a consumer card's in a generation or two. | none named |
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -127,3 +127,21 @@ site. None of this is in the repo; the stats API of this branch is the network s
|
|||
price when ordered.
|
||||
- `EXPLORER_EVM_RPC` on Vercel: no public devnet EVM RPC exists, so balances show "no EVM RPC configured" on the devnet
|
||||
deployment; the testnet's `https://rpc.testnet.igneum.network` is the value for the testnet.
|
||||
|
||||
## 8. Devnet 3 explorer (8 October 2026, the explorer lane; the founder's order of 11:00 UK: a public explorer the same day)
|
||||
|
||||
What serves, all at igneum.network (the host explorer.igneum.network is a CNAME to the same Vercel project with a root rewrite to /explorer):
|
||||
|
||||
| Page | What it shows | Data |
|
||||
|---|---|---|
|
||||
| `/explorer` | the Devnet 3 strip (status, height, DAA, hash rate, chain rate, finality, program class, proving), the DAG picture (newest 150 blocks, one lane per miner, parents drawn, lock and paid marks), latest blocks (class, shards paid, final), latest transactions, the proving summary, the API list | `/api/explorer?stats=1`, `?dag=150`, `?blocks=50`, `?txs=30`, `?proving=1` |
|
||||
| `/block/<hash>` or `/block/<number>` | header, parents, children, mergeset, coinbase, the EVM transactions it executed (from the indexer), the shard plan with each shard's state and the node's verdict, the checkpoint and certificate, the lock that covers it, the class; **the verified badge**: for a block under a lock the browser fetches `/api/checkpoint?index=N` and runs `site/verify/core.js` (header hashes recomputed, BLS keys aggregated, the signature checked over the weight rule) and the badge reads "verified under lock N in this browser" or the failure reason | `?block=`, `?height=`, `/api/checkpoint?index=` |
|
||||
| `/tx/<hash>` | status, value, fee, gas, nonce, type, input, the receipt's Igneum section (miner tip, both burns, pgas, app share, including block and miner), the executing block's lock and shard state, the logs | `?tx=` |
|
||||
| `/address/<addr>` | balance, nonce, code (contract or account), sent and received counts, the transactions of the last 7 days, the blocks mined and what they earned | `?address=` (`&before=<number>` pages the transactions) |
|
||||
| `/proving` | the node's proving state, the newest 60 chain blocks with their shards by state and median lag, the provers of 24 h with payouts, the block-to-paid latency of the last hour (p50, p90) and the 24-hour totals by state | `?proving=1` |
|
||||
|
||||
The indexer: `tools/observer/explorer-indexer.mjs`, the observer's sibling on build-1 (unit `igneum-explorer-dn3`, User build, the same env file, `LIVE_TABLE_PREFIX=dn3_`, `IGNEUM_EVM_RPC` on loopback). It reads `eth_getBlockByNumber` with transactions and `eth_getBlockReceipts` per chain block, refreshes `eth_getBalance`, `eth_getTransactionCount` and `eth_getCode` for every address a block touches and for the observer's miners of the last 10 minutes, and keeps `igneum_getNodeInfo` (the class floors and every activation) in `dn3_explorer_state`. Tables `dn3_live_txs`, `dn3_live_accounts`, `dn3_explorer_blocks`, `dn3_explorer_state`; 7 days of transactions. Measured 10:04 to 10:07 UTC: 26,847 chain blocks and 71,218 transactions from genesis in 3 minutes; steady state 0.4 chain blocks per second at 16 percent of one core. Two classes met the same morning, each with its guard: the unit's first start read the first devnet's node for 25 s (the env file's `IGNEUM_EVM_RPC`), so the indexer now refuses any node whose `igneum_getNodeInfo.network` is not `EXPLORER_NETWORK`; and the observer node's restart at 10:21 UTC on 0324-5b673577 re-executed from block 0, so a tip below the indexed number re-reads from the tip and the API settles `chain_now` against the highest number ever indexed, not the current tip.
|
||||
|
||||
Read against the EVM: a block the observer called a chain block whose number the EVM later gave to another block (tip reorgs on Devnet 3 run to depth 18, `igneum_getBudgets.deepestReorg` at 10:0x UTC) reads "replaced" on the list and the block page. The table prefix default of `/api/explorer`, `/api/stats`, `/api/supply` and `/api/checkpoint` moved to `dn3_` (the live deploy had served the first devnet on those four while `/api/live` served Devnet 3).
|
||||
|
||||
Not yet: the STARK itself is not re-run in the browser (the node's verdict is shown as the node's; the explorer-verify branch's binding check of proof bytes to records is not merged); `eth_sendRawTransaction` and live balances from the public RPC (`rpc.devnet.igneum.network`, up since 11:08 UK) are not wired into the pages (`EXPLORER_EVM_RPC` on the deployment switches the balance read to live); a checkpoints list page; the program id per epoch (no RPC); internal transactions (no tracing RPC).
|
||||
|
|
|
|||
171
infra/build-server/faucet/faucet.mjs
Normal file
171
infra/build-server/faucet/faucet.mjs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// The Devnet 3 faucet (the builder programme, 8 October 2026). A Node service behind Caddy at faucet.igneum.network on a build box:
|
||||
// POST /api/faucet {address} sends AMOUNT_IGN of Devnet 3 coin to the address and answers {ok, tx, amount, chainId, to}
|
||||
// GET /api/faucet the state: network, chain id, amount, the faucet's balance in IGN, sends in the last 24 hours
|
||||
// Rules, enforced here and nowhere else: one send per address per WINDOW_HOURS, one per connection (IP) per WINDOW_HOURS,
|
||||
// DAILY_MAX sends per WINDOW_HOURS in total, and AMOUNT_IGN under the HARD_CAP_IGN the fleet lane set on the faucet's own sends
|
||||
// (the service refuses to start otherwise). Sends are serialised so the nonce is read once per send. The record of sends is an
|
||||
// append-only JSONL file next to the service (FAUCET_STATE, default ./grants.jsonl); the window is read from it at start.
|
||||
// Environment (EnvironmentFile=/srv/faucet/env on the box, mode 600; the key is nowhere else): FAUCET_KEY (0x + 64 hex),
|
||||
// FAUCET_RPC (the Devnet 3 node by address, never chosen by chain id: Devnet 3 answers the same id as the shared devnet),
|
||||
// FAUCET_CHAIN_ID (4463), FAUCET_PORT (8790), FAUCET_ORIGIN (the page's origin for CORS, https://igneum.network).
|
||||
// Signing: site/lib/eth.mjs, copied next to this file by faucet.sh (zero dependencies).
|
||||
// node faucet.mjs the service
|
||||
// node faucet.mjs --self-test the limiter and the handler against a fake node: known-failed cases first
|
||||
import { createServer } from 'node:http';
|
||||
import { readFileSync, appendFileSync, existsSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const { signTransaction, addressOf, isAddress, toWei } = await import(join(here, 'eth.mjs'));
|
||||
|
||||
export const AMOUNT_IGN = 10;
|
||||
export const HARD_CAP_IGN = 100; // the fleet lane's cap on the faucet's own sends (main's rule, 8 October 2026)
|
||||
export const WINDOW_HOURS = 24;
|
||||
export const DAILY_MAX = 500;
|
||||
const WINDOW_MS = WINDOW_HOURS * 3600 * 1000;
|
||||
|
||||
export function limiter(now = () => Date.now()) {
|
||||
// in memory, fed from the JSONL at start; each row {t, address, ip, tx}
|
||||
const rows = [];
|
||||
const prune = () => { const cut = now() - WINDOW_MS; while (rows.length && rows[0].t < cut) rows.shift(); };
|
||||
return {
|
||||
load(row) { rows.push(row); },
|
||||
check(address, ip) {
|
||||
prune();
|
||||
if (rows.some(r => r.address === address)) return `This address had its ${AMOUNT_IGN} IGN in the last ${WINDOW_HOURS} hours. Come back tomorrow.`;
|
||||
if (rows.some(r => r.ip === ip)) return `This connection had its ${AMOUNT_IGN} IGN in the last ${WINDOW_HOURS} hours. Come back tomorrow.`;
|
||||
if (rows.length >= DAILY_MAX) return `The faucet has sent its ${DAILY_MAX} for today. Come back tomorrow.`;
|
||||
return null;
|
||||
},
|
||||
add(row) { rows.push(row); },
|
||||
drop(row) { const i = rows.indexOf(row); if (i >= 0) rows.splice(i, 1); },
|
||||
count() { prune(); return rows.length; },
|
||||
};
|
||||
}
|
||||
|
||||
export function rpcClient(url, fetchImpl = fetch) {
|
||||
let id = 0;
|
||||
return async (method, params = []) => {
|
||||
const r = await fetchImpl(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: ++id, method, params }) });
|
||||
const j = await r.json();
|
||||
if (j.error) throw new Error(`${method}: ${j.error.message || JSON.stringify(j.error)}`);
|
||||
return j.result;
|
||||
};
|
||||
}
|
||||
|
||||
const ignOf = wei => (Number(BigInt(wei) / 10n ** 12n) / 1e6).toFixed(6);
|
||||
|
||||
export function createHandler({ env = process.env, rpc, lim, record = () => {}, now = () => Date.now() } = {}) {
|
||||
const key = env.FAUCET_KEY || '', rpcUrl = env.FAUCET_RPC || '';
|
||||
const chainId = Number(env.FAUCET_CHAIN_ID || 4463);
|
||||
const origin = env.FAUCET_ORIGIN || 'https://igneum.network';
|
||||
if (AMOUNT_IGN > HARD_CAP_IGN) throw new Error(`AMOUNT_IGN ${AMOUNT_IGN} is over the ${HARD_CAP_IGN} IGN cap`);
|
||||
if (!/^0x[0-9a-fA-F]{64}$/.test(key) || !rpcUrl) throw new Error('FAUCET_KEY (0x + 64 hex) and FAUCET_RPC are required');
|
||||
const from = addressOf(key);
|
||||
rpc = rpc || rpcClient(rpcUrl);
|
||||
lim = lim || limiter(now);
|
||||
let chain = Promise.resolve(); // sends one after another: one nonce read per send
|
||||
const json = (res, status, body) => { res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' }); res.end(JSON.stringify(body)); };
|
||||
const cors = (req, res) => {
|
||||
const o = req.headers.origin || '';
|
||||
const allowed = o === origin || /^http:\/\/(127\.0\.0\.1|localhost):\d+$/.test(o);
|
||||
res.setHeader('Access-Control-Allow-Origin', allowed ? o : origin);
|
||||
res.setHeader('Vary', 'Origin');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||
};
|
||||
const clientIp = req => { const fwd = req.headers['x-forwarded-for']; const first = (Array.isArray(fwd) ? fwd[0] : fwd || '').split(',')[0].trim(); return first || String(req.headers['x-real-ip'] || req.socket?.remoteAddress || '').trim() || 'unknown'; };
|
||||
const readBody = req => new Promise((resolve, reject) => { const c = []; let n = 0; req.on('data', d => { n += d.length; if (n > 4096) { reject(new Error('too large')); req.destroy(); } else c.push(d); }); req.on('end', () => { try { resolve(JSON.parse(Buffer.concat(c).toString('utf8') || '{}')); } catch (e) { reject(e); } }); req.on('error', reject); });
|
||||
return async function handler(req, res) {
|
||||
cors(req, res);
|
||||
const path = (req.url || '/').split('?')[0];
|
||||
if (req.method === 'OPTIONS') { res.writeHead(204); return res.end(); }
|
||||
if (path !== '/api/faucet' && path !== '/api/faucet/') return json(res, 404, { ok: false, error: 'not found' });
|
||||
if (req.method === 'GET') {
|
||||
let balance = null;
|
||||
try { balance = ignOf(await rpc('eth_getBalance', [from, 'latest'])); } catch { /* the node is the status */ }
|
||||
return json(res, 200, { ok: true, network: 'igneum-devnet-3', chainId, amount: String(AMOUNT_IGN), window_hours: WINDOW_HOURS, daily_max: DAILY_MAX, address: from, balance_ign: balance, sends_24h: lim.count(), funded: balance !== null && Number(balance) >= AMOUNT_IGN });
|
||||
}
|
||||
if (req.method !== 'POST') { res.setHeader('Allow', 'GET, POST, OPTIONS'); return json(res, 405, { ok: false, error: 'method not allowed' }); }
|
||||
let body;
|
||||
try { body = await readBody(req); } catch { return json(res, 400, { ok: false, error: 'bad json' }); }
|
||||
const address = String(body.address || '').trim();
|
||||
if (!isAddress(address)) return json(res, 400, { ok: false, error: 'That is not an address. It is 0x followed by 40 hex characters.' });
|
||||
const to = address.toLowerCase(), ip = clientIp(req);
|
||||
const refused = lim.check(to, ip);
|
||||
if (refused) return json(res, 429, { ok: false, error: refused });
|
||||
const row = { t: now(), address: to, ip, tx: null };
|
||||
lim.add(row); // reserved before the send, so two asks in the same second cannot both pass
|
||||
const result = chain.then(async () => {
|
||||
const [nonceHex, block, tipHex, balHex] = await Promise.all([
|
||||
rpc('eth_getTransactionCount', [from, 'pending']),
|
||||
rpc('eth_getBlockByNumber', ['latest', false]),
|
||||
rpc('eth_maxPriorityFeePerGas').catch(() => '0x3b9aca00'),
|
||||
rpc('eth_getBalance', [from, 'latest']),
|
||||
]);
|
||||
const value = toWei(AMOUNT_IGN);
|
||||
if (BigInt(balHex) < value * 2n) throw Object.assign(new Error('The faucet is empty right now. It is being refilled; try again in an hour.'), { status: 503 });
|
||||
const baseFee = BigInt(block?.baseFeePerGas || '0x3b9aca00'), tip = BigInt(tipHex || '0x3b9aca00');
|
||||
let gas = 21000n;
|
||||
try { gas = BigInt(await rpc('eth_estimateGas', [{ from, to, value: '0x' + value.toString(16) }])); } catch { /* the plain-transfer default */ }
|
||||
const tx = { chainId, nonce: BigInt(nonceHex), maxPriorityFeePerGas: tip, maxFeePerGas: baseFee * 2n + tip, gas, to, value, data: '0x' };
|
||||
const signed = signTransaction(tx, key);
|
||||
return rpc('eth_sendRawTransaction', [signed.raw]);
|
||||
});
|
||||
chain = result.catch(() => {});
|
||||
try {
|
||||
const hash = await result;
|
||||
row.tx = hash; record(row);
|
||||
return json(res, 200, { ok: true, tx: hash, amount: String(AMOUNT_IGN), chainId, to });
|
||||
} catch (e) {
|
||||
lim.drop(row);
|
||||
return json(res, e.status || 502, { ok: false, error: e.status ? e.message : `The node did not take the transaction: ${String(e.message || e).slice(0, 200)}` });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (process.argv.includes('--self-test')) {
|
||||
// known-failed first: a fake node that answers every read and refuses every send must leave the limiter empty and answer 502
|
||||
let t = 1_000_000; const now = () => t;
|
||||
const fakeNode = (sendOk = true) => async (m, p) => ({
|
||||
eth_getTransactionCount: '0x1', eth_getBlockByNumber: { baseFeePerGas: '0x174876e800' }, eth_maxPriorityFeePerGas: '0x3b9aca00',
|
||||
eth_getBalance: '0x' + (10n ** 21n).toString(16), eth_estimateGas: '0x5208',
|
||||
eth_sendRawTransaction: sendOk ? '0x' + 'ab'.repeat(32) : (() => { throw new Error('refused'); })(),
|
||||
})[m];
|
||||
const call = async (h, method, body, ip = '1.1.1.1') => new Promise(resolve => {
|
||||
const chunks = body === undefined ? [] : [Buffer.from(JSON.stringify(body))];
|
||||
const req = { method, url: '/api/faucet', headers: { 'x-forwarded-for': ip, origin: 'https://igneum.network' }, socket: {}, on(ev, cb) { if (ev === 'data') for (const c of chunks) cb(c); if (ev === 'end') cb(); return this; } };
|
||||
const res = { h: {}, setHeader(k, v) { this.h[k] = v; }, writeHead(s, hh) { this.status = s; Object.assign(this.h, hh || {}); }, end(b) { resolve({ status: this.status, body: b ? JSON.parse(b) : null }); } };
|
||||
h(req, res);
|
||||
});
|
||||
const env = { FAUCET_KEY: '0x' + '11'.repeat(32), FAUCET_RPC: 'http://fake', FAUCET_CHAIN_ID: '4463' };
|
||||
const A = '0x' + 'a1'.repeat(20), B = '0x' + 'b2'.repeat(20);
|
||||
let fails = 0; const expect = (c, msg) => { if (!c) { console.error('self-test failed: ' + msg); fails++; } };
|
||||
{ const lim = limiter(now); const h = createHandler({ env, rpc: fakeNode(false), lim, now }); const r = await call(h, 'POST', { address: A }); expect(r.status === 502 && lim.count() === 0, `a refused send must answer 502 and reserve nothing (got ${r.status}, ${lim.count()})`); }
|
||||
{ const lim = limiter(now); const h = createHandler({ env, rpc: fakeNode(), lim, now }); const r = await call(h, 'POST', { address: 'not-an-address' }); expect(r.status === 400, 'a bad address must answer 400'); }
|
||||
{ const lim = limiter(now); const recorded = []; const h = createHandler({ env, rpc: fakeNode(), lim, record: r => recorded.push(r), now });
|
||||
const r1 = await call(h, 'POST', { address: A }); expect(r1.status === 200 && r1.body.ok && r1.body.tx.startsWith('0x'), 'the first ask sends');
|
||||
expect(recorded.length === 1 && recorded[0].tx === r1.body.tx, 'the send is recorded with its hash');
|
||||
const r2 = await call(h, 'POST', { address: A }); expect(r2.status === 429 && /address/.test(r2.body.error), 'the same address inside the window is refused');
|
||||
const r3 = await call(h, 'POST', { address: B }); expect(r3.status === 429 && /connection/.test(r3.body.error), 'the same connection inside the window is refused');
|
||||
const r4 = await call(h, 'POST', { address: B }, '2.2.2.2'); expect(r4.status === 200, 'another address from another connection sends');
|
||||
t += WINDOW_MS + 1; const r5 = await call(h, 'POST', { address: A }); expect(r5.status === 200, 'after the window the address sends again');
|
||||
const s = await call(h, 'GET'); expect(s.status === 200 && s.body.network === 'igneum-devnet-3' && s.body.sends_24h === 1 && s.body.funded === true, `the status carries the network and the window count (got ${JSON.stringify(s.body)})`);
|
||||
for (let i = 0; i < DAILY_MAX - 1; i++) lim.add({ t: now(), address: '0x' + String(i).padStart(40, '0'), ip: 'x' + i, tx: '0x' });
|
||||
const r6 = await call(h, 'POST', { address: '0x' + 'c3'.repeat(20) }, '3.3.3.3'); expect(r6.status === 429 && /today/.test(r6.body.error), 'the daily total refuses the next ask'); }
|
||||
{ let threw = false; try { createHandler({ env: { ...env, FAUCET_KEY: 'bad' }, rpc: fakeNode(), now }); } catch { threw = true; } expect(threw, 'a bad key must refuse to start'); }
|
||||
expect(AMOUNT_IGN <= HARD_CAP_IGN, 'the amount is under the cap');
|
||||
if (fails) process.exit(1);
|
||||
console.log(`self-test passed: a refused send reserves nothing (502), a bad address 400, the same address and the same connection are refused inside ${WINDOW_HOURS} h (429), another pair sends, the window expires, the status counts, the ${DAILY_MAX}-a-day total refuses, a bad key refuses to start, ${AMOUNT_IGN} IGN is under the ${HARD_CAP_IGN} IGN cap`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1] && !process.argv.includes('--self-test')) {
|
||||
const STATE = process.env.FAUCET_STATE || join(here, 'grants.jsonl');
|
||||
const lim = limiter();
|
||||
if (existsSync(STATE)) { const cut = Date.now() - WINDOW_MS; for (const l of readFileSync(STATE, 'utf8').split('\n')) { if (!l) continue; try { const r = JSON.parse(l); if (r.t >= cut && r.tx) lim.load(r); } catch { /* a torn line */ } } }
|
||||
const handler = createHandler({ lim, record: row => appendFileSync(STATE, JSON.stringify(row) + '\n') });
|
||||
const port = Number(process.env.FAUCET_PORT || 8790);
|
||||
createServer((req, res) => { handler(req, res).catch(e => { try { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: String(e.message || e).slice(0, 200) })); } catch { /* closed */ } }); }).listen(port, '127.0.0.1', () => console.log(`${new Date().toISOString()} faucet on 127.0.0.1:${port}, ${AMOUNT_IGN} IGN per send, ${lim.count()} sends in the window, from ${addressOf(process.env.FAUCET_KEY)}`));
|
||||
}
|
||||
62
infra/build-server/faucet/faucet.sh
Executable file
62
infra/build-server/faucet/faucet.sh
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env bash
|
||||
# The Devnet 3 faucet on a build box (the builder programme, 8 October 2026). Dry run by default, --go executes.
|
||||
# infra/build-server/faucet/faucet.sh install [--go] copy faucet.mjs and site/lib/eth.mjs to /srv/faucet (the build user's), the unit
|
||||
# to /etc/systemd/system, the Caddy block for faucet.igneum.network (validate, reload),
|
||||
# enable and start the unit, read back GET /api/faucet through the loopback
|
||||
# infra/build-server/faucet/faucet.sh status the unit, the loopback status (balance, sends in the window), the Caddy host
|
||||
# infra/build-server/faucet/faucet.sh self-test node faucet.mjs --self-test on the box
|
||||
# /srv/faucet/env (mode 600, the build user's) is written by hand on the box and never by this script: FAUCET_KEY, FAUCET_RPC
|
||||
# (the Devnet 3 node by address), FAUCET_CHAIN_ID, FAUCET_PORT, FAUCET_ORIGIN. The key is nowhere else.
|
||||
set -euo pipefail
|
||||
HERE=$(cd "$(dirname "$0")" && pwd); ROOT=$(cd "$HERE/../../.." && pwd)
|
||||
KEY="${IGNEUM_BUILD_KEY:-$HOME/.ssh/igneum_ed25519}"; HOST=$(head -1 "${IGNEUM_BUILD_HOST_FILE:-$HOME/.config/igneum/build-server}" | tr -d '[:space:]')
|
||||
IP="${HOST#*@}"
|
||||
SSHB=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=15 "$HOST")
|
||||
SSHR=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=15 "root@$IP")
|
||||
say() { echo "$(TZ=UTC date '+%H:%M:%SZ') faucet: $*" >&2; }
|
||||
mode="${1:-}"; shift || true; GO=0; [ "${1:-}" = --go ] && GO=1
|
||||
FAUCET_HOST="${FAUCET_HOST:-faucet.igneum.network}"; PORT="${FAUCET_PORT:-8790}"
|
||||
caddy_block() { cat <<EOF
|
||||
|
||||
# the Devnet 3 faucet (infra/build-server/faucet, 8 October 2026): one Node service on the loopback, nothing cached
|
||||
$FAUCET_HOST {
|
||||
tls {
|
||||
issuer acme
|
||||
}
|
||||
reverse_proxy 127.0.0.1:$PORT
|
||||
header Cache-Control "no-store"
|
||||
request_body {
|
||||
max_size 16KB
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
case "$mode" in
|
||||
install)
|
||||
[ -s "$ROOT/site/lib/eth.mjs" ] || { say "no site/lib/eth.mjs under $ROOT"; exit 1; }
|
||||
if [ "$GO" = 0 ]; then
|
||||
say "DRY: scp faucet.mjs, site/lib/eth.mjs -> $HOST:/srv/faucet/; igneum-faucet.service -> root@$IP:/etc/systemd/system/; append to /etc/caddy/Caddyfile unless $FAUCET_HOST is there:"; caddy_block; say "DRY: systemctl daemon-reload, enable --now igneum-faucet; curl 127.0.0.1:$PORT/api/faucet"; exit 0
|
||||
fi
|
||||
"${SSHB[@]}" 'test -s /srv/faucet/env' || { say "/srv/faucet/env is missing on the box: write it by hand first (FAUCET_KEY, FAUCET_RPC, FAUCET_CHAIN_ID, FAUCET_PORT, FAUCET_ORIGIN)"; exit 1; }
|
||||
scp -q -i "$KEY" "$HERE/faucet.mjs" "$ROOT/site/lib/eth.mjs" "$HOST:/srv/faucet/"
|
||||
"${SSHB[@]}" 'cd /srv/faucet && node faucet.mjs --self-test' || { say "the self-test failed on the box; nothing started"; exit 1; }
|
||||
scp -q -i "$KEY" "$HERE/igneum-faucet.service" "root@$IP:/etc/systemd/system/igneum-faucet.service"
|
||||
"${SSHR[@]}" bash -s -- "$FAUCET_HOST" "$(caddy_block | base64 | tr -d '\n')" <<'REMOTE'
|
||||
set -euo pipefail; host="$1"; block="$(printf '%s' "$2" | base64 -d)"
|
||||
if ! grep -q "^$host {" /etc/caddy/Caddyfile; then
|
||||
cp /etc/caddy/Caddyfile "/etc/caddy/Caddyfile.bak-$(date -u +%Y%m%d%H%M%S)"
|
||||
printf '%s\n' "$block" >> /etc/caddy/Caddyfile
|
||||
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null
|
||||
systemctl reload caddy; echo "caddy: $host block appended and reloaded"
|
||||
else echo "caddy: $host block already present"; fi
|
||||
systemctl daemon-reload; systemctl enable igneum-faucet >/dev/null 2>&1; systemctl restart igneum-faucet; sleep 3; systemctl is-active igneum-faucet; journalctl -u igneum-faucet --since "-30 s" --no-pager | tail -2 | cut -c1-160
|
||||
REMOTE
|
||||
"${SSHB[@]}" "curl -s -m 10 http://127.0.0.1:$PORT/api/faucet; echo"
|
||||
;;
|
||||
status)
|
||||
"${SSHR[@]}" "systemctl is-active igneum-faucet; journalctl -u igneum-faucet --since '-10 min' --no-pager | tail -5 | cut -c1-160; grep -c '^$FAUCET_HOST {' /etc/caddy/Caddyfile"
|
||||
"${SSHB[@]}" "curl -s -m 10 http://127.0.0.1:$PORT/api/faucet; echo; wc -l /srv/faucet/grants.jsonl 2>/dev/null || echo 'no sends yet'"
|
||||
;;
|
||||
self-test) "${SSHB[@]}" 'cd /srv/faucet && node faucet.mjs --self-test' ;;
|
||||
*) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 2 ;;
|
||||
esac
|
||||
22
infra/build-server/faucet/igneum-faucet.service
Normal file
22
infra/build-server/faucet/igneum-faucet.service
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[Unit]
|
||||
Description=Igneum Devnet 3 faucet (infra/build-server/faucet/faucet.mjs), 127.0.0.1:8790 behind Caddy at faucet.igneum.network
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
User=build
|
||||
Group=build
|
||||
WorkingDirectory=/srv/faucet
|
||||
EnvironmentFile=/srv/faucet/env
|
||||
Environment=FAUCET_STATE=/srv/faucet/grants.jsonl
|
||||
ExecStart=/usr/local/bin/node /srv/faucet/faucet.mjs
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Nice=5
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/srv/faucet
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -60,6 +60,7 @@ main{flex:1}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -77,8 +78,6 @@ main{flex:1}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -89,18 +88,30 @@ main{flex:1}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -112,8 +123,6 @@ main{flex:1}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -122,15 +131,25 @@ main{flex:1}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -220,7 +239,7 @@ main{flex:1}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -235,6 +254,9 @@ main{flex:1}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum address</title>
|
||||
<meta name="description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<title>Igneum Devnet 3 address</title>
|
||||
<meta name="description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<link rel="canonical" href="https://igneum.network/address">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum address">
|
||||
<meta property="og:description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<meta property="og:description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<meta property="og:url" content="https://igneum.network/address">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum address">
|
||||
<meta name="twitter:description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<meta name="twitter:description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -92,6 +92,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -108,6 +114,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -125,30 +132,40 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -160,25 +177,33 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -235,7 +260,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Address</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Explorer</a> · address</div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · address</div>
|
||||
<h1 class="hash" id="title">Address</h1>
|
||||
<div id="chips"></div>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -243,11 +268,19 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div id="body" hidden>
|
||||
<div class="strip">
|
||||
<div class="cell"><div class="k">Balance</div><div class="v" id="a-balance">n/a</div><div class="s" id="a-balance-s">eth_getBalance</div></div>
|
||||
<div class="cell"><div class="k">Nonce</div><div class="v" id="a-nonce">n/a</div><div class="s" id="a-nonce-s">transactions sent from this account</div></div>
|
||||
<div class="cell"><div class="k">Transactions, 7 d</div><div class="v" id="a-txs">0</div><div class="s" id="a-txs-s">sent and received, as indexed</div></div>
|
||||
<div class="cell"><div class="k">Code</div><div class="v" id="a-code">n/a</div><div class="s" id="a-code-s">eth_getCode</div></div>
|
||||
<div class="cell"><div class="k">Blocks, 24 h</div><div class="v" id="a-blocks">0</div><div class="s" id="a-blocks-s"></div></div>
|
||||
<div class="cell"><div class="k">Earned, 24 h</div><div class="v" id="a-earned">0<small>IGN</small></div><div class="s">80% of each blue block's subsidy</div></div>
|
||||
<div class="cell"><div class="k">Last block</div><div class="v" id="a-last">n/a</div><div class="s" id="a-first"></div></div>
|
||||
<div class="cell"><div class="k">Network</div><div class="v">Devnet 3</div><div class="s">chain id 4463, coins have no value</div></div>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Identity</h2></div><dl id="ident"></dl><p class="note">A miner names its EVM payout address in every coinbase (the IGNA tag) beside the coinbase script's own address, so the two forms name the same miner. The vote keys are the finality identities that signed these blocks; a card runs several.</p></div>
|
||||
<div class="card"><div class="viz-head"><h2>Transactions</h2><div class="eyebrow" id="tx-eyebrow">newest 50 of the last 7 days</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Transaction</th><th class="n">Block</th><th>Direction</th><th>Counterparty</th><th class="n">Value</th><th>Status</th><th>Time</th></tr></thead><tbody id="txs"></tbody></table></div>
|
||||
<button class="btn" id="more-tx" type="button" style="margin-top:14px">Older transactions</button>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Blocks mined</h2><div class="eyebrow">newest 50 of the last 24 hours</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Colour</th><th class="n">Subsidy</th><th class="n">Txs</th><th>Time</th></tr></thead><tbody id="blocks"></tbody></table></div>
|
||||
</div>
|
||||
|
|
@ -275,7 +308,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -290,6 +323,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -327,26 +363,43 @@ const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').re
|
|||
const link = h => `<a class="hash" href="/block/${esc(h)}" title="${esc(h)}">${esc(shortHash(h, 10, 6))}</a>`;
|
||||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const a = decodeURIComponent(location.pathname.split('/').pop() || '');
|
||||
let now = 0, oldestTx = 0, me = null;
|
||||
function txRow(t) {
|
||||
const out = me && t.from === me; const cp = out ? t.to : t.from;
|
||||
return `<tr><td><a class="hash" href="/tx/${esc(t.hash)}">${esc(shortHash(t.hash, 10, 6))}</a></td><td class="n"><a href="/block/${esc(t.block_hash)}">${int(t.number)}</a></td><td>${out ? '<span class="chip">out</span>' : '<span class="chip ok">in</span>'}</td><td>${cp ? `<a class="hash" href="/address/${esc(cp)}" title="${esc(cp)}">${esc(shortHash(cp, 8, 6))}</a>` : (t.contract_address ? `<span class="kv">created</span> <a class="hash" href="/address/${esc(t.contract_address)}">${esc(shortHash(t.contract_address, 8, 6))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 4)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td title="${t.ts ? new Date(t.ts).toISOString() : ''}">${t.ts ? rel(now - t.ts) : 'n/a'}</td></tr>`;
|
||||
}
|
||||
async function loadMore() {
|
||||
if (!oldestTx) return;
|
||||
const j = await fetch('/api/explorer?address=' + encodeURIComponent(a) + '&before=' + oldestTx).then(r => r.json());
|
||||
if (!j.ok) return; $('txs').insertAdjacentHTML('beforeend', j.txs.map(txRow).join('')); if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number; else $('more-tx').disabled = true;
|
||||
}
|
||||
$('more-tx').addEventListener('click', () => { loadMore().catch(() => {}); });
|
||||
async function load() {
|
||||
const r = await fetch('/api/explorer?address=' + encodeURIComponent(a)); const j = await r.json();
|
||||
$('title').textContent = a;
|
||||
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; return; }
|
||||
document.title = `Igneum address ${shortHash(a, 8, 6)}`;
|
||||
const now = new Date(j.now).getTime();
|
||||
$('chips').innerHTML = `<span class="chip">${j.kind === 'evm' ? 'EVM payout address' : 'coinbase address'}</span>` + (j.blocks_10m ? '<span class="chip hot">mining now</span>' : '');
|
||||
if (j.balance.available) { $('a-balance').innerHTML = esc(ignFromWei(j.balance.wei, 4)) + '<small>IGN</small>'; $('a-balance-s').textContent = `${j.balance.source}, ${j.network || ''}`; }
|
||||
document.title = `Devnet 3 address ${shortHash(a, 8, 6)}`;
|
||||
now = new Date(j.now).getTime(); me = j.evm_address; const ac = j.account;
|
||||
$('chips').innerHTML = `<span class="chip">${j.kind === 'evm' ? (ac && ac.is_contract ? 'contract' : 'EVM account') : 'coinbase address'}</span>` + (j.blocks_10m ? '<span class="chip hot">mining now</span>' : '') + (ac && ac.miner ? '<span class="chip">miner payout address</span>' : '');
|
||||
if (j.balance.available) { $('a-balance').innerHTML = esc(ignFromWei(j.balance.wei, 4)) + '<small>IGN</small>'; $('a-balance-s').textContent = j.balance.source === 'indexer' ? `read by the indexer ${j.balance.refreshed_at ? rel(now - new Date(j.balance.refreshed_at).getTime()) : ''}` : `${j.balance.source}, live`; }
|
||||
else { $('a-balance').textContent = 'n/a'; $('a-balance-s').textContent = j.balance.reason; }
|
||||
$('a-nonce').textContent = ac && ac.nonce !== null ? int(ac.nonce) : 'n/a';
|
||||
$('a-txs').textContent = ac ? int((ac.sent || 0) + (ac.received || 0)) : '0'; $('a-txs-s').textContent = ac ? `${int(ac.sent)} sent, ${int(ac.received)} received, as indexed` : 'none indexed';
|
||||
$('a-code').textContent = ac && ac.code_bytes !== null ? (ac.is_contract ? int(ac.code_bytes) + ' B' : 'none') : 'n/a'; $('a-code-s').textContent = ac && ac.is_contract ? 'a contract: bytes of code at this address' : 'an externally owned account';
|
||||
$('a-blocks').textContent = int(j.blocks_24h); $('a-blocks-s').textContent = `${j.blocks_10m} in 10 min, ${j.blue_24h} blue, ${j.red_24h} red, ${j.chain_24h} on the chain`;
|
||||
$('a-earned').innerHTML = esc(ign(j.earned_24h_sompi, 2)) + '<small>IGN</small>';
|
||||
$('a-last').textContent = j.last_seen ? rel(now - new Date(j.last_seen).getTime()) : 'none in 24 h';
|
||||
$('a-first').textContent = j.first_seen ? 'first in the window ' + rel(now - new Date(j.first_seen).getTime()) : '';
|
||||
$('ident').innerHTML = dl([
|
||||
['EVM address', j.evm_address ? `<a class="hash" href="/address/${esc(j.evm_address)}">${esc(j.evm_address)}</a>` : '<span style="color:var(--ash)">none seen</span>'],
|
||||
['Coinbase address', j.utxo_address ? `<a class="hash" href="/address/${esc(j.utxo_address)}">${esc(j.utxo_address)}</a>` : '<span style="color:var(--ash)">none seen</span>'],
|
||||
['Vote keys', j.miner_ids.length ? j.miner_ids.map(m => `<span class="id">${esc(m.id)}</span> <span style="color:var(--ash)">${m.blocks}</span>`).join(' ') : 'none'],
|
||||
['Earned, 24 h', `${ign(j.earned_24h_sompi, 8)} IGN <span style="color:var(--ash)">${esc(j.earned_note)}</span>`],
|
||||
['EVM address', j.evm_address ? `<a class="hash" href="/address/${esc(j.evm_address)}">${esc(j.evm_address)}</a>` : '<span class="kv">none seen</span>'],
|
||||
['Coinbase address', j.utxo_address ? `<a class="hash" href="/address/${esc(j.utxo_address)}">${esc(j.utxo_address)}</a>` : '<span class="kv">none seen</span>'],
|
||||
ac ? ['First and last seen', `${ac.first_seen_number === null ? 'no transaction indexed' : `chain block ${int(ac.first_seen_number)} to ${int(ac.last_seen_number)}`}`] : null,
|
||||
['Vote keys', j.miner_ids.length ? j.miner_ids.map(m => `<span class="id">${esc(m.id)}</span> <span class="kv">${m.blocks}</span>`).join(' ') : 'none'],
|
||||
['Earned, 24 h', `${ign(j.earned_24h_sompi, 8)} IGN <span class="kv">${esc(j.earned_note)}</span>`],
|
||||
]);
|
||||
$('blocks').innerHTML = j.recent.length ? j.recent.map(b => `<tr><td><i class="sw ${b.chain ? 'chain' : b.color}"></i>${link(b.hash)}</td><td class="n">${b.number === null ? '<span style="color:var(--ash)">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${b.chain ? 'chain' : esc(b.color)}</td><td class="n">${b.subsidy_sompi ? ign(b.subsidy_sompi, 4) : 'n/a'}</td><td class="n">${b.tx_count ?? 'n/a'}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="8" class="empty">No blocks from this address in the last 24 hours.</td></tr>';
|
||||
$('txs').innerHTML = j.txs.length ? j.txs.map(txRow).join('') : `<tr><td colspan="7" class="empty">${j.evm_address ? 'No transaction indexed for this address in the last 7 days.' : 'A coinbase address has no EVM transactions; its EVM payout address does.'}</td></tr>`;
|
||||
if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number; else $('more-tx').hidden = true;
|
||||
$('blocks').innerHTML = j.recent.length ? j.recent.map(b => `<tr><td><i class="sw ${b.chain ? 'chain' : b.color}"></i>${link(b.hash)}</td><td class="n">${b.number === null ? '<span class="kv">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${b.chain ? 'chain' : esc(b.color)}</td><td class="n">${b.subsidy_sompi ? ign(b.subsidy_sompi, 4) + ' IGN' : 'n/a'}</td><td class="n">${b.tx_count ?? 'n/a'}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="8" class="empty">No block mined by this address in the last 24 hours.</td></tr>';
|
||||
$('body').hidden = false;
|
||||
}
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ export function neon(url = process.env.DATABASE_URL) {
|
|||
};
|
||||
}
|
||||
export const num = v => (v === null || v === undefined ? null : Number(v));
|
||||
export const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX || '').replace(/[^a-z0-9_]/gi, '');
|
||||
// LIVE_TABLE_PREFIX names the observer whose tables are read; unset means dn3_ (Devnet 3, the igneum-observer-dn3 unit on the build
|
||||
// box, the same default as live.mjs since 8 October 2026: before that the explorer, stats and supply read the first devnet's tables
|
||||
// while /api/live read Devnet 3). An empty string reads the unprefixed tables.
|
||||
export const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
/** EVM chain id from the network name (docs/design/execution-layer.md 8.1: 4461 mainnet, 4462 testnet, 4463 devnet). */
|
||||
export function chainIdOf(network) {
|
||||
const n = String(network || '');
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
// selected-chain headers from the previous locked checkpoint to this one. Read from what tools/observer wrote to
|
||||
// Neon (table live_certificates, or fintest_live_certificates for the test network).
|
||||
//
|
||||
// ?source=live the live devnet (default; falls back to the test network while the live chain has no lock yet)
|
||||
// ?source=test tonight's finality test network (igneum-devnet-7)
|
||||
// ?source=live Devnet 3 (default: the dn3_ tables, or LIVE_TABLE_PREFIX; falls back to the test network while the chain has no lock yet)
|
||||
// ?source=dn3 the same as live (the Devnet 3 name, for callers that want to say so)
|
||||
// ?source=test the finality test network's tables (fintest_live_certificates)
|
||||
// ?index=N one certified checkpoint by index instead of the newest (the explorer's per-block re-check, 8 October 2026)
|
||||
//
|
||||
// Zero dependencies: Neon's HTTP SQL endpoint over Node's built-in fetch, like live.mjs.
|
||||
|
||||
|
|
@ -29,9 +31,10 @@ function neon() {
|
|||
|
||||
const num = v => (v === null || v === undefined ? null : Number(v));
|
||||
|
||||
async function latest(sql, table) {
|
||||
const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
async function latest(sql, table, index = null) {
|
||||
// A table the observer has not created yet (the live chain before the cut-over) reads as "no certificate"
|
||||
const rows = await sql(`SELECT * FROM ${table} ORDER BY index DESC LIMIT 1`).catch(() => []);
|
||||
const rows = await (index === null ? sql(`SELECT * FROM ${table} ORDER BY index DESC LIMIT 1`) : sql(`SELECT * FROM ${table} WHERE index = $1 LIMIT 1`, [index])).catch(() => []);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +75,34 @@ function shape(row, source) {
|
|||
};
|
||||
}
|
||||
|
||||
/** The earliest certified Devnet 3 checkpoint whose chain block number is at least `number` (the reference apps' receipt:
|
||||
* the smallest proof that a block is final), from the dn3_ rows; null when no certificate reaches that block yet.
|
||||
* `chainNumberOf(hash)` resolves a checkpoint hash to its chain block number (the exec RPC); rows are tried newest first
|
||||
* until one falls below `number`, so the cost is a few lookups. */
|
||||
export async function earliestCheckpointAbove(sql, number, chainNumberOf, table = 'dn3_live_certificates') {
|
||||
const rows = await sql(`SELECT index, hash FROM ${table} ORDER BY index DESC LIMIT 400`).catch(() => []);
|
||||
let pick = null;
|
||||
for (const r of rows) {
|
||||
const n = await chainNumberOf(r.hash).catch(() => null);
|
||||
if (n === null) continue;
|
||||
if (n >= number) pick = r; else break;
|
||||
}
|
||||
if (!pick) return null;
|
||||
const full = await sql(`SELECT * FROM ${table} WHERE index = $1 LIMIT 1`, [Number(pick.index)]);
|
||||
return full[0] ? shape(full[0], 'dn3') : null;
|
||||
}
|
||||
|
||||
/** The latest certified checkpoint of `want` ('live', 'test' or 'dn3') through `sql`, shaped for the verifier, or null
|
||||
* (the reference apps' read service calls this off Vercel: 'dn3' names the dn3_ tables whatever LIVE_TABLE_PREFIX says). */
|
||||
export async function readCheckpoint(sql, want = 'live') {
|
||||
let row = null, source = null;
|
||||
if (want === 'dn3') { row = await latest(sql, 'dn3_live_certificates'); if (row) source = 'dn3'; }
|
||||
if (!row && want !== 'test' && want !== 'dn3') { row = await latest(sql, `${tablePrefix()}live_certificates`); if (row) source = 'live'; }
|
||||
if (!row && want !== 'dn3') { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
return row ? shape(row, source) : null;
|
||||
}
|
||||
export { neon };
|
||||
|
||||
export default async function handler(req, res) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=5');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
|
|
@ -82,13 +113,15 @@ export default async function handler(req, res) {
|
|||
try {
|
||||
const sql = neon();
|
||||
const want = String((req.query && req.query.source) || 'live');
|
||||
const idx = req.query && req.query.index !== undefined && /^\d{1,12}$/.test(String(req.query.index)) ? Number(req.query.index) : null;
|
||||
let row = null, source = null;
|
||||
if (want !== 'test') { row = await latest(sql, 'live_certificates'); if (row) source = 'live'; }
|
||||
if (!row) { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
if (want !== 'test') { row = await latest(sql, `${tablePrefix()}live_certificates`, idx); if (row) source = 'live'; }
|
||||
if (!row && idx === null) { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
if (!row) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
return res.status(404).json({ ok: false, error: 'no certified checkpoint stored yet' });
|
||||
}
|
||||
// the hand merge of 12:22 BST (a0b62cf7) returned `...cp` with no cp bound: every caller read "cp is not defined" (8 Oct 2026, build-server lane)
|
||||
return res.status(200).json({ ok: true, now: new Date().toISOString(), ...shape(row, source) });
|
||||
} catch (e) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
|
|
|
|||
|
|
@ -1,19 +1,47 @@
|
|||
// Igneum DAG explorer, server half. GET /api/explorer with one of:
|
||||
// ?blocks=N[&before=<ms>] the latest N blocks (10 to 200, default 50), older than `before` when given
|
||||
// ?block=<hash> one block: row, header detail, parents, mergeset, transactions, proof records, shards,
|
||||
// checkpoint and certificate when it is one, children, the chain block that merged it
|
||||
// Igneum Devnet 3 explorer, server half. GET /api/explorer with one of:
|
||||
// ?blocks=N[&before=<ms>] the latest N blocks (10 to 200, default 50), older than `before` when given; each with its shard
|
||||
// summary (planned, paid), its lock state and its program class
|
||||
// ?block=<hash> one block: row, header detail, parents, mergeset, transactions (from the indexer), proof records,
|
||||
// shards, checkpoint and certificate when it is one, children, the chain block that merged it,
|
||||
// the lock that covers it, its class
|
||||
// ?height=N the chain block with that number (the EVM block number), same shape as ?block
|
||||
// ?address=<0x.. | igneum..:bech32> blocks mined, 24-hour and 10-minute counts, what those blocks earned, and the
|
||||
// balance through eth_getBalance when EXPLORER_EVM_RPC names a reachable EVM JSON-RPC
|
||||
// ?tx=<hash> one EVM transaction: the indexed row (receipt, logs, the igneum fee split) and its block's state
|
||||
// ?txs=N[&before=<number>] the latest N transactions (10 to 200, default 50), from chain blocks numbered below `before`
|
||||
// ?address=<0x.. | igneum..:bech32> the account (balance, nonce, code, from the indexer), its transactions, the blocks it
|
||||
// mined, 24-hour and 10-minute counts, what those blocks earned; the balance comes live through
|
||||
// eth_getBalance when EXPLORER_EVM_RPC names a reachable EVM JSON-RPC, else from the indexer's read
|
||||
// ?proving=1 the proving view: the node's proving state, the last 60 chain blocks with their shards, the
|
||||
// provers of the last 24 hours with their payouts, the block-to-paid latency
|
||||
// ?stats=1 the network: hash rate, difficulty, DAA, blue score, chain rate, voters and weight, the newest
|
||||
// lock, the class floor and every activation the node reports, the indexer's state
|
||||
// ?dag=N the last N blocks (20 to 400, default 120) with parents, colour, miner, shards and lock, for the DAG view
|
||||
// ?search=<q> routes a hash, a height or an address to its page, or says what it is not
|
||||
// Everything is read from what tools/observer wrote to Neon; the only live call is the balance. Cached 5 s.
|
||||
// Everything is read from what tools/observer and tools/observer/explorer-indexer wrote to Neon (table prefix dn3_ by default,
|
||||
// LIVE_TABLE_PREFIX otherwise); the only live call is the balance. Cached 5 s. Every answer names the network: Devnet 3.
|
||||
import { neon, num, tablePrefix, chainIdOf } from './_neon.mjs';
|
||||
import { classify } from '../lib/explorer.mjs';
|
||||
|
||||
const STALE_AFTER_S = 30;
|
||||
export const NETWORK_LABEL = 'Devnet 3';
|
||||
const ROW = `hash, number, blue_score, daa_score, timestamp_ms, parents, parent_hashes, is_chain_block, vote_key_hash, miner_address, evm_miner, engine,
|
||||
tx_count, proof_records, subsidy_sompi, paid_sompi, selected_parent, color, received_at`;
|
||||
// the EVM's own hash for the block's number (the indexer's explorer_blocks): a block the observer called a chain block that a tip
|
||||
// reorg later replaced keeps its number in live_blocks, so the page reads it against this and says "replaced" (Devnet 3 reorgs at the
|
||||
// tip run to depth 18, igneum_getBudgets.deepestReorg read 8 October 2026 10:0x UTC)
|
||||
const evmHash = T => `(SELECT e.hash FROM ${T}explorer_blocks e WHERE e.number = b.number LIMIT 1) AS evm_hash`;
|
||||
const TXROW = `hash, block_hash, block_number, tx_index, from_addr, to_addr, value_wei, nonce, gas, gas_price, gas_used, effective_gas_price, status,
|
||||
contract_address, input_bytes, selector, logs_count, tx_type, ts_ms`;
|
||||
|
||||
/** The program class a block of this DAA score was mined under, from the node's parameters (program_class_v5_activation_daa). */
|
||||
export function classAt(daa, params) {
|
||||
const p = params || {};
|
||||
const floors = Object.entries(p).filter(([k]) => /^program_class_v(\d+)_activation_daa$/.test(k)).map(([k, v]) => ({ v: Number(k.match(/v(\d+)/)[1]), daa: Number(v) })).filter(x => Number.isFinite(x.daa)).sort((a, b) => a.v - b.v);
|
||||
let cls = 4; // class v4 is the floor of Devnet 3 (every activation at 0 in its network object)
|
||||
for (const f of floors) if (daa !== null && daa !== undefined && daa >= f.daa && f.v > cls) cls = f.v;
|
||||
return { class: `v${cls}`, floors: floors.map(f => ({ class: `v${f.v}`, daa: f.daa })) };
|
||||
}
|
||||
|
||||
let settledBelow = -1; // numbers above this are still moving at the tip; chain_now is left null for them (set per request from the indexer's number)
|
||||
function row(b) {
|
||||
return {
|
||||
hash: b.hash, number: num(b.number), blue_score: num(b.blue_score), daa: num(b.daa_score), ts: num(b.timestamp_ms), rx: new Date(b.received_at).getTime(),
|
||||
|
|
@ -21,8 +49,28 @@ function row(b) {
|
|||
miner_id: b.vote_key_hash ? String(b.vote_key_hash).slice(0, 8) : null, vote_key_hash: b.vote_key_hash || null, miner: b.miner_address || null, evm_miner: b.evm_miner || null, engine: b.engine || null,
|
||||
tx_count: num(b.tx_count), proof_records: num(b.proof_records), subsidy_sompi: b.subsidy_sompi === null || b.subsidy_sompi === undefined ? null : String(b.subsidy_sompi),
|
||||
paid_sompi: b.paid_sompi === null || b.paid_sompi === undefined ? null : String(b.paid_sompi), selected_parent: b.selected_parent || null,
|
||||
// chain_now: still the chain block of its number by the EVM's reading (null when the indexer has not reached the number)
|
||||
chain_now: b.is_chain_block ? (b.evm_hash === undefined || b.evm_hash === null || num(b.number) > settledBelow ? null : b.evm_hash === b.hash) : false,
|
||||
};
|
||||
}
|
||||
function txrow(t) {
|
||||
return {
|
||||
hash: t.hash, block_hash: t.block_hash, number: num(t.block_number), index: num(t.tx_index), from: t.from_addr, to: t.to_addr, value_wei: t.value_wei === null || t.value_wei === undefined ? '0' : String(t.value_wei),
|
||||
nonce: num(t.nonce), gas: num(t.gas), gas_price: t.gas_price === null || t.gas_price === undefined ? null : String(t.gas_price), gas_used: num(t.gas_used),
|
||||
effective_gas_price: t.effective_gas_price === null || t.effective_gas_price === undefined ? null : String(t.effective_gas_price),
|
||||
status: t.status === null || t.status === undefined ? null : (Number(t.status) === 1 ? 'success' : 'failed'), contract_address: t.contract_address || null,
|
||||
input_bytes: num(t.input_bytes), selector: t.selector || null, logs_count: num(t.logs_count), type: num(t.tx_type), ts: num(t.ts_ms),
|
||||
};
|
||||
}
|
||||
const shardSummary = s => ({ planned: num(s.planned) || 0, proving: num(s.proving) || 0, verified: num(s.verified) || 0, paid: num(s.paid) || 0, total: num(s.total) || 0, median_lag: s.median_lag === null || s.median_lag === undefined ? null : Number(s.median_lag) });
|
||||
|
||||
/** Lock state of a block against the newest lock: a chain block at or under the lock's blue score is final; a merged block is final with its merger. */
|
||||
function lockState(b, lock, mergerBlue) {
|
||||
if (!lock) return { final: false, reason: 'no lock yet' };
|
||||
if (b.chain) return b.blue_score <= lock.blue_score ? { final: true, index: lock.index, reason: `chain block under lock ${lock.index}` } : { final: false, index: lock.index, reason: `above lock ${lock.index} (blue score ${lock.blue_score})` };
|
||||
if (mergerBlue !== null && mergerBlue !== undefined) return mergerBlue <= lock.blue_score ? { final: true, index: lock.index, reason: `merged by a chain block under lock ${lock.index}` } : { final: false, index: lock.index, reason: `merged above lock ${lock.index}` };
|
||||
return { final: false, index: lock.index, reason: 'not merged yet' };
|
||||
}
|
||||
|
||||
async function evmCall(url, method, params) {
|
||||
const r = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(4000) });
|
||||
|
|
@ -41,10 +89,22 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
const EVM = env.EXPLORER_EVM_RPC || null;
|
||||
try {
|
||||
sql = sql || neon(env.DATABASE_URL);
|
||||
const head = await sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state`);
|
||||
const now = new Date(head[0].now).getTime(); const s = head[0].state || null;
|
||||
const head = await sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state,
|
||||
(SELECT row_to_json(x) FROM ${T}explorer_state x WHERE x.id = 1) AS indexer, (SELECT max(number) FROM ${T}explorer_blocks) AS indexed_max`).catch(async e => {
|
||||
if (/explorer_state/.test(String(e.message))) return sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state, NULL AS indexer`);
|
||||
throw e;
|
||||
});
|
||||
const now = new Date(head[0].now).getTime(); const s = head[0].state || null; const ix = head[0].indexer || null;
|
||||
const updated = s && s.updated_at ? new Date(s.updated_at).getTime() : null;
|
||||
const base = { ok: true, now: new Date(now).toISOString(), network: s ? s.network : null, chain_id: s ? chainIdOf(s.network) : null, stale: updated === null || (now - updated) / 1000 > STALE_AFTER_S, evm_rpc_configured: !!EVM };
|
||||
const params = ix && ix.node_info && ix.node_info.params ? ix.node_info.params : null;
|
||||
const indexer = ix ? { indexed_number: num(ix.indexed_number), tip_number: num(ix.tip_number), backlog: num(ix.backlog), txs_total: num(ix.txs_total), accounts_total: num(ix.accounts_total), blocks_per_s: num(ix.blocks_per_s), updated_at: ix.updated_at, stale: !ix.updated_at || (now - new Date(ix.updated_at).getTime()) / 1000 > STALE_AFTER_S, last_error: ix.last_error || null } : { stale: true, reason: 'the explorer indexer has not written yet' };
|
||||
// the highest number the indexer has ever read, less three: a node re-syncing from a snapshot reports a low tip for a while
|
||||
// (10:21 UTC on 8 October 2026: the observer node restarted and its tip read 1,981 against 27,145 indexed) and must not unsettle the table
|
||||
settledBelow = head[0].indexed_max === null || head[0].indexed_max === undefined ? -1 : Number(head[0].indexed_max) - 3;
|
||||
const base = { ok: true, now: new Date(now).toISOString(), network: s ? s.network : null, network_label: NETWORK_LABEL, chain_id: ix && ix.chain_id ? num(ix.chain_id) : (s ? chainIdOf(s.network) : null), stale: updated === null || (now - updated) / 1000 > STALE_AFTER_S, evm_rpc_configured: !!EVM, indexer };
|
||||
const lockRow = await sql(`SELECT index, hash, blue_score, daa_score, fraction_total, voters, locked_at FROM ${T}live_checkpoints WHERE state = 'locked' ORDER BY index DESC LIMIT 1`).catch(() => []);
|
||||
const lock = lockRow[0] ? { index: num(lockRow[0].index), hash: lockRow[0].hash, blue_score: num(lockRow[0].blue_score), daa: num(lockRow[0].daa_score), fraction_total: num(lockRow[0].fraction_total), voters: num(lockRow[0].voters), locked_at: lockRow[0].locked_at } : null;
|
||||
base.lock = lock;
|
||||
|
||||
// ---- search ----
|
||||
if (q.has('search')) {
|
||||
|
|
@ -58,20 +118,116 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
}
|
||||
const b = await sql(`SELECT hash FROM ${T}live_blocks WHERE hash = $1`, [c.value]);
|
||||
if (b.length) return res.status(200).json({ ...base, type: 'block', href: `/block/${c.value}` });
|
||||
const t = await sql(`SELECT hash FROM ${T}live_blocks WHERE tx_count > 0 AND detail->'txs' @> $1::jsonb LIMIT 1`, [JSON.stringify([{ hash: '0x' + c.value }])]);
|
||||
if (t.length) return res.status(200).json({ ...base, type: 'tx', href: `/block/${t[0].hash}#tx-${c.value}` });
|
||||
return res.status(404).json({ ...base, ok: false, error: 'No block or transaction with that hash in the last 24 hours.' });
|
||||
const t = await sql(`SELECT hash FROM ${T}live_txs WHERE hash = $1`, ['0x' + c.value]).catch(() => []);
|
||||
if (t.length) return res.status(200).json({ ...base, type: 'tx', href: `/tx/0x${c.value}` });
|
||||
return res.status(404).json({ ...base, ok: false, error: 'No block in the last 24 hours and no transaction in the last 7 days with that hash.' });
|
||||
}
|
||||
|
||||
// ---- stats ----
|
||||
if (q.has('stats')) {
|
||||
const [chain10, fin, paid10] = await Promise.all([
|
||||
sql(`SELECT count(*)::int AS blocks_10m, count(*) FILTER (WHERE is_chain_block)::int AS chain_10m, count(DISTINCT vote_key_hash)::int AS miners_10m, max(daa_score) AS daa, max(number) AS height FROM ${T}live_blocks WHERE received_at > now() - interval '10 minutes'`),
|
||||
Promise.resolve(s && s.finality ? s.finality : null),
|
||||
// payments landing in the window for blocks of any age (the observer's shards_paid_10m counts only blocks of the last 10 minutes, which reads 0 while the lag runs to 500 DAA)
|
||||
sql(`SELECT count(*)::int AS n, count(DISTINCT prover)::int AS provers, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '10 minutes'`).catch(() => [{ n: null, provers: null, payout_wei: null }]),
|
||||
]);
|
||||
const c = chain10[0] || {};
|
||||
const p10 = paid10[0] || {};
|
||||
const w = fin && fin.weights ? fin.weights : null;
|
||||
const activations = params ? Object.entries(params).filter(([k, v]) => /_activation_daa$/.test(k) && Number.isFinite(Number(v))).map(([k, v]) => ({ name: k.replace(/_activation_daa$/, ''), daa: Number(v) })) : [];
|
||||
return res.status(200).json({
|
||||
...base,
|
||||
node_version: s ? s.node_version : null, height: num(c.height), daa: num(c.daa), blue_score: s ? num(s.blue_score) : null, block_count: s ? num(s.block_count) : null,
|
||||
difficulty: s ? num(s.difficulty) : null, hashrate: s ? num(s.hashes_per_second_estimate) : null, peers: s ? num(s.peers) : null, mempool: s ? num(s.mempool) : null,
|
||||
blocks_10m: num(c.blocks_10m), chain_blocks_10m: num(c.chain_10m), blocks_per_s_10m: c.blocks_10m === null ? null : Math.round(Number(c.blocks_10m) / 600 * 100) / 100, chain_blocks_per_s_10m: c.chain_10m === null ? null : Math.round(Number(c.chain_10m) / 600 * 100) / 100,
|
||||
miners_10m: num(c.miners_10m),
|
||||
finality: fin ? { active: !!fin.finality_active, voters: w ? num(w.voters) : null, total_weight: w ? num(w.total_weight) : null, active_weight: w ? num(w.active_weight) : null, keys: w && Array.isArray(w.keys) ? w.keys.length : null, latest_locked_index: num(fin.latest_locked_index), latest_locked_blue_score: num(fin.latest_locked_blue_score), params: fin.params || null } : null,
|
||||
proving: s && s.proving ? s.proving : null,
|
||||
paid_10m_any_age: { shards: num(p10.n), provers: num(p10.provers), payout_wei: p10.payout_wei || '0', note: 'shards paid in the last 10 minutes for blocks of any age' },
|
||||
class: classAt(num(c.daa), params), activations, digest: ix && ix.node_info ? ix.node_info.digest : null, genesis: ix && ix.node_info ? ix.node_info.genesis : null,
|
||||
budgets: null,
|
||||
});
|
||||
}
|
||||
|
||||
// ---- proving view ----
|
||||
if (q.has('proving')) {
|
||||
const [blocks, provers24, provers1, lat, totals, paid10] = await Promise.all([
|
||||
sql(`SELECT b.hash, b.number, b.daa_score, b.blue_score, b.timestamp_ms, b.vote_key_hash, b.evm_miner, b.tx_count, b.proof_records,
|
||||
count(p.shard)::int AS total, count(*) FILTER (WHERE p.state = 'planned')::int AS planned, count(*) FILTER (WHERE p.state = 'proving')::int AS proving,
|
||||
count(*) FILTER (WHERE p.state = 'verified')::int AS verified, count(*) FILTER (WHERE p.state = 'paid')::int AS paid,
|
||||
percentile_cont(0.5) WITHIN GROUP (ORDER BY p.lag_daa) FILTER (WHERE p.state = 'paid') AS median_lag, sum(p.pgas) AS pgas
|
||||
FROM ${T}live_blocks b LEFT JOIN ${T}live_proofs p ON p.block_hash = b.hash
|
||||
WHERE b.is_chain_block AND b.number IS NOT NULL AND b.received_at > now() - interval '24 hours'
|
||||
GROUP BY b.hash, b.number, b.daa_score, b.blue_score, b.timestamp_ms, b.vote_key_hash, b.evm_miner, b.tx_count, b.proof_records ORDER BY b.number DESC LIMIT 60`),
|
||||
sql(`SELECT prover, count(*)::int AS shards, sum(payout_wei::numeric)::text AS payout_wei, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) AS median_lag, max(updated_at) AS last_paid
|
||||
FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '24 hours' AND prover IS NOT NULL GROUP BY prover ORDER BY shards DESC LIMIT 64`),
|
||||
sql(`SELECT prover, count(*)::int AS shards, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '1 hour' AND prover IS NOT NULL GROUP BY prover`),
|
||||
sql(`SELECT count(*)::int AS paid_1h, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) AS p50, percentile_cont(0.9) WITHIN GROUP (ORDER BY lag_daa) AS p90, max(lag_daa) AS max_lag, min(lag_daa) AS min_lag
|
||||
FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '1 hour'`),
|
||||
sql(`SELECT state, count(*)::int AS n, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE received_at > now() - interval '24 hours' GROUP BY state`),
|
||||
sql(`SELECT count(*)::int AS n, count(DISTINCT prover)::int AS provers, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '10 minutes'`).catch(() => []),
|
||||
]);
|
||||
const hour = new Map(provers1.map(p => [p.prover, p]));
|
||||
return res.status(200).json({
|
||||
...base, proving: s && s.proving ? s.proving : null,
|
||||
blocks: blocks.map(b => ({ hash: b.hash, number: num(b.number), daa: num(b.daa_score), blue_score: num(b.blue_score), ts: num(b.timestamp_ms), miner_id: b.vote_key_hash ? String(b.vote_key_hash).slice(0, 8) : null, evm_miner: b.evm_miner, tx_count: num(b.tx_count), proof_records: num(b.proof_records), pgas: num(b.pgas), shards: shardSummary(b), class: classAt(num(b.daa_score), params).class })),
|
||||
provers: provers24.map(p => ({ id: p.prover, shards_24h: num(p.shards), payout_wei_24h: p.payout_wei || '0', median_lag_24h: p.median_lag === null ? null : Number(p.median_lag), shards_1h: hour.has(p.prover) ? num(hour.get(p.prover).shards) : 0, payout_wei_1h: hour.has(p.prover) ? hour.get(p.prover).payout_wei || '0' : '0', last_paid: p.last_paid })),
|
||||
latency_1h: lat[0] ? { paid: num(lat[0].paid_1h), p50_daa: lat[0].p50 === null ? null : Number(lat[0].p50), p90_daa: lat[0].p90 === null ? null : Number(lat[0].p90), min_daa: num(lat[0].min_lag), max_daa: num(lat[0].max_lag), note: 'lag in DAA score from the proven block to the block whose coinbase paid the shard; Devnet 3 targets one DAA step per second' } : null,
|
||||
totals_24h: Object.fromEntries(totals.map(t => [t.state, { shards: num(t.n), payout_wei: t.payout_wei || '0' }])),
|
||||
paid_10m_any_age: paid10[0] ? { shards: num(paid10[0].n), provers: num(paid10[0].provers), payout_wei: paid10[0].payout_wei || '0' } : null,
|
||||
});
|
||||
}
|
||||
|
||||
// ---- the DAG ----
|
||||
if (q.has('dag')) {
|
||||
const n = Math.max(20, Math.min(400, Number(q.get('dag')) || 120));
|
||||
const rows = await sql(`SELECT ${ROW}, ${evmHash(T)}, (SELECT json_build_object('total', count(*), 'paid', count(*) FILTER (WHERE state = 'paid'), 'planned', count(*) FILTER (WHERE state = 'planned'), 'proving', count(*) FILTER (WHERE state = 'proving'), 'verified', count(*) FILTER (WHERE state = 'verified')) FROM ${T}live_proofs p WHERE p.block_hash = b.hash) AS sh
|
||||
FROM ${T}live_blocks b ORDER BY received_at DESC LIMIT $1`, [n]).catch(() => sql(`SELECT ${ROW} FROM ${T}live_blocks b ORDER BY received_at DESC LIMIT $1`, [n]));
|
||||
const cps = await sql(`SELECT hash, index, state FROM ${T}live_checkpoints ORDER BY index DESC LIMIT 400`).catch(() => []);
|
||||
const cp = new Map(cps.map(c => [c.hash, { index: num(c.index), state: c.state }]));
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => { const r = row(b); return { ...r, shards: b.sh ? shardSummary(b.sh) : null, checkpoint: cp.get(b.hash) || null, final: lockState(r, lock, null).final, class: classAt(r.daa, params).class }; }).reverse() });
|
||||
}
|
||||
|
||||
// ---- latest transactions ----
|
||||
if (q.has('txs')) {
|
||||
const n = Math.max(10, Math.min(200, Number(q.get('txs')) || 50));
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const rows = before
|
||||
? await sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE block_number < $2 ORDER BY block_number DESC, tx_index ASC LIMIT $1`, [n, before])
|
||||
: await sql(`SELECT ${TXROW} FROM ${T}live_txs ORDER BY block_number DESC, tx_index ASC LIMIT $1`, [n]);
|
||||
return res.status(200).json({ ...base, txs: rows.map(txrow) });
|
||||
}
|
||||
|
||||
// ---- one transaction ----
|
||||
if (q.has('tx')) {
|
||||
const h = String(q.get('tx') || '').toLowerCase().replace(/^(0x)?/, '0x');
|
||||
if (!/^0x[0-9a-f]{64}$/.test(h)) return res.status(400).json({ ...base, ok: false, error: 'A transaction hash is 0x plus 64 hex characters.' });
|
||||
const rows = await sql(`SELECT ${TXROW}, logs, igneum FROM ${T}live_txs WHERE hash = $1`, [h]);
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No transaction with that hash in the last 7 days. The explorer keeps seven days of transactions; older ones live in the node.' });
|
||||
const t = rows[0];
|
||||
const [blk, sh, acct] = await Promise.all([
|
||||
sql(`SELECT ${ROW}, ${evmHash(T)} FROM ${T}live_blocks b WHERE hash = $1`, [t.block_hash]),
|
||||
sql(`SELECT count(*)::int AS total, count(*) FILTER (WHERE state = 'planned')::int AS planned, count(*) FILTER (WHERE state = 'proving')::int AS proving, count(*) FILTER (WHERE state = 'verified')::int AS verified, count(*) FILTER (WHERE state = 'paid')::int AS paid, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) FILTER (WHERE state = 'paid') AS median_lag FROM ${T}live_proofs WHERE block_hash = $1`, [t.block_hash]).catch(() => []),
|
||||
sql(`SELECT address, is_contract, code_bytes FROM ${T}live_accounts WHERE address = ANY($1::text[])`, [[t.from_addr, t.to_addr, t.contract_address].filter(Boolean)]).catch(() => []),
|
||||
]);
|
||||
const b = blk[0] ? row(blk[0]) : null;
|
||||
const contracts = Object.fromEntries(acct.filter(a => a.is_contract).map(a => [a.address, num(a.code_bytes)]));
|
||||
return res.status(200).json({
|
||||
...base, tx: { ...txrow(t), logs: t.logs || [], igneum: t.igneum || null, contracts },
|
||||
block: b ? { ...b, class: classAt(b.daa, params).class, shards: sh[0] ? shardSummary(sh[0]) : null, lock: lockState(b, lock, null), in_observer: true } : { hash: t.block_hash, number: num(t.block_number), in_observer: false, note: 'the observer keeps one day of blocks; the transaction is older or its block left the observer window' },
|
||||
});
|
||||
}
|
||||
|
||||
// ---- latest blocks ----
|
||||
if (q.has('blocks') || (!q.has('block') && !q.has('height') && !q.has('address'))) {
|
||||
const n = Math.max(10, Math.min(200, Number(q.get('blocks')) || 50));
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const sel = `SELECT ${ROW}, ${evmHash(T)}, (SELECT json_build_object('total', count(*), 'paid', count(*) FILTER (WHERE state = 'paid'), 'planned', count(*) FILTER (WHERE state = 'planned'), 'proving', count(*) FILTER (WHERE state = 'proving'), 'verified', count(*) FILTER (WHERE state = 'verified')) FROM ${T}live_proofs p WHERE p.block_hash = b.hash) AS sh FROM ${T}live_blocks b`;
|
||||
const rows = before
|
||||
? await sql(`SELECT ${ROW} FROM ${T}live_blocks WHERE received_at < to_timestamp($2 / 1000.0) ORDER BY received_at DESC LIMIT $1`, [n, before])
|
||||
: await sql(`SELECT ${ROW} FROM ${T}live_blocks ORDER BY received_at DESC LIMIT $1`, [n]);
|
||||
? await sql(`${sel} WHERE received_at < to_timestamp($2 / 1000.0) ORDER BY received_at DESC LIMIT $1`, [n, before])
|
||||
: await sql(`${sel} ORDER BY received_at DESC LIMIT $1`, [n]);
|
||||
const locked = new Set((await sql(`SELECT hash FROM ${T}live_checkpoints WHERE state = 'locked' ORDER BY index DESC LIMIT 200`).catch(() => [])).map(c => c.hash));
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => ({ ...row(b), locked: locked.has(b.hash) })) });
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => { const r = row(b); return { ...r, locked: locked.has(b.hash), shards: b.sh ? shardSummary(b.sh) : null, final: lockState(r, lock, null).final, class: classAt(r.daa, params).class }; }) });
|
||||
}
|
||||
|
||||
// ---- one block ----
|
||||
|
|
@ -83,30 +239,34 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
hash = r[0].hash;
|
||||
}
|
||||
if (!/^[0-9a-f]{64}$/.test(hash)) return res.status(400).json({ ...base, ok: false, error: 'A block hash is 64 hex characters.' });
|
||||
const rows = await sql(`SELECT ${ROW}, detail FROM ${T}live_blocks WHERE hash = $1`, [hash]);
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No block with that hash in the last 24 hours. The explorer keeps one day; older blocks live in the node.' });
|
||||
const rows = await sql(`SELECT ${ROW}, ${evmHash(T)}, detail FROM ${T}live_blocks b WHERE hash = $1`, [hash]).catch(() => sql(`SELECT ${ROW}, detail FROM ${T}live_blocks WHERE hash = $1`, [hash]));
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No block with that hash in the last 24 hours. The explorer keeps one day of blocks; older blocks live in the node.' });
|
||||
const b = rows[0];
|
||||
const [shards, cps, certs, children, mergedBy] = await Promise.all([
|
||||
sql(`SELECT shard, shards, state, prover, lag_daa, payout_wei, pgas, carried_by, carrier_number FROM ${T}live_proofs WHERE block_hash = $1 ORDER BY shard`, [hash]).catch(() => []),
|
||||
const [shards, cps, certs, children, mergedBy, txs] = await Promise.all([
|
||||
sql(`SELECT shard, shards, state, prover, lag_daa, payout_wei, pgas, carried_by, carrier_number, verified FROM ${T}live_proofs WHERE block_hash = $1 ORDER BY shard`, [hash]).catch(() => []),
|
||||
sql(`SELECT index, state, signed_weight, active_weight, total_weight, fraction_active, fraction_total, votes_seen, voters, locked_at FROM ${T}live_checkpoints WHERE hash = $1`, [hash]).catch(() => []),
|
||||
sql(`SELECT index, hash, carrier, voter_count, aggregator, total_weight, active_weight, prev_index, prev_hash, headers_complete, created_at FROM ${T}live_certificates WHERE hash = $1 OR carrier = $1`, [hash]).catch(() => []),
|
||||
sql(`SELECT hash FROM ${T}live_blocks WHERE received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND $1 = ANY(parent_hashes) ORDER BY received_at LIMIT 20`, [hash, b.received_at]),
|
||||
b.is_chain_block ? Promise.resolve([]) : sql(`SELECT hash FROM ${T}live_blocks WHERE is_chain_block AND received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND (detail->'mergeset'->'blues' ? $1 OR detail->'mergeset'->'reds' ? $1) LIMIT 1`, [hash, b.received_at]),
|
||||
b.is_chain_block ? Promise.resolve([]) : sql(`SELECT hash, blue_score FROM ${T}live_blocks WHERE is_chain_block AND received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND (detail->'mergeset'->'blues' ? $1 OR detail->'mergeset'->'reds' ? $1) LIMIT 1`, [hash, b.received_at]),
|
||||
sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE block_hash = $1 ORDER BY tx_index LIMIT 500`, [hash]).catch(() => []),
|
||||
]);
|
||||
let evmView = null; // the EVM's view of a chain block, when the deployment has an EVM RPC
|
||||
if (EVM && b.is_chain_block) {
|
||||
try {
|
||||
const e = await evm(EVM, 'eth_getBlockByHash', ['0x' + hash, true]);
|
||||
const e = await evm(EVM, 'eth_getBlockByHash', ['0x' + hash, false]);
|
||||
if (e) evmView = { number: parseInt(e.number, 16), gas_used: parseInt(e.gasUsed, 16), base_fee_per_gas: e.baseFeePerGas, state_root: e.stateRoot, miner: e.miner,
|
||||
transactions: (e.transactions || []).map(t => ({ hash: t.hash, from: t.from, to: t.to, value: t.value, nonce: parseInt(t.nonce, 16), gas: parseInt(t.gas, 16) })),
|
||||
igneum: e.igneum ? { rewards: e.igneum.rewards, proving_pool_credit: e.igneum.provingPoolCredit, pgas_used: e.igneum.pgasUsed, skipped: e.igneum.skipped } : null };
|
||||
} catch (err) { evmView = { error: String(err.message || err).slice(0, 120) }; }
|
||||
}
|
||||
const r = row(b);
|
||||
const mergerBlue = b.is_chain_block ? null : (mergedBy[0] ? num(mergedBy[0].blue_score) : null);
|
||||
const counts = { total: shards.length, planned: shards.filter(x => x.state === 'planned').length, proving: shards.filter(x => x.state === 'proving').length, verified: shards.filter(x => x.state === 'verified').length, paid: shards.filter(x => x.state === 'paid').length };
|
||||
return res.status(200).json({
|
||||
...base, block: { ...row(b), detail: b.detail || null }, shards: shards.map(x => ({ i: num(x.shard), n: num(x.shards), state: x.state, prover: x.prover, lag: num(x.lag_daa), payout_wei: x.payout_wei, pgas: num(x.pgas), carried_by: x.carried_by, carrier_number: num(x.carrier_number) })),
|
||||
...base, block: { ...r, detail: b.detail || null, class: classAt(r.daa, params), lock: lockState(r, lock, mergerBlue), shard_summary: counts },
|
||||
shards: shards.map(x => ({ i: num(x.shard), n: num(x.shards), state: x.state, prover: x.prover, lag: num(x.lag_daa), payout_wei: x.payout_wei, pgas: num(x.pgas), carried_by: x.carried_by, carrier_number: num(x.carrier_number), node_verified: x.verified === null || x.verified === undefined ? null : !!x.verified })),
|
||||
checkpoint: cps[0] ? { index: num(cps[0].index), state: cps[0].state, signed: num(cps[0].signed_weight), active: num(cps[0].active_weight), total: num(cps[0].total_weight), fraction_active: num(cps[0].fraction_active), fraction_total: num(cps[0].fraction_total), votes: num(cps[0].votes_seen), voters: num(cps[0].voters), locked_at: cps[0].locked_at } : null,
|
||||
certificates: certs.map(c => ({ index: num(c.index), checkpoint: c.hash, carrier: c.carrier, role: c.hash === hash ? 'checkpoint' : 'carrier', voter_count: num(c.voter_count), aggregator: c.aggregator, total_weight: num(c.total_weight), active_weight: num(c.active_weight), previous: c.prev_index === null ? null : { index: num(c.prev_index), hash: c.prev_hash }, headers_complete: !!c.headers_complete })),
|
||||
children: children.map(c => c.hash), merged_by: b.is_chain_block ? hash : (mergedBy[0] ? mergedBy[0].hash : null), evm: evmView,
|
||||
children: children.map(c => c.hash), merged_by: b.is_chain_block ? hash : (mergedBy[0] ? mergedBy[0].hash : null), evm: evmView, txs: txs.map(txrow),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -122,30 +282,40 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
coalesce(sum(subsidy_sompi) FILTER (WHERE color = 'blue'), 0)::text AS blue_subsidy_sompi,
|
||||
max(evm_miner) AS evm_miner, max(miner_address) AS miner_address
|
||||
FROM ${T}live_blocks WHERE ${col} = $1`, [c.value]),
|
||||
sql(`SELECT ${ROW} FROM ${T}live_blocks WHERE ${col} = $1 ORDER BY received_at DESC LIMIT 50`, [c.value]),
|
||||
sql(`SELECT ${ROW}, ${evmHash(T)} FROM ${T}live_blocks b WHERE ${col} = $1 ORDER BY received_at DESC LIMIT 50`, [c.value]),
|
||||
sql(`SELECT vote_key_hash, count(*)::int AS n FROM ${T}live_blocks WHERE ${col} = $1 AND vote_key_hash IS NOT NULL GROUP BY 1 ORDER BY n DESC LIMIT 32`, [c.value]),
|
||||
]);
|
||||
const t = sum[0];
|
||||
const evmAddress = c.kind === 'evm' ? c.value : (t.evm_miner || null);
|
||||
let balance = { available: false, reason: EVM ? 'no EVM address known for this coinbase address' : 'no EVM RPC configured on this deployment (EXPLORER_EVM_RPC)' };
|
||||
let account = null, txs = [];
|
||||
if (evmAddress) {
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const [a, tx] = await Promise.all([
|
||||
sql(`SELECT address, balance_wei, nonce, code_bytes, is_contract, sent, received, first_seen_number, last_seen_number, miner, refreshed_at FROM ${T}live_accounts WHERE address = $1`, [evmAddress]).catch(() => []),
|
||||
sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE (from_addr = $1 OR to_addr = $1) ${before ? 'AND block_number < $2' : ''} ORDER BY block_number DESC, tx_index ASC LIMIT 50`, before ? [evmAddress, before] : [evmAddress]).catch(() => []),
|
||||
]);
|
||||
if (a[0]) account = { address: a[0].address, balance_wei: a[0].balance_wei === null ? null : String(a[0].balance_wei), nonce: num(a[0].nonce), code_bytes: num(a[0].code_bytes), is_contract: !!a[0].is_contract, sent: num(a[0].sent), received: num(a[0].received), first_seen_number: num(a[0].first_seen_number), last_seen_number: num(a[0].last_seen_number), miner: !!a[0].miner, refreshed_at: a[0].refreshed_at, source: 'the explorer indexer (eth_getBalance, eth_getTransactionCount, eth_getCode on the observer node)' };
|
||||
txs = tx.map(txrow);
|
||||
}
|
||||
let balance = account && account.balance_wei !== null ? { available: true, wei: account.balance_wei, address: evmAddress, source: 'indexer', refreshed_at: account.refreshed_at } : { available: false, reason: evmAddress ? 'not read yet: the indexer reads an address after its first transaction or mined block' : 'no EVM address known for this coinbase address' };
|
||||
if (EVM && evmAddress) {
|
||||
try { const wei = await evm(EVM, 'eth_getBalance', [evmAddress, 'latest']); balance = { available: true, wei: BigInt(wei).toString(), address: evmAddress, source: 'eth_getBalance latest' }; }
|
||||
catch (err) { balance = { available: false, reason: String(err.message || err).slice(0, 120) }; }
|
||||
catch (err) { if (!balance.available) balance = { available: false, reason: String(err.message || err).slice(0, 120) }; }
|
||||
}
|
||||
// what the blocks earned: each blue block pays 80% of the subsidy its payload declares to this miner, through the coinbase of the block that merges it
|
||||
const blue = BigInt(t.blue_subsidy_sompi || 0); const earned = blue * 80n / 100n;
|
||||
return res.status(200).json({
|
||||
...base, address: c.value, kind: c.kind, evm_address: evmAddress, utxo_address: c.kind === 'utxo' ? c.value : (t.miner_address || null),
|
||||
account, txs,
|
||||
blocks_24h: t.blocks_24h, blocks_10m: t.blocks_10m, blue_24h: t.blue_24h, red_24h: t.red_24h, chain_24h: t.chain_24h,
|
||||
first_seen: t.first_ts ? new Date(num(t.first_ts)).toISOString() : null, last_seen: t.last_ts ? new Date(num(t.last_ts)).toISOString() : null,
|
||||
earned_24h_sompi: earned.toString(), earned_note: '80% of the declared subsidy of every blue block this address mined in the last 24 hours, paid by the coinbase of the block that merged each one (coinbase.rs); red blocks pay the merging miner instead',
|
||||
miner_ids: ids.map(i => ({ id: String(i.vote_key_hash).slice(0, 8), blocks: i.n })), balance, recent: recent.map(row),
|
||||
});
|
||||
}
|
||||
return res.status(400).json({ ...base, ok: false, error: 'blocks, block, height, address or search' });
|
||||
return res.status(400).json({ ...base, ok: false, error: 'blocks, block, height, tx, txs, address, proving, stats, dag or search' });
|
||||
} catch (e) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
return res.status(500).json({ ok: false, error: String(e.message || e) });
|
||||
return res.status(500).json({ ok: false, network_label: NETWORK_LABEL, error: String(e.message || e) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -99,8 +100,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -111,18 +110,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -134,8 +145,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -144,15 +153,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -472,7 +491,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -487,6 +506,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
119
site/block.html
119
site/block.html
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum block</title>
|
||||
<title>Igneum Devnet 3 block</title>
|
||||
<meta name="description" content="One Igneum block: header, parents, mergeset, transactions, proof records and, when it is a checkpoint, its finality certificate.">
|
||||
<link rel="canonical" href="https://igneum.network/block">
|
||||
<meta name="robots" content="noindex">
|
||||
|
|
@ -92,6 +92,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -108,6 +114,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -125,30 +132,40 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -160,25 +177,33 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -235,7 +260,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Block</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Explorer</a> · block</div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · block</div>
|
||||
<h1 class="hash" id="title">Block</h1>
|
||||
<div id="chips"></div>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -250,8 +275,8 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="card"><div class="viz-head"><h2>Mergeset</h2><div class="eyebrow">what this block merges</div></div><div id="mergeset"></div><p class="note">A chain block merges the blocks in its past that no earlier chain block merged. Blue ones are paid by this block's coinbase; red ones are excluded from the order and their reward goes to this block's miner.</p></div>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Transactions</h2><div class="eyebrow" id="tx-n"></div></div><div id="coinbase"></div><div class="tbl" id="txs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Proof records and shards</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Shard plan and proofs</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div><div id="recheck"></div></div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
|
|
@ -276,7 +301,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -291,6 +316,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -330,28 +358,47 @@ const addr = a => a ? `<a class="hash" href="/address/${esc(a)}">${esc(a)}</a>`
|
|||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const id = decodeURIComponent(location.pathname.split('/').pop() || '');
|
||||
const query = /^\d{1,12}$/.test(id) ? 'height=' + id : 'block=' + encodeURIComponent(id.replace(/^0x/i, ''));
|
||||
async function recheck(index, blockHash, isCheckpoint) {
|
||||
// the verified badge: this browser fetches the certificate that covers the block and checks it with the site's light client
|
||||
const el = $('recheck'); el.innerHTML = `<p class="note" id="rc-line">Re-checking certificate ${int(index)} in this browser. The STARK proofs of the shards are not re-run here; the node's verdict on them is shown in the shard table as the node's.</p>`;
|
||||
const badge = document.createElement('span'); badge.className = 'badge wait'; badge.textContent = 'checking the certificate'; $('chips').appendChild(badge);
|
||||
try {
|
||||
const { fetchCheckpoint, verify } = await import('/verify/verify.js');
|
||||
const data = await fetchCheckpoint('/api/checkpoint?index=' + index);
|
||||
const r = verify(data);
|
||||
if (r.verified) {
|
||||
badge.className = 'badge ok'; badge.textContent = "certificate re-checked in this browser; the node's verdict on the STARK";
|
||||
$('rc-line').innerHTML = `Certificate ${int(index)} re-checked in this browser in ${r.ms} ms: ${int(r.headers_checked)} header hashes recomputed, ${int(r.signers)} of ${int(r.voters)} voters' BLS keys aggregated, the signature verifies over ${(r.weight_fraction_total * 100).toFixed(1)}% of all weight. ${isCheckpoint ? 'This block is the certified checkpoint.' : 'This block sits under that lock on the selected chain.'} The light client is <a href="/verify/core.js">/verify/core.js</a>; the data it checked is <a href="/api/checkpoint?index=${index}">/api/checkpoint?index=${index}</a>.`;
|
||||
} else { badge.className = 'badge bad'; badge.textContent = 'certificate did not verify'; $('rc-line').textContent = `Certificate ${int(index)} did not verify in this browser: ${r.error || 'unknown reason'}.`; }
|
||||
} catch (e) { badge.className = 'badge wait'; badge.textContent = 're-check unavailable'; $('rc-line').textContent = 'The re-check could not run: ' + (e.message || e); }
|
||||
}
|
||||
async function load() {
|
||||
const r = await fetch('/api/explorer?' + query); const j = await r.json();
|
||||
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; $('title').textContent = /^\d/.test(id) ? 'Chain block ' + id : shortHash(id, 10, 8); return; }
|
||||
const b = j.block, d = b.detail || {}, now = new Date(j.now).getTime();
|
||||
document.title = `Igneum block ${shortHash(b.hash, 8, 6)}`;
|
||||
const b = j.block, d = b.detail || {}, now = new Date(j.now).getTime(), sum = b.shard_summary || { total: 0, paid: 0 };
|
||||
document.title = `Devnet 3 block ${shortHash(b.hash, 8, 6)}`;
|
||||
$('title').textContent = b.hash;
|
||||
const chips = [b.chain ? '<span class="chip hot">chain block</span>' : `<span class="chip">${esc(b.color)}</span>`];
|
||||
const chips = [b.chain ? (b.chain_now === false ? '<span class="chip" title="the observer saw it as the chain block of its number; a tip reorg gave the number to another block">chain block, replaced</span>' : '<span class="chip hot">chain block</span>') : `<span class="chip">${esc(b.color)}</span>`, `<span class="chip" title="the hash program family this block was mined under">class ${esc(b.class ? b.class.class : 'v4')}</span>`];
|
||||
if (j.checkpoint) chips.push(`<span class="chip ${j.checkpoint.state === 'locked' ? 'ok' : ''}">checkpoint ${j.checkpoint.index}, ${esc(j.checkpoint.state)}</span>`);
|
||||
if (b.proof_records) chips.push(`<span class="chip">${b.proof_records} proof record${b.proof_records === 1 ? '' : 's'}</span>`);
|
||||
if (b.tx_count) chips.push(`<span class="chip">${b.tx_count} transaction${b.tx_count === 1 ? '' : 's'}</span>`);
|
||||
chips.push(b.lock && b.lock.final ? `<span class="chip ok" title="${esc(b.lock.reason)}">final under lock ${int(b.lock.index)}</span>` : `<span class="chip" title="${esc(b.lock ? b.lock.reason : '')}">not under a lock yet</span>`);
|
||||
if (b.chain) chips.push(sum.total ? `<span class="chip ${sum.paid === sum.total ? 'ok' : ''}">${sum.paid} of ${sum.total} shards paid</span>` : '<span class="chip">plan not read yet</span>');
|
||||
if (b.proof_records) chips.push(`<span class="chip">carries ${b.proof_records} proof record${b.proof_records === 1 ? '' : 's'}</span>`);
|
||||
if (j.txs.length) chips.push(`<span class="chip">${j.txs.length} transaction${j.txs.length === 1 ? '' : 's'} executed</span>`);
|
||||
$('chips').innerHTML = chips.join('');
|
||||
$('summary').innerHTML = dl([
|
||||
['Number', b.number === null ? '<span style="color:var(--ash)">none, not a chain block</span>' : int(b.number)],
|
||||
['Time', `${utc(b.ts)} <span style="color:var(--ash)">(${rel(now - b.ts)})</span>`],
|
||||
['Network', 'Devnet 3, chain id ' + esc(j.chain_id ?? 4463)],
|
||||
['Number', b.number === null ? '<span class="kv">none, not a chain block</span>' : (b.chain_now === false ? `${int(b.number)} <span class="kv">as the observer first saw it; a tip reorg gave this number to another block, so the EVM executed that one</span>` : int(b.number))],
|
||||
['Time', `${utc(b.ts)} <span class="kv">(${rel(now - b.ts)})</span>`],
|
||||
['DAA score', int(b.daa)], ['Blue score', int(b.blue_score)],
|
||||
['Class', `${esc(b.class ? b.class.class : 'v4')} <span class="kv">${b.class && b.class.floors ? b.class.floors.map(f => `${f.class} from DAA ${int(f.daa)}`).join(', ') : ''}</span>`],
|
||||
['Lock state', b.lock ? `${b.lock.final ? 'final' : 'not final'} <span class="kv">${esc(b.lock.reason)}${j.lock ? `; newest lock ${int(j.lock.index)} at blue score ${int(j.lock.blue_score)}, ${(j.lock.fraction_total * 100).toFixed(1)}% of all weight` : ''}</span>` : 'n/a'],
|
||||
['Miner', addr(b.evm_miner)], ['Coinbase address', addr(b.miner)],
|
||||
['Vote key', `<span class="id">${esc(b.miner_id || 'n/a')}</span> <span class="hash" style="color:var(--ash);font-size:12px">${esc(b.vote_key_hash || '')}</span>`],
|
||||
['Vote key', `<span class="id">${esc(b.miner_id || 'n/a')}</span> <span class="hash kv" style="font-size:12px">${esc(b.vote_key_hash || '')}</span>`],
|
||||
b.engine ? ['Engine', esc(b.engine)] : null,
|
||||
['Difficulty', d.difficulty ? int(d.difficulty) : 'n/a'],
|
||||
['Declared subsidy', b.subsidy_sompi ? `${ign(b.subsidy_sompi, 8)} IGN <span style="color:var(--ash)">E(DAA) of spec 2.5, paid when a later chain block merges this one</span>` : 'n/a'],
|
||||
['Coinbase paid', b.paid_sompi ? `${ign(b.paid_sompi, 8)} IGN <span style="color:var(--ash)">to the blocks it merges</span>` : 'n/a'],
|
||||
['Merged by', b.chain ? 'itself (chain block)' : (j.merged_by ? link(j.merged_by) : '<span style="color:var(--ash)">not yet</span>')],
|
||||
['Declared subsidy', b.subsidy_sompi ? `${ign(b.subsidy_sompi, 8)} IGN <span class="kv">E(DAA) of spec 2.5, paid when a later chain block merges this one</span>` : 'n/a'],
|
||||
['Coinbase paid', b.paid_sompi ? `${ign(b.paid_sompi, 8)} IGN <span class="kv">to the blocks it merges</span>` : 'n/a'],
|
||||
['Merged by', b.chain ? 'itself (chain block)' : (j.merged_by ? link(j.merged_by) : '<span class="kv">not yet</span>')],
|
||||
['Selected parent', b.selected_parent ? link(b.selected_parent) : 'n/a'],
|
||||
]);
|
||||
$('header').innerHTML = dl([
|
||||
|
|
@ -366,21 +413,25 @@ async function load() {
|
|||
const ms = d.mergeset || { blues: [], reds: [] };
|
||||
$('mergeset').innerHTML = (ms.blues.length || ms.reds.length) ? `<div style="display:flex;flex-direction:column;gap:6px">${ms.blues.map(h => `<div><i class="sw blue"></i>${link(h)}</div>`).join('')}${ms.reds.map(h => `<div><i class="sw red"></i>${link(h)}</div>`).join('')}</div>` : '<div class="empty">Empty.</div>';
|
||||
const cb = d.coinbase;
|
||||
$('tx-n').textContent = `${b.tx_count ?? 0} EVM, 1 coinbase`;
|
||||
$('coinbase').innerHTML = cb ? `<dl>${dl([['Coinbase', `<span class="hash">${esc(cb.id)}</span>`], ['Outputs', cb.outputs.map(o => `${o.pool ? '<span style="color:var(--ash)">proving pool (burns on the UTXO side, credited on the EVM side)</span>' : addr(o.address)} <b>${ign(o.value, 8)} IGN</b>`).join('<br>') || 'none'], ['Carries', `${cb.records} proof record${cb.records === 1 ? '' : 's'}${cb.reveal ? ', a key reveal' : ''}${(d.certificates || []).length ? `, certificate ${d.certificates.join(', ')}` : ''}`]])}</dl>` : '<div class="empty">No coinbase decoded.</div>';
|
||||
const txs = d.txs || []; const ev = j.evm && j.evm.transactions ? new Map(j.evm.transactions.map(t => [t.hash, t])) : null;
|
||||
$('txs').innerHTML = txs.length ? `<table><thead><tr><th>Transaction</th><th>From</th><th>To</th><th class="n">Value</th><th class="n">Bytes</th></tr></thead><tbody>${txs.map(t => { const e = ev && ev.get(t.hash); return `<tr id="tx-${esc((t.hash || '').replace(/^0x/, ''))}"><td class="hash">${esc(t.hash || '?')}</td><td>${e ? addr(e.from) : '<span style="color:var(--ash)">needs an EVM RPC</span>'}</td><td>${e ? addr(e.to) : ''}</td><td class="n">${e ? ignFromWei(e.value) + ' IGN' : ''}</td><td class="n">${t.size ?? ''}</td></tr>`; }).join('')}</tbody></table>` : '<div class="empty" style="margin-top:8px">No EVM transactions in this block.</div>';
|
||||
$('tx-n').textContent = `${b.tx_count ?? 0} carried, ${j.txs.length} executed by the EVM, 1 coinbase`;
|
||||
$('coinbase').innerHTML = cb ? `<dl>${dl([['Coinbase', `<span class="hash">${esc(cb.id)}</span>`], ['Outputs', cb.outputs.map(o => `${o.pool ? '<span class="kv">proving pool (burns on the UTXO side, credited on the EVM side)</span>' : addr(o.address)} <b>${ign(o.value, 8)} IGN</b>`).join('<br>') || 'none'], ['Carries', `${cb.records} proof record${cb.records === 1 ? '' : 's'}${cb.reveal ? ', a key reveal' : ''}${(d.certificates || []).length ? `, certificate ${d.certificates.join(', ')}` : ''}`]])}</dl>` : '<div class="empty">No coinbase decoded.</div>';
|
||||
const carried = d.txs || [];
|
||||
$('txs').innerHTML = j.txs.length ? `<table><thead><tr><th>Transaction</th><th>From</th><th>To</th><th class="n">Value</th><th>Status</th><th class="n">Gas used</th></tr></thead><tbody>${j.txs.map(t => `<tr id="tx-${esc(t.hash.replace(/^0x/, ''))}"><td><a class="hash" href="/tx/${esc(t.hash)}">${esc(shortHash(t.hash, 12, 8))}</a></td><td>${t.from ? `<a class="hash" href="/address/${esc(t.from)}">${esc(shortHash(t.from, 8, 6))}</a>` : ''}</td><td>${t.to ? `<a class="hash" href="/address/${esc(t.to)}">${esc(shortHash(t.to, 8, 6))}</a>` : (t.contract_address ? `<span class="kv">created</span> <a class="hash" href="/address/${esc(t.contract_address)}">${esc(shortHash(t.contract_address, 8, 6))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 6)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td class="n">${int(t.gas_used)}</td></tr>`).join('')}</tbody></table>` :
|
||||
(carried.length ? `<p class="note">This block carries ${carried.length} transaction${carried.length === 1 ? '' : 's'}; ${b.chain ? 'the indexer has not read the block yet, or every one had already been executed in an earlier chain block' : 'they execute in the chain block that merges this one'}.</p>` : '<div class="empty" style="margin-top:8px">No EVM transactions in this block.</div>');
|
||||
if (j.evm && !j.evm.error) $('txs').insertAdjacentHTML('beforeend', `<p class="note">EVM view of this chain block: gas used ${int(j.evm.gas_used)}, state root <span class="hash">${esc(shortHash(j.evm.state_root, 10, 6))}</span>${j.evm.igneum ? `, rewards ${j.evm.igneum.rewards.map(r => ignFromWei(r.wei) + ' IGN to ' + shortHash(r.miner, 6, 4)).join(', ')}, proving pool credit ${ignFromWei(j.evm.igneum.proving_pool_credit)} IGN` : ''}.</p>`);
|
||||
const sh = j.shards;
|
||||
$('proof-eyebrow').textContent = b.chain ? `${sh.length} shard${sh.length === 1 ? '' : 's'} planned for this chain block` : 'not a chain block';
|
||||
$('proofs').innerHTML = `<p style="font-size:14px;color:var(--ink-2)">This block carries <b>${b.proof_records ?? 0}</b> proof record${b.proof_records === 1 ? '' : 's'} for earlier chain blocks (274 bytes each, in the coinbase extra data).</p>` +
|
||||
(sh.length ? `<div class="tbl"><table><thead><tr><th class="n">Shard</th><th>State</th><th>Prover</th><th class="n">pgas</th><th class="n">Proof lag, DAA</th><th>Carried by</th><th class="n">Payout</th></tr></thead><tbody>${sh.map(s => `<tr><td class="n">${s.i} of ${s.n}</td><td><span class="chip ${s.state === 'paid' ? 'ok' : s.state === 'verified' ? 'hot' : ''}">${esc(s.state)}</span></td><td class="id">${esc(s.prover || '')}</td><td class="n">${int(s.pgas)}</td><td class="n">${s.lag === null ? '' : int(s.lag)}</td><td>${s.carried_by ? link(s.carried_by) : ''}</td><td class="n">${s.payout_wei ? ignFromWei(s.payout_wei, 6) + ' IGN' : ''}</td></tr>`).join('')}</tbody></table></div>` : (b.chain ? '<div class="empty">No shard plan recorded (the proving feed was not reading this block).</div>' : ''));
|
||||
$('proofs').innerHTML = `<p style="font-size:14px;color:var(--ink-2)">This block carries <b>${b.proof_records ?? 0}</b> proof record${b.proof_records === 1 ? '' : 's'} for earlier chain blocks (274 bytes each, in the coinbase extra data).${b.chain ? ` Its own execution is split into <b>${sum.total}</b> shard${sum.total === 1 ? '' : 's'}: ${sum.paid} paid, ${sum.verified} verified, ${sum.proving} proving, ${sum.planned} planned.` : ''}</p>` +
|
||||
(sh.length ? `<div class="tbl"><table><thead><tr><th class="n">Shard</th><th>State</th><th>Prover</th><th class="n">pgas</th><th class="n">Proof lag, DAA</th><th>Carried by</th><th class="n">Payout</th><th>Node verdict</th></tr></thead><tbody>${sh.map(s => `<tr><td class="n">${s.i} of ${s.n}</td><td><span class="chip ${s.state === 'paid' ? 'ok' : s.state === 'verified' || s.state === 'proving' ? 'hot' : ''}">${esc(s.state)}</span></td><td class="id">${esc(s.prover || '')}</td><td class="n">${int(s.pgas)}</td><td class="n">${s.lag === null ? '' : int(s.lag)}</td><td>${s.carried_by ? link(s.carried_by) : ''}</td><td class="n">${s.payout_wei ? ignFromWei(s.payout_wei, 6) + ' IGN' : ''}</td><td>${s.node_verified === true ? 'proof verified by the node' : s.node_verified === false ? 'not verified' : '<span class="kv">no record yet</span>'}</td></tr>`).join('')}</tbody></table></div><p class="note">State follows the record: planned when the node published the shard plan, proving when a prover's record is in the pool, verified when the node's SP1 verifier accepted the proof, paid when a later coinbase carried and paid it. The explorer does not re-run the STARK itself; the node's verdict is shown as the node's. Every state, number and record on this page is read from the observer node, the chain the finality certificates follow.</p>` : (b.chain ? '<div class="empty">No shard plan recorded (the proving feed has not read this block).</div>' : ''));
|
||||
const cp = j.checkpoint, certs = j.certificates || [];
|
||||
$('fin-eyebrow').textContent = cp ? `checkpoint ${cp.index}` : (certs.length ? 'carries a certificate' : 'not a checkpoint');
|
||||
$('finality').innerHTML = (cp ? `<dl>${dl([['State', `<span class="chip ${cp.state === 'locked' ? 'ok' : ''}">${esc(cp.state)}</span>`], ['Signed weight', `${int(cp.signed)} of ${int(cp.total)} (${(cp.fraction_total * 100).toFixed(1)}% of all weight, ${(cp.fraction_active * 100).toFixed(1)}% of active)`], ['Votes', `${int(cp.votes)} of ${int(cp.voters)} voters`], cp.locked_at ? ['Locked', utc(new Date(cp.locked_at).getTime())] : null])}</dl>` : '') +
|
||||
certs.map(c => `<dl style="margin-top:14px">${dl([[c.role === 'checkpoint' ? 'Certificate' : 'Carries certificate', `index ${c.index}, ${c.voter_count} voters, aggregator <span class="id">${esc(shortHash(c.aggregator, 8, 0))}</span>, ${c.role === 'checkpoint' ? 'carried by ' + link(c.carrier) : 'for checkpoint ' + link(c.checkpoint)}`], ['Weight', `${int(c.total_weight)} total, ${int(c.active_weight)} active at the lock`], c.previous ? ['Previous lock', `index ${c.previous.index}, ${link(c.previous.hash)}${c.headers_complete ? ', header chain stored' : ''}`] : null, ['Verify', `<a href="/api/checkpoint">/api/checkpoint</a> serves the newest certificate for the in-browser verifier`]])}</dl>`).join('') +
|
||||
(!cp && !certs.length ? '<div class="empty">This block is neither a checkpoint nor a certificate carrier. Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight.</div>' : '');
|
||||
certs.map(c => `<dl style="margin-top:14px">${dl([[c.role === 'checkpoint' ? 'Certificate' : 'Carries certificate', `index ${c.index}, ${c.voter_count} voters, aggregator <span class="id">${esc(shortHash(c.aggregator, 8, 0))}</span>, ${c.role === 'checkpoint' ? 'carried by ' + link(c.carrier) : 'for checkpoint ' + link(c.checkpoint)}`], ['Weight', `${int(c.total_weight)} total, ${int(c.active_weight)} active at the lock`], c.previous ? ['Previous lock', `index ${c.previous.index}, ${link(c.previous.hash)}${c.headers_complete ? ', header chain stored' : ''}`] : null, ['Data', `<a href="/api/checkpoint?index=${c.index}">/api/checkpoint?index=${c.index}</a> serves this certificate for the in-browser verifier`]])}</dl>`).join('') +
|
||||
(!cp && !certs.length ? `<div class="empty">This block is neither a checkpoint nor a certificate carrier. Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight.${b.lock && b.lock.final ? ` This block is under lock ${int(b.lock.index)}.` : ''}</div>` : '');
|
||||
$('body').hidden = false;
|
||||
const ownCert = certs.find(c => c.role === 'checkpoint');
|
||||
if (ownCert) recheck(ownCert.index, b.hash, true);
|
||||
else if (b.lock && b.lock.final && b.lock.index !== undefined) recheck(b.lock.index, b.hash, false);
|
||||
}
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
</script>
|
||||
|
|
|
|||
367
site/build.html
Normal file
367
site/build.html
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Build on Igneum: chain ids, RPC, a contract in five minutes</title>
|
||||
<meta name="description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<link rel="canonical" href="https://igneum.network/build">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Build on Igneum: chain ids, RPC, a contract in five minutes">
|
||||
<meta property="og:description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<meta property="og:url" content="https://igneum.network/build">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Build on Igneum: chain ids, RPC, a contract in five minutes">
|
||||
<meta name="twitter:description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* generated-page block (the engineering log, the bench table, the provenance table): the page hero, the contents rail, the sections; tokens, type and components are in /site.css */
|
||||
[id]{scroll-margin-top:120px}
|
||||
article h1{display:none}
|
||||
article{color:var(--ink-2)}
|
||||
article h2{font-size:var(--t-h3);margin:0 0 12px}
|
||||
article h3{font-size:16px;margin:26px 0 8px}
|
||||
article h4{font:600 15px/1.4 var(--f-sans);margin:20px 0 6px;color:var(--bone)}
|
||||
article p{margin:0 0 14px}article ul,article ol{margin:0 0 14px;padding-left:22px}article li{margin-bottom:6px}
|
||||
article p,article li,article h2,article h3{overflow-wrap:anywhere}
|
||||
article pre{margin:0 0 var(--s-4)}
|
||||
.doc-section:last-child{border-bottom:0}
|
||||
.doc-section[hidden]{display:none}
|
||||
.tbl{margin:var(--s-4) 0 var(--s-5)}
|
||||
table{min-width:560px}
|
||||
.gen{color:var(--ash);font-size:13px;margin:40px 0 0;max-width:72ch}
|
||||
.doc-tools{margin:0 0 var(--s-5)}
|
||||
.doc-tools .searchbar{max-width:560px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build" aria-current="page"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build" aria-current="page"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Build on Igneum</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Developers</div>
|
||||
<h1>Build on Igneum</h1>
|
||||
<p class="lead">Built to prove every block. A lock in minutes. Nothing to stake. The EVM you already know: Solidity deploys unchanged. Here are the chain ids, the endpoints and a contract in five minutes.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
||||
<div class="docs-layout">
|
||||
<nav class="doc-nav" aria-label="Contents"><div class="eyebrow">Contents</div><a href="#what-is-different">What is different</a><a href="#networks">Networks</a><a href="#endpoints-and-tools">Endpoints and tools</a><a href="#your-first-contract-in-five-minutes">Your first contract in five minutes</a><a href="#the-rpc-the-node-serves">The RPC the node serves</a><a href="#verify-a-block-in-your-browser">Verify a block in your browser</a><a href="#where-to-ask">Where to ask</a></nav>
|
||||
<article class="doc-body" data-filter-list="build"><section class="doc-section"><h1 id="build-on-igneum">Build on Igneum</h1>
|
||||
<p>This file is the source of <a href="https://igneum.network/build" rel="noopener">igneum.network/build</a>. The site build renders it as the page. The other files in this directory are the walkthrough, the RPC list, the faucet, the verifier and the grants.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="what-is-different">What is different</h2>
|
||||
<p><strong>Every block is built to be proven.</strong> A chain block carries a zero-knowledge proof of its execution. The miners are the provers: the same cards that find blocks prove them, in shards. On Devnet 3 a share of blocks carries a proof today; the live page shows the share and the lag, and the design target at launch is under a minute. Full nodes execute every block themselves, so a bad proof is a light-client problem and never a chain split.</p>
|
||||
<p><strong>A lock in minutes, not an hour of confirmations.</strong> Miners sign a checkpoint every 30 seconds. When two thirds of the mining weight of the last 30 days have signed, the checkpoint is locked. Weight is blocks mined, nothing else. The lock lands in about two minutes. The <a href="/litepaper">litepaper</a> has the rule.</p>
|
||||
<p><strong>Nothing to stake.</strong> No validator set, no delegation, no slashing, no bonded class above the miners. Finality comes from mining weight alone. Nobody holds a key that the chain depends on.</p>
|
||||
<p><strong>The EVM you already know.</strong> Solidity deploys unchanged. Standard JSON-RPC, EIP-1559 transactions, the chain id in the signature, <code>cancun</code> as the EVM version. Gas has two dimensions on Igneum, execution and proving, and the node folds the second into the price it quotes, so <code>eth_estimateGas</code> and <code>eth_gasPrice</code> work as they do on Ethereum.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="networks">Networks</h2>
|
||||
<div class="tbl"><table><thead><tr><th></th><th>Devnet 3</th><th>Testnet</th><th>Mainnet</th></tr></thead><tbody><tr><td>Chain id</td><td>4463 (<code>0x116f</code>)</td><td>4462 (<code>0x116e</code>)</td><td>4461 (<code>0x116d</code>)</td></tr><tr><td>Network id</td><td><code>igneum-devnet-3</code></td><td><code>igneum-testnet-1</code></td><td>not started</td></tr><tr><td>RPC</td><td><code>https://rpc.devnet.igneum.network</code> (a node you run serves <code>http://127.0.0.1:26790</code>)</td><td><code>https://rpc.testnet.igneum.network</code> (answers; nothing mines there yet, so a transaction waits)</td><td>none</td></tr><tr><td>Coins</td><td>no value, resets without notice</td><td>no value, resets with notice</td><td>not started</td></tr><tr><td>Symbol, decimals</td><td>IGN, 18</td><td>IGN, 18</td><td>IGN, 18</td></tr></tbody></table></div>
|
||||
<p>Devnet 3 is where you build today. It is a developer network: it resets without notice and its coins have no value. Its public RPC takes the read methods, <code>eth_sendRawTransaction</code> and a wRPC websocket at <code>/ws</code>, at 20 requests a second per address. The public testnet exists, its RPC answers, and no blocks are being produced on it until it opens. Mainnet has no date. Devnet 3 answers chain id 4463 until its class v5 floor, then 4464.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="endpoints-and-tools">Endpoints and tools</h2>
|
||||
<ul><li><strong>Wallet.</strong> Any Ethereum wallet. <a href="/metamask">Add Igneum to MetaMask</a> with one click, or the <a href="/wallet">Igneum wallet</a>.</li><li><strong>Faucet.</strong> <a href="/faucet">10 IGN of Devnet 3 coin</a> per address per day. No account.</li><li><strong>Explorer.</strong> <a href="/explorer">The explorer</a> shows blocks, the DAG, miners and addresses. The EVM views, transactions and contracts, are being built and link from the same page as they land.</li><li><strong>Swap.</strong> <a href="/swap">The swap</a>: test tokens on Devnet 3, every swap in a proven block.</li><li><strong>Source.</strong> <a href="https://git.igneum.network/igneum-network/igneum" rel="noopener">git.igneum.network/igneum-network/igneum</a>: the node, the miner, the site, and these pages under <code>docs/build/</code>.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="your-first-contract-in-five-minutes">Your first contract in five minutes</h2>
|
||||
<p>With <a href="https://getfoundry.sh" rel="noopener">Foundry</a>. Tested end to end on Devnet 3 on a build box; the full walkthrough with the expected output is <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/first-contract.md" rel="noopener">docs/build/first-contract.md</a>.</p>
|
||||
<pre>curl -L https://foundry.paradigm.xyz | bash && foundryup
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast wallet new # an address and a private key, for the devnet only</pre>
|
||||
<p>Paste the address into <a href="/faucet">the faucet</a>. Then:</p>
|
||||
<pre>export PK=0x... # the private key cast printed
|
||||
cast balance $(cast wallet address $PK) --rpc-url $RPC --ether
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast</pre>
|
||||
<p><code>forge create</code> prints <code>Deployed to: 0x...</code>. Call it:</p>
|
||||
<pre>cast send 0xDEPLOYED "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call 0xDEPLOYED "number()(uint256)" --rpc-url $RPC</pre>
|
||||
<p>The call answers <code>1</code>. Paste the transaction hash into <a href="/explorer">the explorer</a>. Hardhat, ethers and viem work the same way: chain id 4463, the RPC above.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-rpc-the-node-serves">The RPC the node serves</h2>
|
||||
<p>Read from a Devnet 3 node, not from a spec. <code>web3_clientVersion</code> answers <code>igneumd/2.1.0/execution-layer-v3</code>. The full list, served and not served, with the probe that produced it: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/rpc.md" rel="noopener">docs/build/rpc.md</a>.</p>
|
||||
<ul><li><strong>Served.</strong> <code>eth_chainId</code>, <code>eth_blockNumber</code>, <code>eth_getBalance</code>, <code>eth_getTransactionCount</code>, <code>eth_getCode</code>, <code>eth_getStorageAt</code>, <code>eth_getBlockByNumber</code>, <code>eth_getBlockByHash</code>, <code>eth_getTransactionByHash</code>, <code>eth_getTransactionReceipt</code>, <code>eth_getBlockReceipts</code>, <code>eth_getLogs</code>, <code>eth_call</code>, <code>eth_estimateGas</code>, <code>eth_gasPrice</code>, <code>eth_maxPriorityFeePerGas</code>, <code>eth_feeHistory</code>, <code>eth_sendRawTransaction</code>, <code>eth_syncing</code>, <code>eth_accounts</code>, <code>net_version</code>, <code>net_peerCount</code>, <code>net_listening</code>, <code>web3_clientVersion</code>.</li><li><strong>Igneum's own.</strong> <code>igneum_getExecStatus</code>, <code>igneum_getProvingStatus</code>, <code>igneum_getShardPlan</code>, <code>igneum_getProofRecords</code>, <code>igneum_getTransactionStatus</code>, <code>igneum_estimateGas</code>, <code>igneum_getBudgets</code> and the segment and proof calls. <code>igneum_estimateGas</code> returns both gas dimensions and whether a call exceeds the proving limit.</li><li><strong>Not served.</strong> Filters and subscriptions (<code>eth_newFilter</code>, <code>eth_subscribe</code>), <code>txpool_*</code>, <code>debug_*</code>, <code>trace_*</code>, <code>eth_sendTransaction</code>, <code>eth_sign</code>, <code>eth_getProof</code>, the uncle calls. Poll <code>eth_blockNumber</code> and <code>eth_getLogs</code>. Sign on your side.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="verify-a-block-in-your-browser">Verify a block in your browser</h2>
|
||||
<p>The site ships a light client. Your browser fetches the latest certified checkpoint from <code>/api/checkpoint</code> and verifies the BLS aggregate signature, the voter weights and the header chain itself, in the tab. Nothing is trusted from the server but the data. The example, in twelve lines, is <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/verify-a-block.md" rel="noopener">docs/build/verify-a-block.md</a>; the live run is <a href="/verify/test.html">verify/test.html</a>, genuine and tampered cases side by side.</p>
|
||||
<pre>import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified, r.signers, 'of', r.voters, 'voters', r.ms, 'ms');</pre>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="where-to-ask">Where to ask</h2>
|
||||
<ul><li>An issue on <a href="https://git.igneum.network/igneum-network/igneum/issues" rel="noopener">the repository</a>.</li><li><a href="https://discord.gg/igneum" rel="noopener">Discord</a>, the builders channel.</li><li><a href="/grants">Grants</a> for tooling, reference apps, infrastructure and research.</li></ul>
|
||||
<p>Devnet and testnet coins have no value. Nothing on this page is an offer to sell anything.</p></section></article>
|
||||
</div>
|
||||
<p class="gen">Generated from docs/build/build.md in the repository at build time. Times are UTC.</p>
|
||||
</div></section>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script src="/ui.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,6 +19,7 @@ function inline(s) {
|
|||
s = s.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
s = s.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||
s = s.replace(/\[([^\]]+)\]\((https?:[^)]+)\)/g, '<a href="$2" rel="noopener">$1</a>');
|
||||
s = s.replace(/\[([^\]]+)\]\((\/[^)\s]*)\)/g, '<a href="$2">$1</a>'); // a site-relative link (the builder pages, 8 October 2026)
|
||||
return s;
|
||||
}
|
||||
function md(src) {
|
||||
|
|
@ -278,6 +279,21 @@ if (existsSync(join(docs, 'bench-log.md'))) {
|
|||
built.push('journey.json (' + j.log.length + ' entries)');
|
||||
}
|
||||
|
||||
// The builder programme (8 October 2026): /build and /grants are rendered from docs/build/build.md and docs/build/grants.md
|
||||
// through the same generated-page shell as /bench, so the markdown is the source and the served page follows it. The other
|
||||
// files of docs/build/ (the walkthrough, the RPC list, the faucet, the verifier) are linked from /build on the git host.
|
||||
for (const [src, file, title, desc, heading, lead, eyebrow] of [
|
||||
['build.md', 'build.html', 'Build on Igneum: chain ids, RPC, a contract in five minutes', 'The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.', 'Build on Igneum', 'Built to prove every block. A lock in minutes. Nothing to stake. The EVM you already know: Solidity deploys unchanged. Here are the chain ids, the endpoints and a contract in five minutes.', 'Developers'],
|
||||
['grants.md', 'grants.html', 'Igneum grants: tooling, reference apps, infrastructure, research', 'The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.', 'Grants', 'Paid in IGN from the dev fee fund, on delivery, on the public testnet first. Four tiers. One issue to apply. A weekly review.', 'The programme'],
|
||||
]) {
|
||||
const mdp = join(docs, 'build', src);
|
||||
if (!existsSync(mdp)) continue; // the gate builds a copy of site/ alone: the committed page stands, as for /bench
|
||||
const { html, toc } = md(readFileSync(mdp, 'utf8'));
|
||||
const path = '/' + file.replace(/\.html$/, '');
|
||||
writeFileSync(join(here, file), page(title, desc, html, toc, lead, { path, heading, crumb: heading, eyebrow, filter: false }).replace('<p class="gen">Generated from the repository at build time. Times are UTC. Machine names are model names.</p>', `<p class="gen">Generated from docs/build/${src} in the repository at build time. Times are UTC.</p>`));
|
||||
built.push(file);
|
||||
}
|
||||
|
||||
// The hand-written pages: shared head, nav (with the active link marked) and footer injected in place; the homepage also
|
||||
// gets journey.json inlined so the phases and the log render without a fetch and without a layout shift.
|
||||
const journey = JSON.parse(readFileSync(join(here, 'journey.json'), 'utf8'));
|
||||
|
|
@ -389,11 +405,14 @@ function renderEvidence(html) {
|
|||
return html;
|
||||
}
|
||||
|
||||
const PAGES = [['index.html', ''], ['download.html', 'download'], ['income.html', 'income'], ['litepaper.html', 'litepaper'], ['live.html', 'live'], ['evidence.html', 'evidence'], ['miner.html', 'miner'], ['app.html', 'app'], ['wallet.html', 'wallet'], ['ledger.html', 'ledger'], ['metamask.html', 'metamask'], ['faucet.html', 'faucet'], ['404.html', ''],
|
||||
// the DAG explorer (5 Oct 2026): /explorer, /block/<hash> and /address/<addr> (vercel.json rewrites the last two)
|
||||
['explorer.html', 'live'], ['block.html', 'live'], ['address.html', 'live'],
|
||||
const PAGES = [['index.html', ''], ['download.html', 'download'], ['income.html', 'income'], ['economics.html', 'economics'], ['litepaper.html', 'litepaper'], ['live.html', 'live'], ['evidence.html', 'evidence'], ['miner.html', 'miner'], ['app.html', 'app'], ['wallet.html', 'wallet'], ['ledger.html', 'ledger'], ['metamask.html', 'metamask'], ['faucet.html', 'faucet'], ['swap.html', 'swap'], ['404.html', ''],
|
||||
// the Devnet 3 explorer (5 Oct 2026, extended 8 Oct 2026): /explorer, /block/<hash>, /address/<addr>, /tx/<hash> (vercel.json rewrites
|
||||
// the three) and /proving; the Explorer entry of the Network panel is the current one on all five
|
||||
['explorer.html', 'explorer'], ['block.html', 'explorer'], ['address.html', 'explorer'], ['tx.html', 'explorer'], ['proving.html', 'explorer'],
|
||||
// the scenes lab (6 Oct 2026): three animated views of the live feed, unlinked, noindex
|
||||
['scenes.html', '']];
|
||||
['scenes.html', ''],
|
||||
// the reference apps (8 Oct 2026): the light wallet, the payment receipt, the Sepolia state oracle
|
||||
['light.html', 'light'], ['receipt.html', 'receipt'], ['oracle.html', 'oracle']];
|
||||
for (const [file, active] of PAGES) {
|
||||
const p = join(here, file);
|
||||
if (!existsSync(p)) throw new Error(`missing page ${file}`);
|
||||
|
|
@ -406,6 +425,17 @@ for (const [file, active] of PAGES) {
|
|||
html = stampMarks(html);
|
||||
if (file === 'evidence.html') html = renderEvidence(html);
|
||||
if (file === 'index.html' && html.includes('<!-- journey:start -->')) html = inject(html, 'journey', `<script type="application/json" id="journey-data">${JSON.stringify(journey).replace(/</g, '\\u003c')}</script>`, file);
|
||||
// /income (8 October 2026): the calculator's card list is the bench table's current rows, stock and tuned apart, inlined
|
||||
// at build so the page needs no fetch; a row's watts carry their class when they were read under another (watts_class)
|
||||
if (file === 'income.html' && html.includes('<!-- income-data:start -->')) {
|
||||
const bj = JSON.parse(readFileSync(join(here, 'miner-bench.json'), 'utf8'));
|
||||
const tunedOf = (r) => /Ember Tune|core lock/.test(r.tuned || '') ? 'tuned' : 'stock';
|
||||
const list = bj.rows.filter(r => r.generator === 'v2' && r.date >= '2026-10-06' && r.group !== 'datacentre' && r.mh_s > 0)
|
||||
// a tuned row's rate is the tune point's (the display reads "136.1 stock (127.7 tuned)"), never the stock best beside tuned watts
|
||||
.map(r => { const t = tunedOf(r) === 'tuned' && /\(([\d.]+) tuned\)/.exec(r.mh_s_display || ''); const mhs = t ? Number(t[1]) : r.mh_s; return { key: r.card + '|' + r.date + '|' + tunedOf(r), card: r.card.replace(/ \(.*$/, ''), mh_s: mhs, mh_s_display: t ? `${mhs} MH/s tuned` : (r.mh_s_display || null), watts: r.watts ?? null, watts_class: r.watts_class || null, state: tunedOf(r), by: r.by, date: r.date }; })
|
||||
.sort((a, b) => b.mh_s - a.mh_s);
|
||||
html = inject(html, 'income-data', `<script type="application/json" id="income-data">${JSON.stringify(list).replace(/</g, '\\u003c')}</script>`, file);
|
||||
}
|
||||
writeFileSync(p, html);
|
||||
built.push(file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,8 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,18 +114,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims" aria-current="page"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -138,8 +149,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -148,15 +157,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims" aria-current="page"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -224,7 +243,7 @@
|
|||
<div class="derived"><p>Here are the limits, stated before anyone else states them.</p>
|
||||
<ul>
|
||||
<li><strong>A proof in seconds.</strong> Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held for about seven years; the one chip announced against it, Bitmain’s Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held its miners on commodity hardware for about seven years: one chip shipped against it, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, the Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured; RandomX v2 was released on 25 March 2026 with its activation pending. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A guaranteed income floor.</strong> No. External proving is a small market today. Igneum's miners' electricity cost in it is close to power, but the price they must charge is the subsidy they forgo, which falls as one over network hash: an edge at scale and nothing more.</li>
|
||||
<li><strong>A memory-hard prototype on every vendor.</strong> Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open.</li>
|
||||
<li><strong>Finality in the first month.</strong> No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears.</li>
|
||||
|
|
@ -264,7 +283,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -279,6 +298,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,8 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee" aria-current="page"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,18 +114,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -138,8 +149,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee" aria-current="page"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -148,15 +157,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -272,7 +291,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -287,6 +306,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -93,8 +94,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -105,18 +104,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -128,8 +139,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -138,15 +147,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -237,16 +256,16 @@
|
|||
<div><h3>Ember for Linux</h3><div class="sub">one tarball, the miner and the node inside</div></div>
|
||||
<div class="body">
|
||||
<p>Unpack it, run <code>igneum</code> with your payout address. The same signed manifest as the desktop apps. NVIDIA through CUDA, AMD through OpenCL.</p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><span class="osmark bare" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="sha"><b>sha256</b> <span data-dl-sha="miner-hive">0d716ed92560b6b2eccb63ca1bd7a4d9eb64c9b334e8370e1263f0344cee294e</span></div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><span class="osmark bare" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.22 · 28.8 MB</span></a>
|
||||
<div class="sha"><b>sha256</b> <span data-dl-sha="miner-hive">8ad6dcef9edc57dcd33e8d5a97cbef5cdda0e384a6e56d3f62f8903029c4c764</span></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="dl-card" id="hive">
|
||||
<span class="osmark" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>
|
||||
<div><h3>Ember on HiveOS</h3><div class="sub">for the rig people, the same tarball</div></div>
|
||||
<div class="body">
|
||||
<div class="hive-sheet"><b>Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.23.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn"><span class="osmark bare" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet"><b>Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.22.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn"><span class="osmark bare" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.22 · 28.8 MB</span></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
|
@ -310,7 +329,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -325,6 +344,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
336
site/economics.html
Normal file
336
site/economics.html
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum economics: the emission as the node encodes it</title>
|
||||
<meta name="description" content="The emission schedule, the 80/20 split, the fee routes, the proving-fee market, the switchable 1 percent client fee and the decimals, each as a table with its file and line in the node. No price, no projection.">
|
||||
<link rel="canonical" href="https://igneum.network/economics">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics" aria-current="page"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics" aria-current="page"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero"><div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Economics</span></div>
|
||||
<h1>The economics, as the node encodes them.</h1>
|
||||
<p class="lead">Every number below is read from the node’s source at one commit, with the file and the line. No price of IGN appears and nothing is projected: this page says what the code pays, to whom, and from what.</p>
|
||||
</div></section>
|
||||
<section class="section"><div class="container">
|
||||
<p class="src"><b>Source:</b> the node fork, branch <code>release-0.3.25-node</code> at <code>e0644958</code> (the Devnet 3 cut of 8 October 2026), confirmed by the node lane on 8 October 2026; every line number is that commit’s. Devnet 3 inherits the devnet parameters (<code>consensus/core/src/config/params.rs</code> 2173 and 2207).</p>
|
||||
|
||||
<h2>Emission</h2>
|
||||
<p>The node carries two schedules in one struct (<code>consensus/core/src/emission.rs</code> 85 to 123) and installs one per network (<code>params.rs</code> 2158, 1910, 1764). A year is 31,557,600 seconds (<code>emission.rs</code> 32); the chain counts time in DAA seconds, one a block at one block a second.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Field</th><th><code>CURRENT</code> (Devnet 3 today, mainnet)</th><th><code>TESTNET_1</code> (igneum-testnet-1)</th><th>Where</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Launch rate</td><td class="num">3,168,808,781 base units a DAA second (10<sup>9</sup> IGN x 10<sup>8</sup> / 31,557,600, floored: one billion IGN in year one)</td><td class="num">100 IGN a DAA second</td><td><code>emission.rs</code> 85 to 123; <code>igneum.rs</code> 34</td></tr>
|
||||
<tr><td>Ramp</td><td class="num">2,592,000 s (30 days) from 10 percent</td><td class="num">7,776,000 s (90 days) from 10 percent</td><td><code>igneum.rs</code> 76 <code>launch_ramp</code></td></tr>
|
||||
<tr><td>Step</td><td class="num">63,115,200 s (two years), the rate halved each step (decay 2<sup>31</sup> of 2<sup>32</sup>)</td><td class="num">2,629,800 s (a month), the rate times 2<sup>-1/24</sup> each step (decay 4,172,697,914 of 2<sup>32</sup>: a two-year half-life)</td><td><code>emission.rs</code> 85 to 123</td></tr>
|
||||
<tr><td>Tail</td><td class="num">none: the curve runs to zero and the sum is the hard cap, 4,000,000,000 IGN</td><td class="num">1 percent of supply a year (100 basis points) once the glide falls below it</td><td><code>emission.rs</code> 69 to 71</td></tr>
|
||||
<tr><td>Where each runs</td><td>Devnet 3 (8 decimals); mainnet (rescaled to 18)</td><td>igneum-testnet-1 (rescaled to 18)</td><td><code>params.rs</code> 2158, 1764, 1910</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>The schedule is a genesis parameter: the devnet digest does not move when a network installs another (<code>params.rs</code> 2095, the test). The live devnet’s block reward at its current DAA score is on <a href="/income">the income page</a>, computed from the <code>CURRENT</code> rule.</p>
|
||||
|
||||
<h2>Where a block’s coins go</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Share</th><th>Goes to</th><th>State</th><th>Where</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td class="num">80 percent</td><td>the miner whose key found the block</td><td>in consensus on every network</td><td><code>consensus/core/src/igneum.rs</code> 44 (<code>PROVING_POOL_SHARE_PERCENT = 20</code>), applied at 87 and 202</td></tr>
|
||||
<tr><td class="num">20 percent</td><td>the proving pool, paid per shard to the provers of a segment record from a keyless escrow account</td><td>in consensus; the escrow is <code>PROVING_POOL_ADDRESS</code> in the execution layer</td><td><code>igneum.rs</code> 44; <code>igneum/exec/src/config.rs</code></td></tr>
|
||||
<tr><td>A silent block’s bonus</td><td>a slice of the producer’s share moved to the pool when the producer did not sign its checkpoints, nothing destroyed</td><td>designed and in the code, not active: <code>signing_bonus_activation_daa</code> is <code>u64::MAX</code> on every object</td><td><code>igneum.rs</code> 96 <code>silent_split</code>; <code>params.rs</code> 1717</td></tr>
|
||||
<tr><td class="num">0</td><td>any team, foundation, fund or treasury</td><td>no such output exists in the subsidy and no protocol tip reaches any address</td><td><code>igneum.rs</code>; spec 05 section 5.5</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>Where fees go</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Route</th><th>What happens</th><th>State</th><th>Where</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Base fee, both gas dimensions</td><td>burned in full: gas used times the execution base fee, pgas used times the proving base fee, debited and credited to no one</td><td>in the code on Devnet 3</td><td><code>igneum/exec/src/executor.rs</code> 320 to 371 (327 and 357, 328 and 360)</td></tr>
|
||||
<tr><td>Priority fee (the tip)</td><td>80 percent to the block’s miner; 20 percent to the developer registrations of the contracts whose code ran, pro rata by each frame’s gas; an unregistered frame’s part is credited to nobody, which is a burn</td><td>in the code on Devnet 3</td><td><code>executor.rs</code> 335 to 339; <code>igneum/exec/src/pgas.rs</code> 290; <code>igneum/exec/src/config.rs</code> 76 (<code>DEVELOPER_SHARE_PERCENT = 20</code>)</td></tr>
|
||||
<tr><td>External proving jobs</td><td>90 percent to the provers who delivered, 10 percent burned, once jobs settle in IGN</td><td>designed, not in the code: no constant exists; at launch a job is paid on the customer’s own chain</td><td>spec 05 section 5.4; the litepaper’s Proving section</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>The proving-fee market</h2>
|
||||
<p>The second income of a card is the proving pool above: 20 percent of every block, paid per shard against a valid proof record, plus the provers’ part of the priority fee. The price a prover must charge an outside customer is the subsidy it forgoes while it proves, which falls as one over the network’s hash rate; the formula and its measured inputs are in the litepaper (<a href="/litepaper#building">Building on Igneum</a>). The market itself is designed and not built. What the pool pays today is measured: on Devnet 3 in the 24 hours to 12:16 UK on 8 October 2026 the chain paid 8,209 shards, 9,913.09 IGN in all, to 29 prover keys; 905 shards were paid in the hour to that minute; the lag from a proven block to the block that pays its shards read p50 514 and p90 953 DAA seconds; 40,502 shards were planned and 54 proving at that minute (the observer’s proof tables, read through <code>/api/explorer?proving=1</code>; the same numbers live on <a href="/proving">the proving page</a>). Devnet 3 IGN has no value; the rows show the mechanism paying, not an income.</p>
|
||||
|
||||
<h2>The client fee and the fund it fills</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Item</th><th>What</th><th>Where</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>The dev fee</td><td>Ember, the official miner, requests one block template in a hundred with the dev payout address instead of yours: 1 percent, a counter, not a draw; off with <code>--dev-fee 0</code>, the switch in the app or <code>DEV_FEE=0</code> on HiveOS; none in pool mode, where the pool issues the templates</td><td><code>igneum/miner/src/main.rs</code> 718 (<code>DEV_FEE_DEFAULT_PERCENT = 1</code>), 712 (the release address), 716 (the devnet address)</td></tr>
|
||||
<tr><td>What it is</td><td>the software’s fee, never the protocol’s: any other client is welcome and pays nothing</td><td><a href="/dev-fee">the dev fee page</a></td></tr>
|
||||
<tr><td>The fund it fills</td><td>the IGN the dev fee collects goes to Igneum Labs, the company that ships the software; that is the fund the <a href="/grants">grants</a> are paid from. The protocol carries no fund and no grant is paid from emission</td><td><a href="/grants">the grants page</a></td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>Units and decimals</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Network</th><th>Consensus side</th><th>EVM side</th><th>Where</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Devnet 3 (today)</td><td class="num">8 decimals (base units of 10<sup>-8</sup> IGN)</td><td class="num">18 decimals, through a bridge of 10<sup>10</sup> wei per unit</td><td><code>params.rs</code> 2120; <code>consensus/core/src/unit.rs</code>; <code>igneum/exec/src/config.rs</code> 51</td></tr>
|
||||
<tr><td>igneum-testnet-1</td><td class="num">18 decimals</td><td class="num">18 decimals</td><td><code>params.rs</code> 1866; the emission rescaled by 10<sup>10</sup></td></tr>
|
||||
<tr><td>Mainnet</td><td class="num">18 decimals</td><td class="num">18 decimals</td><td><code>params.rs</code> 1724</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>The symbol is IGN on every network. A wallet shows 18 decimals everywhere; on Devnet 3 the chain pays in 8 and the bridge shows the same amount at 18.</p>
|
||||
|
||||
<h2>What this page does not do</h2>
|
||||
<p>It names no price, projects no income and models no market. The <a href="/income">income page</a> turns these rules into IGN a day for a card you pick, and money a day only at a price you type. Devnet and testnet IGN have no value.</p>
|
||||
<p>Not legal advice.</p>
|
||||
</div></section>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -97,6 +97,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -114,8 +115,6 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -126,18 +125,30 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence" aria-current="page"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -149,8 +160,6 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -159,15 +168,25 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence" aria-current="page"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -257,7 +276,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<tr data-status="implemented"><td class="n">15</td><td class="claim">Every block is proven, with the proof landing within about a minute at launch<div class="where">Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>d7e1f89</code> (GPU proof), <code>e01a3cc</code>, <code>292e800</code>, <code>eedd136</code> (<code>proving/igneum-prove</code>: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6</td><td><code>proving/windows-wsl2</code> (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; <code>igneum-prove-host --mode block</code> on <code>proving/fixtures/</code>; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards"</td><td>First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture <code>block-78-increment</code> (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in <code>docs/benchmarks/proving-e2e.md</code>. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on the RTX 5090 Windows rig in 34 s, verified on the Apple M5 Max in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind <code>proving_v1_activation_daa</code> (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="designed"><td class="n">16</td><td class="claim">A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves)<div class="where">Litepaper Proving ("The proving budget"); roadmap gate 2</div></td><td><span class="st st-0">designed</span></td><td class="mono">spec 5.1 (Target), 7.6 (<code>S_p</code> provisional, 7,500,000 pgas = <code>B_p</code> / 4)</td><td><code>PROVE-SHARD.bat</code> on the RTX 5090 (pending); the end-to-end standard in <code>docs/benchmarks/proving-e2e.md</code>; bench-log "proving: devnet v4 shards"</td><td>Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional <code>S_p</code> is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="designed"><td class="n">17</td><td class="claim">The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state)<div class="where">the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line</div></td><td><span class="st st-0">tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured</span></td><td class="mono"><code>docs/analysis/chip-model-v3.md</code> 5 and 6; <code>docs/analysis/latency-shadow-2026-10-06.md</code>; <code>docs/plans/counter-asic-3-status.md</code>; <code>docs/analysis/attack-pass/f8-uniform.md</code>, <code>f4-weakday.md</code>, <code>docs/analysis/ca3-v4-uniform.md</code>; <code>docs/design/class-v5-stored-state.md</code>; the H100 and market-cap rows of 7 October; <code>docs/plans/cryptanalysis/in-house-pass.md</code> (the internal adversarial pass)</td><td>the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses <code>tools/attack/f8-uniform</code> and the F4 census; the verifier by <code>igneum-pow bench</code></td><td>136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, the RTX 5090 Windows rig's RTX 5090, the three-card Windows rig's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026).</td><td class="iv">none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), whose floor reading is in (measured, 8 October 2026; ledger AP-F8-1 and AP-F8-6): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test, and no outside review has run yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">18</td><td class="claim">The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache<div class="where">Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">readwidth e752fc7 (<code>docs/plans/read-width.md</code>), ca2-era 78c0ee4, ca2-cache 2de19e5 (<code>docs/plans/hot-table.md</code>)</td><td>The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load</td><td>Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">18</td><td class="claim">The chip resistance measurements: the program is latency-bound (dependent reads spread over the whole dataset), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache; measured 8 October 2026: the distinct-index floor holds at 0.995 on every accepted program, about half of epochs carry one load site with a biased address bit at the era's stride rotation, priced at about 1.6 percent of a hash's reads to a chip storing half the dataset and nothing to one storing all of it (<code>docs/analysis/class-v6/family-gate.md</code>, lane D; adv-cache-2's <code>report-chained-cache-2.md</code> section 2.3 on its branch; ledger AP-F8-7)<div class="where">Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">readwidth e752fc7 (<code>docs/plans/read-width.md</code>), ca2-era 78c0ee4, ca2-cache 2de19e5 (<code>docs/plans/hot-table.md</code>)</td><td>The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load</td><td>Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">19</td><td class="claim">The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors<div class="where">Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">ca2-mixer 1ab8b21 (<code>tests/mixer.rs</code>, <code>tests/scratch.rs</code>), ca2-era 78c0ee4, ca2-soundness a465881 (<code>docs/analysis/scratch-soundness.md</code>), <code>igneum-pow/tests/packs.rs</code></td><td>The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card</td><td>Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing)</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="implemented"><td class="n">20</td><td class="claim">No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%)<div class="where">Homepage stats and Economics tiles; litepaper Supply, Economics</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>6ac80a3</code>; fork "igneum-node devnet v0"; <code>consensus/core/src/igneum.rs</code>, <code>coinbase.rs</code></td><td><code>cargo test -p kaspa-consensus-core igneum</code> (8 pass: subsidy table, ramp, split, cap) and <code>cargo test -p kaspa-consensus coinbase</code> (8 pass); <code>igneum-miner inspect 40</code>; bench-log "igneum-node devnet v0"</td><td>Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the <code>igneum-proving-pool-v0</code> output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">21</td><td class="claim">The proving pool's 20% reaches shard provers and aggregators<div class="where">Litepaper Economics; homepage "20% provers"</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">spec 5.3; <code>proving/igneum-prove</code> carries the prover's payout address in every shard proof (ledger P12)</td><td>None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (<code>proving.rs shard_payouts</code>, the carrying segment pays the first valid record per shard its part of the segment's pool credit)</td><td>The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (<code>sim/economy</code>, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to the RTX 5090 Windows rig's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid")</td><td class="iv">none yet</td></tr>
|
||||
|
|
@ -305,7 +324,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -320,6 +339,9 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum explorer</title>
|
||||
<meta name="description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
|
||||
<title>Igneum Devnet 3 explorer</title>
|
||||
<meta name="description" content="Devnet 3, block by block: the DAG, every transaction, every account, the shard plan and proof of each block, the finality lock that covers it. A test network: coins have no value.">
|
||||
<link rel="canonical" href="https://igneum.network/explorer">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum explorer">
|
||||
<meta property="og:description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
|
||||
<meta property="og:title" content="Igneum Devnet 3 explorer">
|
||||
<meta property="og:description" content="Devnet 3, block by block: the DAG, every transaction, every account, the shard plan and proof of each block, the finality lock that covers it. A test network: coins have no value.">
|
||||
<meta property="og:url" content="https://igneum.network/explorer">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
<meta property="og:image:height" content="256">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum explorer">
|
||||
<meta name="twitter:description" content="The Igneum block DAG, block by block, with the network numbers and the supply.">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 explorer">
|
||||
<meta name="twitter:description" content="Devnet 3, block by block: the DAG, transactions, accounts, proofs and finality. A test network.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -91,6 +91,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body class="off">
|
||||
|
|
@ -107,6 +113,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -124,30 +131,40 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -159,25 +176,33 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -234,11 +259,11 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Explorer</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>devnet, last 24 hours</div>
|
||||
<h1>Explorer<span class="accent">.</span></h1>
|
||||
<p>Every block the devnet made in the last day, read from a node by the observer. Paste a block hash, a transaction hash, a chain block number or an address, or click any row.</p>
|
||||
<div class="eyebrow"><span class="line"></span>Devnet 3, chain id 4463</div>
|
||||
<h1>Devnet 3 explorer<span class="accent">.</span></h1>
|
||||
<p>Every block Devnet 3 made in the last day and every transaction of the last seven days, read from a node by the observer and the indexer. Paste a block hash, a transaction hash, a chain block number or an address, or click any row. Devnet 3 is a test network: its coins have no value and the chain may reset. Every number here comes from one node, the observer node on the build box, the chain the finality certificates follow; the indexer reads that node's execution RPC and nothing else.</p>
|
||||
<form class="search" id="search" role="search">
|
||||
<input id="q" type="search" autocomplete="off" spellcheck="false" placeholder="block hash, transaction hash, chain block number, 0x address or igneumdev:… address" aria-label="Search the explorer">
|
||||
<input id="q" type="search" autocomplete="off" spellcheck="false" placeholder="block hash, transaction hash, chain block number, 0x address or igneumdev:… address" aria-label="Search the Devnet 3 explorer">
|
||||
<button class="btn primary" type="submit">Search</button>
|
||||
</form>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -247,32 +272,53 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="cell status"><div class="k">Status</div><div class="v"><span class="dot"></span><span id="st-status">OFFLINE</span></div><div class="s" id="st-age">no observer update yet</div></div>
|
||||
<div class="cell"><div class="k">Height</div><div class="v" id="st-height">0</div><div class="s" id="st-count">chain block number, 0 blocks in the DAG</div></div>
|
||||
<div class="cell"><div class="k">DAA score</div><div class="v" id="st-daa">0</div><div class="s" id="st-blue">blue score 0</div></div>
|
||||
<div class="cell"><div class="k">Difficulty</div><div class="v" id="st-diff">0</div><div class="s" id="st-bt">target per block</div></div>
|
||||
<div class="cell"><div class="k">Hash rate</div><div class="v" id="st-hps">0</div><div class="s">network estimate</div></div>
|
||||
<div class="cell"><div class="k">Block reward</div><div class="v" id="st-reward">0<small>IGN</small></div><div class="s" id="st-split">80% miner, 20% proving pool</div></div>
|
||||
<div class="cell"><div class="k">Circulating</div><div class="v" id="st-supply">0<small>IGN</small></div><div class="s" id="st-cap">of 4,000,000,000 by the rule</div></div>
|
||||
<div class="cell"><div class="k">Next halving</div><div class="v" id="st-halving">0<small>d</small></div><div class="s" id="st-ramp">ramp</div></div>
|
||||
<div class="cell"><div class="k">Hash rate</div><div class="v" id="st-hps">0</div><div class="s" id="st-diff">difficulty 0</div></div>
|
||||
<div class="cell"><div class="k">Chain rate, 10 min</div><div class="v" id="st-rate">0<small>blocks/s</small></div><div class="s" id="st-rate-s">DAG blocks per second; chain blocks per second</div></div>
|
||||
<div class="cell"><div class="k">Finality</div><div class="v" id="st-fin">n/a</div><div class="s" id="st-fin-s">voters and weight</div></div>
|
||||
<div class="cell"><div class="k">Program class</div><div class="v" id="st-class">v4</div><div class="s" id="st-class-s">the hash program family at the tip</div></div>
|
||||
<div class="cell"><div class="k">Proving</div><div class="v" id="st-prov">0<small>paid</small></div><div class="s" id="st-prov-s">shards paid in the last 10 min for blocks of any age</div></div>
|
||||
</div>
|
||||
<div class="card" aria-label="The DAG">
|
||||
<div class="viz-head"><h2>The DAG</h2><div class="eyebrow" id="dag-eyebrow">the newest 150 blocks, one lane per miner</div></div>
|
||||
<div class="dagbox"><canvas id="dag" aria-label="The last 150 blocks of Devnet 3 as a graph: time left to right, one lane per miner, lines to parents"></canvas><div class="dagtip" id="dag-tip"></div></div>
|
||||
<div class="legend" style="margin-top:12px"><span><i class="sw chain"></i>chain block</span><span><i class="sw blue"></i>blue, merged</span><span><i class="sw red"></i>red, excluded</span><span><i class="sw"></i>pending</span><span>◆ under a lock</span><span>● every shard paid</span></div>
|
||||
<p class="note">Left to right is arrival order at the observer; a line joins a block to each parent in the picture. Blue blocks are merged and paid; red blocks are excluded from the order. A diamond outline marks a block under a finality lock, a filled dot a block whose every planned shard has been paid. Click a block for its page.</p>
|
||||
</div>
|
||||
<div class="card" aria-label="Latest blocks">
|
||||
<div class="viz-head"><h2>Latest blocks</h2><div class="eyebrow" id="blk-eyebrow">newest first, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Miner</th><th class="n">Txs</th><th class="n">Proof records</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="8" class="empty">Loading.</td></tr></tbody>
|
||||
<thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Class</th><th>Miner</th><th class="n">Txs</th><th>Shards paid</th><th>Final</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="10" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="legend"><span><i class="sw chain"></i>chain block</span><span><i class="sw blue"></i>blue, merged and paid</span><span><i class="sw red"></i>red, excluded</span><span><i class="sw"></i>pending, not merged yet</span><span>★ locked checkpoint</span></div>
|
||||
<p class="note">Number is the chain block number, the same number the EVM reports; a block off the selected chain has none. Miner is the payout address the coinbase names. Proof records is how many shard proofs the block carries for earlier blocks. Click a row for the block.</p>
|
||||
<p class="note">Number is the chain block number, the same number the EVM reports; a block off the selected chain has none. Class is the hash program family the block was mined under. Txs is what the block carries; the EVM executes each transaction once, in the first chain block that includes it. Shards paid counts the block's proof shards a later coinbase has paid. Final means a finality lock covers the block.</p>
|
||||
<button class="btn" id="more" type="button" style="margin-top:14px">Older blocks</button>
|
||||
</div>
|
||||
<div class="card" aria-label="Public API">
|
||||
<div class="viz-head"><h2>Public API</h2><div class="eyebrow">JSON, cached 10 s</div></div>
|
||||
<dl>
|
||||
<dt>/api/stats</dt><dd><a href="/api/stats" class="hash">network hash rate, difficulty, block time, block reward now, blocks per day, DAA, blue score, height, last block, chain id, version</a></dd>
|
||||
<dt>/api/supply</dt><dd><a href="/api/supply" class="hash">circulating by the emission rule, the 4,000,000,000 cap, the halving table, the 30-day ramp, the observer's coinbase check</a></dd>
|
||||
<dt>/api/explorer</dt><dd><a href="/api/explorer?blocks=20" class="hash">?blocks=N, ?block=hash, ?height=N, ?address=addr, ?search=q</a></dd>
|
||||
</dl>
|
||||
<p class="note">Reward and supply come from the emission rule of the specification (section 2.5) at the node's DAA score; the observer checks the chain's coinbase sums against it every hour and the result is in /api/supply under check.</p>
|
||||
<div class="card" aria-label="Latest transactions">
|
||||
<div class="viz-head"><h2>Latest transactions</h2><div class="eyebrow" id="tx-eyebrow">newest first, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th>Transaction</th><th class="n">Block</th><th>From</th><th>To</th><th class="n">Value</th><th>Status</th><th>Time</th></tr></thead>
|
||||
<tbody id="txs"><tr><td colspan="7" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="note">EVM transactions as the indexer read them from the node's receipts: seven days are kept. Value is in IGN (18 decimals on the EVM side).</p>
|
||||
<button class="btn" id="more-tx" type="button" style="margin-top:14px">Older transactions</button>
|
||||
</div>
|
||||
<div class="two two-wrap">
|
||||
<div class="card" aria-label="Proving"><div class="viz-head"><h2>Proving</h2><div class="eyebrow" id="pv-eyebrow">shards, provers, latency</div></div><dl id="pv"></dl><p class="note"><a href="/proving">The proving view</a>: every chain block's shard plan, who proved what, and the block-to-paid latency.</p></div>
|
||||
<div class="card" aria-label="Public API"><div class="viz-head"><h2>Public API</h2><div class="eyebrow">JSON, cached 5 to 10 s</div></div>
|
||||
<dl>
|
||||
<dt>/api/stats</dt><dd><a href="/api/stats" class="hash">hash rate, difficulty, block time, reward, DAA, blue score, height</a></dd>
|
||||
<dt>/api/supply</dt><dd><a href="/api/supply" class="hash">circulating by the emission rule, the cap, the halving table</a></dd>
|
||||
<dt>/api/explorer</dt><dd><a href="/api/explorer?blocks=20" class="hash">?blocks=N, ?block=hash, ?height=N, ?tx=hash, ?txs=N, ?address=addr, ?proving=1, ?stats=1, ?dag=N, ?search=q</a></dd>
|
||||
<dt>/api/checkpoint</dt><dd><a href="/api/checkpoint" class="hash">the newest certified checkpoint with its voter table and headers; ?index=N for one</a></dd>
|
||||
<dt>/api/live</dt><dd><a href="/api/live" class="hash">the observer's feed: blocks of the last 90 s, miners, events, finality, proving</a></dd>
|
||||
</dl>
|
||||
<p class="note">Every answer names the network (Devnet 3, chain id 4463). The RPC itself is at rpc.devnet.igneum.network (read methods and eth_sendRawTransaction, 20 requests per second per address).</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
|
|
@ -297,7 +343,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -312,6 +358,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -343,11 +392,12 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
</script>
|
||||
<!-- footer:end -->
|
||||
<script type="module">
|
||||
import { classify, hrefFor, ign, shortHash, hashrate, rel, int } from '/lib/explorer.mjs';
|
||||
import { classify, hrefFor, ign, ignFromWei, shortHash, hashrate, rel, int } from '/lib/explorer.mjs';
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
let oldest = 0, serverNow = 0, serverAt = 0;
|
||||
const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
let oldest = 0, oldestTx = 0, serverNow = 0, serverAt = 0;
|
||||
const vnow = () => serverNow + (performance.now() - serverAt);
|
||||
const stamp = iso => iso ? new Date(iso).toISOString().slice(11, 19) + ' UTC' : '';
|
||||
$('search').addEventListener('submit', async e => {
|
||||
e.preventDefault();
|
||||
const c = classify($('q').value);
|
||||
|
|
@ -360,46 +410,109 @@ $('search').addEventListener('submit', async e => {
|
|||
if (j.ok && j.href) location.href = j.href; else $('msg').textContent = j.error || 'Not found.';
|
||||
} catch { $('msg').textContent = 'The API did not answer.'; }
|
||||
});
|
||||
const minerCell = b => (b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}" title="${esc(b.evm_miner)}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : (b.miner ? `<a class="hash" href="/address/${esc(b.miner)}">${esc(shortHash(b.miner, 14, 4))}</a>` : '<span class="id">' + esc(b.miner_id || '?') + '</span>')) + `<span class="id" style="margin-left:8px;font-size:12px">${esc(b.miner_id || '')}</span>`;
|
||||
function shardsCell(b) {
|
||||
const s = b.shards; if (!s || !s.total) return b.chain ? '<span class="kv">no plan yet</span>' : '<span class="kv">not a chain block</span>';
|
||||
const pct = Math.round(s.paid / s.total * 100);
|
||||
return `<span class="bar" title="${s.paid} paid, ${s.verified} verified, ${s.proving} proving, ${s.planned} planned"><i class="${s.paid === s.total ? '' : 'part'}" style="width:${pct}%"></i></span>${s.paid} of ${s.total}`;
|
||||
}
|
||||
function rowHtml(b) {
|
||||
const sw = b.chain ? 'chain' : b.color;
|
||||
const miner = b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}" title="${esc(b.evm_miner)}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : (b.miner ? `<a class="hash" href="/address/${esc(b.miner)}">${esc(shortHash(b.miner, 14, 4))}</a>` : '<span class="id">' + esc(b.miner_id || '?') + '</span>');
|
||||
return `<tr data-href="/block/${b.hash}"><td><i class="sw ${sw}" title="${b.chain ? 'chain block' : b.color}"></i><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a>${b.locked ? ' ★' : ''}</td><td class="n">${b.number === null ? '<span style="color:var(--ash)">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${miner}<span class="id" style="margin-left:8px;font-size:12px">${esc(b.miner_id || '')}</span></td><td class="n">${b.tx_count === null ? 'n/a' : b.tx_count}</td><td class="n">${b.proof_records === null ? 'n/a' : b.proof_records}</td><td title="${new Date(b.ts).toISOString()}">${rel(vnow() - b.ts)}</td></tr>`;
|
||||
const replaced = b.chain && b.chain_now === false, sw = replaced ? '' : (b.chain ? 'chain' : b.color);
|
||||
return `<tr data-href="/block/${b.hash}"><td><i class="sw ${sw}" title="${replaced ? 'was the chain block of its number, replaced by a tip reorg' : (b.chain ? 'chain block' : b.color)}"></i><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a>${b.locked ? ' ★' : ''}</td><td class="n">${b.number === null ? '<span class="kv">off chain</span>' : (replaced ? `<span class="kv" title="a tip reorg gave this number to another block">${int(b.number)}, replaced</span>` : int(b.number))}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td><span class="chip">${esc(b.class || 'v4')}</span></td><td>${minerCell(b)}</td><td class="n">${b.tx_count === null ? 'n/a' : b.tx_count}</td><td>${shardsCell(b)}</td><td>${b.final ? '<span class="chip ok">final</span>' : '<span class="kv">not yet</span>'}</td><td title="${new Date(b.ts).toISOString()}">${rel(vnow() - b.ts)}</td></tr>`;
|
||||
}
|
||||
async function loadBlocks(before) {
|
||||
const r = await fetch('/api/explorer?blocks=50' + (before ? '&before=' + before : ''));
|
||||
const j = await r.json(); if (!j.ok) throw new Error(j.error);
|
||||
serverNow = new Date(j.now).getTime(); serverAt = performance.now();
|
||||
const html = j.blocks.map(rowHtml).join('');
|
||||
if (before) $('blocks').insertAdjacentHTML('beforeend', html); else $('blocks').innerHTML = html || '<tr><td colspan="8" class="empty">No blocks in the last 24 hours.</td></tr>';
|
||||
if (before) $('blocks').insertAdjacentHTML('beforeend', html); else $('blocks').innerHTML = html || '<tr><td colspan="10" class="empty">No blocks in the last 24 hours.</td></tr>';
|
||||
if (j.blocks.length) oldest = j.blocks[j.blocks.length - 1].rx;
|
||||
$('blk-eyebrow').textContent = (j.stale ? 'observer offline, last known' : 'newest first, every 5 s') + (j.network ? ', ' + j.network : '');
|
||||
$('blk-eyebrow').textContent = (j.stale ? 'observer offline, last known' : 'newest first, every 5 s') + (j.lock ? `, lock ${int(j.lock.index)} at blue score ${int(j.lock.blue_score)}` : ', no lock yet');
|
||||
}
|
||||
$('blocks').addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
function txHtml(t) {
|
||||
return `<tr data-href="/tx/${t.hash}"><td><a class="hash" href="/tx/${t.hash}">${esc(shortHash(t.hash, 10, 6))}</a></td><td class="n"><a href="/block/${t.block_hash}">${int(t.number)}</a></td><td><a class="hash" href="/address/${t.from}" title="${esc(t.from)}">${esc(shortHash(t.from, 6, 4))}</a></td><td>${t.to ? `<a class="hash" href="/address/${t.to}" title="${esc(t.to)}">${esc(shortHash(t.to, 6, 4))}</a>` : (t.contract_address ? `<span class="kv">created </span><a class="hash" href="/address/${t.contract_address}">${esc(shortHash(t.contract_address, 6, 4))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 4)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td title="${t.ts ? new Date(t.ts).toISOString() : ''}">${t.ts ? rel(vnow() - t.ts) : 'n/a'}</td></tr>`;
|
||||
}
|
||||
async function loadTxs(before) {
|
||||
const r = await fetch('/api/explorer?txs=30' + (before ? '&before=' + before : ''));
|
||||
const j = await r.json(); if (!j.ok) throw new Error(j.error);
|
||||
const html = j.txs.map(txHtml).join('');
|
||||
if (before) $('txs').insertAdjacentHTML('beforeend', html); else $('txs').innerHTML = html || '<tr><td colspan="7" class="empty">No transactions indexed yet.</td></tr>';
|
||||
if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number;
|
||||
const ix = j.indexer || {};
|
||||
$('tx-eyebrow').textContent = ix.stale ? 'indexer stale, last known' : `newest first, every 5 s; ${int(ix.txs_total)} transactions and ${int(ix.accounts_total)} accounts in seven days, indexed to chain block ${int(ix.indexed_number)}`;
|
||||
}
|
||||
for (const [tb] of [['blocks'], ['txs']]) $(tb).addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
$('more').addEventListener('click', () => { $('more').disabled = true; loadBlocks(oldest).catch(() => {}).finally(() => { $('more').disabled = false; clearInterval(timer); }); });
|
||||
$('more-tx').addEventListener('click', () => { $('more-tx').disabled = true; loadTxs(oldestTx).catch(() => {}).finally(() => { $('more-tx').disabled = false; clearInterval(timerTx); }); });
|
||||
async function loadStats() {
|
||||
const [s, p] = await Promise.all([fetch('/api/stats').then(r => r.json()), fetch('/api/supply').then(r => r.json())]);
|
||||
const s = await fetch('/api/explorer?stats=1').then(r => r.json()); if (!s.ok) throw new Error(s.error);
|
||||
document.body.classList.toggle('on', !s.stale); document.body.classList.toggle('off', !!s.stale);
|
||||
$('st-status').textContent = s.stale ? 'OFFLINE' : 'LIVE';
|
||||
$('st-age').textContent = s.age_s === null ? 'no observer update yet' : (s.stale ? `last update ${rel(s.age_s * 1000)}` : `${s.network || ''}, node ${s.node_version || '?'}`);
|
||||
$('st-age').textContent = s.stale ? 'observer stale' : `${s.network || 'Devnet 3'}, node ${s.node_version || '?'}, read ${stamp(s.now)}`;
|
||||
$('st-height').textContent = s.height === null ? 'n/a' : int(s.height);
|
||||
$('st-count').textContent = `chain block number, ${int(s.block_count)} blocks in the DAG`;
|
||||
$('st-daa').textContent = int(s.daa); $('st-blue').textContent = 'blue score ' + int(s.blue_score);
|
||||
$('st-diff').textContent = s.difficulty === null ? 'n/a' : (s.difficulty >= 1e6 ? (s.difficulty / 1e6).toFixed(2) + ' M' : int(s.difficulty));
|
||||
$('st-bt').textContent = s.block_time_measured_s === null ? 'target 1 s per block' : `${s.block_time_measured_s} s per block over 60 s, target 1 s`;
|
||||
$('st-hps').textContent = hashrate(s.hashrate);
|
||||
if (s.block_reward) { $('st-reward').innerHTML = esc(Number(s.block_reward.ign).toFixed(4)) + '<small>IGN</small>'; $('st-split').textContent = `${Number(s.block_reward.miner_ign).toFixed(4)} miner, ${Number(s.block_reward.proving_pool_ign).toFixed(4)} proving pool`; }
|
||||
if (p.ok) {
|
||||
$('st-supply').innerHTML = esc(int(Number(p.circulating_ign))) + '<small>IGN</small>';
|
||||
$('st-cap').textContent = `of ${int(Number(p.max_supply_ign))}, ${(Number(p.circulating_ign) / Number(p.max_supply_ign) * 100).toFixed(3)}% by the rule`;
|
||||
const d = p.halving.next_halving_in_s / 86400;
|
||||
$('st-halving').innerHTML = esc(d >= 1 ? Math.floor(d).toLocaleString('en-GB') : (p.halving.next_halving_in_s / 3600).toFixed(1)) + '<small>' + (d >= 1 ? 'days' : 'h') + '</small>';
|
||||
$('st-ramp').textContent = p.ramp.complete ? 'launch ramp complete' : `launch ramp at ${(p.ramp.factor_now * 100).toFixed(1)}%, full at DAA ${int(p.ramp.length_daa_s)}`;
|
||||
}
|
||||
$('st-hps').textContent = hashrate(s.hashrate); $('st-diff').textContent = 'difficulty ' + (s.difficulty === null ? 'n/a' : (s.difficulty >= 1e6 ? (s.difficulty / 1e6).toFixed(2) + ' M' : int(s.difficulty)));
|
||||
$('st-rate').innerHTML = esc(s.blocks_per_s_10m === null ? 'n/a' : s.blocks_per_s_10m.toFixed(2)) + '<small>blocks/s</small>';
|
||||
$('st-rate-s').textContent = `${s.chain_blocks_per_s_10m === null ? 'n/a' : s.chain_blocks_per_s_10m.toFixed(2)} chain blocks per second, ${int(s.miners_10m)} miners in 10 min`;
|
||||
const f = s.finality;
|
||||
if (f) { $('st-fin').innerHTML = f.latest_locked_index === null ? 'no lock' : `lock ${int(f.latest_locked_index)}`; $('st-fin-s').textContent = `${int(f.voters)} voters, ${int(f.total_weight)} blocks of weight${s.lock ? `, ${(s.lock.fraction_total * 100).toFixed(1)}% signed the newest lock` : ''}${f.active ? '' : ', finality paused'}`; }
|
||||
$('st-class').textContent = s.class ? s.class.class : 'v4';
|
||||
const next = s.class && s.class.floors ? s.class.floors.find(x => x.daa > (s.daa || 0)) : null;
|
||||
$('st-class-s').textContent = next ? `${next.class} from DAA ${int(next.daa)}` : (s.class && s.class.floors && s.class.floors.length ? `since DAA ${int(s.class.floors[s.class.floors.length - 1].daa)}` : 'the hash program family at the tip');
|
||||
const p = s.proving || {}, pa = s.paid_10m_any_age || {};
|
||||
$('st-prov').innerHTML = esc(int(pa.shards ?? 0)) + '<small>paid</small>';
|
||||
$('st-prov-s').textContent = p.supported === false ? 'the node reports no proving layer' : `shards paid in the last 10 min for blocks of any age, ${int(pa.provers ?? 0)} provers, ${int(p.open_blocks ?? 0)} open blocks`;
|
||||
}
|
||||
async function loadProving() {
|
||||
const j = await fetch('/api/explorer?proving=1').then(r => r.json()); if (!j.ok) throw new Error(j.error);
|
||||
const p = j.proving || {}, l = j.latency_1h || {}, t = j.totals_24h || {};
|
||||
const dl = pairs => pairs.map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
$('pv-eyebrow').textContent = `read ${stamp(j.now)}`;
|
||||
$('pv').innerHTML = dl([
|
||||
['Paid, 24 h', `${int(t.paid ? t.paid.shards : 0)} shards, ${ignFromWei(t.paid ? t.paid.payout_wei : '0', 2)} IGN to provers`],
|
||||
['Open now', `${int(t.planned ? t.planned.shards : 0)} planned, ${int(t.proving ? t.proving.shards : 0)} proving, ${int(t.verified ? t.verified.shards : 0)} verified and unpaid`],
|
||||
['Provers, 24 h', `${int(j.provers.length)} keys paid`],
|
||||
['Latency, 1 h', l.paid ? `${int(l.paid)} paid; p50 ${int(l.p50_daa)} DAA, p90 ${int(l.p90_daa)} DAA from the block to its payer` : 'no shard paid in the last hour'],
|
||||
['Verifier', p.verifier ? 'the observer node checks every record it sees' : 'n/a'],
|
||||
]);
|
||||
}
|
||||
// the DAG picture: arrival order left to right, one lane per miner, links to parents in the picture
|
||||
const dagTip = $('dag-tip'); let dagBlocks = [], dagPos = new Map();
|
||||
function drawDag() {
|
||||
const cv = $('dag'); if (!cv || !dagBlocks.length) return;
|
||||
const dpr = Math.min(devicePixelRatio || 1, 2), W = cv.clientWidth, H = cv.clientHeight; cv.width = W * dpr; cv.height = H * dpr;
|
||||
const ctx = cv.getContext('2d'); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.clearRect(0, 0, W, H);
|
||||
const cs = getComputedStyle(document.documentElement), col = k => cs.getPropertyValue(k).trim();
|
||||
const lanes = []; const laneOf = new Map();
|
||||
for (const b of dagBlocks) { const m = b.miner_id || '?'; if (!laneOf.has(m)) { laneOf.set(m, lanes.length); lanes.push(m); } }
|
||||
const n = dagBlocks.length, padX = 18, padY = 16, lh = Math.max(14, (H - 2 * padY) / Math.max(1, lanes.length)), xs = (W - 2 * padX) / Math.max(1, n - 1);
|
||||
dagPos = new Map(); dagBlocks.forEach((b, i) => dagPos.set(b.hash, { x: padX + i * xs, y: padY + laneOf.get(b.miner_id || '?') * lh + lh / 2, b }));
|
||||
ctx.lineWidth = 1;
|
||||
for (const b of dagBlocks) { const p = dagPos.get(b.hash); for (const ph of b.parent_hashes || []) { const q = dagPos.get(ph); if (!q) continue; ctx.strokeStyle = b.chain && ph === b.selected_parent ? col('--ember') : 'rgba(154,154,158,.35)'; ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(q.x, q.y); ctx.stroke(); } }
|
||||
for (const b of dagBlocks) {
|
||||
const p = dagPos.get(b.hash), r = b.chain ? 5 : 3.5;
|
||||
ctx.fillStyle = b.chain && b.chain_now !== false ? col('--ember') : b.color === 'blue' ? col('--included') : b.color === 'red' ? col('--excluded') : col('--ash');
|
||||
ctx.beginPath(); ctx.arc(p.x, p.y, r, 0, Math.PI * 2); ctx.fill();
|
||||
if (b.final) { ctx.strokeStyle = col('--molten'); ctx.beginPath(); ctx.moveTo(p.x, p.y - r - 4); ctx.lineTo(p.x + r + 4, p.y); ctx.lineTo(p.x, p.y + r + 4); ctx.lineTo(p.x - r - 4, p.y); ctx.closePath(); ctx.stroke(); }
|
||||
if (b.shards && b.shards.total && b.shards.paid === b.shards.total) { ctx.fillStyle = col('--bone'); ctx.beginPath(); ctx.arc(p.x, p.y, 1.6, 0, Math.PI * 2); ctx.fill(); }
|
||||
}
|
||||
ctx.font = '10px ' + (col('--mono') || 'monospace'); ctx.fillStyle = col('--ash');
|
||||
lanes.forEach((m, i) => ctx.fillText(m, 4, padY + i * lh + lh / 2 - 7));
|
||||
}
|
||||
function nearest(ev) { const cv = $('dag'), r = cv.getBoundingClientRect(), x = ev.clientX - r.left, y = ev.clientY - r.top; let best = null, bd = 144; for (const p of dagPos.values()) { const d = (p.x - x) ** 2 + (p.y - y) ** 2; if (d < bd) { bd = d; best = p; } } return best; }
|
||||
$('dag').addEventListener('mousemove', ev => { const p = nearest(ev); if (!p) { dagTip.style.display = 'none'; return; } const b = p.b, s = b.shards; dagTip.style.display = 'block'; dagTip.style.left = Math.min(p.x + 12, $('dag').clientWidth - 310) + 'px'; dagTip.style.top = (p.y + 12) + 'px'; dagTip.innerHTML = `${esc(shortHash(b.hash, 10, 6))}<br>${b.chain ? (b.chain_now === false ? 'replaced chain block ' + int(b.number) : 'chain block ' + int(b.number)) : esc(b.color)}, blue score ${int(b.blue_score)}, DAA ${int(b.daa)}<br>miner ${esc(b.miner_id || '?')}, class ${esc(b.class || 'v4')}, ${b.parents} parent${b.parents === 1 ? '' : 's'}<br>${s && s.total ? `${s.paid} of ${s.total} shards paid` : (b.chain ? 'plan not read yet' : 'no shards (not a chain block)')}${b.final ? ', under a lock' : ''}`; });
|
||||
$('dag').addEventListener('mouseleave', () => { dagTip.style.display = 'none'; });
|
||||
$('dag').addEventListener('click', ev => { const p = nearest(ev); if (p) location.href = '/block/' + p.b.hash; });
|
||||
async function loadDag() { const j = await fetch('/api/explorer?dag=150').then(r => r.json()); if (!j.ok) throw new Error(j.error); dagBlocks = j.blocks; $('dag-eyebrow').textContent = `the newest ${j.blocks.length} blocks, one lane per miner, read ${stamp(j.now)}`; drawDag(); }
|
||||
window.addEventListener('resize', drawDag); document.addEventListener('igneum-theme', drawDag);
|
||||
const timer = setInterval(() => { loadBlocks().catch(() => {}); }, 5000);
|
||||
setInterval(() => { loadStats().catch(() => {}); }, 10000);
|
||||
loadBlocks().catch(e => { $('blocks').innerHTML = `<tr><td colspan="8" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadStats().catch(() => {});
|
||||
const timerTx = setInterval(() => { loadTxs().catch(() => {}); }, 5000);
|
||||
setInterval(() => { loadStats().catch(() => {}); loadProving().catch(() => {}); }, 10000);
|
||||
setInterval(() => { loadDag().catch(() => {}); }, 4000);
|
||||
loadBlocks().catch(e => { $('blocks').innerHTML = `<tr><td colspan="10" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadTxs().catch(e => { $('txs').innerHTML = `<tr><td colspan="7" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadStats().catch(() => {}); loadProving().catch(() => {}); loadDag().catch(() => {});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum testnet faucet. 10 IGN a day for testing</title>
|
||||
<meta name="description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account. Paste an address, get a transaction hash.">
|
||||
<title>Igneum Devnet 3 faucet. 10 IGN a day for building</title>
|
||||
<meta name="description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account. Paste an address, get a transaction hash.">
|
||||
<link rel="canonical" href="https://igneum.network/faucet">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum testnet faucet">
|
||||
<meta property="og:description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account.">
|
||||
<meta property="og:title" content="Igneum Devnet 3 faucet">
|
||||
<meta property="og:description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account.">
|
||||
<meta property="og:url" content="https://igneum.network/faucet">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum testnet faucet">
|
||||
<meta name="twitter:description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account.">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 faucet">
|
||||
<meta name="twitter:description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
|
|
@ -86,9 +86,10 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -106,8 +107,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -118,18 +117,30 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -141,8 +152,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -151,15 +160,25 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -215,16 +234,16 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Testnet faucet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Testnet faucet</div>
|
||||
<h1>10 IGN a day, <span class="accent">for testing.</span></h1>
|
||||
<p>Paste an address. The faucet sends 10 testnet IGN and shows you the transaction hash. Once per address per day, once per connection per day. No account, no sign-in, nothing to install.</p>
|
||||
<p data-testnet-notice class="notice">Public testnet: not yet open. The faucet is prepared on the devnet and answers "not open yet" until the testnet starts.</p>
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Devnet 3 faucet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Devnet 3 faucet</div>
|
||||
<h1>10 IGN a day, <span class="accent">for building.</span></h1>
|
||||
<p>Paste an address. The faucet sends 10 IGN of Devnet 3 coin and shows you the transaction hash. Once per address per day, once per connection per day. No account, no sign-in, nothing to install.</p>
|
||||
<p class="notice" id="faucet-state">Devnet 3, chain id 4463. The coins have no value and the chain resets without notice. <span id="faucet-balance"></span></p>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<section class="card" aria-labelledby="ask">
|
||||
<h2 id="ask">Ask for 10 IGN</h2>
|
||||
<p>An Ethereum-style address: 0x and 40 hex characters. The one the miner made for you, or any wallet you have pointed at the Igneum testnet.</p>
|
||||
<p>An Ethereum-style address: 0x and 40 hex characters. The one <code>cast wallet new</code> printed, the one the miner made for you, or any wallet you have pointed at Devnet 3.</p>
|
||||
<form id="faucet-form" novalidate>
|
||||
<label for="address">Address</label>
|
||||
<input id="address" name="address" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" required pattern="^0x[0-9a-fA-F]{40}$" aria-describedby="status">
|
||||
|
|
@ -235,15 +254,17 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<aside class="card" aria-labelledby="rules">
|
||||
<h2 id="rules">The rules</h2>
|
||||
<div class="rules">
|
||||
<div class="rule"><span class="num">01</span><div><b>No value</b><span>Testnet IGN cannot be sold, bought or redeemed, now or at mainnet. Mainnet starts from an empty genesis.</span></div></div>
|
||||
<div class="rule"><span class="num">02</span><div><b>10 IGN per address per day</b><span>And 10 per connection per day. The limit resets 24 hours after the last grant.</span></div></div>
|
||||
<div class="rule"><span class="num">03</span><div><b>Resets</b><span>The chain restarts from a fresh genesis when a consensus rule changes. Balances do not carry over.</span></div></div>
|
||||
<div class="rule"><span class="num">04</span><div><b>What is stored</b><span>The address, the connection's IP, the transaction hash and the time, for 24 hours of rate limiting. Nothing else.</span></div></div>
|
||||
<div class="rule"><span class="num">01</span><div><b>No value</b><span>Devnet IGN cannot be sold, bought or redeemed, now or at mainnet. Mainnet starts from an empty genesis.</span></div></div>
|
||||
<div class="rule"><span class="num">02</span><div><b>10 IGN per address per day</b><span>And 10 per connection per day, 500 sends a day in all. The limit resets 24 hours after the last send.</span></div></div>
|
||||
<div class="rule"><span class="num">03</span><div><b>Resets</b><span>Devnet 3 is a developer network. It restarts from a fresh genesis without notice. Balances do not carry over.</span></div></div>
|
||||
<div class="rule"><span class="num">04</span><div><b>What is stored</b><span>The address, the connection's IP, the transaction hash and the time, on the box that runs the faucet, for 24 hours of rate limiting. Nothing else.</span></div></div>
|
||||
</div>
|
||||
<dl>
|
||||
<dt>Chain id</dt><dd>4462 (testnet), 4463 (devnet)</dd>
|
||||
<dt>Chain id</dt><dd>4463 (Devnet 3)</dd>
|
||||
<dt>RPC</dt><dd>https://rpc.devnet.igneum.network</dd>
|
||||
<dt>Wallet set-up</dt><dd><a href="/metamask">MetaMask: chain id, RPC, one click</a></dd>
|
||||
<dt>Mine instead</dt><dd><a href="/miner#get">Get the miner</a></dd>
|
||||
<dt>Then</dt><dd><a href="/build">Deploy a contract in five minutes</a></dd>
|
||||
<dt>Testnet</dt><dd>its faucet opens with the public testnet</dd>
|
||||
</dl>
|
||||
</aside>
|
||||
</div>
|
||||
|
|
@ -270,7 +291,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -285,6 +306,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -317,17 +341,20 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
var form=document.getElementById('faucet-form'),input=document.getElementById('address'),btn=document.getElementById('send'),out=document.getElementById('status');
|
||||
// the faucet service runs on a build box behind Caddy (infra/build-server/faucet), not on the site's host
|
||||
var FAUCET='https://faucet.igneum.network/api/faucet';
|
||||
var form=document.getElementById('faucet-form'),input=document.getElementById('address'),btn=document.getElementById('send'),out=document.getElementById('status'),bal=document.getElementById('faucet-balance');
|
||||
fetch(FAUCET,{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){if(!d||!d.ok)return;if(d.balance_ign!==null&&d.balance_ign!==undefined){bal.textContent=d.funded?('The faucet holds '+Math.floor(Number(d.balance_ign)).toLocaleString('en-GB')+' IGN; '+d.sends_24h+' sends in the last 24 hours.'):'The faucet is being refilled; try again in an hour.';}}).catch(function(){});
|
||||
function say(text,state,html){out.setAttribute('data-state',state||'');if(html){out.innerHTML=html;}else{out.textContent=text;}}
|
||||
form.addEventListener('submit',function(e){
|
||||
e.preventDefault();
|
||||
var a=input.value.trim();
|
||||
if(!/^0x[0-9a-fA-F]{40}$/.test(a)){say('That is not an address. It is 0x followed by 40 hex characters.','bad');input.focus();return;}
|
||||
btn.disabled=true;say('Sending…','');
|
||||
fetch('/api/faucet',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({address:a})})
|
||||
fetch(FAUCET,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({address:a})})
|
||||
.then(function(r){return r.json().then(function(j){return {status:r.status,body:j};});})
|
||||
.then(function(r){
|
||||
if(r.body&&r.body.ok){var h=String(r.body.tx||'');say('',"ok",'Sent 10 IGN. Transaction <code>'+h.replace(/[^0-9a-fx]/gi,'')+'</code>. It is in a block within a few seconds.');}
|
||||
if(r.body&&r.body.ok){var h=String(r.body.tx||'').replace(/[^0-9a-fx]/gi,'');say('',"ok",'Sent 10 IGN. Transaction <code>'+h+'</code>. It is in a block within a few seconds. <a href="/explorer">Paste it into the explorer</a>.');}
|
||||
else{say((r.body&&r.body.error)||('The faucet answered '+r.status+'.'),'bad');}
|
||||
})
|
||||
.catch(function(){say('The faucet did not answer. Try again in a minute.','bad');})
|
||||
|
|
|
|||
344
site/grants.html
Normal file
344
site/grants.html
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum grants: tooling, reference apps, infrastructure, research</title>
|
||||
<meta name="description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<link rel="canonical" href="https://igneum.network/grants">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum grants: tooling, reference apps, infrastructure, research">
|
||||
<meta property="og:description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<meta property="og:url" content="https://igneum.network/grants">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum grants: tooling, reference apps, infrastructure, research">
|
||||
<meta name="twitter:description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* generated-page block (the engineering log, the bench table, the provenance table): the page hero, the contents rail, the sections; tokens, type and components are in /site.css */
|
||||
[id]{scroll-margin-top:120px}
|
||||
article h1{display:none}
|
||||
article{color:var(--ink-2)}
|
||||
article h2{font-size:var(--t-h3);margin:0 0 12px}
|
||||
article h3{font-size:16px;margin:26px 0 8px}
|
||||
article h4{font:600 15px/1.4 var(--f-sans);margin:20px 0 6px;color:var(--bone)}
|
||||
article p{margin:0 0 14px}article ul,article ol{margin:0 0 14px;padding-left:22px}article li{margin-bottom:6px}
|
||||
article p,article li,article h2,article h3{overflow-wrap:anywhere}
|
||||
article pre{margin:0 0 var(--s-4)}
|
||||
.doc-section:last-child{border-bottom:0}
|
||||
.doc-section[hidden]{display:none}
|
||||
.tbl{margin:var(--s-4) 0 var(--s-5)}
|
||||
table{min-width:560px}
|
||||
.gen{color:var(--ash);font-size:13px;margin:40px 0 0;max-width:72ch}
|
||||
.doc-tools{margin:0 0 var(--s-5)}
|
||||
.doc-tools .searchbar{max-width:560px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants" aria-current="page"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants" aria-current="page"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Grants</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>The programme</div>
|
||||
<h1>Grants</h1>
|
||||
<p class="lead">Paid in IGN from the dev fee fund, on delivery, on the public testnet first. Four tiers. One issue to apply. A weekly review.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
||||
<div class="docs-layout">
|
||||
<nav class="doc-nav" aria-label="Contents"><div class="eyebrow">Contents</div><a href="#what-a-grant-is">What a grant is</a><a href="#the-tiers">The tiers</a><a href="#how-to-apply">How to apply</a><a href="#the-review">The review</a><a href="#the-honest-lines">The honest lines</a></nav>
|
||||
<article class="doc-body" data-filter-list="grants"><section class="doc-section"><h1 id="grants">Grants</h1>
|
||||
<p>This file is the source of <a href="https://igneum.network/grants" rel="noopener">igneum.network/grants</a>.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="what-a-grant-is">What a grant is</h2>
|
||||
<p>Grants are paid in IGN from the dev fee fund, on delivery. You propose a piece of work, it is accepted with a written definition of done, you build it, and it runs on the public testnet. Not a salary, not an advance, not an investment.</p>
|
||||
<p>The money is the dev fee fund: the IGN that the Ember dev fee collects. Ember, the official miner, takes an optional 1% of a miner's rewards, in full view and off with one flag; that fee goes to Igneum Labs, the company that ships the software. The protocol itself carries no fee, no fund and no allocation, and no grant is paid from emission. <a href="/dev-fee">The dev fee</a> has the mechanism.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-tiers">The tiers</h2>
|
||||
<div class="tbl"><table><thead><tr><th>Tier</th><th>What fits</th></tr></thead><tbody><tr><td>Tooling</td><td>SDK bindings, indexers, a Hardhat or Foundry plugin for the two gas dimensions, verification tooling, a light client in another language</td></tr><tr><td>Reference apps</td><td>A token, a swap, a registry, a wallet integration, an app that uses <code>igneum_getTransactionStatus</code> and the lock the way it is meant to be used</td></tr><tr><td>Infrastructure</td><td>RPC providers, archive nodes, seed nodes in new regions, pool software, an explorer back end</td></tr><tr><td>Research</td><td>The lottery hash, the finality rule, the proving layer, the fee model; attacks on the public test vectors; measurements the project does not have</td></tr></tbody></table></div>
|
||||
<p>A grant is sized by the work in front of it, not by a table. Two grants in the same tier can differ.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="how-to-apply">How to apply</h2>
|
||||
<p>Open an issue on <a href="https://git.igneum.network/igneum-network/igneum/issues/new?template=.forgejo%2Fissue_template%2Fgrant.md" rel="noopener">git.igneum.network/igneum-network/igneum</a> and pick the Grant template. It asks for:</p>
|
||||
<ol><li>What you will build, in a paragraph, and which tier it is.</li><li>What done looks like: what runs where, what a reviewer can click or call to see it working on the public testnet.</li><li>Your public work: a repository, a package, a paper, a deployed thing.</li><li>How you want to be reached.</li></ol>
|
||||
<p>A short issue is fine. The definition of done is the part that matters.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-review">The review</h2>
|
||||
<ul><li>Every Friday. Each open application gets one of three answers inside seven days: accepted with a definition of done, questions, or no with the reason.</li><li>Accepted work is tracked in its issue. The reviewer and the builder agree the definition of done there before any work starts.</li><li>Delivery is reviewed on the public testnet first. Payment follows the review, in the issue, in the open.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-honest-lines">The honest lines</h2>
|
||||
<ul><li>Devnet and testnet coins have no value. Before mainnet there is no IGN with value: a grant delivered on the testnet is recorded in its issue, and payment comes from the fund when the fund holds IGN. Nothing is promised about when, or whether, that is.</li><li>No amount, price or date is promised. The fund is what the dev fee collects, and it is zero today.</li><li>A grant is for work delivered, never for a user count, a listing, a post or a referral.</li><li>Igneum Labs may decline any application and may close the programme; what has been accepted and delivered is still paid.</li></ul>
|
||||
<p>Not legal advice.</p></section></article>
|
||||
</div>
|
||||
<p class="gen">Generated from docs/build/grants.md in the repository at build time. Times are UTC.</p>
|
||||
</div></section>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script src="/ui.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
72
site/income-calc.js
Normal file
72
site/income-calc.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* The /income calculator (8 October 2026): pick a card (every /miners row, stock and tuned apart), set a kWh price (the
|
||||
default is the region's tariff from money.js, GBP 0.25 named when the region is unknown), type an IGN price (no default:
|
||||
there is no market), and read IGN a day and money a day at that price. The network's hash rate and the newest block's
|
||||
DAA score come from /api/live every 15 s; the block reward is the chain's own rule at that DAA (/lib/emission.mjs, the
|
||||
emission the node encodes), the miner's share 80 percent. The arithmetic is /lib/income-calc.mjs; its test holds the
|
||||
known-failed case (no price, no money figure). Devnet and testnet IGN have no value; the page says so beside the figure. */
|
||||
(function () {
|
||||
var root = document.getElementById('income-calc'); if (!root) return;
|
||||
var data = document.getElementById('income-data'); if (!data) return;
|
||||
var rows = JSON.parse(data.textContent || '[]');
|
||||
var M = window.IgneumMoney || null;
|
||||
var calc = null, emission = null, net = null, daa = null, live = false;
|
||||
var saved = (function () { try { return localStorage.getItem('igneum-currency') || ''; } catch (e) { return ''; } })();
|
||||
var choice = (M && M.currencyChoice) ? M.currencyChoice(saved, navigator.language) : null;
|
||||
var region = (choice && choice.region && M.regionOf) ? M.regionOf(choice.region) : null;
|
||||
var cur = choice ? choice.code : 'GBP';
|
||||
// money.js carries the tariff in minor units per kWh (26.32 pence); the named default is GBP 0.25 when the region has none
|
||||
var kwhDefault = region && region.price > 0 && region.cur === cur ? Math.round(region.price) / 100 : 0.25;
|
||||
var tariffSource = region && region.price > 0 && region.cur === cur ? region.source : 'GBP 0.25 a kWh, a UK retail rate, as the default';
|
||||
var chosen = (function () { try { return localStorage.getItem('igneum-income-card') || ''; } catch (e) { return ''; } })();
|
||||
function esc(s) { return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
|
||||
function fmtN(v, d) { return v === null || v === undefined || isNaN(v) ? 'pending' : Number(v).toLocaleString('en-GB', { maximumFractionDigits: d === undefined ? 2 : d }); }
|
||||
function fmtMoney(v) { if (v === null || v === undefined || isNaN(v)) return ''; if (M && M.fmtMoney) return M.fmtMoney(v, cur); return cur + ' ' + v.toFixed(2); }
|
||||
function dur(sec) { if (!(sec > 0)) return 'pending'; if (sec < 90) return Math.round(sec) + ' s'; if (sec < 5400) return Math.round(sec / 60) + ' min'; if (sec < 172800) return (sec / 3600).toFixed(1) + ' h'; return (sec / 86400).toFixed(1) + ' days'; }
|
||||
var stock = rows.filter(function (r) { return r.state !== 'tuned'; }), tuned = rows.filter(function (r) { return r.state === 'tuned'; });
|
||||
function option(r, i) { return '<option value="' + i + '"' + (chosen === r.key ? ' selected' : '') + '>' + esc(r.card + ' · ' + (r.mh_s_display || (fmtN(r.mh_s, 1) + ' MH/s')) + ' · ' + (r.watts ? fmtN(r.watts, 0) + ' W' + (r.watts_class ? ' (' + r.watts_class + ')' : '') : 'watts not read') + ' · ' + (r.state === 'tuned' ? 'tuned' : 'stock')) + '</option>'; }
|
||||
root.innerHTML =
|
||||
'<div class="calc-grid">' +
|
||||
'<label class="field"><span>Your card</span><select id="ic-card" aria-label="Your card">' +
|
||||
'<optgroup label="Stock (as bought, measured)">' + stock.map(function (r) { return option(r, rows.indexOf(r)); }).join('') + '</optgroup>' +
|
||||
(tuned.length ? '<optgroup label="Tuned (Ember Tune or a core lock, measured)">' + tuned.map(function (r) { return option(r, rows.indexOf(r)); }).join('') + '</optgroup>' : '') +
|
||||
'</select></label>' +
|
||||
'<label class="field"><span>Electricity, per kWh (' + esc(cur) + ')</span><input id="ic-kwh" type="number" inputmode="decimal" min="0" step="0.01" value="' + kwhDefault + '" aria-describedby="ic-kwh-note"><small id="ic-kwh-note">' + esc(tariffSource) + '. Your own bill is the number.</small></label>' +
|
||||
'<label class="field"><span>IGN price (' + esc(cur) + ')</span><input id="ic-price" type="number" inputmode="decimal" min="0" step="any" placeholder="no market yet: enter a price to see the figure" aria-describedby="ic-price-note"><small id="ic-price-note">Nobody sells IGN and the project quotes no price. Devnet and testnet IGN have no value.</small></label>' +
|
||||
'</div>' +
|
||||
'<div class="calc-out" aria-live="polite">' +
|
||||
'<div class="k">Network hash rate</div><div class="v" id="ic-net">connecting</div><div class="d" id="ic-net-d">from the observer, every 15 s</div>' +
|
||||
'<div class="k">Block reward now</div><div class="v" id="ic-reward">pending</div><div class="d" id="ic-reward-d">the chain’s own rule at the newest block’s DAA score, 80 percent of it to the miner</div>' +
|
||||
'<div class="k">Your share</div><div class="v" id="ic-ign">pending</div><div class="d" id="ic-ign-d">IGN a day; one block about every <b id="ic-wait">pending</b></div>' +
|
||||
'<div class="k">Electricity</div><div class="v" id="ic-el">pending</div><div class="d" id="ic-el-d">a day at your price</div>' +
|
||||
'<div class="k">Money a day</div><div class="v" id="ic-money">enter a price</div><div class="d" id="ic-money-d">IGN a day at the price you typed, electricity taken off. Devnet and testnet IGN have no value: this is arithmetic on a number you chose, not an income.</div>' +
|
||||
'</div>';
|
||||
var sel = document.getElementById('ic-card'), kwh = document.getElementById('ic-kwh'), price = document.getElementById('ic-price');
|
||||
function row() { var i = Number(sel.value); return rows[i] || rows[0]; }
|
||||
function render() {
|
||||
var r = row(); if (!r || !calc) return;
|
||||
var reward = (emission && daa !== null) ? Number(emission.sompiToIgn(emission.blockSubsidy(daa, 1))) : null;
|
||||
var ign = net && reward !== null ? calc.ignPerDay({ cardMhs: r.mh_s, networkHs: net, blockRewardIgn: reward }) : null;
|
||||
var el = calc.electricityPerDay({ watts: r.watts, kwhPrice: Number(kwh.value) });
|
||||
var money = ign === null ? null : calc.moneyPerDay({ ignPerDay: ign, ignPrice: price.value, electricity: el });
|
||||
document.getElementById('ic-net').textContent = net ? (net >= 1e9 ? (net / 1e9).toFixed(2) + ' GH/s' : (net / 1e6).toFixed(1) + ' MH/s') : (live ? 'pending' : 'connecting');
|
||||
document.getElementById('ic-reward').textContent = reward === null ? 'pending' : fmtN(reward, 4) + ' IGN';
|
||||
document.getElementById('ic-reward-d').textContent = daa === null ? 'the chain’s own rule at the newest block’s DAA score, 80 percent of it to the miner' : 'DAA ' + fmtN(daa, 0) + (daa < 2592000 ? ', inside the 30-day ramp from 10 percent' : '') + '; 80 percent of the block to the miner, 20 to the proving pool';
|
||||
document.getElementById('ic-ign').textContent = ign === null ? 'pending' : fmtN(ign, ign < 10 ? 3 : 1) + ' IGN';
|
||||
document.getElementById('ic-wait').textContent = dur(calc.secondsToBlock({ cardMhs: r.mh_s, networkHs: net }));
|
||||
document.getElementById('ic-el').textContent = el === null ? (r.watts ? 'pending' : 'watts not read for this row') : fmtMoney(el);
|
||||
document.getElementById('ic-el-d').textContent = r.watts ? fmtN(r.watts, 0) + ' W' + (r.watts_class ? ' (' + r.watts_class + ' watts)' : '') + ' x 24 h at ' + fmtMoney(Number(kwh.value)) + ' a kWh' : 'no power reading on this row';
|
||||
document.getElementById('ic-money').textContent = money === null ? (calc.parsePrice(price.value) === null ? 'enter a price' : 'pending') : fmtMoney(money);
|
||||
}
|
||||
sel.addEventListener('change', function () { try { localStorage.setItem('igneum-income-card', row().key); } catch (e) {} render(); });
|
||||
kwh.addEventListener('input', render); price.addEventListener('input', render);
|
||||
function poll() {
|
||||
fetch('/api/live?window=30', { cache: 'no-store' }).then(function (r) { return r.json(); }).then(function (d) {
|
||||
live = true;
|
||||
if (d && d.ok && d.state && d.state.hashes_per_second_estimate > 0) net = d.state.hashes_per_second_estimate;
|
||||
var best = null; (d && d.blocks || []).forEach(function (b) { if (b && b.daa > best) best = b.daa; });
|
||||
if (best !== null) daa = best;
|
||||
render();
|
||||
}).catch(function () { live = true; render(); });
|
||||
}
|
||||
Promise.all([import('/lib/income-calc.mjs'), import('/lib/emission.mjs')]).then(function (m) { calc = m[0]; emission = m[1]; render(); poll(); setInterval(function () { if (!document.hidden) poll(); }, 15000); });
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -78,6 +78,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -95,8 +96,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -107,18 +106,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -130,8 +141,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -140,15 +149,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -279,7 +298,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -294,6 +313,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,8 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,18 +114,30 @@
|
|||
<a href="/journey" data-nav="journey" aria-current="page"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -138,8 +149,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -148,15 +157,25 @@
|
|||
<a href="/journey" data-nav="journey" aria-current="page"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -214,7 +233,7 @@
|
|||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>The journey</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 7 Oct 2026</div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 8 Oct 2026</div>
|
||||
<h1>The journey.</h1>
|
||||
<p class="lead">Six phases from the specification to a fair launch. Each closes at its gate, a measurement published whether it passes or fails, so there is no date to slip. Below the phases, the latest entries of the engineering log.</p></div></div>
|
||||
</div>
|
||||
|
|
@ -228,7 +247,8 @@
|
|||
<div class="milestone next" id="phase-5"><div class="when">Armed: opens on the go word</div><div><span class="badge">Next</span><h3>5. Public testnet</h3><p>Three seed nodes and the public RPC are up; the one-click miner app on Windows, macOS and Linux, HiveOS, pools, the first rollup as a proving customer, no coin yet</p><p class="gate"><b>Gate:</b> 1,000 independent miners run 30 days and rollup proofs are delivered on time</p></div></div>
|
||||
<div class="milestone next" id="phase-6"><div class="when">After the testnet has passed its gate (1,000 independent miners for 30 days, rollup proofs on time) and one proving customer has signed: a customer paying for proofs at a published rate, or a letter of intent with a volume</div><div><span class="badge">Next</span><h3>6. Mainnet fair launch</h3><p>Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project</p></div></div></div>
|
||||
<div class="section-head" style="margin-top:100px"><div><div class="eyebrow"><span class="line"></span>The log, newest first</div><h2>Lately, in the log.</h2></div><div class="searchbar" style="min-width:min(100%,360px)"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/></svg><label for="log-q" class="visually-hidden">Filter the log</label><input id="log-q" data-filter-input="log" placeholder="Filter: a card, a date, a word" autocomplete="off" spellcheck="false"><span class="small" data-filter-count="log"></span></div></div>
|
||||
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-07">7 Oct 2026</time><span class="badge">log</span></div><h3>The first 16 GB card</h3><p>The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig</p></article>
|
||||
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-08">8 Oct 2026</time><span class="badge">log</span></div><h3>The hot-table packs on the RTX 5090</h3><p>The hot-table packs on the RTX 5090: ld.global.cs against the plain load, unlocked and at the 1,300 MHz lock</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-07">7 Oct 2026</time><span class="badge">log</span></div><h3>The first 16 GB card</h3><p>The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0</h3><p>Counter ASIC 3.0: the class v4 rehearsal</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>16:01Z: Ember run 6 on the three-card Windows rig</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0 item 2</h3><p>Counter ASIC 3.0 item 2: the per-day derivation</p></article>
|
||||
|
|
@ -261,13 +281,12 @@
|
|||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>Live devnet: real transactions, the first non-empty shard proven and…</h3><p>Live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>The program id split</h3><p>The program id split: why the Apple M5 Max rejected the RTX 5090 Windows rig's proofs, and the verifier at 114 s</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>Live devnet: the first shards proven, verified and paid</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>One-click Windows workers</h3><p>One-click Windows workers: what the Apple M5 Max could measure</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live hourly swap: no pause on Mac, NVIDIA or AMD</h3><p>First hourly program swap on the live devnet: compile-ahead, no pause, two cards</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live finality lock: 77.4% of weight, 17 voters</h3><p>First finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>The gfx1036 worker fault and what the Apple M5 Max could and could…</h3><p>The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>A node 60 s behind the clock is silently dead</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First machine on the one-click app: a 5090 at 118 MH/s</h3><p>First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe</p></article></div>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Economy simulation: mining versus proving under stress</h3><p>Sim/economy: mining versus proving under stress, agent-based</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Difficulty rule attacked seven ways</h3><p>Difficulty rule under attack: pool hopping, pulsed rental, timestamp stretching, short-lane oscillation, epoch games, polluted window, block flood</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Timestamp attack on the difficulty rule fixed</h3><p>Difficulty rule: timestamp attack fixed , simulator regression, 3-node forger test</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Devnet v4: nine branches merged into one node</h3><p>Devnet-v4 integration: nine branches merged, 3-node test network on the merged node, Windows cross-build</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Generator v2 adopted: every hash does 128 distinct reads</h3><p>Generator version 2 adopted: exact load count, fresh-source loads, program acceptance; every vector re-cut, three workers re-checked, 20,000-program census, devnet-v4 binaries rebuilt</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First GPU proof of an Igneum block: 1.4 s on an RTX 5090</h3><p>Proving v0 on the RTX 5090: first GPU proof of an Igneum block</p></article></div>
|
||||
<p class="empty-state" data-filter-empty="log" hidden>Nothing in the log matches that.</p>
|
||||
<p class="note">Every entry is a dated heading of <a href="/bench">the engineering log</a>, where the commands and the hardware are. The phases and their gates are the litepaper’s <a href="/litepaper#roadmap">roadmap</a>.</p>
|
||||
<div class="onward"><a href="/bench" class="btn">The engineering log</a><a href="/evidence" class="btn">Every claim and its status</a><a href="/live" class="btn">The live devnet</a></div>
|
||||
|
|
@ -296,7 +315,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -311,6 +330,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"updated": "2026-10-07",
|
||||
"updated": "2026-10-08",
|
||||
"stage": "phase-3",
|
||||
"phases": [
|
||||
{
|
||||
|
|
@ -50,6 +50,11 @@
|
|||
}
|
||||
],
|
||||
"log": [
|
||||
{
|
||||
"date": "2026-10-08",
|
||||
"text": "The hot-table packs on the RTX 5090: ld.global.cs against the plain load, unlocked and at the 1,300 MHz lock",
|
||||
"short": "The hot-table packs on the RTX 5090"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-07",
|
||||
"text": "The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig",
|
||||
|
|
@ -217,38 +222,33 @@
|
|||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "One-click Windows workers: what the Apple M5 Max could measure",
|
||||
"short": "One-click Windows workers"
|
||||
"text": "Sim/economy: mining versus proving under stress, agent-based",
|
||||
"short": "Economy simulation: mining versus proving under stress"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "First hourly program swap on the live devnet: compile-ahead, no pause, two cards",
|
||||
"short": "First live hourly swap: no pause on Mac, NVIDIA or AMD"
|
||||
"text": "Difficulty rule under attack: pool hopping, pulsed rental, timestamp stretching, short-lane oscillation, epoch games, polluted window, block flood",
|
||||
"short": "Difficulty rule attacked seven ways"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine",
|
||||
"short": "Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine"
|
||||
"text": "Difficulty rule: timestamp attack fixed , simulator regression, 3-node forger test",
|
||||
"short": "Timestamp attack on the difficulty rule fixed"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "First finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis",
|
||||
"short": "First live finality lock: 77.4% of weight, 17 voters"
|
||||
"text": "Devnet-v4 integration: nine branches merged, 3-node test network on the merged node, Windows cross-build",
|
||||
"short": "Devnet v4: nine branches merged into one node"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce",
|
||||
"short": "The gfx1036 worker fault and what the Apple M5 Max could and could…"
|
||||
"text": "Generator version 2 adopted: exact load count, fresh-source loads, program acceptance; every vector re-cut, three workers re-checked, 20,000-program census, devnet-v4 binaries rebuilt",
|
||||
"short": "Generator v2 adopted: every hash does 128 distinct reads"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "A node 60 s behind the clock is silently dead",
|
||||
"short": "A node 60 s behind the clock is silently dead"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe",
|
||||
"short": "First machine on the one-click app: a 5090 at 118 MH/s"
|
||||
"text": "Proving v0 on the RTX 5090: first GPU proof of an Igneum block",
|
||||
"short": "First GPU proof of an Igneum block: 1.4 s on an RTX 5090"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
119
site/lc/app.js
Normal file
119
site/lc/app.js
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Igneum reference apps, the browser driver for /light and /receipt (8 October 2026). Fetches data from the read
|
||||
// service behind rpc.devnet.igneum.network/light and verifies every byte in this tab with core.js. Libraries, pinned:
|
||||
// BLAKE2b and keccak from @noble/hashes 2.4.0, BLS12-381 from @noble/curves 2.4.0 (pure JavaScript, served by jsdelivr
|
||||
// as ES modules). Known-failed first: before the genuine result is shown, a copy of the same proof with one byte
|
||||
// altered is run through the same verifier and must read as refused.
|
||||
import { blake2b } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/blake2.js/+esm';
|
||||
import { keccak_256 } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/sha3.js/+esm';
|
||||
import { bls12_381 } from 'https://cdn.jsdelivr.net/npm/@noble/curves@2.4.0/bls12-381.js/+esm';
|
||||
import { verifyBalance, verifyReceipt, formatIgn } from './core.js';
|
||||
|
||||
export const LIBRARIES = { '@noble/hashes': '2.4.0', '@noble/curves': '2.4.0' };
|
||||
const deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
|
||||
const q = new URLSearchParams(location.search);
|
||||
export const API = (q.get('api') || 'https://rpc.devnet.igneum.network/light').replace(/\/$/, '');
|
||||
const $ = s => document.querySelector(s);
|
||||
const esc = s => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
const short = h => { const s = String(h).replace(/^0x/, ''); return s.slice(0, 8) + '…' + s.slice(-6); };
|
||||
const clone = x => JSON.parse(JSON.stringify(x));
|
||||
const flipHex = (s, at) => { const h = s.replace(/^0x/, ''); const i = Math.min(at, h.length - 1); const d = (parseInt(h[i], 16) ^ 1).toString(16); return (s.startsWith('0x') ? '0x' : '') + h.slice(0, i) + d + h.slice(i + 1); };
|
||||
|
||||
async function getJson(url) {
|
||||
const r = await fetch(url, { cache: 'no-store' });
|
||||
let j = null; try { j = await r.json(); } catch { j = null; }
|
||||
if (!j) throw new Error(`${url.replace(API, '')} answered ${r.status} with no JSON`);
|
||||
if (!j.ok) throw new Error(j.error || `${url.replace(API, '')} answered ${r.status}`);
|
||||
return j;
|
||||
}
|
||||
|
||||
function setStatus(text, kind = '') { const el = $('[data-status]'); if (!el) return; el.textContent = text; el.dataset.kind = kind; }
|
||||
function stepsHtml(result) {
|
||||
return '<ol class="steps">' + result.steps.map(s => `<li class="${s.ok ? 'ok' : 'bad'}"><b>${s.ok ? 'checked' : 'refused'}</b><span>${esc(s.name)}</span><small>${esc(s.detail)}</small></li>`).join('') + '</ol>';
|
||||
}
|
||||
function negativeHtml(name, result) {
|
||||
return `<div class="neg ${result.verified ? 'wrong' : 'right'}"><b>${result.verified ? 'NOT REFUSED (this is a bug)' : 'refused'}</b> <span>${esc(name)}</span><small>${esc(result.reason || 'verified')}</small></div>`;
|
||||
}
|
||||
const ago = ms => { const s = Math.max(0, Math.round((Date.now() - Number(ms)) / 1000)); return s < 90 ? `${s} s ago` : s < 5400 ? `${Math.round(s / 60)} min ago` : `${(s / 3600).toFixed(1)} h ago`; };
|
||||
|
||||
// ---- /light -------------------------------------------------------------------------------------------------------
|
||||
export async function runLight(address) {
|
||||
const out = $('[data-result]'); out.innerHTML = '';
|
||||
setStatus('fetching the latest certified checkpoint…', 'busy');
|
||||
const cp = await getJson(`${API}/checkpoint`);
|
||||
setStatus(`checkpoint ${cp.index} fetched; fetching the proof for ${short(address)}…`, 'busy');
|
||||
const proof = await getJson(`${API}/balance?address=${address}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
// the service may answer with an earlier certificate (the first checkpoint above the carrier: the smallest proof); verified like any other
|
||||
if (proof.checkpoint_certificate) { Object.assign(cp, proof.checkpoint_certificate); }
|
||||
setStatus('verifying in this tab…', 'busy');
|
||||
await new Promise(r => setTimeout(r, 20));
|
||||
// known-failed first: the same proof with one byte of the last account-proof node altered
|
||||
const bad = clone(proof); const last = bad.account.accountProof.length - 1;
|
||||
bad.account.accountProof[last] = flipHex(bad.account.accountProof[last], 30);
|
||||
const neg = verifyBalance(cp, bad, deps);
|
||||
const res = verifyBalance(cp, proof, deps);
|
||||
window.__igneumLight = { cp, proof, neg, res };
|
||||
const top = res.verified
|
||||
? `<div class="headline"><div class="eyebrow ember">Proven balance · Devnet 3, no value</div><div class="big">${esc(formatIgn(res.balance_wei))} <span>IGN</span></div>
|
||||
<p class="pt">${esc(res.balance_wei)} wei at chain block ${res.block}, under checkpoint ${res.checkpoint} (locked ${esc(ago(Number(proof.headers[proof.headers.length - 1].timestamp)))}). Verified here in ${res.ms} ms, ${res.headers} headers checked.</p></div>`
|
||||
: `<div class="headline bad"><div class="eyebrow">Not verified · Devnet 3, no value</div><p class="pt">${esc(res.reason)}</p></div>`;
|
||||
out.innerHTML = top + negativeHtml('a copy of this proof with one byte of a trie node altered', neg) + stepsHtml(res)
|
||||
+ `<p class="note">Data served by ${esc(API)} (a read service in front of a Devnet 3 node). Nothing it answered was taken on trust: the certificate, every header hash and parent link, the coinbase inclusion, the segment record's signature and the account proof were recomputed in this tab. What is trusted: that the aggregator's statement is the true execution result (every node checks it natively before paying the record; the SP1 proof behind it is verified by nodes, not in this tab yet), and the voter list with weights, which came from the node (spec 10.1).</p>`;
|
||||
setStatus(res.verified ? 'verified' : 'refused', res.verified ? 'ok' : 'bad');
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---- /receipt -----------------------------------------------------------------------------------------------------
|
||||
export async function runReceipt(tx) {
|
||||
const out = $('[data-result]'); out.innerHTML = '';
|
||||
setStatus('fetching the latest certified checkpoint…', 'busy');
|
||||
const cp = await getJson(`${API}/checkpoint`);
|
||||
setStatus(`checkpoint ${cp.index} fetched; fetching the inclusion proof…`, 'busy');
|
||||
const r = await getJson(`${API}/receipt?tx=${tx}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
// the service may answer with an earlier certificate (the first checkpoint above the block: the smallest proof); it is verified like any other
|
||||
const receipt = { format: 'igneum-receipt-v1', issued: new Date().toISOString(), ...r, checkpoint: { ...r.checkpoint, certificate: r.checkpoint.certificate || cp } };
|
||||
delete receipt.ok; delete receipt.now;
|
||||
setStatus('verifying in this tab…', 'busy');
|
||||
await new Promise(resolve => setTimeout(resolve, 20));
|
||||
const bad = clone(receipt); bad.raw_tx_hex = flipHex(bad.raw_tx_hex, 40);
|
||||
const neg = verifyReceipt(bad, deps);
|
||||
const res = verifyReceipt(receipt, deps);
|
||||
window.__igneumReceipt = { receipt, neg, res };
|
||||
const t = res.tx || {};
|
||||
const when = new Date(Number(res.block_time || 0)).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
|
||||
const top = res.verified
|
||||
? `<div class="headline"><div class="eyebrow ember">Final · Devnet 3, no value</div><div class="big">${esc(formatIgn(t.value || '0'))} <span>IGN</span></div>
|
||||
<div class="kv"><div class="k">To</div><div class="mono">${esc(t.to || 'contract creation')}</div><div class="k">From</div><div class="mono">${esc(receipt.tx_as_reported.from)} <small>(as the node reports it; the signature is the chain's check)</small></div>
|
||||
<div class="k">Transaction</div><div class="mono">0x${esc(receipt.tx_hash)}</div><div class="k">Block</div><div class="mono">${esc(res.block)} <small>at ${esc(when)}, DAA ${esc(res.block_daa)}</small></div>
|
||||
<div class="k">Finality</div><div>checkpoint ${res.checkpoint}, ${esc(res.certificate)}; ${res.headers} headers from the block to the checkpoint, verified here in ${res.ms} ms</div>
|
||||
${receipt.execution ? `<div class="k">Execution</div><div>status ${receipt.execution.status === '0x1' ? 'success' : 'failed'}, gas ${parseInt(receipt.execution.gas_used, 16)}, ${receipt.execution.logs} log(s) <small>(as the node reports it, not proven here)</small></div>` : ''}</div></div>`
|
||||
: `<div class="headline bad"><div class="eyebrow">Not verified · Devnet 3, no value</div><p class="pt">${esc(res.reason)}</p></div>`;
|
||||
out.innerHTML = top + negativeHtml('a copy of this receipt with one nibble of the raw transaction altered', neg) + stepsHtml(res)
|
||||
+ (res.verified ? `<p><button class="btn" type="button" data-download>Download the receipt (JSON, ${Math.round(JSON.stringify(receipt).length / 1024)} KB)</button></p>
|
||||
<p class="note">The file carries the raw transaction, the including block's header and merkle path, every header up to the certified checkpoint, the certificate and the voter table. Anyone re-verifies it offline with the one-file verifier: <code>node verify-receipt.js receipt.json</code> (<a href="/lc/verify-receipt.js" download>verify-receipt.js</a>, plain JavaScript, no npm, no network). A tampered file fails there the same way the copy above failed here.</p>` : '');
|
||||
const dl = $('[data-download]');
|
||||
if (dl) dl.addEventListener('click', () => {
|
||||
const blob = new Blob([JSON.stringify(receipt, null, 1)], { type: 'application/json' });
|
||||
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `igneum-receipt-${receipt.tx_hash.slice(0, 12)}.json`; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 5000);
|
||||
});
|
||||
setStatus(res.verified ? 'verified' : 'refused', res.verified ? 'ok' : 'bad');
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---- wiring ---------------------------------------------------------------------------------------------------------
|
||||
function wire() {
|
||||
const form = $('[data-form]'); if (!form) return;
|
||||
const input = form.querySelector('input'); const kind = form.dataset.form;
|
||||
if (q.get(kind === 'light' ? 'address' : 'tx')) input.value = q.get(kind === 'light' ? 'address' : 'tx');
|
||||
form.addEventListener('submit', async e => {
|
||||
e.preventDefault();
|
||||
const v = input.value.trim();
|
||||
const ok = kind === 'light' ? /^0x[0-9a-fA-F]{40}$/.test(v) : /^0x[0-9a-fA-F]{64}$/.test(v);
|
||||
if (!ok) { setStatus(kind === 'light' ? 'an address is 0x and 40 hex digits' : 'a transaction hash is 0x and 64 hex digits', 'bad'); return; }
|
||||
form.querySelector('button').disabled = true;
|
||||
try { if (kind === 'light') await runLight(v); else await runReceipt(v); }
|
||||
catch (err) { setStatus(String(err.message || err), 'bad'); $('[data-result]').innerHTML = `<div class="headline bad"><div class="eyebrow">Could not fetch · Devnet 3, no value</div><p class="pt">${esc(String(err.message || err))}</p></div>`; }
|
||||
finally { form.querySelector('button').disabled = false; }
|
||||
});
|
||||
if (input.value) form.requestSubmit();
|
||||
}
|
||||
if (typeof document !== 'undefined') { if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', wire); else wire(); }
|
||||
388
site/lc/core.js
Normal file
388
site/lc/core.js
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
// Igneum reference apps, the checks (no I/O, no DOM). 8 October 2026. Used by the light wallet (/light), the receipt
|
||||
// page (/receipt) and the one-file offline receipt verifier. Everything here recomputes; nothing is taken on trust
|
||||
// from the node that served the data. `deps` is { blake2b, bls, keccak } (@noble/hashes blake2b and keccak_256,
|
||||
// @noble/curves bls12_381), injected so the browser, Node and the bundled verifier share one file.
|
||||
//
|
||||
// What a balance proof chains together (every link recomputed here):
|
||||
// certificate ──signs──> checkpoint header ──parents──> ... ──parents──> carrier header
|
||||
// carrier header.hash_merkle_root ──merkle path──> coinbase transaction hash ──payload──> IGNS segment record
|
||||
// segment record ──BLS signature by a voter──> public values ──post_root──> MPT account proof ──> balance
|
||||
// What a receipt proof chains together: certificate ──> checkpoint ──parents──> including block ──merkle──> raw tx.
|
||||
//
|
||||
// Formats, from the node's own code (vendor/igneum-node-light at 5b673577 plus e6081dd6): consensus/core/src/hashing
|
||||
// (header, transaction), crypto/merkle (the body root), consensus/core/src/proving.rs (IGNS, SegmentRecord,
|
||||
// BlockStatement), consensus/core/src/finality.rs (the coinbase extra data and IGNF), igneum/exec/src/state.rs
|
||||
// (the keccak-keyed MPT in reth's layout, eth_getProof).
|
||||
import { headerHash, voteKeyHash, verifyCheckpoint, hexToBytes, bytesToHex } from '../verify/core.js';
|
||||
|
||||
export { headerHash, voteKeyHash, verifyCheckpoint, hexToBytes, bytesToHex };
|
||||
|
||||
export const DST_SEGMENT = 'IGNEUM_SEGMENT_RECORD_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_';
|
||||
export const SEGMENT_RECORD_LEN = 2 + 8 + 8 + 32 + 48 + 20 + 340 + 32 + 96;
|
||||
export const ZERO32 = new Uint8Array(32);
|
||||
const te = new TextEncoder();
|
||||
const strip = s => String(s).replace(/^0x/i, '');
|
||||
const u64le = v => { const b = new Uint8Array(8); new DataView(b.buffer).setBigUint64(0, BigInt(v), true); return b; };
|
||||
const u16le = v => { const b = new Uint8Array(2); new DataView(b.buffer).setUint16(0, Number(v), true); return b; };
|
||||
const u32le = v => { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, Number(v), true); return b; };
|
||||
function concat(parts) { const n = parts.reduce((a, p) => a + p.length, 0); const m = new Uint8Array(n); let o = 0; for (const p of parts) { m.set(p, o); o += p.length; } return m; }
|
||||
const eq = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
|
||||
const bigOf = b => { let v = 0n; for (const x of b) v = (v << 8n) | BigInt(x); return v; };
|
||||
export const keyed = (blake2b, key) => data => blake2b(data, { dkLen: 32, key: te.encode(key) });
|
||||
|
||||
// ---- the body merkle root (crypto/merkle/src/lib.rs): leaves padded to a power of two, a missing right child is the
|
||||
// zero hash, inner node = BLAKE2b-256 keyed "MerkleBranchHash" over left || right; one leaf is its own root --------
|
||||
export function merkleRoot(leaves, blake2b) {
|
||||
const H = keyed(blake2b, 'MerkleBranchHash');
|
||||
if (leaves.length === 0) return ZERO32;
|
||||
let level = leaves.slice();
|
||||
while (level.length > 1) {
|
||||
const next = [];
|
||||
for (let i = 0; i < level.length; i += 2) next.push(H(concat([level[i], level[i + 1] || ZERO32])));
|
||||
level = next;
|
||||
}
|
||||
return level[0];
|
||||
}
|
||||
export function merklePath(leaves, index) {
|
||||
const path = []; let level = leaves.slice(); let i = index;
|
||||
while (level.length > 1) {
|
||||
const sib = i % 2 === 0 ? (level[i + 1] || ZERO32) : level[i - 1];
|
||||
path.push(sib);
|
||||
const next = []; for (let k = 0; k < level.length; k += 2) next.push(new Uint8Array(0));
|
||||
// only the shape matters here; the hashes are recomputed by the verifier
|
||||
level = next; i = i >> 1;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
export function merkleRootFromPath(leaf, index, siblings, blake2b) {
|
||||
const H = keyed(blake2b, 'MerkleBranchHash');
|
||||
let h = leaf, i = index;
|
||||
for (const s of siblings) { h = i % 2 === 0 ? H(concat([h, s])) : H(concat([s, h])); i = i >> 1; }
|
||||
return h;
|
||||
}
|
||||
|
||||
// ---- the coinbase transaction hash (consensus/core/src/hashing/tx.rs, FULL flags) from the RPC's JSON ------------
|
||||
export function coinbaseTxHash(tx, blake2b, amountWireLen = 8) {
|
||||
const version = Number(tx.version || 0);
|
||||
const parts = [u16le(version), u64le((tx.inputs || []).length)];
|
||||
for (const inp of tx.inputs || []) {
|
||||
parts.push(hexToBytes(strip(inp.previousOutpoint.transactionId)), u32le(inp.previousOutpoint.index));
|
||||
const sig = hexToBytes(strip(inp.signatureScript || ''));
|
||||
parts.push(u64le(sig.length), sig);
|
||||
if (version < 1) parts.push(new Uint8Array([Number(inp.sigOpCount || 0)]));
|
||||
parts.push(u64le(inp.sequence));
|
||||
if (version >= 1) parts.push(u16le(inp.computeBudget || 0));
|
||||
}
|
||||
parts.push(u64le((tx.outputs || []).length));
|
||||
for (const out of tx.outputs || []) {
|
||||
const v = new Uint8Array(amountWireLen); let x = BigInt(out.value);
|
||||
for (let i = 0; i < amountWireLen; i++) { v[i] = Number(x & 0xffn); x >>= 8n; }
|
||||
const spk = hexToBytes(strip(out.scriptPublicKey)); // version u16 LE || script, as the RPC serialises it
|
||||
parts.push(v, spk.subarray(0, 2), u64le(spk.length - 2), spk.subarray(2));
|
||||
if (version >= 1) parts.push(new Uint8Array([out.covenant ? 1 : 0]));
|
||||
}
|
||||
const payload = hexToBytes(strip(tx.payload || ''));
|
||||
parts.push(u64le(tx.lockTime || 0), hexToBytes(strip(tx.subnetworkId)), u64le(tx.gas || 0), u64le(payload.length), payload);
|
||||
const mass = BigInt(tx.mass || 0);
|
||||
if (version < 1) { if (mass > 0n) parts.push(u64le(mass)); } else parts.push(u64le(mass));
|
||||
return keyed(blake2b, 'TransactionHash')(concat(parts));
|
||||
}
|
||||
|
||||
// ---- the coinbase payload: blue_score u64 || subsidy || script version u16 || script len u8 || script || extra; the
|
||||
// extra data ends with nested sections `items || len_le32 || TAG`: IGNF last, IGNP before it, IGNS before that ----
|
||||
export function coinbaseExtraData(payload) {
|
||||
if (payload.length < 19) return new Uint8Array(0);
|
||||
const scriptLen = payload[18];
|
||||
return payload.subarray(19 + scriptLen);
|
||||
}
|
||||
function takeSection(extra, tag) {
|
||||
const n = extra.length;
|
||||
if (n < 8) return { items: null, before: extra };
|
||||
const t = String.fromCharCode(...extra.subarray(n - 4));
|
||||
if (t !== tag) return { items: null, before: extra };
|
||||
const len = new DataView(extra.buffer, extra.byteOffset + n - 8, 4).getUint32(0, true);
|
||||
if (len + 8 > n) return { items: null, before: extra };
|
||||
return { items: extra.subarray(n - 8 - len, n - 8), before: extra.subarray(0, n - 8 - len) };
|
||||
}
|
||||
export function segmentRecordsOf(payload) {
|
||||
const extra = coinbaseExtraData(payload);
|
||||
const f = takeSection(extra, 'IGNF');
|
||||
const p = takeSection(f.before, 'IGNP');
|
||||
const s = takeSection(p.before, 'IGNS');
|
||||
const out = [];
|
||||
if (!s.items) return out;
|
||||
for (let o = 0; o + SEGMENT_RECORD_LEN <= s.items.length; o += SEGMENT_RECORD_LEN) out.push(parseSegmentRecord(s.items.subarray(o, o + SEGMENT_RECORD_LEN)));
|
||||
return out;
|
||||
}
|
||||
export function parseSegmentRecord(b) {
|
||||
if (b.length !== SEGMENT_RECORD_LEN) throw new Error(`segment record is ${b.length} bytes, not ${SEGMENT_RECORD_LEN}`);
|
||||
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
||||
let o = 0;
|
||||
const version = dv.getUint16(o, true); o += 2;
|
||||
const first = dv.getBigUint64(o, true); o += 8;
|
||||
const last = dv.getBigUint64(o, true); o += 8;
|
||||
const block = b.subarray(o, o + 32); o += 32;
|
||||
const pubkey = b.subarray(o, o + 48); o += 48;
|
||||
const payout = b.subarray(o, o + 20); o += 20;
|
||||
const publicValues = b.subarray(o, o + 340); o += 340;
|
||||
const proofHash = b.subarray(o, o + 32); o += 32;
|
||||
const signature = b.subarray(o, o + 96);
|
||||
return { bytes: b, version, first, last, block, pubkey, payout, publicValues, proofHash, signature, statement: parseBlockStatement(publicValues) };
|
||||
}
|
||||
export function parseBlockStatement(b) {
|
||||
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
||||
const h = o => bytesToHex(b.subarray(o, o + 32));
|
||||
return {
|
||||
chain_id: dv.getBigUint64(0), number: dv.getBigUint64(8), block_hash: h(16), parent_hash: h(48), shard_count: dv.getUint32(80),
|
||||
tx_commitment: h(84), pre_root: h(116), post_root: h(148), receipts: h(180), gas_used: dv.getBigUint64(212), pgas_used: dv.getBigUint64(220),
|
||||
executed: dv.getUint32(228), skipped: dv.getUint32(232), provers: h(236), shard_vk: h(268), agg_vk: h(300), chain_len: dv.getBigUint64(332),
|
||||
};
|
||||
}
|
||||
export function segmentRecordMessage(chainId, r) {
|
||||
return concat([te.encode('igneum-segment-record-v1/' + chainId), new Uint8Array([0]), u64le(r.first), u64le(r.last), r.block, r.payout, r.publicValues, r.proofHash]);
|
||||
}
|
||||
export function verifySegmentRecordSignature(chainId, r, bls) {
|
||||
const L = bls.longSignatures;
|
||||
return L.verify(r.signature, L.hash(segmentRecordMessage(chainId, r), DST_SEGMENT), r.pubkey);
|
||||
}
|
||||
|
||||
// ---- RLP and the Merkle Patricia trie (keccak-keyed, Ethereum's layout) ----------------------------------------
|
||||
export function rlpDecode(b) {
|
||||
const [item, rest] = rlpItem(b, 0);
|
||||
if (rest !== b.length) throw new Error('rlp: trailing bytes');
|
||||
return item;
|
||||
}
|
||||
function rlpItem(b, o) {
|
||||
if (o >= b.length) throw new Error('rlp: short');
|
||||
const x = b[o];
|
||||
if (x < 0x80) return [b.subarray(o, o + 1), o + 1];
|
||||
if (x < 0xb8) { const n = x - 0x80; return [b.subarray(o + 1, o + 1 + n), o + 1 + n]; }
|
||||
if (x < 0xc0) { const ll = x - 0xb7; const n = Number(bigOf(b.subarray(o + 1, o + 1 + ll))); return [b.subarray(o + 1 + ll, o + 1 + ll + n), o + 1 + ll + n]; }
|
||||
let n, start;
|
||||
if (x < 0xf8) { n = x - 0xc0; start = o + 1; } else { const ll = x - 0xf7; n = Number(bigOf(b.subarray(o + 1, o + 1 + ll))); start = o + 1 + ll; }
|
||||
const end = start + n; if (end > b.length) throw new Error('rlp: list overruns');
|
||||
const items = []; let p = start;
|
||||
while (p < end) { const [it, q] = rlpItem(b, p); items.push(it); p = q; }
|
||||
return [items, end];
|
||||
}
|
||||
export function rlpEncode(item) {
|
||||
if (item instanceof Uint8Array) {
|
||||
if (item.length === 1 && item[0] < 0x80) return item;
|
||||
return concat([rlpLen(item.length, 0x80), item]);
|
||||
}
|
||||
const body = concat(item.map(rlpEncode));
|
||||
return concat([rlpLen(body.length, 0xc0), body]);
|
||||
}
|
||||
function rlpLen(n, base) {
|
||||
if (n < 56) return new Uint8Array([base + n]);
|
||||
const bytes = []; let x = n; while (x > 0) { bytes.unshift(x & 0xff); x = Math.floor(x / 256); }
|
||||
return new Uint8Array([base + 55 + bytes.length, ...bytes]);
|
||||
}
|
||||
export const trimBig = v => { v = BigInt(v); if (v === 0n) return new Uint8Array(0); let h = v.toString(16); if (h.length % 2) h = '0' + h; return hexToBytes(h); };
|
||||
const nibbles = b => { const out = []; for (const x of b) { out.push(x >> 4, x & 15); } return out; };
|
||||
function hpDecode(b) { // hex-prefix: returns [nibbles, isLeaf]
|
||||
const n = nibbles(b); const flag = n[0];
|
||||
const body = flag & 1 ? n.slice(1) : n.slice(2);
|
||||
return [body, (flag & 2) !== 0];
|
||||
}
|
||||
// Walks the proof from the root to the key; returns the value bytes (Uint8Array) or null for a proven absence.
|
||||
// Throws on any node that does not hash to its reference, any malformed node, or a path that does not reach a verdict.
|
||||
export function mptVerify(root, key, proofNodes, keccak) {
|
||||
const path = nibbles(key); let want = root; let pos = 0;
|
||||
const byHash = new Map(); for (const n of proofNodes) byHash.set(bytesToHex(keccak(n)), n);
|
||||
if (proofNodes.length === 0) { if (eq(root, keccak(rlpEncode(new Uint8Array(0))))) return null; throw new Error('mpt: no proof nodes for a non-empty root'); }
|
||||
let node = byHash.get(bytesToHex(want));
|
||||
if (!node) throw new Error('mpt: the first proof node is not the root');
|
||||
for (let guard = 0; guard < 128; guard++) {
|
||||
const items = rlpDecode(node);
|
||||
if (!Array.isArray(items)) throw new Error('mpt: node is not a list');
|
||||
let next;
|
||||
if (items.length === 17) {
|
||||
if (pos === path.length) { const v = items[16]; return v.length ? v : null; }
|
||||
next = items[path[pos]]; pos += 1;
|
||||
} else if (items.length === 2) {
|
||||
const [np, leaf] = hpDecode(items[0]);
|
||||
for (let i = 0; i < np.length; i++) if (path[pos + i] !== np[i]) return null; // the key diverges: proven absent
|
||||
pos += np.length;
|
||||
if (leaf) { if (pos !== path.length) return null; return items[1]; }
|
||||
next = items[1];
|
||||
} else throw new Error('mpt: node with ' + items.length + ' items');
|
||||
if (next instanceof Uint8Array) {
|
||||
if (next.length === 0) return null; // an empty slot: proven absent
|
||||
if (next.length !== 32) throw new Error('mpt: bad reference');
|
||||
node = byHash.get(bytesToHex(next));
|
||||
if (!node) throw new Error('mpt: a referenced node is missing from the proof');
|
||||
want = next;
|
||||
} else {
|
||||
node = rlpEncode(next); // an embedded node (under 32 bytes)
|
||||
}
|
||||
}
|
||||
throw new Error('mpt: path too deep');
|
||||
}
|
||||
// Verifies an eth_getProof account proof against `stateRoot`; returns {exists, nonce, balance, storageRoot, codeHash}.
|
||||
export function verifyAccountProof(stateRoot, address, proofHex, keccak) {
|
||||
const key = keccak(hexToBytes(strip(address)));
|
||||
const v = mptVerify(stateRoot, key, proofHex.map(h => hexToBytes(strip(h))), keccak);
|
||||
if (v === null) return { exists: false, nonce: 0n, balance: 0n, storageRoot: null, codeHash: null };
|
||||
const items = rlpDecode(v);
|
||||
if (!Array.isArray(items) || items.length !== 4) throw new Error('mpt: account leaf is not [nonce, balance, storageRoot, codeHash]');
|
||||
return { exists: true, nonce: bigOf(items[0]), balance: bigOf(items[1]), storageRoot: bytesToHex(items[2]), codeHash: bytesToHex(items[3]) };
|
||||
}
|
||||
export function verifyStorageProof(storageRoot, slot, proofHex, keccak) {
|
||||
const key = keccak(hexToBytes(strip(slot).padStart(64, '0')));
|
||||
const v = mptVerify(storageRoot, key, proofHex.map(h => hexToBytes(strip(h))), keccak);
|
||||
if (v === null) return 0n;
|
||||
const item = rlpDecode(v);
|
||||
if (Array.isArray(item)) throw new Error('mpt: storage leaf is a list');
|
||||
return bigOf(item);
|
||||
}
|
||||
|
||||
// ---- the header path: headers[0] is the oldest, each next header names the previous as a direct parent ------------
|
||||
export function verifyHeaderPath(headers, blake2b, fromHash, toHash) {
|
||||
if (!headers.length) throw new Error('no headers');
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
const h = headers[i];
|
||||
const got = headerHash(h, blake2b);
|
||||
if (got !== strip(h.hash)) throw new Error(`header ${i} (${strip(h.hash).slice(0, 12)}) does not recompute: ${got.slice(0, 12)}`);
|
||||
if (i > 0) {
|
||||
const direct = (h.parents_by_level && h.parents_by_level[0]) || [];
|
||||
if (!direct.includes(strip(headers[i - 1].hash))) throw new Error(`header ${i} does not name header ${i - 1} as a direct parent`);
|
||||
}
|
||||
}
|
||||
if (fromHash && strip(headers[0].hash) !== strip(fromHash)) throw new Error('the first header is not the block the proof starts from');
|
||||
if (toHash && strip(headers[headers.length - 1].hash) !== strip(toHash)) throw new Error('the last header is not the certified checkpoint');
|
||||
return headers.length;
|
||||
}
|
||||
|
||||
// ---- the balance proof ------------------------------------------------------------------------------------------
|
||||
// `cp` is the /api/checkpoint body (certificate, voters, headers to the previous lock); `proof` is the /balance body:
|
||||
// { address, chain_id, checkpoint: {hash, index}, headers: [carrier .. checkpoint], carrier: { coinbase: <RpcTransaction>,
|
||||
// evm_tx_hashes: [hex...], leaf_index: 0, merkle_siblings: [hex...] }, segment_record_hex, account: eth_getProof result }.
|
||||
// Returns { verified, steps: [{name, ok, detail}], balance, ... } and stops at the first failing step.
|
||||
export function verifyBalance(cp, proof, deps) {
|
||||
const { blake2b, bls, keccak } = deps;
|
||||
const steps = []; const t0 = now();
|
||||
const step = (name, fn) => { try { const d = fn(); steps.push({ name, ok: true, detail: d }); return d; } catch (e) { steps.push({ name, ok: false, detail: String(e.message || e) }); throw e; } };
|
||||
const done = extra => ({ ...extra, steps, ms: Math.round((now() - t0) * 10) / 10 });
|
||||
try {
|
||||
const cert = step('certificate: BLS aggregate over the checkpoint, 2/3 of active and 17/30 of total weight', () => {
|
||||
const r = verifyCheckpoint(cp, { blake2b, bls });
|
||||
if (!r.verified) throw new Error(r.reason);
|
||||
return `checkpoint ${r.index}, ${r.signers} of ${r.voters} voters, ${(r.weight_fraction_total * 100).toFixed(1)}% of total weight, ${r.headers_checked} headers to the previous lock`;
|
||||
});
|
||||
step('the proof names the certified checkpoint', () => {
|
||||
if (strip(proof.checkpoint.hash) !== strip(cp.hash) || Number(proof.checkpoint.index) !== Number(cp.index)) throw new Error('the balance proof is for another checkpoint than the certificate');
|
||||
if (proof.chain_id !== cp.chain_id) throw new Error(`chain ${proof.chain_id} is not ${cp.chain_id}`);
|
||||
return `${cp.chain_id}, checkpoint ${cp.index}`;
|
||||
});
|
||||
step('header chain from the carrier block up to the checkpoint (every hash recomputed, every parent link checked)', () =>
|
||||
`${verifyHeaderPath(proof.headers, blake2b, proof.headers[0].hash, cp.hash)} headers, ${strip(proof.headers[0].hash).slice(0, 12)} up to ${strip(cp.hash).slice(0, 12)}`);
|
||||
const carrier = proof.headers[0];
|
||||
const record = step('the coinbase transaction is in the carrier block (hash recomputed, merkle path to hash_merkle_root)', () => {
|
||||
const cb = coinbaseTxHash(proof.carrier.coinbase, blake2b, proof.carrier.amount_wire_len || 8);
|
||||
const sibs = proof.carrier.merkle_siblings.map(s => hexToBytes(strip(s)));
|
||||
const root = merkleRootFromPath(cb, Number(proof.carrier.leaf_index), sibs, blake2b);
|
||||
if (bytesToHex(root) !== strip(carrier.hash_merkle_root)) throw new Error('the merkle path does not reach the carrier\'s hash_merkle_root');
|
||||
const recs = segmentRecordsOf(hexToBytes(strip(proof.carrier.coinbase.payload)));
|
||||
const want = strip(proof.segment_record_hex);
|
||||
const rec = recs.find(r => bytesToHex(r.bytes) === want);
|
||||
if (!rec) throw new Error(`the carrier's coinbase carries ${recs.length} segment record(s), none is the named one`);
|
||||
return `coinbase ${bytesToHex(cb).slice(0, 12)}, leaf ${proof.carrier.leaf_index} of ${proof.carrier.evm_tx_hashes.length + 1}, record for blocks ${rec.first} to ${rec.last}`;
|
||||
}) && segmentRecordsOf(hexToBytes(strip(proof.carrier.coinbase.payload))).find(r => bytesToHex(r.bytes) === strip(proof.segment_record_hex));
|
||||
const agg = step('the segment record is signed by its aggregator (BLS over the record under the network\'s tag)', () => {
|
||||
if (!verifySegmentRecordSignature(cp.chain_id, record, bls)) throw new Error('the aggregator\'s signature does not verify');
|
||||
// the aggregator signs with a vote key; a prove-only key has no mining weight and is not in the voter table, which is
|
||||
// reported, not refused (the record's standing comes from the nodes' native check and the payout, not from weight)
|
||||
const kh = voteKeyHash(record.pubkey, blake2b);
|
||||
const voter = (cp.voters || []).find(v => (v.vote_key_hash || voteKeyHash(hexToBytes(v.pubkey_hex), blake2b)) === kh);
|
||||
const total = (cp.voters || []).reduce((a, v) => a + Number(v.weight), 0);
|
||||
return voter
|
||||
? `aggregator ${kh.slice(0, 12)}, a voter with weight ${voter.weight} of ${total} (${(100 * Number(voter.weight) / total).toFixed(2)}%)`
|
||||
: `aggregator ${kh.slice(0, 12)}, a prove-only key (not in the voter table of ${cp.voters.length}, no mining weight)`;
|
||||
});
|
||||
const st = record.statement;
|
||||
step('the record\'s statement names the chain and the block whose state it commits', () => {
|
||||
if (Number(st.number) !== Number(record.last)) throw new Error('the statement is not for the segment\'s last block');
|
||||
if (bytesToHex(record.block) !== st.block_hash) throw new Error('the record\'s block hash is not the statement\'s');
|
||||
// the EVM chain id in the statement is the one in force at that block (Devnet 3: 4463 below its class v5 floor, 4464 above);
|
||||
// the record's binding to the chain is the signed message, which names the network by its string ("igneum-devnet-3")
|
||||
const ids = cp.chain_id === 'igneum-devnet-3' ? [4463, 4464] : [Number(proof.account.evm_chain_id)];
|
||||
if (!ids.includes(Number(st.chain_id))) throw new Error(`statement chain id ${st.chain_id} is not ${cp.chain_id}'s (${ids.join(' or ')})`);
|
||||
return `EVM chain id ${st.chain_id}, chain block ${st.number}, post_root ${st.post_root.slice(0, 12)}, ${st.executed} executed, chain_len ${st.chain_len}`;
|
||||
});
|
||||
let acct = null;
|
||||
step('account proof under post_root (keccak-keyed Merkle Patricia trie, every node hashed)', () => {
|
||||
if (Number(proof.account.blockNumber) !== Number(st.number)) throw new Error('the account proof is for another block than the statement');
|
||||
if (strip(proof.account.stateRoot) !== st.post_root) throw new Error('the node\'s state root is not the proven post_root');
|
||||
const a = verifyAccountProof(hexToBytes(st.post_root), proof.address, proof.account.accountProof, keccak);
|
||||
acct = a;
|
||||
if (a.exists && a.balance !== BigInt(proof.account.balance)) throw new Error('the proven balance is not the balance the node reported');
|
||||
if (!a.exists && BigInt(proof.account.balance) !== 0n) throw new Error('the node reports a balance for an account the trie does not hold');
|
||||
return `${proof.account.accountProof.length} nodes, ${a.exists ? 'account present' : 'account absent (exclusion proof)'}`;
|
||||
});
|
||||
const balance = acct.exists ? acct.balance : 0n;
|
||||
return done({ verified: true, balance, balance_wei: balance.toString(), nonce: acct.nonce.toString(), block: Number(st.number), post_root: st.post_root, checkpoint: Number(cp.index), headers: proof.headers.length, aggregator: agg, certificate: cert });
|
||||
} catch (e) {
|
||||
return done({ verified: false, reason: String(e.message || e) });
|
||||
}
|
||||
}
|
||||
|
||||
// ---- the receipt proof ------------------------------------------------------------------------------------------
|
||||
// `receipt` = { chain_id, tx_hash, raw_tx_hex, checkpoint: {hash, index, certificate: <the /api/checkpoint body>},
|
||||
// including_block: { header, evm_tx_hashes, leaf_index, merkle_siblings }, headers: [including .. checkpoint],
|
||||
// execution (optional, as the node reports it): { chain_block, status, gas_used, ... } }
|
||||
export function verifyReceipt(receipt, deps) {
|
||||
const { blake2b, bls, keccak } = deps;
|
||||
const steps = []; const t0 = now();
|
||||
const step = (name, fn) => { try { const d = fn(); steps.push({ name, ok: true, detail: d }); return d; } catch (e) { steps.push({ name, ok: false, detail: String(e.message || e) }); throw e; } };
|
||||
const done = extra => ({ ...extra, steps, ms: Math.round((now() - t0) * 10) / 10 });
|
||||
try {
|
||||
const cp = receipt.checkpoint.certificate;
|
||||
const cert = step('certificate: BLS aggregate over the checkpoint, 2/3 of active and 17/30 of total weight', () => {
|
||||
const r = verifyCheckpoint(cp, { blake2b, bls });
|
||||
if (!r.verified) throw new Error(r.reason);
|
||||
if (strip(cp.hash) !== strip(receipt.checkpoint.hash) || receipt.chain_id !== cp.chain_id) throw new Error('the receipt names another checkpoint or chain than its certificate');
|
||||
return `checkpoint ${r.index} on ${cp.chain_id}, ${r.signers} of ${r.voters} voters, ${(r.weight_fraction_total * 100).toFixed(1)}% of total weight`;
|
||||
});
|
||||
let tx = null;
|
||||
step('the transaction hash is keccak256 of the raw signed transaction', () => {
|
||||
const raw = hexToBytes(strip(receipt.raw_tx_hex));
|
||||
const h = bytesToHex(keccak(raw));
|
||||
if (h !== strip(receipt.tx_hash)) throw new Error(`the raw bytes hash to ${h.slice(0, 12)}, not ${strip(receipt.tx_hash).slice(0, 12)}`);
|
||||
tx = parseTx(raw);
|
||||
return `${raw.length} bytes, type ${tx.type}, to ${tx.to || 'contract creation'}, value ${tx.value} wei, nonce ${tx.nonce}`;
|
||||
});
|
||||
step('header chain from the including block up to the checkpoint (every hash recomputed, every parent link checked)', () =>
|
||||
`${verifyHeaderPath(receipt.headers, blake2b, receipt.including_block.header.hash, cp.hash)} headers, ${strip(receipt.headers[0].hash).slice(0, 12)} up to ${strip(cp.hash).slice(0, 12)}`);
|
||||
step('the transaction is a leaf of the including block\'s hash_merkle_root', () => {
|
||||
const ib = receipt.including_block;
|
||||
const sibs = ib.merkle_siblings.map(s => hexToBytes(strip(s)));
|
||||
const root = merkleRootFromPath(hexToBytes(strip(receipt.tx_hash)), Number(ib.leaf_index), sibs, blake2b);
|
||||
if (bytesToHex(root) !== strip(receipt.headers[0].hash_merkle_root)) throw new Error('the merkle path does not reach the including block\'s hash_merkle_root');
|
||||
return `leaf ${ib.leaf_index} of ${ib.leaf_count}`;
|
||||
});
|
||||
return done({ verified: true, tx, headers: receipt.headers.length, checkpoint: Number(cp.index), certificate: cert, block: strip(receipt.headers[0].hash), block_daa: receipt.headers[0].daa_score, block_time: receipt.headers[0].timestamp });
|
||||
} catch (e) {
|
||||
return done({ verified: false, reason: String(e.message || e) });
|
||||
}
|
||||
}
|
||||
|
||||
// A typed (EIP-1559 type 2, EIP-2930 type 1) or legacy raw transaction: the fields a receipt shows. No signature
|
||||
// recovery here (the node's `from` is shown as reported; the chain's own check of the signature is what put the
|
||||
// transaction in a block).
|
||||
export function parseTx(raw) {
|
||||
const type = raw[0] <= 0x7f ? raw[0] : 0;
|
||||
const body = rlpDecode(type ? raw.subarray(1) : raw);
|
||||
const hex = b => '0x' + bytesToHex(b);
|
||||
if (type === 2) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[5].length ? hex(body[5]) : null, value: bigOf(body[6]).toString(), data: hex(body[7]), gas: bigOf(body[4]).toString() };
|
||||
if (type === 1) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[4].length ? hex(body[4]) : null, value: bigOf(body[5]).toString(), data: hex(body[6]), gas: bigOf(body[3]).toString() };
|
||||
return { type: 0, nonce: bigOf(body[0]).toString(), to: body[3].length ? hex(body[3]) : null, value: bigOf(body[4]).toString(), data: hex(body[5]), gas: bigOf(body[2]).toString() };
|
||||
}
|
||||
|
||||
export function formatIgn(wei, decimals = 18) {
|
||||
const v = BigInt(wei); const base = 10n ** BigInt(decimals);
|
||||
const whole = v / base; let frac = (v % base).toString().padStart(decimals, '0').replace(/0+$/, '');
|
||||
if (frac.length > 6) frac = frac.slice(0, 6);
|
||||
return whole.toString() + (frac ? '.' + frac : '');
|
||||
}
|
||||
const now = () => (typeof performance !== 'undefined' ? performance : Date).now();
|
||||
86
site/lc/test.html
Normal file
86
site/lc/test.html
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Igneum reference apps test: genuine and tampered</title>
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>body{font-family:ui-monospace,Menlo,monospace;font-size:13px;background:#0C0C0E;color:#E8E4DA;padding:24px;max-width:1100px}h1{font-size:16px}h2{font-size:14px;margin-top:28px}table{display:block;overflow-x:auto;max-width:100%}code{overflow-wrap:anywhere}td{padding:4px 10px;border-bottom:1px solid #222;vertical-align:top}.ok{color:#7ED957}.bad{color:#F2541B}p{max-width:90ch}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Igneum reference apps: the negative cases, in this tab (Devnet 3, no value)</h1>
|
||||
<p>Each row runs <code>site/lc/core.js</code> on live Devnet 3 data from <code id="api"></code>. A tampered case must read <b>refused</b>; the genuine case must read <b>verified</b>. The same cases run under Node in <code>tools/reference-apps/light-service/verify.test.mjs</code>. Parameters: <code>?api=</code> (the read service), <code>?address=</code> (the balance to prove; default: the miner of the latest block), <code>?tx=</code> (a transaction; default: one in a recent block).</p>
|
||||
<h2>Receipt</h2>
|
||||
<table id="r"><thead><tr><td>case</td><td>result</td><td>ms</td><td>reason</td></tr></thead><tbody></tbody></table>
|
||||
<h2>Balance</h2>
|
||||
<table id="b"><thead><tr><td>case</td><td>result</td><td>ms</td><td>reason</td></tr></thead><tbody></tbody></table>
|
||||
<pre id="done"></pre>
|
||||
<script type="module">
|
||||
import { blake2b } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/blake2.js/+esm';
|
||||
import { keccak_256 } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/sha3.js/+esm';
|
||||
import { bls12_381 } from 'https://cdn.jsdelivr.net/npm/@noble/curves@2.4.0/bls12-381.js/+esm';
|
||||
import { verifyBalance, verifyReceipt } from './core.js';
|
||||
const deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
|
||||
const q = new URLSearchParams(location.search);
|
||||
const API = (q.get('api') || 'https://rpc.devnet.igneum.network/light').replace(/\/$/, '');
|
||||
const RPC = q.get('rpc') || 'https://rpc.devnet.igneum.network';
|
||||
document.getElementById('api').textContent = API;
|
||||
const clone = x => JSON.parse(JSON.stringify(x));
|
||||
const flipHex = (s, at) => { const h = s.replace(/^0x/, ''); const i = Math.min(at, h.length - 1); const d = (parseInt(h[i], 16) ^ 1).toString(16); return (s.startsWith('0x') ? '0x' : '') + h.slice(0, i) + d + h.slice(i + 1); };
|
||||
const get = async u => { const r = await fetch(u, { cache: 'no-store' }); const j = await r.json(); if (!j.ok) throw new Error(j.error || r.status); return j; };
|
||||
const rpc = async (method, params) => { const r = await fetch(RPC, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) }); const j = await r.json(); if (j.error) throw new Error(j.error.message); return j.result; };
|
||||
const out = [];
|
||||
function row(table, name, r, want) {
|
||||
const ok = r.verified === want; out.push({ table, name, want, ...r, behaved: ok });
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `<td>${name}</td><td class="${ok ? 'ok' : 'bad'}">${r.verified ? 'verified' : 'refused'}${ok ? '' : ' (WRONG)'}</td><td>${r.ms}</td><td>${r.reason || ''}</td>`;
|
||||
document.querySelector('#' + table + ' tbody').appendChild(tr);
|
||||
}
|
||||
try {
|
||||
const cp = await get(`${API}/checkpoint`);
|
||||
// a transaction to prove: the first in a chain block below the checkpoint
|
||||
let tx = q.get('tx');
|
||||
if (!tx) { const cb = await rpc('eth_getBlockByHash', ['0x' + cp.hash, false]); const n = parseInt(cb.number, 16); for (let k = n - 1; k > n - 200 && !tx; k--) { const b = await rpc('eth_getBlockByNumber', ['0x' + k.toString(16), false]); if (b && b.transactions.length) tx = b.transactions[0]; } }
|
||||
const rr = await get(`${API}/receipt?tx=${tx}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
const receipt = { format: 'igneum-receipt-v1', ...rr, checkpoint: { ...rr.checkpoint, certificate: rr.checkpoint.certificate || cp } };
|
||||
const R = [
|
||||
['raw transaction altered by one nibble', d => { d.raw_tx_hex = flipHex(d.raw_tx_hex, 40); }],
|
||||
['transaction hash altered', d => { d.tx_hash = flipHex(d.tx_hash, 10); }],
|
||||
['merkle leaf index moved', d => { d.including_block.leaf_index = d.including_block.leaf_index === 1 ? 2 : 1; }],
|
||||
['a merkle sibling altered', d => { d.including_block.merkle_siblings[0] = flipHex(d.including_block.merkle_siblings[0], 3); }],
|
||||
['a header removed from the path', d => { if (d.headers.length > 2) d.headers.splice(Math.floor(d.headers.length / 2), 1); else d.headers[0].nonce = String(BigInt(d.headers[0].nonce) ^ 1n); }],
|
||||
['a header nonce altered', d => { const h = d.headers[Math.floor(d.headers.length / 2)]; h.nonce = String(BigInt(h.nonce) ^ 1n); }],
|
||||
['certificate signature altered', d => { d.checkpoint.certificate.certificate.aggregate_signature_hex = flipHex(d.checkpoint.certificate.certificate.aggregate_signature_hex, 20); }],
|
||||
['receipt names another checkpoint than its certificate', d => { d.checkpoint.hash = flipHex(d.checkpoint.hash, 60); }],
|
||||
];
|
||||
for (const [name, mutate] of R) { const d = clone(receipt); mutate(d); row('r', name, verifyReceipt(d, deps), false); }
|
||||
row('r', `genuine receipt for ${tx.slice(0, 14)} (${receipt.headers.length} headers, checkpoint ${cp.index})`, verifyReceipt(receipt, deps), true);
|
||||
// a balance to prove
|
||||
let address = q.get('address');
|
||||
if (!address) { const b = await rpc('eth_getBlockByNumber', ['latest', false]); address = b.igneum.rewards[0].miner; }
|
||||
let proof = null;
|
||||
try { proof = await get(`${API}/balance?address=${address}&checkpoint=${cp.hash}&index=${cp.index}`); } catch (e) { document.querySelector('#b tbody').innerHTML = `<tr><td colspan="4" class="bad">balance proof not available: ${e.message}</td></tr>`; }
|
||||
if (proof && proof.checkpoint_certificate) Object.assign(cp, proof.checkpoint_certificate);
|
||||
if (proof) {
|
||||
const B = [
|
||||
['account proof: a node altered', d => { const i = d.account.accountProof.length - 1; d.account.accountProof[i] = flipHex(d.account.accountProof[i], 30); }],
|
||||
['reported balance raised by one wei', d => { d.account.balance = '0x' + (BigInt(d.account.balance) + 1n).toString(16); }],
|
||||
['state root altered', d => { d.account.stateRoot = flipHex(d.account.stateRoot, 8); }],
|
||||
['post_root altered inside the segment record', d => { d.segment_record_hex = flipHex(d.segment_record_hex, 2 * (2 + 8 + 8 + 32 + 48 + 20 + 148) + 3); }],
|
||||
['aggregator signature altered', d => { d.segment_record_hex = flipHex(d.segment_record_hex, d.segment_record_hex.length - 10); }],
|
||||
['coinbase payload altered', d => { d.carrier.coinbase.payload = flipHex(d.carrier.coinbase.payload, 30); }],
|
||||
['a merkle sibling altered (or added to a one-leaf body)', d => { if (d.carrier.merkle_siblings.length) d.carrier.merkle_siblings[0] = flipHex(d.carrier.merkle_siblings[0], 1); else d.carrier.merkle_siblings.push('00'.repeat(32)); }],
|
||||
['a header removed from the path', d => { if (d.headers.length > 2) d.headers.splice(1, 1); else d.headers[0].nonce = String(BigInt(d.headers[0].nonce) ^ 1n); }],
|
||||
['another address with this proof', d => { d.address = '0x' + '11'.repeat(20); }],
|
||||
];
|
||||
for (const [name, mutate] of B) { const d = clone(proof); mutate(d); row('b', name, verifyBalance(cp, d, deps), false); }
|
||||
{ const c = clone(cp); c.certificate.aggregate_signature_hex = flipHex(c.certificate.aggregate_signature_hex, 20); row('b', 'certificate signature altered', verifyBalance(c, proof, deps), false); }
|
||||
const g = verifyBalance(cp, proof, deps);
|
||||
row('b', `genuine balance of ${address.slice(0, 12)} at chain block ${proof.segment.last} (${proof.headers.length} headers, checkpoint ${cp.index})`, g, true);
|
||||
}
|
||||
} catch (e) { document.getElementById('done').textContent = 'ERROR ' + (e.message || e); }
|
||||
const bad = out.filter(x => !x.behaved).length + (document.getElementById('done').textContent.startsWith('ERROR') ? 1 : 0);
|
||||
document.getElementById('done').textContent += (bad ? `\nFAILED ${bad} case(s)` : `\nRESULT every case behaved (${out.length} cases)`) + '\n' + JSON.stringify(out.map(x => ({ table: x.table, name: x.name, verified: x.verified, ms: x.ms, reason: x.reason || null })));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5322
site/lc/verify-receipt.js
Normal file
5322
site/lc/verify-receipt.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4,13 +4,13 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum ledger: every criticism, answered</title>
|
||||
<meta name="description" content="Every criticism Igneum expects, in the critic's words, with what was done, the status and the date. 189 entries. Nothing deleted, nothing softened.">
|
||||
<meta name="description" content="Every criticism Igneum expects, in the critic's words, with what was done, the status and the date. 190 entries. Nothing deleted, nothing softened.">
|
||||
<link rel="canonical" href="https://igneum.network/ledger">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum ledger: every criticism, answered">
|
||||
<meta property="og:description" content="189 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta property="og:description" content="190 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta property="og:url" content="https://igneum.network/ledger">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum ledger: every criticism, answered">
|
||||
<meta name="twitter:description" content="189 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta name="twitter:description" content="190 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -90,6 +90,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -107,8 +108,6 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -119,18 +118,30 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger" aria-current="page"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -142,8 +153,6 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -152,15 +161,25 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger" aria-current="page"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -218,9 +237,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>The ledger</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Ledger · 189 entries · regenerated from the repository</div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Ledger · 190 entries · regenerated from the repository</div>
|
||||
<h1>Every criticism, answered<br><span class="accent">or conceded.</span></h1>
|
||||
<p class="lead">This is every criticism the project expects, in the critic's words, with what was done about it and the date. 189 entries since 3 October 2026. Entries are never deleted; a status that changes keeps its history on the line. Where the critic was right the entry says Conceded. Where nothing has been done it says Open and names what settles it. The founder mined through the GPU years. Ethereum's move to proof of stake in September 2022 ended that income and the miners' place in that chain. This is one person building, with AI systems doing the engineering, the coin he wanted to exist for miners: GPU-mined, the miners are the provers, no founder allocation, every cost stated. Help is welcome and a team is wanted: cryptographers, node engineers, miners who will test. This ledger is the application form: pick an open row and write to <a href="mailto:hello@igneum.network">hello@igneum.network</a> with its id.</p></div></div>
|
||||
<p class="lead">This is every criticism the project expects, in the critic's words, with what was done about it and the date. 190 entries since 3 October 2026. Entries are never deleted; a status that changes keeps its history on the line. Where the critic was right the entry says Conceded. Where nothing has been done it says Open and names what settles it. The founder mined through the GPU years. Ethereum's move to proof of stake in September 2022 ended that income and the miners' place in that chain. This is one person building, with AI systems doing the engineering, the coin he wanted to exist for miners: GPU-mined, the miners are the provers, no founder allocation, every cost stated. Help is welcome and a team is wanted: cryptographers, node engineers, miners who will test. This ledger is the application form: pick an open row and write to <a href="mailto:hello@igneum.network">hello@igneum.network</a> with its id.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
|
@ -229,11 +248,11 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<tbody>
|
||||
<tr><td class="num">3</td><td><button type="button" class="chip" data-filter="Open">Open</button></td><td>Nothing has settled it yet. The entry names what will</td></tr>
|
||||
<tr><td class="num">64</td><td><button type="button" class="chip" data-filter="Conceded">Conceded</button></td><td>The critic is right. "Stated" means the public text says so; "not yet stated" means it does not yet</td></tr>
|
||||
<tr><td class="num">64</td><td><button type="button" class="chip" data-filter="Fixed or built">Fixed or built</button></td><td>A code, spec or text change answers it, with the commit or the page named</td></tr>
|
||||
<tr><td class="num">65</td><td><button type="button" class="chip" data-filter="Fixed or built">Fixed or built</button></td><td>A code, spec or text change answers it, with the commit or the page named</td></tr>
|
||||
<tr><td class="num">27</td><td><button type="button" class="chip" data-filter="Closed by rule or decided">Closed by rule or decided</button></td><td>A consensus rule or a decision by the owner answers it, dated</td></tr>
|
||||
<tr><td class="num">15</td><td><button type="button" class="chip" data-filter="Answered with evidence">Answered with evidence</button></td><td>A measurement or a simulation exists and is named</td></tr>
|
||||
<tr><td class="num">16</td><td><button type="button" class="chip" data-filter="Answered by design">Answered by design</button></td><td>A design rule answers it; no measurement is possible yet</td></tr>
|
||||
<tr><td class="num">189</td><td><button type="button" class="chip" data-filter="">All</button></td><td>Every entry. The sections: <a href="#ap">The in-house adversarial pass</a>, <a href="#m">Mining and chips</a>, <a href="#f">Finality and attacks</a>, <a href="#p">Proving and the zkEVM</a>, <a href="#e">Economics and the coin</a>, <a href="#g">Governance and the founders</a>, <a href="#c">Comparisons</a>, <a href="#l">Legal and regulatory</a>, <a href="#x">Launch and operations</a>, <a href="#d">Builders</a></td></tr>
|
||||
<tr><td class="num">190</td><td><button type="button" class="chip" data-filter="">All</button></td><td>Every entry. The sections: <a href="#ap">The in-house adversarial pass</a>, <a href="#m">Mining and chips</a>, <a href="#f">Finality and attacks</a>, <a href="#p">Proving and the zkEVM</a>, <a href="#e">Economics and the coin</a>, <a href="#g">Governance and the founders</a>, <a href="#c">Comparisons</a>, <a href="#l">Legal and regulatory</a>, <a href="#x">Launch and operations</a>, <a href="#d">Builders</a></td></tr>
|
||||
</tbody></table></div>
|
||||
<div class="toolbar"><input type="search" id="q" placeholder="Search the ledger" aria-label="Search the ledger"><span id="shown"></span></div>
|
||||
<h2 id="m">Mining and chips</h2>
|
||||
|
|
@ -1397,7 +1416,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<article class="entry" id="AP-F8-1" data-bucket="Fixed or built">
|
||||
<div class="head"><span class="id">AP-F8-1</span><h3>A load whose source was last written by <code>or</code>, <code>mul</code> or <code>mulhi</code> makes a cross-hash hot set</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>The item histogram of class v4 over 2^26 nonces is not uniform: the top 0.1 percent of items take 0.520 percent of reads against 0.115 for a uniform control (4.05x), one item takes 78,479 reads (153x the mean), and site 15 feeds 6.37 percent of its reads into that top 0.1 percent in every iteration." (attack-pass row F8, <code>a repository file</code>, 7 October 2026)</blockquote>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Fixed in part, finding bounded, stated</span> <span class="did">7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is <code>a repository file</code> section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 local time; the logs under <code>a repository file/</code> on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 local time on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only.</span></div>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Fixed in part, finding bounded, stated</span> <span class="did">7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is <code>a repository file</code> section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 local time; the logs under <code>a repository file/</code> on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 local time on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only. The tail is attributed (8 October 2026, 09:46 UK, the hash lane): one narrow-window site per seed with a quarter-bit bucket concentration from a mad, xor or sub writer, no lossy source, no chip consequence beyond the window model; the per-site bucket bound that would refuse it is a morning item for the next class, not a change to 017e7037.</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct as a fault, wrong as a null. The window layer (spec 01 1.13.1 as proposed, <code>a repository file</code> 1.4) moves the uniform null from 0.115 to 0.160 percent at the top 0.1 percent (1.39x, not 4.05x) and explains every per-site row of F8's attribution except site 15. Site 15's source r6 was last written by <code>or r6, r4</code> (instruction 61, the load at 63), a non-injective op whose output bits are 1 with probability 3/4, so the all-ones source recurs with probability (3/4)^32 per read; the era map sends it to item 0xca5b92, F8's hottest item exactly, and F8's next seven items are exactly the seven one-zero-bit sources whose zero survives the window mask. The popcount model at the measured bias (p = 0.7585) predicts 77,348 all-ones reads against 78,479, and the program's top-0.1-percent share at 0.58 against 0.52. The acceptance rule's part (a) takes any write as a fresh source and part (c) counts saturation on final register values only, so the class of fault passes it: of 1,024 chain-shaped class v4 programs 96.6 percent carry a load whose source's last writer is <code>or</code>, <code>mul</code> or <code>mulhi</code>, 48.5 percent an <code>or</code>-sourced one (0.30 percent of all reads per site), 4.9 percent an <code>or</code>-of-<code>or</code> chain (p3's class: 72 percent of that site's reads, 4.6 percent of all reads, on 0.1 percent of items). The ceiling under rule (c)'s 120-of-128 floor is one site repeating its item in all 8 iterations, 6.25 percent of reads, a chip edge of at most 1.067x in 64 bytes of SRAM; the public claim's 2x margin stands, and the public line says "bounded", not "uniform" (<code>a repository file</code> sections 1 to 4).</p></details>
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-4" data-bucket="Fixed or built">
|
||||
|
|
@ -1406,12 +1425,18 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="status"><span class="badge b-fixed-or-built">Fixed</span> <span class="did">7 October 2026, night): the id and its derivation text come from one byte recipe, every pinned pack's id re-derives from its own text in the suite (the igneum-pow suite on box 2 green at 0f45c8be: 64 + 2 + 7 + 4 + 19 + 2 + 7), the spec states the suffix; no object moved.</span></div>
|
||||
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-5" data-bucket="Conceded">
|
||||
<article class="entry" id="AP-F8-5" data-bucket="Fixed or built">
|
||||
<div class="head"><span class="id">AP-F8-5</span><h3>The public specification did not describe the shipped acceptance rule (documentary; no object change)</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>An implementation written from a repository file section 1.4.6 at 017e7037 mines a different program from the node on 264 of 400 epochs." Found by the in-house pass adv-accept-3 (report-acceptance-rule-3.md at 0c150e3c, finding 3, section 6.2, 7 October 2026, night): the text described (a), (b) and (c) with a 32-attempt cap and an id without a suffix, while the code adds (a') with the shared-operand rule, (c'), (c'') at 2^20 evaluations, the 256-attempt cap keyed on the class v4 shape, the total draw with the last resort, generator 4 and the sub-version suffix, and executes the 256-instruction shadow block 27 times per iteration inside the acceptance interpreter. Measured (sweep 97, 400 seeds, 1,317 attempt verdicts): 759 verdicts differ (758 the code rejects and the text accepts: (a') 733, (c'') 15, (c) 10; 1 the other way, the shadow block changing a (c) statistic); 264 of 400 seeds choose another attempt; the parts the text did carry, (a) and (b), agree on every row.</blockquote>
|
||||
<div class="status"><span class="badge b-conceded">Conceded, stated</span> <span class="did">7 October 2026, night, the ledger close): <code>a repository file</code>, What Igneum does not claim, "A delay function that outlives a quantum computer. No." with the fallback (a hash-chain delay behind the version byte that moves the signature scheme, one class change) and the reading (a liveness nuisance, not a break of finality). Still not sized. Was: Conceded, flagged in spec 04 section 4.8.</span></div>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Spec fixed</span> <span class="did">7 October 2026, night, the site audit lane by main's order, branch spec-accept-23): sections 1.4.3 and 1.4.6 of <code>a repository file</code> rewritten to the shipped rule at igneum-pow 017e7037 with every constant named and every order of operations stated (1.4.3: the two per-register states of the draw, the dataflow table, the shared-operand rule, the shadow block's draw and the draw counts per class; 1.4.6.1 to 1.4.6.6: (a) cyclic over two passes, (b), (a') to the fixpoint then a checking pass, (c) with the shadow executed and its limits in a table, (c') and (c'') with the integer form of the ratio compare, the attempts and the two caps with the measured per-part rates, the last resort stated as unreachable and unverified, the program id with the generator-4 suffix, a constants table in the shape the crate's read-back test parses, the pinned ids a reader must reproduce); section 1.7 gains the shadow block's execution; section 1.13.1 names the two consumed era draws. The hash lane's <code>igneum-pow/tests</code> read-back test parses the two tables against the crate's <code>pub const</code> items and derives every pinned id (its landing is the row's check; AP-F8-4 carries the derivation-text half of the same finding). Fixed on two measurements by the finding lane: Q4c at master 8b834634, before the closed-form dataset was stated, a text-only implementation of sections 1.3, 1.4.2, 1.4.3, 1.4.6, 1.6, 1.7 and 1.13.1 re-derived the 400 epoch programs of sweep 97 under the Devnet 3 era with 0 of 400 differing on any field and one function (<code>dataset_elem</code>) taken from the crate (report section 6.5, log 983-textderive-8b834634.tsv); Q4d at master 56eebc0d, with <code>dataset_elem</code> written from 1.4.6.4 and its two pinned vectors reproduced, 0 of 400 differing with 0 crate imports (report section 6.6, log 984-textderive-56eebc0d.tsv, 8 October 2026, 01:5x UK).</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct, and the largest divergence source the pass found was documentary. The rule the chain runs was right; the text a second implementer would read was three sub-versions behind it. The fix is the text, written to the code line by line, and a test that fails when the two drift again.</p></details>
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-7" data-bucket="Conceded">
|
||||
<div class="head"><span class="id">AP-F8-7</span><h3>The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>The served text says every hash is a chain of random reads over the dataset. Measured at the acceptance rule's own 2^20 sample over 4,900 drawn eras (lane D's family harness, 8 October 2026) and in adv-cache-2's drawn-program reading the night before: the reads are spread over the whole dataset and the distinct-index floor holds at 0.995 on every accepted program, but 52 to 58 percent of accepted programs in every stratum carry one load site whose address bit R (the era's stride rotation), R+1 or R+2 is biased over 6 sigma, a third over 100 sigma, the worst z 1,024: a product's bit 0 at P = 1/4 landing on an address bit.</blockquote>
|
||||
<div class="status"><span class="badge b-conceded">Conceded, stated</span> <span class="did">7 October 2026, night, the ledger close): <code>a repository file</code>, What Igneum does not claim, "A delay function that outlives a quantum computer. No." with the fallback (a hash-chain delay behind the version byte that moves the signature scheme, one class change) and the reading (a liveness nuisance, not a break of finality). Still not sized. Was: Conceded, flagged in spec 04 section 4.8.</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct as a measurement and bounded as a gain. The favoured half of one site's window serves 75 instead of 50 percent of that site's reads, 25 percent of 1/16 of a hash's reads, about 1.6 percent, to a chip storing half the dataset; a chip storing all of it gains nothing (the f = 1 verdict unchanged, and the partial store already costs 1.26x the ops). The sentence that said "random" now says what was measured.</p></details>
|
||||
</article>
|
||||
|
||||
<p class="intro" style="margin-top:var(--sec)">Source: the project's criticism ledger, a file in the repository, rendered to this page at build time; the repository is published at the public testnet. A criticism that is not here, or that shows an entry is wrong, is added with credit if wanted: <a href="mailto:hello@igneum.network">hello@igneum.network</a> or <a href="https://github.com/igneum-network/spec/issues" rel="noopener">an issue on the specification repository</a>.</p>
|
||||
</div></section>
|
||||
|
|
@ -1428,7 +1453,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span data-os="windows" class="mini"></span>Windows</a><a href="/download#mac"><span data-os="mac" class="mini"></span>macOS</a><a href="/download#linux"><span data-os="linux" class="mini"></span>Linux</a><a href="/download#hive"><span data-os="hive" class="mini"></span>HiveOS</a></div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
|
|
@ -1438,7 +1463,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -1453,6 +1478,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
41
site/lib/income-calc.mjs
Normal file
41
site/lib/income-calc.mjs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// The /income calculator's arithmetic (8 October 2026, the founder's value-economics question through main): what one card
|
||||
// mines a day as its share of the network, what its electricity costs, and what that is worth at a price the reader types.
|
||||
// No price is assumed: with no price typed there is no money figure (income-calc.test.mjs, the known-failed case first).
|
||||
// Shared by the page script (site/income-calc.js, through window.IgneumIncome) and the test.
|
||||
|
||||
export const PRODUCER_SHARE = 0.8; // spec 02 2.5: 80 percent of a block to the miner who found it, 20 to the proving pool
|
||||
export const BLOCKS_PER_DAY = 86_400; // one block a DAA second; blockRewardIgn is the per-block figure at 1 block a second
|
||||
|
||||
/** A typed price: a finite number above zero, else null (empty, zero, negative, not a number). */
|
||||
export function parsePrice(s) {
|
||||
if (s === null || s === undefined) return null;
|
||||
const t = String(s).trim().replace(/,/g, '');
|
||||
if (t === '') return null;
|
||||
const n = Number(t);
|
||||
return Number.isFinite(n) && n > 0 ? n : null;
|
||||
}
|
||||
|
||||
/** IGN a day for a card at `cardMhs` on a network at `networkHs` hashes a second paying `blockRewardIgn` a block. */
|
||||
export function ignPerDay({ cardMhs, networkHs, blockRewardIgn, producerShare = PRODUCER_SHARE }) {
|
||||
if (!(cardMhs > 0) || !(networkHs > 0) || !(blockRewardIgn >= 0)) return null;
|
||||
return (cardMhs * 1e6 / networkHs) * BLOCKS_PER_DAY * blockRewardIgn * producerShare;
|
||||
}
|
||||
|
||||
/** Electricity a day in the tariff's currency: watts x 24 h x the price of a kWh. Null without a watt figure. */
|
||||
export function electricityPerDay({ watts, kwhPrice }) {
|
||||
if (!(watts > 0) || !(kwhPrice >= 0)) return null;
|
||||
return watts / 1000 * 24 * kwhPrice;
|
||||
}
|
||||
|
||||
/** Money a day at a typed IGN price, electricity taken off. No price, no figure: null. */
|
||||
export function moneyPerDay({ ignPerDay: ign, ignPrice, electricity }) {
|
||||
const p = parsePrice(ignPrice);
|
||||
if (p === null || !(ign >= 0)) return null;
|
||||
return ign * p - (electricity > 0 ? electricity : 0);
|
||||
}
|
||||
|
||||
/** Seconds to a block for one card: the network's rate over the card's, at one block a second. */
|
||||
export function secondsToBlock({ cardMhs, networkHs }) {
|
||||
if (!(cardMhs > 0) || !(networkHs > 0)) return null;
|
||||
return networkHs / (cardMhs * 1e6);
|
||||
}
|
||||
34
site/lib/income-calc.test.mjs
Normal file
34
site/lib/income-calc.test.mjs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// node --test site/lib/income-calc.test.mjs (the pre-push gate runs it)
|
||||
// Known-failed first: an empty, zero, negative or non-numeric IGN price gives NO money figure, whatever the rest reads.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { parsePrice, ignPerDay, electricityPerDay, moneyPerDay, secondsToBlock, PRODUCER_SHARE, BLOCKS_PER_DAY } from './income-calc.mjs';
|
||||
|
||||
test('an empty price shows no money figure (the known-failed case)', () => {
|
||||
const ign = ignPerDay({ cardMhs: 100, networkHs: 1e9, blockRewardIgn: 10 });
|
||||
assert.ok(ign > 0);
|
||||
for (const bad of ['', ' ', null, undefined, '0', '-1', 'abc', 'NaN', 'Infinity']) {
|
||||
assert.equal(parsePrice(bad), null, `price ${JSON.stringify(bad)} must parse to null`);
|
||||
assert.equal(moneyPerDay({ ignPerDay: ign, ignPrice: bad, electricity: 1 }), null, `price ${JSON.stringify(bad)} must give no money figure`);
|
||||
}
|
||||
});
|
||||
|
||||
test('a typed price gives IGN a day times the price, electricity off', () => {
|
||||
const ign = ignPerDay({ cardMhs: 100, networkHs: 1e9, blockRewardIgn: 10 });
|
||||
// 100 MH/s of 1 GH/s is a tenth of 86,400 blocks at 10 IGN x 0.8
|
||||
assert.equal(ign, 0.1 * BLOCKS_PER_DAY * 10 * PRODUCER_SHARE);
|
||||
assert.equal(parsePrice('0.01'), 0.01);
|
||||
assert.equal(parsePrice('1,000'), 1000);
|
||||
const el = electricityPerDay({ watts: 250, kwhPrice: 0.25 });
|
||||
assert.equal(el, 1.5);
|
||||
assert.equal(moneyPerDay({ ignPerDay: ign, ignPrice: '0.01', electricity: el }), ign * 0.01 - 1.5);
|
||||
assert.equal(moneyPerDay({ ignPerDay: ign, ignPrice: '0.01', electricity: null }), ign * 0.01);
|
||||
});
|
||||
|
||||
test('no watts, no electricity; no network, no share; the block wait is the ratio of rates', () => {
|
||||
assert.equal(electricityPerDay({ watts: null, kwhPrice: 0.25 }), null);
|
||||
assert.equal(ignPerDay({ cardMhs: 100, networkHs: 0, blockRewardIgn: 10 }), null);
|
||||
assert.equal(ignPerDay({ cardMhs: 100, networkHs: 1e9, blockRewardIgn: 0 }), 0);
|
||||
assert.equal(secondsToBlock({ cardMhs: 100, networkHs: 1e9 }), 10);
|
||||
assert.equal(secondsToBlock({ cardMhs: 0, networkHs: 1e9 }), null);
|
||||
});
|
||||
364
site/light.html
Normal file
364
site/light.html
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum light wallet</title>
|
||||
<meta name="description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/light">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum light wallet">
|
||||
<meta property="og:description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/light">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum light wallet">
|
||||
<meta name="twitter:description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light" aria-current="page"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light" aria-current="page"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Light wallet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 1 · Devnet 3, no value</div>
|
||||
<h1>A balance your browser proves<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">Paste a Devnet 3 address. This tab fetches the latest finality certificate, the header chain, the carrier block's coinbase, the segment record and an account proof from a read service, then checks every byte itself: BLS over the checkpoint, every header hash and parent link, the merkle path, the aggregator's signature, the Merkle Patricia proof under the proven state root. The service cannot lie about the balance. It can only refuse to answer.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> The balance rests on a state root that an aggregator signed inside a block, after proving the segment's execution, and that every node checks against its own execution before paying the record. On a chain without proofs a light client has only a node's word for a balance.</p>
|
||||
<p>Source: <code>site/lc/core.js</code> (the checks), <code>site/lc/app.js</code> (this page), <code>tools/reference-apps/light-service/serve.mjs</code> (the read service), fork branch <code>light-apps-node</code> (<code>eth_getProof</code> on the node). Test with the negative cases: <a href="/lc/test">/lc/test</a> in the browser, <code>tools/reference-apps/light-service/verify.test.mjs</code> under Node.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="verify">
|
||||
<h2 id="verify">Verify a balance</h2>
|
||||
<form class="vform" data-form="light" novalidate>
|
||||
<label for="address">Devnet 3 address</label>
|
||||
<div class="row"><input id="address" name="address" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" pattern="^0x[0-9a-fA-F]{40}$"><button class="btn primary" type="submit">Verify in this tab</button></div>
|
||||
<div class="vstatus" data-status role="status" aria-live="polite">Devnet 3, no value. Nothing here is a wallet that sends. It reads and proves.</div>
|
||||
</form>
|
||||
<div data-result></div>
|
||||
</section>
|
||||
|
||||
<h2 id="checked">What is checked, in order</h2>
|
||||
<ol>
|
||||
<li>The certificate: the aggregate BLS signature of the signers over <code>igneum-vote-v1/igneum-devnet-3 || index || checkpoint hash</code>, the canonical voter order, the rule (two thirds of active weight, 17/30 of total), and the header chain from the previous lock.</li>
|
||||
<li>The header path from the carrier block up to the certified checkpoint: every header hash recomputes (BLAKE2b-256 keyed BlockHash over the header fields), every next header names the previous as a direct parent.</li>
|
||||
<li>The coinbase transaction is in the carrier block: its hash recomputes (BLAKE2b-256 keyed TransactionHash over the serialized transaction) and the merkle path reaches the header's <code>hash_merkle_root</code>.</li>
|
||||
<li>The segment record in the coinbase extra data: the aggregator's BLS signature over the record under the network's tag, whether the key is a voter with weight or a prove-only key, and the statement names the chain and the block whose state it commits.</li>
|
||||
<li>The account proof: a keccak-keyed Merkle Patricia proof under the record's <code>post_root</code>, every node hashed on the way down, the balance read from the leaf.</li>
|
||||
</ol>
|
||||
<p class="note">What is trusted and said so on the result: the aggregator's statement being the true execution result (nodes check it natively before paying; the SP1 proof behind it is verified by nodes, not in this tab yet), and the voter table with weights, which comes from the node (spec 10.1). The read service names the node it reads.</p>
|
||||
<p class="asof">Devnet 3, no value. The chain may reset. Pages like this one are demonstrations of the verification path, not a product.</p>
|
||||
</main>
|
||||
<script type="module" src="/lc/app.js"></script>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -143,6 +143,7 @@ body.all .pager{display:none}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -160,8 +161,6 @@ body.all .pager{display:none}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -172,18 +171,30 @@ body.all .pager{display:none}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper" aria-current="page"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -195,8 +206,6 @@ body.all .pager{display:none}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -205,15 +214,25 @@ body.all .pager{display:none}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper" aria-current="page"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -332,7 +351,7 @@ body.all .pager{display:none}
|
|||
<div class="tbl"><table>
|
||||
<thead><tr><th>Piece</th><th>Closest precedent</th><th>What Igneum adds</th><th>State, 7 Oct 2026</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>A mining program that regenerates itself, for GPUs</td><td>RandomX on Monero since 2019, for CPUs, a program per hash; the one chip announced against it, Bitmain’s Antminer X9, withdrawn in May 2026 before launch. ProgPoW, as KAWPOW on Ravencoin since 2020, changes the maths inside a fixed program shape every few blocks on GPUs (approximate)</td><td>A whole kernel per hour compiled to native code, a daily dataset from a 256 MB cache, a verifiable delay before the seed, era draws from a genesis reserve</td><td>Measured: hourly swaps on Apple, NVIDIA and AMD cards on the live devnet, 4 October 2026</td></tr>
|
||||
<tr><td>A mining program that regenerates itself, for GPUs</td><td>RandomX on Monero since 2019, for CPUs, a program per hash; one chip shipped against it, Bitmain’s Antminer X5 (September 2023), a board of RISC-V chips at 1.46x per joule over a desktop CPU, on silicon believed mining privately from about 2021; the X9 was withdrawn in May 2026 with zero units; RandomX v2 was released on 25 March 2026 with its activation pending. ProgPoW, as KAWPOW on Ravencoin since 2020, changes the maths inside a fixed program shape every few blocks on GPUs (approximate)</td><td>A whole kernel per hour compiled to native code, a daily dataset from a 256 MB cache, a verifiable delay before the seed, era draws from a genesis reserve</td><td>Measured: hourly swaps on Apple, NVIDIA and AMD cards on the live devnet, 4 October 2026</td></tr>
|
||||
<tr><td>The mining card does paid, useful, verifiable work</td><td>Primecoin's prime chains in 2013 were not useful. Aleo ran proving as consensus and the fastest prover won (both approximate)</td><td>Proving kept apart from the lottery; shards assigned by sortition, not by speed</td><td>Implemented: proving v0 and v1 on Devnet 3 from block zero (7 October 2026), v0 on the first devnet since 5 October 2026. The job market for other chains is Designed</td></tr>
|
||||
<tr><td>A proof-of-work chain where every block is proven</td><td>zkEVMs run as rollups on proof-of-stake Ethereum. Conflux has run GPU-mined EVM apps on a DAG since 2020, without proofs (approximate)</td><td>Proven state on a proof-of-work base layer, produced by the miners themselves</td><td>Implemented in part: shards proven and paid on the devnet. The aggregated block proof checked in consensus is Designed</td></tr>
|
||||
<tr><td>Finality held by miners and not moved by hour-long rentals</td><td>Decred votes with stake. Horizen penalises hidden chains. Kaspa limits merge depth (approximate)</td><td>Vote weight is 30 days of blocks per key. Hashrate that appeared today has no vote</td><td>Implemented: rule v3 live on Devnet 3 from block zero, first lock 7 October 2026; rule v2 ran the first devnet from its first lock on 4 October 2026. External review is owed at gate 3</td></tr>
|
||||
|
|
@ -426,19 +445,19 @@ body.all .pager{display:none}
|
|||
<section id="mining">
|
||||
<h2>Mining: a program that never holds still</h2>
|
||||
<p>Every GPU chain that promised ASIC resistance shipped a fixed algorithm, and a fixed algorithm gets a chip the moment the prize pays for one. Igneum does not have a fixed algorithm.</p>
|
||||
<p>Each hour the chain derives a seed from a locked checkpoint one epoch back, passes it through a ten-minute verifiable delay so no miner can see which program a seed implies before choosing whether to publish a block, and feeds it to a deterministic generator. The generator emits a random integer program built from what graphics cards are uniquely good at: wide parallel integer maths, shuffles between the 32 lanes of a warp, and random reads over a multi-gigabyte dataset that changes daily, so the program waits on memory latency, not on maths or bandwidth. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes (engineering log, the RTX 5090 entries). The memory footprint and instruction count are fixed and only the maths sequence is random, so no hour favours one vendor's cards and nobody gains by grinding the seed. Miners compile the program once per hour. Anyone running a node, a wallet or an exchange checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp, so nobody needs a GPU except to mine. Measured: 0.61 ms per warp on one Apple M5 Max core for class v2 and 2.1 ms for class v3 (the mixer at x8, 5 October 2026, one core at load average 5.5, worst cold unit 2.15 ms), 3.4x the class v2 verifier; the 10 ms gate leaves 4.8x (4.6x on the worst cold unit); a 2019-class laptop core is not yet measured.</p>
|
||||
<p>Each hour the chain derives a seed from a locked checkpoint one epoch back, passes it through a ten-minute verifiable delay so no miner can see which program a seed implies before choosing whether to publish a block, and feeds it to a deterministic generator. The generator emits a random integer program built from what graphics cards are uniquely good at: wide parallel integer maths, shuffles between the 32 lanes of a warp, and dependent reads spread over a multi-gigabyte dataset that changes daily, so the program waits on memory latency, not on maths or bandwidth. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes (engineering log, the RTX 5090 entries). The memory footprint and instruction count are fixed and only the maths sequence is random, so no hour favours one vendor's cards and nobody gains by grinding the seed. Miners compile the program once per hour. Anyone running a node, a wallet or an exchange checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp, so nobody needs a GPU except to mine. Measured: 0.61 ms per warp on one Apple M5 Max core for class v2 and 2.1 ms for class v3 (the mixer at x8, 5 October 2026, one core at load average 5.5, worst cold unit 2.15 ms), 3.4x the class v2 verifier; the 10 ms gate leaves 4.8x (4.6x on the worst cold unit); a 2019-class laptop core is not yet measured.</p>
|
||||
<p>The hash is a lottery, not a general-purpose cryptographic hash. It has to be unpredictable per nonce, free of any shortcut cheaper than honest evaluation, and free of bias a miner can exploit. It does not need preimage or collision resistance. Open: no analysis of the lottery properties exists yet. It is the first job of the external review in phase 1, and until then the hash is a design claim backed by the measurements below.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Clock</th><th>What changes</th><th>Miner update needed?</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Every hash</td><td>The 128 dataset addresses depend on the nonce, so every hash reads different memory. The one-bit select inside the maths costs a chip nothing and is not a defence; the random reads are</td><td>No</td></tr>
|
||||
<tr><td>Every hash</td><td>The 128 dataset addresses depend on the nonce, so every hash reads different memory. The one-bit select inside the maths costs a chip nothing and is not a defence; the dependent reads are</td><td>No</td></tr>
|
||||
<tr><td>Every hour</td><td>A new random program</td><td>No, the miner compiles whatever arrives</td></tr>
|
||||
<tr><td>Every day</td><td>A new dataset</td><td>No</td></tr>
|
||||
<tr><td>Every six months</td><td>A new instruction mix and memory pattern drawn by the chain from rules fixed at genesis, and a new family of instructions unlocked from a reserve written at genesis, so the program space widens every era. A schedule change against fixed datapaths and human forks, not a surprise: a programmable chip reads every drawn parameter as firmware</td><td>No</td></tr>
|
||||
<tr><td>Continuously</td><td>The dataset grows on a schedule fixed at genesis, slowly enough that consumer cards keep up for years. A chip is built with fixed memory, so it is on a countdown from the day it ships. Ethereum's growing dataset ran Bitmain's E3 out of memory in 2020 this way, approximate, with nobody doing anything</td><td>No</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Three ideas carry the chip resistance. <strong>The hash rewrites itself.</strong> A new program every hour, drawn from the chain. Its memory pattern changes with it. The rules change on a schedule fixed at launch. No release, no vote. These are automatic schedule changes: they defeat a chip wired for one datapath and they need no human fork. Against a chip that stores the dataset every drawn parameter is firmware, and what meets that chip is the latency-shadow work (class v4) and the price per joule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). <strong>It waits on memory, not maths.</strong> Every hash is a chain of random reads into a table too big for a chip to carry. The wait is the same physics for everyone. <strong>Miners hold the switch.</strong> Spare defences are written into the rules, switched off. A miner signal turns one on, at the class-change threshold: miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. No fork.</p>
|
||||
<p>Three ideas carry the chip resistance. <strong>The hash rewrites itself.</strong> A new program every hour, drawn from the chain. Its memory pattern changes with it. The rules change on a schedule fixed at launch. No release, no vote. These are automatic schedule changes: they defeat a chip wired for one datapath and they need no human fork. Against a chip that stores the dataset every drawn parameter is firmware, and what meets that chip is the latency-shadow work (class v4) and the price per joule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). <strong>It waits on memory, not maths.</strong> Every hash is a chain of random reads into a table too big for a chip to carry. Measured (8 October 2026; lane D’s family harness at the acceptance rule’s own 2^20 sample over 4,900 drawn eras, and the chained-cache pass’s reading of the night before): every hash’s 128 dependent reads land across the whole dataset and the distinct-index floor holds at 0.995 on every accepted program; about half of epochs carry one load site whose address bit at the era’s stride rotation is biased, which prices about 1.6 percent of a hash’s reads to a chip storing half the dataset and nothing to a chip storing all of it; the next class folds the product’s low bits before the rotation, so no era lands a biased bit on an address bit. The wait is the same physics for everyone. <strong>Miners hold the switch.</strong> Spare defences are written into the rules, switched off. A miner signal turns one on, at the class-change threshold: miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. No fork.</p>
|
||||
<p><strong>The work that waits can grow.</strong> Class v4 adds a block of latency-shadow arithmetic to every hash, about 100,000 integer operations that run while the memory reads are in flight, so a chip that stores the whole dataset still has to pay for a core. That size sits on a ladder fixed at genesis, six rungs from about 100,000 to about 1,000,000 operations, and it moves one rung at a time only when 90 percent of blue blocks in each of seven consecutive days ask for it; it can never move two rungs inside a week and never past a rung the reference verifier cannot check under 10 ms with its sibling thread busy (measured on the build server, 6 October 2026: the first three rungs pass at 8.8, 8.9 and 9.2 ms, the fourth misses by 0.08 ms on a loaded box and stays out until a quiet re-measurement, the two doublings are out at 12.4 and 15.0 ms). What it buys, on the measured cards: against a dataset-storing chip whose core costs what an RTX 5090's does per operation, the chip's per-joule edge falls from 2.1x at the first rung to 1.3x at the third; against a core as good as the one Bitmain claimed for its withdrawn Antminer X9 (about 3x per joule over a desktop CPU, never measured), from 3.4x to 2.8x. What it costs, per rung, is measured too: the Apple tier gives up 3 points of rate at the first step and 6 more at the second, the RTX 5090 nothing until the second; so the miners who pay for a step are the ones who take it (<a href="/ledger#M34">ledger M34</a>).</p>
|
||||
<h3 id="chip-model">The chip model</h3>
|
||||
<p>We price the strongest chip we can design against an RTX 5090 and publish the arithmetic. Class v4 is live from the first block on the testnet and the mainnet (the ladder’s rung 0 at genesis), so the launch number is the class v4 row. The honest card: an RTX 5090 mines class v3 at 136 MH/s on 350 W in the bench and 290 W in the app (measured, 6 October 2026); under class v4 the same card reads 136.84 MH/s at 475.5 W unlocked and 134.98 MH/s at 316.3 W at a 1,400 MHz core lock, and 133.80 MH/s at 305.1 W at 1,200 MHz, against a class v3 control of 134.68 MH/s at 228.0 W (measured, 7 October 2026); an Apple M5 Max at 27 MH/s on 21 W (measured, 6 October 2026); an H100 SXM at 249 MH/s, 98 percent of its random-read ceiling like the 5090, 1.78x the 5090’s hash at 1.15x the tuned 5090’s hash per watt and a third of the hash per rented dollar (measured, 7 October 2026), so datacentre silicon does not change the chip question. The CPU verifier takes 2.33 ms per warp of 32 hashes on one M5 Max core under class v4 (measured, 6 October 2026), against a gate of 10 ms.</p>
|
||||
|
|
@ -451,14 +470,14 @@ body.all .pager{display:none}
|
|||
<tr><td>When a stored-dataset chip pays for itself</td><td>at about USD 100 M of market cap in the first two years, not before</td><td>modelled, 7 October 2026</td></tr>
|
||||
<tr><td>The baseline the work started from: the same chip under class v3, without the shadow (the Ethash class)</td><td>5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x)</td><td>modelled, 6 October 2026; the precedent measured by others, 2020 to 2022; never the launch state</td></tr>
|
||||
</tbody></table></div>
|
||||
<p>What a miner sees from this. Class v4 costs a 5090 145 W more unlocked, 88 W more at a 1,400 MHz core lock and 82 W at the best operating points (class v4 at 1,200 MHz, class v3 at 1,300; the knee is 1,300 MHz on both), for 0.2 percent more rate (measured, 7 October 2026; the 80 W read on 6 October was at the app's tuned cap); an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). Devnet 3 runs class v4 from its first block (7 October 2026); the first devnet started on class v3 and reaches class v4 by miner signal at a published height. The next test of the model is an internal adversarial pass, not an independent review: three lanes that have never worked on the hash code attack the mixer, the chained cache and the acceptance rule with only what an outsider has (the public kit, the frozen object, the spec, the harnesses) and publish the break or the bound they reach. No outside review has run yet.</p>
|
||||
<p>No hash has stayed free of chips forever. Igneum does not claim to. It states the gain its own model finds, the response takes a week, and both are measured. The model is public: <a href="/bench#counter-asic-2-0-the-numbers">the numbers</a>; the claim is tested by the in-house adversarial pass and the public benchmark. Monero has run on RandomX since 2019 (approximate) with no chip shipped. Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked. A box with about a 2x per joule edge over the best CPUs, and about 3x over a desktop, was withdrawn rather than face a RandomX re-tune of 1.5x or more. That is the band Igneum’s class v4 model sits in (2.1x to 3.4x over an RTX 5090), and the defence that held was a maintained algorithm with a credible upgrade path, which is what the ladder is.</p>
|
||||
<p>What a miner sees from this. Class v4 costs a 5090 145 W more unlocked, 88 W more at a 1,400 MHz core lock and 82 W at the best operating points (class v4 at 1,200 MHz, class v3 at 1,300; the knee is 1,300 MHz on both), for 0.2 percent more rate (measured, 7 October 2026; the 80 W read on 6 October was at the app's tuned cap); an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). Devnet 3 runs class v4 from its first block (7 October 2026); the first devnet started on class v3 and reaches class v4 by miner signal at a published height. Classes rotate on findings and at least yearly; a class change is a release activated by block height. Class v5 crosses on Devnet 3 by height; class v6 is the design in progress (opened 8 October 2026), with four layers as its spine: per-era draws of the parameters a release now fixes, a dataset whose size tracks the chain state, scheduled family epochs by height, and the acceptance floor generalised to every era’s draw. The next test of the model is an internal adversarial pass, not an independent review: three lanes that have never worked on the hash code attack the mixer, the chained cache and the acceptance rule with only what an outsider has (the public kit, the frozen object, the spec, the harnesses) and publish the break or the bound they reach. No outside review has run yet.</p>
|
||||
<p>No hash has stayed free of chips forever. Igneum does not claim to. It states the gain its own model finds, the response takes a week, and both are measured. The model is public: <a href="/bench#counter-asic-2-0-the-numbers">the numbers</a>; the claim is tested by the in-house adversarial pass and the public benchmark. Monero has run on RandomX since November 2019; one chip shipped against it, Bitmain’s Antminer X5 (September 2023), a board of RISC-V chips at 1.46x per joule over a desktop CPU, on silicon believed mining privately from about 2021; RandomX v2 was released on 25 March 2026 with its mainnet activation pending. Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked. A box with about a 2x per joule edge over the best CPUs, and about 3x over a desktop, was withdrawn rather than face a RandomX re-tune of 1.5x or more. That is the band Igneum’s class v4 model sits in (2.1x to 3.4x over an RTX 5090), and the defence that held was a maintained algorithm with a credible upgrade path, which is what the ladder is.</p>
|
||||
<p>One thing takes a person, here and on every chain that exists: writing new code. A chain cannot safely write its own generator, and it cannot safely tell a chip from a wave of honest new cards by hashrate alone. If the design above ever failed, anyone could publish a new generator and miners would switch it on by signalling, as Monero's community can fork. Igneum is built to make that day unlikely, and does not depend on avoiding it.</p>
|
||||
</section>
|
||||
|
||||
<section id="randomx">
|
||||
<h2>Monero's idea, finished for GPUs</h2>
|
||||
<p>RandomX has kept chips off Monero since 2019 (approximate) by making the mining program random, so the hardware that runs it well is the hardware everyone already owns. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<p>RandomX has kept Monero on commodity hardware since 2019 by making the mining program random, so the hardware that runs it well is close to the hardware everyone already owns: the one chip that shipped, Bitmain’s Antminer X5 (September 2023), is a board of RISC-V chips at 1.46x per joule over a desktop CPU. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 with its mainnet activation pending (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Property</th><th>RandomX, Monero</th><th>Igneum</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -469,7 +488,7 @@ body.all .pager{display:none}
|
|||
<tr><td>Changes over time</td><td>None. A fixed design, unchanged for seven years</td><td>A new program every hour, its memory pattern with it; era draws and reserved families on a schedule fixed at genesis. Nobody touches it</td></tr>
|
||||
<tr><td>Seed grinding</td><td>Not applicable, the program comes from the hash input</td><td>Closed by a verifiable delay between seed and program</td></tr>
|
||||
<tr><td>Useful work</td><td>None. Hashing only</td><td>Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years without a shipped chip; the one announced, Bitmain’s Antminer X9, was withdrawn in May 2026 before launch</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years with one shipped chip, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, Bitmain’s Antminer X9, was withdrawn in May 2026 with zero units; RandomX v2 released 25 March 2026, activation pending</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Measured so far: the same hourly program, generated on an Apple M5 Max, compiled by Apple's Metal and NVIDIA's CUDA on an RTX 5090, produced identical hashes on both, 192 of 192 across two programs. On a 1 GB dataset the 5090 ran at about 228 million hashes a second and the Mac at about 45 million, both bound by random memory access rather than arithmetic. Those are prototype figures, not mining rates. The first prototype dataset was a closed-form function, and a miner could compute items instead of loading them: measured 111x faster that way on the Mac. The 256 MB cache construction replaced it on 3 October 2026. With the cache, computing items on the fly runs 4.8x slower than loading them, measured on the Mac, and the honest rate is unchanged on both vendors. Open: the same shortcut ratio on NVIDIA and on a discrete AMD card, and the time-memory trade-off between the two measured points. Inside the 5090's 96 MB cache the same program ran nearly six times faster, which is why the dataset starts at 2 GB and grows. On 4 October 2026 the live devnet crossed an hourly program change on all three vendors with no pause and no rejected block: a Mac at 26.7 million hashes a second, an RTX 5090 at 123 million and an integrated AMD chip at 2.7 million, every hash doing 128 distinct reads of the memory-hard dataset.</p>
|
||||
|
|
@ -808,7 +827,7 @@ body.all .pager{display:none}
|
|||
<p>Here are the limits, stated before anyone else states them.</p>
|
||||
<ul>
|
||||
<li><strong>A proof in seconds.</strong> Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held for about seven years; the one chip announced against it, Bitmain’s Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held its miners on commodity hardware for about seven years: one chip shipped against it, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, the Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured; RandomX v2 was released on 25 March 2026 with its activation pending. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A guaranteed income floor.</strong> No. External proving is a small market today. Igneum's miners' electricity cost in it is close to power, but the price they must charge is the subsidy they forgo, which falls as one over network hash: an edge at scale and nothing more.</li>
|
||||
<li><strong>A memory-hard prototype on every vendor.</strong> Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open.</li>
|
||||
<li><strong>Finality in the first month.</strong> No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears.</li>
|
||||
|
|
@ -849,7 +868,7 @@ body.all .pager{display:none}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -864,6 +883,9 @@ body.all .pager{display:none}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -244,8 +245,6 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -256,18 +255,30 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -279,8 +290,6 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -289,15 +298,25 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -512,7 +531,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -527,6 +546,9 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -105,8 +106,6 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask" aria-current="page"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -117,18 +116,30 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -140,8 +151,6 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask" aria-current="page"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -150,15 +159,25 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -303,7 +322,7 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -318,6 +337,9 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -818,13 +818,13 @@
|
|||
"card": "NVIDIA RTX 5070 Ti (16 GB)",
|
||||
"generator": "v2",
|
||||
"mh_s": 78.45,
|
||||
"mh_per_w": 0.577,
|
||||
"watts": 135.9,
|
||||
"mh_per_w": 0.322,
|
||||
"watts": 214,
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"source": "model sweep 2026-10-08, row 1 (a rented card, result cb2-rtx-5070-ti-16-gb-7324-result.json; 09:23Z)",
|
||||
"source": "model sweep 2026-10-08, row 1 (a rented card, result cb2-rtx-5070-ti-16-gb-7324-result.json; 09:23Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-5070-ti-16-gb-1858-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 135.9 W (instant 139.0, max 140.0, limit 300 W), SM 2,795 MHz mean, memory 13,801 MHz, 47 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the same rate on this card (78.72 MH/s, fingerprint matched); read ceiling 79.6 MH/s, so the hash runs at 0.99 of it. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 135.9 W (instant 139.0, max 140.0, limit 300 W), SM 2,795 MHz mean, memory 13,801 MHz, 47 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the same rate on this card (78.72 MH/s, fingerprint matched); read ceiling 79.6 MH/s, so the hash runs at 0.99 of it. Class v4 watts (8 October 2026, the rerun, self-test PASS): 214 W at 68.94 MH/s, 0.322 MH per watt; the class v3 pack on the same host read 140.2 W at the same rate, so the shadow premium on this card is +52.6 percent of watts for no rate. two 5070 Ti memory populations exist: this board and one 7 October board read 69 MH/s, three others 78.4 to 78.8, all reporting the same 13,801 MHz memory clock, so the rate reads as a range with the host; the grid lane's own pair on a 78 MH/s board (141 W class v3, 224 W class v4, +59 percent) agrees on the watts to 10 W and gives 0.350 MH per watt there",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
|
|
@ -835,8 +835,8 @@
|
|||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "135.9 (class v3)"
|
||||
"watts_display": "214 (class v4)",
|
||||
"mh_s_display": "69 to 78 by board (68.94 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -854,13 +854,13 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4070 Ti Super (16 GB)",
|
||||
"mh_s": 41.24,
|
||||
"watts": 142.6,
|
||||
"mh_per_w": 0.289,
|
||||
"watts": 137.8,
|
||||
"mh_per_w": 0.268,
|
||||
"driver_os": "NVIDIA driver 615.71.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 2 (a rented card, result cb2-rtx-4070-ti-super-7325-result.json; 09:26Z)",
|
||||
"note": "rented single-card host, 0.10 h; power.draw mean 142.6 W (max 145.2, limit 285 W), SM 2,885 MHz mean, memory 10,251 MHz, 47 C, the SW thermal bit set with no rate effect (three runs within 0.02 percent); self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (41.37 MH/s, fingerprint matched); read ceiling 41.6 MH/s, the hash at 0.99 of it. The Ada 192-bit bus class: the same MH per watt as the 4070 Ti; the extra 4 GB buys headroom, not rate. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "142.6 (class v3)"
|
||||
"source": "model sweep 2026-10-08, row 2 (a rented card, result cb2-rtx-4070-ti-super-7325-result.json; 09:26Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-ti-super-5733-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.10 h; power.draw mean 142.6 W (max 145.2, limit 285 W), SM 2,885 MHz mean, memory 10,251 MHz, 47 C, the SW thermal bit set with no rate effect (three runs within 0.02 percent); self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (41.37 MH/s, fingerprint matched); read ceiling 41.6 MH/s, the hash at 0.99 of it. The Ada 192-bit bus class: the same MH per watt as the 4070 Ti; the extra 4 GB buys headroom, not rate. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 137.8 W at 36.93 MH/s, 0.268 MH per watt; the class v3 pack on the same host read 102.3 W at the same rate, so the shadow premium on this card is +34.7 percent of watts for no rate (the class is memory-bound). this host is a 210 W, 2,400 MHz board at 36.9 MH/s on both classes against the morning board's 41.2, so the rate reads as a range with the host noted; the premium is smaller than the 5070's because this board sits nearer its cap",
|
||||
"watts_display": "137.8 (class v4)",
|
||||
"mh_s_display": "37 to 41 by board (36.93 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -882,9 +882,9 @@
|
|||
"mh_per_w": 0.201,
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 3 (a rented card, result cb2-rtx-3080-ti-12-gb-efll-result.json; 09:28Z)",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 293.5 W (max 299.6, limit 320 W), SM 1,936 MHz mean, memory 9,251 MHz, 74 C, the SW power-cap bit set 26 W under the limit; self-test PASS (96 of 96 vector lanes); the class v5 kit runs 2.5 percent faster on this card (60.38 MH/s, fingerprint matched); read ceiling 58.9 MH/s, the hash at 1.00 of it. Matches the 7 October row (58.95 MH/s) across hosts; the worst MH per watt of the sweep and the cheapest MH per rented hour, so a buyer on a power bill prefers the 5070 Ti and a renter this card. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 293.5 W (max 299.6, limit 320 W), SM 1,936 MHz mean, memory 9,251 MHz, 74 C, the SW power-cap bit set 26 W under the limit; self-test PASS (96 of 96 vector lanes); the class v5 kit runs 2.5 percent faster on this card (60.38 MH/s, fingerprint matched); read ceiling 58.9 MH/s, the hash at 1.00 of it. Matches the 7 October row (58.95 MH/s) across hosts; the worst MH per watt of the sweep and the cheapest MH per rented hour, so a buyer on a power bill prefers the 5070 Ti and a renter this card. Class v4 pair (8 October 2026, result cb4-rtx-3080-ti-12-gb-7647-result.json, a different and deep-capped board: 220 W host cap on a 350 W card, the SM clock collapsed to 749 MHz): 42.24 MH/s mean at 216.2 W under class v4 against 44.93 MH/s at 166.2 W under class v3 on that board, the shadow premium +30.1 percent of watts and, on this cap, 5 percent of rate: the first cap that costs rate (a cap near 63 percent of stock on a 350 W GDDR6X card starves the SM clock the memory loop needs, where the 4070 Super at half its 220 W and the 3070 at 88 percent held full rate). The uncapped morning rate (58.86 MH/s) stands as this card's rate; its class v4 watts on an uncapped board are not yet measured and would read about 380 W by this pair's ratio (an estimate). The rule from the pairs so far: a power cap holds the rate until the SM clock falls below roughly 1.8 GHz on Ampere and 2.4 GHz on Ada",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "293.5 (class v3)"
|
||||
"watts_display": "293.5 (class v3, uncapped board)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -902,13 +902,12 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4080 (16 GB)",
|
||||
"mh_s": 40.71,
|
||||
"watts": 128.6,
|
||||
"mh_per_w": 0.317,
|
||||
"watts": 185.6,
|
||||
"mh_per_w": 0.219,
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 4 (a rented card, result cb2-rtx-4080-16-gb-7347-result.json; 09:28Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 128.6 W (max 130.5, limit 320 W), SM 2,776 MHz mean, memory 10,801 MHz, 38 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (40.80 MH/s, fingerprint matched); read ceiling 41.0 MH/s, the hash at 0.99 of it. One percent under the 4070 Ti Super at 14 W less: the Ada 16 GB tier is a 41 MH/s tier whichever card. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "128.6 (class v3)"
|
||||
"source": "model sweep 2026-10-08, row 4 (a rented card, result cb2-rtx-4080-16-gb-7347-result.json; 09:28Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4080-16-gb-7107-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 128.6 W (max 130.5, limit 320 W), SM 2,776 MHz mean, memory 10,801 MHz, 38 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (40.80 MH/s, fingerprint matched); read ceiling 41.0 MH/s, the hash at 0.99 of it. One percent under the 4070 Ti Super at 14 W less: the Ada 16 GB tier is a 41 MH/s tier whichever card. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 185.6 W at 40.73 MH/s, 0.219 MH per watt; the class v3 pack on the same host read 128.1 W at the same rate, so the shadow premium on this card is +44.9 percent of watts for no rate (the class is memory-bound). the same board as the morning row (offer 54551253; the v3 draw repeats to half a watt); the 256-bit board's premium sits above the 192-bit cards' third",
|
||||
"watts_display": "185.6 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -920,19 +919,18 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3070 (8 GB)",
|
||||
"mh_s": 37.09,
|
||||
"watts": 142.3,
|
||||
"mh_per_w": 0.261,
|
||||
"watts": 196.4,
|
||||
"mh_per_w": 0.189,
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 5 (a rented card, result cb2-rtx-3070-8-gb-qh9j-result.json; 09:32Z)",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 142.3 W (max 146.7, limit 225 W), SM 2,002 MHz mean, memory 6,801 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (37.14 MH/s, fingerprint matched); read ceiling 37.2 MH/s, the hash at 1.00 of it. Against the 3070 Ti: 5 percent less rate for 25 percent less power, the better owner card of the two; 8 GB holds the class v4 set with room. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 5 (a rented card, result cb2-rtx-3070-8-gb-qh9j-result.json; 09:32Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-3070-8-gb-l6mu-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 142.3 W (max 146.7, limit 225 W), SM 2,002 MHz mean, memory 6,801 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (37.14 MH/s, fingerprint matched); read ceiling 37.2 MH/s, the hash at 1.00 of it. Against the 3070 Ti: 5 percent less rate for 25 percent less power, the better owner card of the two; 8 GB holds the class v4 set with room. Class v4 watts (8 October 2026, the rerun, self-test PASS): 196.4 W at 37.11 MH/s, 0.189 MH per watt; the class v3 pack on the same host read 153.4 W at the same rate, so the shadow premium on this card is +28 percent of watts for no rate. this board is capped at 193 W by the host (stock 220) and the class v4 draw sits on the cap with the power-cap bit set while the rate holds, the same shape as the capped 4070 Super; the first Ampere pair",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "142.3 (class v3)"
|
||||
"watts_display": "196.4 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -944,19 +942,18 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3070 Ti (8 GB)",
|
||||
"mh_s": 38.98,
|
||||
"watts": 177.1,
|
||||
"mh_per_w": 0.22,
|
||||
"watts": 267.6,
|
||||
"mh_per_w": 0.146,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 6 (a rented card, result cb2-rtx-3070-ti-8-gb-8528-result.json; 09:33Z)",
|
||||
"note": "rented single-card host, 0.07 h; power.draw mean 177.1 W (max 183.6, limit 290 W), SM 1,955 MHz mean, memory 9,251 MHz, 67 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (39.12 MH/s, fingerprint matched); read ceiling 39.1 MH/s, the hash at 1.00 of it. Repeats the 7 October row on another host (38.98 then, 38.98 now; 178 then 177 W), so the class v4 number is host-independent to 0.1 percent. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 6 (a rented card, result cb2-rtx-3070-ti-8-gb-8528-result.json; 09:33Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-3070-ti-8-gb-7705-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.07 h; power.draw mean 177.1 W (max 183.6, limit 290 W), SM 1,955 MHz mean, memory 9,251 MHz, 67 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (39.12 MH/s, fingerprint matched); read ceiling 39.1 MH/s, the hash at 1.00 of it. Repeats the 7 October row on another host (38.98 then, 38.98 now; 178 then 177 W), so the class v4 number is host-independent to 0.1 percent. Class v4 watts (8 October 2026, the rerun, self-test PASS): 267.6 W at 39.1 MH/s, 0.146 MH per watt; the class v3 pack on the same host read 180.4 W at the same rate, so the shadow premium on this card is +48.3 percent of watts for no rate. the same board as the 7 October row (offer 36538839), uncapped (a 310 W AIB); the uncapped GDDR6X Ampere premium sits with the 4080's and the 5070's rather than the 192-bit Ada third, so the premium scales with the SM the board had idle under class v3",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "177.1 (class v3)"
|
||||
"watts_display": "267.6 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -968,19 +965,18 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4060 Ti (16 GB)",
|
||||
"mh_s": 20.07,
|
||||
"watts": 79.2,
|
||||
"mh_per_w": 0.253,
|
||||
"watts": 102.3,
|
||||
"mh_per_w": 0.196,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 7 (a rented card, result cb2-rtx-4060-ti-16-gb-7364-result.json; 09:33Z)",
|
||||
"note": "rented single-card host, 0.22 h; power.draw mean 79.2 W (max 86.2, limit 165 W), SM 2,836 MHz mean, memory 8,751 MHz, 63 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (20.10 MH/s, fingerprint matched). Repeats the 7 October number (20.10 then, 20.07 now); the one card of the sweep well under its probed read ceiling (0.65 of 30.9 MH/s: the 128-bit bus with the large L2 makes the chase probe optimistic), so 20 MH/s at 79 W is the card's rate; 16 GB holds any class with room. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 7 (a rented card, result cb2-rtx-4060-ti-16-gb-7364-result.json; 09:33Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4060-ti-16-gb-6679-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.22 h; power.draw mean 79.2 W (max 86.2, limit 165 W), SM 2,836 MHz mean, memory 8,751 MHz, 63 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (20.10 MH/s, fingerprint matched). Repeats the 7 October number (20.10 then, 20.07 now); the one card of the sweep well under its probed read ceiling (0.65 of 30.9 MH/s: the 128-bit bus with the large L2 makes the chase probe optimistic), so 20 MH/s at 79 W is the card's rate; 16 GB holds any class with room. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 102.3 W at 20.1 MH/s, 0.196 MH per watt; the class v3 pack on the same host read 76.6 W at the same rate, so the shadow premium on this card is +33.6 percent of watts for no rate (the class is memory-bound). the same board as the 7 October row (offer 47543124); the rate is the same on every 4060 Ti host and both classes (20.07 to 20.10)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "79.2 (class v3)"
|
||||
"watts_display": "102.3 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -992,19 +988,19 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 5070 (12 GB)",
|
||||
"mh_s": 51.81,
|
||||
"watts": 110.8,
|
||||
"mh_per_w": 0.468,
|
||||
"watts": 176.1,
|
||||
"mh_per_w": 0.334,
|
||||
"driver_os": "NVIDIA driver 580.173.02, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 8 (a rented card, result cb2-rtx-5070-12-gb-8750-result.json; 09:35Z)",
|
||||
"note": "rented single-card host, 0.09 h; power.draw mean 110.8 W (max 112.0, limit 250 W), SM 2,851 MHz mean, memory 13,801 MHz, 60 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (51.98 MH/s, fingerprint matched); read ceiling 52.3 MH/s, the hash at 0.99 of it. Repeats the 7 October row (52.01 then, 51.82 now) at 8 W more on this host; second to the 5070 Ti in MH per watt among consumer cards (GDDR7 lifts Blackwell here, not SM count); 12 GB holds the class v4 set with 10 GB spare. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 8 (a rented card, result cb2-rtx-5070-12-gb-8750-result.json; 09:35Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-5070-12-gb-5732-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.09 h; power.draw mean 110.8 W (max 112.0, limit 250 W), SM 2,851 MHz mean, memory 13,801 MHz, 60 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (51.98 MH/s, fingerprint matched); read ceiling 52.3 MH/s, the hash at 0.99 of it. Repeats the 7 October row (52.01 then, 51.82 now) at 8 W more on this host; second to the 5070 Ti in MH per watt among consumer cards (GDDR7 lifts Blackwell here, not SM count); 12 GB holds the class v4 set with 10 GB spare. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 176.1 W at 58.89 MH/s, 0.334 MH per watt; the class v3 pack on the same host read 113.1 W at the same rate, so the shadow premium on this card is +55.7 percent of watts for no rate (the class is memory-bound). board-to-board spread: this host 58.9 MH/s on both classes, the morning host 51.8 (GDDR7 memory clocks differ by board), so the rate reads as a range with the host noted",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "110.8 (class v3)"
|
||||
"watts_display": "176.1 (class v4)",
|
||||
"mh_s_display": "52 to 59 by board (58.89 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1016,19 +1012,18 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4070 Super (12 GB)",
|
||||
"mh_s": 31.24,
|
||||
"watts": 100.2,
|
||||
"mh_per_w": 0.312,
|
||||
"watts": 108.4,
|
||||
"mh_per_w": 0.288,
|
||||
"driver_os": "NVIDIA driver 580.178.04, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 9 (a rented card, result cb2-rtx-4070-super-12--8582-result.json; 09:36Z)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 100.2 W (max 103.9) under a 110 W host cap (stock 220 W), SM 2,764 MHz mean, memory 10,251 MHz, 53 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.29 MH/s, fingerprint matched); read ceiling 34.4 MH/s, the hash at 0.91 of it. Lands on the 4070 Ti's number (31.26 on 7 October) at 7 W less (the same 192-bit 21 Gbps bus); the host's 110 W cap cost no rate, a tune-down reading in itself: an owner can cap a 4070 Super at half its stock power and lose nothing on class v4. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 9 (a rented card, result cb2-rtx-4070-super-12--8582-result.json; 09:36Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-super-12--6238-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 100.2 W (max 103.9) under a 110 W host cap (stock 220 W), SM 2,764 MHz mean, memory 10,251 MHz, 53 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.29 MH/s, fingerprint matched); read ceiling 34.4 MH/s, the hash at 0.91 of it. Lands on the 4070 Ti's number (31.26 on 7 October) at 7 W less (the same 192-bit 21 Gbps bus); the host's 110 W cap cost no rate, a tune-down reading in itself: an owner can cap a 4070 Super at half its stock power and lose nothing on class v4. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 108.4 W at 31.25 MH/s, 0.288 MH per watt; the class v3 pack on the same host read 99.2 W at the same rate, so the shadow premium on this card is +9.3 percent of watts for no rate (the class is memory-bound). the same board as the morning row (host offer 51485188), capped at 110 W by the host (stock 220) with the SW power-cap bit set the whole run: the cap absorbs the class v4 stage's extra draw (the SM clock drops 10 percent, the rate does not move), so the premium is 9 percent here against a third on uncapped Ada boards; a power cap near half stock costs a 192-bit Ada card nothing on class v4",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "100.2 (class v3)"
|
||||
"watts_display": "108.4 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1040,19 +1035,19 @@
|
|||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3060 Ti (8 GB)",
|
||||
"mh_s": 31.7,
|
||||
"watts": 100.4,
|
||||
"mh_per_w": 0.316,
|
||||
"watts": 128.7,
|
||||
"mh_per_w": 0.256,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 10 (a rented card, result cb2-rtx-3060-ti-8-gb-8771-result.json; 09:37Z)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 100.4 W (max 104.7, limit 180 W), SM 1,560 MHz mean, memory 5,001 MHz on this host (below the 7,000 MHz GDDR6 stock), 61 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.75 MH/s, fingerprint matched); read ceiling 31.8 MH/s, the hash at 1.00 of it. Four percent under the 7 October 3060 Ti row (33.1 on another host), consistent with this host's lower memory clock; the best MH per watt of the Ampere cards. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 10 (a rented card, result cb2-rtx-3060-ti-8-gb-8771-result.json; 09:37Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-3060-ti-8-gb-8620-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 100.4 W (max 104.7, limit 180 W), SM 1,560 MHz mean, memory 5,001 MHz on this host (below the 7,000 MHz GDDR6 stock), 61 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.75 MH/s, fingerprint matched); read ceiling 31.8 MH/s, the hash at 1.00 of it. Four percent under the 7 October 3060 Ti row (33.1 on another host), consistent with this host's lower memory clock; the best MH per watt of the Ampere cards. Class v4 watts (8 October 2026, the rerun, self-test PASS): 128.7 W at 32.92 MH/s, 0.256 MH per watt; the class v3 pack on the same host read 129.9 W at the same rate, so the shadow premium on this card is -0.9 percent of watts for no rate. the cleanest cap reading of the set: this board is capped at 130 W by the host (stock 200) and both classes sit on the cap, the SM giving a quarter of its clock (1,722 to 1,297 MHz) while the rate holds, so a 3060 Ti at 65 percent of stock runs class v4 at full rate with no premium; the rate on this board (33.1) matches the 7 October host and sits 4 percent over the morning's slow-memory board, so the rate reads as a range",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "100.4 (class v3)"
|
||||
"watts_display": "128.7 (class v4)",
|
||||
"mh_s_display": "32 to 33 by board (33.06 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1064,19 +1059,19 @@
|
|||
"card": "NVIDIA RTX 2080 Ti (11 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 26.01,
|
||||
"watts": 224.6,
|
||||
"mh_per_w": 0.116,
|
||||
"watts": 161.1,
|
||||
"mh_per_w": 0.174,
|
||||
"driver_os": "NVIDIA driver 580.159.03, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 11 (a rented card, result cb2-rtx-2080-ti-9077-result.json; 09:40Z)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 224.6 W (max 234.7, limit 300 W; the driver reports no power average on Turing), SM 1,914 MHz mean, memory 6,802 MHz, 72 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (26.04 MH/s, fingerprint matched); read ceiling 29.9 MH/s, the hash at 0.87 of it. The first Turing row: the 7 October 2080 Ti pod that left no result was a host fault, not the card. The worst MH per watt measured on any card (the Titan RTX, the same silicon, read 28.3 MH/s at 226 W on 7 October): an owner mines at a loss on any real power price; 11 GB holds the set. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 11 (a rented card, result cb2-rtx-2080-ti-9077-result.json; 09:40Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-2080-ti-0387-result.json, a different board: 22 GB modded, the core held at 1,095 MHz, a 170 W cap; the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 224.6 W (max 234.7, limit 300 W; the driver reports no power average on Turing), SM 1,914 MHz mean, memory 6,802 MHz, 72 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (26.04 MH/s, fingerprint matched); read ceiling 29.9 MH/s, the hash at 0.87 of it. The first Turing row: the 7 October 2080 Ti pod that left no result was a host fault, not the card. The worst MH per watt measured on any card (the Titan RTX, the same silicon, read 28.3 MH/s at 226 W on 7 October): an owner mines at a loss on any real power price; 11 GB holds the set. Class v4 watts (8 October 2026, the rerun, self-test PASS) on a tuned board (22 GB memory mod, the core held at 1,095 MHz by the host, a 170 W cap): 161.1 W at 28.05 MH/s, 0.174 MH per watt, the class v3 pack on the same host 139.2 W at 28.04, a premium of +15.7 percent for no rate; this tuned board runs 8 percent over the morning's stock 11 GB board (26.0 MH/s at 1,914 MHz and 224.6 W class v3), so the 2080 Ti's rate is set by its memory and a core lock near 1.1 GHz with a 170 W cap is the way to run one; the morning's stock board under class v4 would read about 0.09 MH per watt by the 2070 Super's premium (an inference)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "224.6 (class v3)"
|
||||
"watts_display": "161.1 (class v4, a tuned board)",
|
||||
"mh_s_display": "26 to 28 by board (28.05 tuned on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1088,19 +1083,18 @@
|
|||
"card": "NVIDIA RTX 2070 Super (8 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 19.09,
|
||||
"watts": 166,
|
||||
"mh_per_w": 0.115,
|
||||
"watts": 204.2,
|
||||
"mh_per_w": 0.094,
|
||||
"driver_os": "NVIDIA driver 575.57.08, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 12 (a rented card, result cb2-rtx-2070-super-8-g-9129-result.json; 09:41Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 166.0 W (max 167.8, limit 215 W; no power average on Turing), SM 1,955 MHz mean, memory 6,802 MHz, 64 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.12 MH/s, fingerprint matched); read ceiling 30.1 MH/s, the hash at 0.63 of it: Turing does not overlap the independent reads the hash needs (its indep probe 2.45 G loads/s binds). The Turing per-watt floor: a 4060's rate at twice the power. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 12 (a rented card, result cb2-rtx-2070-super-8-g-9129-result.json; 09:41Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-2070-super-8-g-9125-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 166.0 W (max 167.8, limit 215 W; no power average on Turing), SM 1,955 MHz mean, memory 6,802 MHz, 64 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.12 MH/s, fingerprint matched); read ceiling 30.1 MH/s, the hash at 0.63 of it: Turing does not overlap the independent reads the hash needs (its indep probe 2.45 G loads/s binds). The Turing per-watt floor: a 4060's rate at twice the power. Class v4 watts (8 October 2026, the rerun, self-test PASS): 204.2 W at 19.1 MH/s, 0.094 MH per watt; the class v3 pack on the same host read 165.9 W at the same rate, so the shadow premium on this card is +23.1 percent of watts for no rate. the same board as the morning row; the first Turing pair, the smallest premium of the uncapped boards because Turing's SMs were busy under class v3 already (0.63 of its read ceiling); a 2060-class rate at a 3080-class draw: an owner mines at a loss on any real power price",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "166 (class v3)"
|
||||
"watts_display": "204.2 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1112,19 +1106,18 @@
|
|||
"card": "NVIDIA A100 SXM4 (80 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 138.1,
|
||||
"watts": 268.6,
|
||||
"mh_per_w": 0.515,
|
||||
"watts": 489.3,
|
||||
"mh_per_w": 0.282,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 13 (a rented card, result cb2-a100-80-gb-j79g-result.json; 09:43Z)",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 268.6 W (max 274.1, limit 400 W; no power average on this host), SM 1,410 MHz, HBM2e 1,593 MHz, 44 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 136.48 MH/s, 1.3 percent under class v4 (fingerprint matched), the first card where v5 is not level with v4; read ceiling 138.6 MH/s, the hash at 1.00 of it. Repeats the three 7 October readings (138.39, 138.74, 138.76) to 0.3 percent on a fourth host; datacentre-class per watt, a third of a 3080 Ti's MH per rented dollar. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 13 (a rented card, result cb2-a100-80-gb-j79g-result.json; 09:43Z); the class v4 watts rerun, 8 October 2026 (result cb4-a100-80-gb-mdfz-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 268.6 W (max 274.1, limit 400 W; no power average on this host), SM 1,410 MHz, HBM2e 1,593 MHz, 44 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 136.48 MH/s, 1.3 percent under class v4 (fingerprint matched), the first card where v5 is not level with v4; read ceiling 138.6 MH/s, the hash at 1.00 of it. Repeats the three 7 October readings (138.39, 138.74, 138.76) to 0.3 percent on a fourth host; datacentre-class per watt, a third of a 3080 Ti's MH per rented dollar. Class v4 watts (8 October 2026, the rerun, self-test PASS): 489.3 W at 138 MH/s, 0.282 MH per watt; the class v3 pack on the same host read 274.3 W at the same rate, so the shadow premium on this card is +78.4 percent of watts for no rate. the 500 W SKU (the morning's board was the 400 W SKU; the class v3 draw holds across both); the largest premium of the pairs so far: the 108 SMs sit nearly idle under class v3 and the shadow stage puts them all to work, the card touching its 500 W cap without losing rate; under the live class the A100 falls from datacentre-class per watt to the capped 4070 Super's level; on the 400 W SKU the cap would bind and the rate should hold by the Ampere rule (an inference until a 400 W board is paired)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "268.6 (class v3)"
|
||||
"watts_display": "489.3 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1136,19 +1129,18 @@
|
|||
"card": "NVIDIA H100 SXM (80 GB HBM3)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 248.3,
|
||||
"watts": 411.7,
|
||||
"mh_per_w": 0.605,
|
||||
"watts": 695.1,
|
||||
"mh_per_w": 0.36,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 14 (a rented card, result cb2-h100-80-gb-rs3d-result.json; 09:43Z)",
|
||||
"note": "rented single-card host, 0.03 h; power.draw mean 411.7 W (instant 434.1, the largest gap between the two fields in the sweep, 22 W; max 437.1, limit 700 W), SM 1,980 MHz, HBM3 2,619 MHz, 36 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 252.64 MH/s, 1.5 percent over class v4 (fingerprint matched); read ceiling 252.4 MH/s, the hash at 0.99 of it. Repeats the 7 October rows (248.70, 248.21) on a third host; the best per-watt figure of the sweep on power.draw (0.573 on the instant field) and the worst MH per rented dollar: an owner's card on cheap power, never a renter's. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 14 (a rented card, result cb2-h100-80-gb-rs3d-result.json; 09:43Z); the class v4 watts rerun, 8 October 2026 (result cb4-h100-80-gb-sbwo-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.03 h; power.draw mean 411.7 W (instant 434.1, the largest gap between the two fields in the sweep, 22 W; max 437.1, limit 700 W), SM 1,980 MHz, HBM3 2,619 MHz, 36 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 252.64 MH/s, 1.5 percent over class v4 (fingerprint matched); read ceiling 252.4 MH/s, the hash at 0.99 of it. Repeats the 7 October rows (248.70, 248.21) on a third host; the best per-watt figure of the sweep on power.draw (0.573 on the instant field) and the worst MH per rented dollar: an owner's card on cheap power, never a renter's. Class v4 watts (8 October 2026, the rerun, self-test PASS): 695.1 W at 250.02 MH/s, 0.36 MH per watt; the class v3 pack on the same host read 456.9 W at the same rate, so the shadow premium on this card is +52.1 percent of watts for no rate. this board draws 45 W more than the morning's under class v3 at 1 percent more rate; under class v4 the H100 sits on its 700 W cap (SM 1,774 MHz, down from 1,980) and holds the rate; still the worst MH per rented dollar",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "411.7 (class v3)"
|
||||
"watts_display": "695.1 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1160,19 +1152,18 @@
|
|||
"card": "NVIDIA RTX A4000 (16 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 31.41,
|
||||
"watts": 112.8,
|
||||
"mh_per_w": 0.279,
|
||||
"watts": 135.2,
|
||||
"mh_per_w": 0.232,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 15 (a rented card, result cb2-rtx-a4000-16-gb-9473-result.json; 09:45Z)",
|
||||
"note": "rented single-card host, 0.16 h; power.draw mean 112.8 W on a host that caps the card at 114 W (stock 140 W; the SW power-cap bit set the whole run), SM 1,562 MHz mean, memory 6,501 MHz, 81 C; self-test PASS (96 of 96 vector lanes); read ceiling 31.6 MH/s, the hash at 0.99 of it. Class v4 repeats the 7 October row (31.45 then, 31.41 now) under the cap. The class v5 kit's reading on this capped host is held off the page until an uncapped A4000 confirms it. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 15 (a rented card, result cb2-rtx-a4000-16-gb-9473-result.json; 09:45Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-a4000-16-gb-0549-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.16 h; power.draw mean 112.8 W on a host that caps the card at 114 W (stock 140 W; the SW power-cap bit set the whole run), SM 1,562 MHz mean, memory 6,501 MHz, 81 C; self-test PASS (96 of 96 vector lanes); read ceiling 31.6 MH/s, the hash at 0.99 of it. Class v4 repeats the 7 October row (31.45 then, 31.41 now) under the cap. The class v5 kit's reading on this capped host is held off the page until an uncapped A4000 confirms it. Class v4 watts (8 October 2026, the rerun, self-test PASS): 135.2 W at 31.36 MH/s, 0.232 MH per watt; the class v3 pack on the same host read 136.1 W at the same rate, so the shadow premium on this card is -0.7 percent of watts for no rate. a different board from the morning's 114 W-capped one, at its 140 W stock limit and hot (96 C, the thermal bit set under both classes): the A4000 is a capped card already under class v3 on every host, so under class v4 it draws the same 135 to 140 W and holds the full rate with the SM giving a quarter of its clock; the morning's class v5 reading on the 114 W board follows from the same cap. The best renter's card under the live class after the capped 3060 Ti",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "112.8 (class v3)"
|
||||
"watts_display": "135.2 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1184,19 +1175,18 @@
|
|||
"card": "NVIDIA RTX A6000 (48 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 53.64,
|
||||
"watts": 239.1,
|
||||
"mh_per_w": 0.224,
|
||||
"watts": 295,
|
||||
"mh_per_w": 0.182,
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 16 (a rented card, result cb2-rtx-a6000-48-gb-9600-result.json; 09:46Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 239.1 W (max 251.0, limit 300 W), SM 1,913 MHz mean, memory 7,601 MHz, 65 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (53.82 MH/s, fingerprint matched), so on an uncapped sm_86 card v5 is level with v4 and the A4000's v5 reading narrows to its power cap; read ceiling 53.8 MH/s, the hash at 1.00 of it. Repeats the 7 October row (53.66 then, 53.64 now) at 43 W less on this host; a 3090-class rate at a 3090-class draw. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 16 (a rented card, result cb2-rtx-a6000-48-gb-9600-result.json; 09:46Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-a6000-48-gb-1814-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 239.1 W (max 251.0, limit 300 W), SM 1,913 MHz mean, memory 7,601 MHz, 65 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (53.82 MH/s, fingerprint matched), so on an uncapped sm_86 card v5 is level with v4 and the A4000's v5 reading narrows to its power cap; read ceiling 53.8 MH/s, the hash at 1.00 of it. Repeats the 7 October row (53.66 then, 53.64 now) at 43 W less on this host; a 3090-class rate at a 3090-class draw. Class v4 watts (8 October 2026, the rerun, self-test PASS): 295.0 W at 53.67 MH/s, 0.182 MH per watt; the class v3 pack on the same host read 253.9 W at the same rate (the board 9 C warmer than the morning, 15 W over its morning class v3 reading), so the shadow premium on this card is +16.2 percent of watts for no rate: the A6000 lands on its stock 300 W cap under class v4 and holds the rate, the fourth card to do so with the H100, the A100 and the A4000, so a stock cap reached under class v4 is a note, not a penalty. The rerun is complete: 22 class v4 watts rows on 22 models, every pod destroyed",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "239.1 (class v3)"
|
||||
"watts_display": "295 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1208,19 +1198,18 @@
|
|||
"card": "NVIDIA GTX 1080 Ti (11 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 16.26,
|
||||
"watts": 124.3,
|
||||
"mh_per_w": 0.131,
|
||||
"watts": 202.7,
|
||||
"mh_per_w": 0.08,
|
||||
"driver_os": "NVIDIA driver 580.173.02, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, rows 17 and 22 (two rented hosts, results cb2-gtx-1080-ti-11-gb-0377-result.json and cb2-gtx-1080-ti-11-gb-1452-result.json; 09:49Z and 10:02Z)",
|
||||
"note": "the mean of the first host's two clean runs (16.26 MH/s at 124.3 W, the card uncapped at a 280 W limit); a second host read 16.29 MH/s at 129.4 W under a 130 W host cap with five of five self-tests passing, so the first host's one-in-three cache self-test failure was that host's VRAM and not Pascal, and the flag is cleared. Power.draw on the first host max 125.5 W (no power average on Pascal), SM 1,936 MHz mean, memory 5,005 MHz, 59 C; the class v5 kit held the rate on the uncapped host (16.27 MH/s) and read 13.27 MH/s on the 130 W-capped one (fingerprint matched on both); read ceiling 16.3 MH/s, the hash at 1.00 of it. The first Pascal row: a 2017 card that runs the class at its own ceiling. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, rows 17 and 22 (two rented hosts, results cb2-gtx-1080-ti-11-gb-0377-result.json and cb2-gtx-1080-ti-11-gb-1452-result.json; 09:49Z and 10:02Z); the class v4 watts rerun, 8 October 2026 (result cb4-gtx-1080-ti-11-gb-9935-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "the mean of the first host's two clean runs (16.26 MH/s at 124.3 W, the card uncapped at a 280 W limit); a second host read 16.29 MH/s at 129.4 W under a 130 W host cap with five of five self-tests passing, so the first host's one-in-three cache self-test failure was that host's VRAM and not Pascal, and the flag is cleared. Power.draw on the first host max 125.5 W (no power average on Pascal), SM 1,936 MHz mean, memory 5,005 MHz, 59 C; the class v5 kit held the rate on the uncapped host (16.27 MH/s) and read 13.27 MH/s on the 130 W-capped one (fingerprint matched on both); read ceiling 16.3 MH/s, the hash at 1.00 of it. The first Pascal row: a 2017 card that runs the class at its own ceiling. Class v4 watts (8 October 2026, the rerun, self-test PASS): 202.7 W at 16.29 MH/s, 0.08 MH per watt; the class v3 pack on the same host read 124.5 W at the same rate, so the shadow premium on this card is +62.8 percent of watts for no rate. an uncapped 280 W board (five of five self-tests PASS, so the first host's cache fault stays that host's); the largest premium of the pairs, pure added work (the SM clock did not move between classes): Pascal has no fast integer path for the shadow stage and ran class v3 at half its power limit; the worst MH per watt of every card measured, a 2017 card that cannot pay its own power on any tariff",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card; Pascal has no clock lock; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "124.3 (class v3)"
|
||||
"watts_display": "202.7 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1235,15 +1224,14 @@
|
|||
"watts": null,
|
||||
"mh_per_w": null,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 18 (a rented card, result cb2-rtx-4060-8-gb-0672-result.json; 09:53Z)",
|
||||
"note": "watts not read: this host exposes no power sensor (every power field absent on all 244 samples, as the 7 October 4060 host); a third host is being rented for the watts, and the card's draw is about 60 to 70 W by its 115 W limit and the 4060 Ti's 79 W, an estimate until then. Rented single-card host, 0.12 h; SM 2,732 MHz mean, memory 8,251 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.11 MH/s, fingerprint matched); read ceiling 30.2 MH/s, the hash at 0.63 of it (the 128-bit bus: the independent-read line binds, as on the 2070 Super). Repeats the 7 October row (19.09 then, 19.10 now). Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 18 (a rented card, result cb2-rtx-4060-8-gb-0672-result.json; 09:53Z); the class v4 rerun, 8 October 2026 (result cb4-rtx-4060-8-gb-7165-result.json: the rate on both classes, no watts)",
|
||||
"note": "watts not reported by any rented host (four 4060 boards across 7 and 8 October, one machine family, every power field absent; two other hosts never answered ssh); the class v4 rerun on 8 October read the same rate on both classes (19.09 MH/s class v4, 19.094 class v3) and still no watts; by the 4060 Ti pair on the same silicon (+33.6 percent) the class v4 draw is about 80 to 90 W from a class v3 draw of about 60 to 70 W under the 115 W limit, an estimate until an owner measures at the wall.12 h; SM 2,732 MHz mean, memory 8,251 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.11 MH/s, fingerprint matched); read ceiling 30.2 MH/s, the hash at 0.63 of it (the 128-bit bus: the independent-read line binds, as on the 2070 Super). Repeats the 7 October row (19.09 then, 19.10 now)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1255,19 +1243,19 @@
|
|||
"card": "NVIDIA RTX 2060 (6 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 14.13,
|
||||
"watts": 120.6,
|
||||
"watts": 127,
|
||||
"mh_per_w": 0.117,
|
||||
"driver_os": "NVIDIA driver 580.159.03, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 19 (a rented card, result cb2-rtx-2060-0673-result.json; 09:55Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 120.6 W (max 124.6, limit 160 W; no power average on Turing), SM 1,948 MHz mean, memory 6,801 MHz, 69 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (14.14 MH/s, fingerprint matched); read ceiling 16.1 MH/s, the hash at 0.88 of it. The floor of the list and the smallest card on it: the class v4 set fits with 4.6 GB spare; the same Turing per-watt floor as the 2070 Super and the 2080 Ti, so every Turing card earns the same per watt and only the absolute rate differs. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 19 (a rented card, result cb2-rtx-2060-0673-result.json; 09:55Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-2060-0819-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 120.6 W (max 124.6, limit 160 W; no power average on Turing), SM 1,948 MHz mean, memory 6,801 MHz, 69 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (14.14 MH/s, fingerprint matched); read ceiling 16.1 MH/s, the hash at 0.88 of it. The floor of the list and the smallest card on it: the class v4 set fits with 4.6 GB spare; the same Turing per-watt floor as the 2070 Super and the 2080 Ti, so every Turing card earns the same per watt and only the absolute rate differs. Class v4 watts (8 October 2026, the rerun, self-test PASS): 127 W at 14.9 MH/s, 0.117 MH per watt; the class v3 pack on the same host read 124.9 W at the same rate, so the shadow premium on this card is +1.7 percent of watts for no rate. the 12 GB variant on a 130 W host cap (stock 185), 5 percent over the morning's 6 GB board (its memory runs faster), so the rate reads as a range; the cap absorbs the premium with the SM giving 7 percent of its clock; the Turing floor under class v4 is 0.09 to 0.12 MH per watt: every Turing card mines at a loss on a real tariff",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "120.6 (class v3)"
|
||||
"watts_display": "127 (class v4)",
|
||||
"mh_s_display": "14 to 15 by board (14.90 on this 12 GB board)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1279,19 +1267,18 @@
|
|||
"card": "NVIDIA RTX 4070 Ti (12 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 31.24,
|
||||
"watts": 95.4,
|
||||
"mh_per_w": 0.327,
|
||||
"watts": 155.3,
|
||||
"mh_per_w": 0.201,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 20 (a rented card, result cb2-rtx-4070-ti-12-gb-0695-result.json; 09:57Z)",
|
||||
"note": "rented single-card host, 0.18 h; power.draw mean 95.4 W (max 96.7, limit 285 W), SM 2,825 MHz mean, memory 10,251 MHz, 49 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.28 MH/s, fingerprint matched); read ceiling 31.7 MH/s, the hash at 0.99 of it. Repeats the 7 October rate to 0.07 percent on another provider at 12 W less; the 192-bit Ada pair (4070 Ti, 4070 Super) land on one number, 31.2 MH/s under 100 W. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 20 (a rented card, result cb2-rtx-4070-ti-12-gb-0695-result.json; 09:57Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-ti-12-gb-5744-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.18 h; power.draw mean 95.4 W (max 96.7, limit 285 W), SM 2,825 MHz mean, memory 10,251 MHz, 49 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.28 MH/s, fingerprint matched); read ceiling 31.7 MH/s, the hash at 0.99 of it. Repeats the 7 October rate to 0.07 percent on another provider at 12 W less; the 192-bit Ada pair (4070 Ti, 4070 Super) land on one number, 31.2 MH/s under 100 W. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 155.3 W at 31.26 MH/s, 0.201 MH per watt; the class v3 pack on the same host read 113.8 W at the same rate, so the shadow premium on this card is +36.5 percent of watts for no rate (the class is memory-bound). the rate matches the morning and 7 October rows on a third host (no host spread on this card); driver 570.169 ran the class v4 pack clean",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "95.4 (class v3)"
|
||||
"watts_display": "155.3 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1303,19 +1290,18 @@
|
|||
"card": "NVIDIA L40S (48 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 56.41,
|
||||
"watts": 220.7,
|
||||
"mh_per_w": 0.256,
|
||||
"watts": 277.6,
|
||||
"mh_per_w": 0.203,
|
||||
"driver_os": "NVIDIA driver 570.133.20, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 21 (a rented card, result cb2-l40s-48-gb-0890-result.json; 09:57Z)",
|
||||
"note": "rented single-card host, 0.17 h; power.draw mean 220.7 W (max 227.2, limit 350 W), SM 2,520 MHz, memory 9,001 MHz, 45 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (56.51 MH/s, fingerprint matched); read ceiling 57.8 MH/s, the hash at 0.98 of it. Repeats the 7 October row (56.36 then, 56.41 now) at 20 W less on this host; a 384-bit GDDR6 card that lands where the 3090 Ti and the A6000 do at a datacentre price. Driver 570.133, the oldest of the sweep, ran the CUDA 12.8 worker clean: 570 is a safe floor. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 21 (a rented card, result cb2-l40s-48-gb-0890-result.json; 09:57Z); the class v4 watts rerun, 8 October 2026 (result cb4-l40s-48-gb-1574-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.17 h; power.draw mean 220.7 W (max 227.2, limit 350 W), SM 2,520 MHz, memory 9,001 MHz, 45 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (56.51 MH/s, fingerprint matched); read ceiling 57.8 MH/s, the hash at 0.98 of it. Repeats the 7 October row (56.36 then, 56.41 now) at 20 W less on this host; a 384-bit GDDR6 card that lands where the 3090 Ti and the A6000 do at a datacentre price. Driver 570.133, the oldest of the sweep, ran the CUDA 12.8 worker clean: 570 is a safe floor. Class v4 watts (8 October 2026, the rerun, self-test PASS): 277.6 W at 56.4 MH/s, 0.203 MH per watt; the class v3 pack on the same host read 219.3 W at the same rate, so the shadow premium on this card is +26.6 percent of watts for no rate. a sibling board of the morning's host, uncapped; the smallest premium of the uncapped Ada boards, the 142 SMs running the shadow stage inside their idle margin without moving the clock; level with the 4070 Ti and the capped 3080 Ti per watt, at a datacentre price",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "220.7 (class v3)"
|
||||
"watts_display": "277.6 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
|
|
@ -1327,19 +1313,18 @@
|
|||
"card": "NVIDIA RTX 4080 Super (16 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 42.6,
|
||||
"watts": 134.9,
|
||||
"mh_per_w": 0.316,
|
||||
"watts": 195.7,
|
||||
"mh_per_w": 0.218,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 23 (a rented card, result cb2-rtx-4080-super-16-g-2453-result.json; 10:03Z)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 134.9 W (max 138.4, limit 320 W), SM 2,740 MHz mean, memory 11,254 MHz, 51 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (42.68 MH/s, fingerprint matched); read ceiling 43.1 MH/s, the hash at 0.99 of it. The 23 Gbps GDDR6X gives it 4.6 percent over the 4080 for 6 W more at the same MH per watt: the Ada 256-bit tier is 41 to 43 MH/s whichever card. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"source": "model sweep 2026-10-08, row 23 (a rented card, result cb2-rtx-4080-super-16-g-2453-result.json; 10:03Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4080-super-16-g-8479-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 134.9 W (max 138.4, limit 320 W), SM 2,740 MHz mean, memory 11,254 MHz, 51 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (42.68 MH/s, fingerprint matched); read ceiling 43.1 MH/s, the hash at 0.99 of it. The 23 Gbps GDDR6X gives it 4.6 percent over the 4080 for 6 W more at the same MH per watt: the Ada 256-bit tier is 41 to 43 MH/s whichever card. Class v4 watts (8 October 2026, the rerun, self-test PASS): 195.7 W at 42.63 MH/s, 0.218 MH per watt; the class v3 pack on the same host read 139.8 W at the same rate, so the shadow premium on this card is +40.0 percent of watts for no rate. a sibling board of the morning's host; the rate and the v3 draw repeat the morning; the Ada 256-bit tier reads 0.22 MH per watt under class v4 whichever card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "134.9 (class v3)"
|
||||
"watts_display": "195.7 (class v4)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -100,8 +101,6 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -112,18 +111,30 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -135,8 +146,6 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -145,15 +154,25 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -270,9 +289,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="platform-body" id="panel-hive" role="tabpanel" aria-labelledby="tab-hive" data-platform-panel="hive" hidden>
|
||||
<div class="download-platform"><span class="osmark" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span><div><h3>Ember for Linux and HiveOS</h3><p>a tarball for rigs and Hive flight sheets</p></div></div>
|
||||
<p class="download-note">For the rig people. One tarball, the miner and the node inside, the same signed manifest as the desktop apps.</p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 16v4h14v-4"/></svg>Download the tarball <span data-dl-meta="miner-hive" style="font-weight:400;opacity:.85">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet" id="hive"><b>HiveOS Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.23.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<p class="sha">sha256 <span data-dl-sha="miner-hive">0d716ed92560b6b2eccb63ca1bd7a4d9eb64c9b334e8370e1263f0344cee294e</span></p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 16v4h14v-4"/></svg>Download the tarball <span data-dl-meta="miner-hive" style="font-weight:400;opacity:.85">v0.3.22 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet" id="hive"><b>HiveOS Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.22.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<p class="sha">sha256 <span data-dl-sha="miner-hive">8ad6dcef9edc57dcd33e8d5a97cbef5cdda0e384a6e56d3f62f8903029c4c764</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -455,7 +474,7 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -470,6 +489,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
363
site/oracle.html
Normal file
363
site/oracle.html
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum state oracle on Sepolia</title>
|
||||
<meta name="description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/oracle">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum state oracle on Sepolia">
|
||||
<meta property="og:description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/oracle">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum state oracle on Sepolia">
|
||||
<meta name="twitter:description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle" aria-current="page"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle" aria-current="page"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>State oracle on Sepolia</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 3 · Devnet 3, no value</div>
|
||||
<h1>Devnet 3 balances, read from Sepolia<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">A contract on Ethereum Sepolia stores Igneum Devnet 3 finality certificates that anyone submits, checked by a shared certificate verifier, and state roots bound to those checkpoints through the header chain, the coinbase and the segment record. Other contracts then read a proven Devnet 3 balance or storage slot with an ordinary Merkle Patricia proof. No relayer is trusted: a wrong certificate or a wrong proof reverts.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> Another chain can only use Igneum state if a contract can check it without running an Igneum node: a weighted certificate over a checkpoint and a state root proven under it are small enough to verify in a few hundred thousand gas. A chain whose state is only "what most nodes say" has nothing a contract can check.</p>
|
||||
<p>Source: <code>tools/reference-apps/oracle/contracts/</code> (IgneumStateOracle.sol and its libraries), <code>tools/reference-apps/oracle/demo.mjs</code> (the demo that reads a Devnet 3 balance from Sepolia), <code>tools/reference-apps/oracle/test.mjs</code> (the negative cases through eth_call). The shared certificate verifier is the DEX lane's <code>contracts/bridge/src/IgneumCertificateVerifier.sol</code>.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="deployed">
|
||||
<h2 id="deployed">On Sepolia</h2>
|
||||
<div class="kv" data-oracle-kv>
|
||||
<div class="k">Oracle</div><div class="mono" data-oracle-address>0xefe9879de29c401eeff195d5bf71c86b9caaa1b2 <small>IgneumStateOracle, deployed 8 October 2026 (tx 0xb8650f5b…d644, block 11869608)</small></div>
|
||||
<div class="k">Verifier</div><div class="mono" data-verifier-address>0xa197ef31d5d5613125779179668e2482ac69a6f6 <small>StubCertificateVerifier, the stand-in: it records any well-formed certificate and does not check the BLS signature; the shared IgneumCertificateVerifier replaces it through setVerifier the day it lands</small></div>
|
||||
<div class="k">Chain</div><div>Sepolia, chain id 11155111; Devnet 3 (igneum-devnet-3), no value</div>
|
||||
<div class="k">First proven root</div><div class="mono">Devnet 3 chain block 26631, post_root 0xf567a84f…a82fd, stored 8 October 2026 (tx 0xf360e54c…224b, 404,376 gas); provenBalance read 92.029323 IGN for 0x636de2dc…44ea on Sepolia, equal to the Devnet 3 node's eth_getProof</div>
|
||||
</div>
|
||||
<p class="note">How to read a balance from another contract: <code>IIgneumStateOracle(oracle).provenBalance(number, account, accountProof)</code>, where <code>number</code> is a Devnet 3 chain block whose state root the oracle holds and <code>accountProof</code> is the <code>eth_getProof</code> account proof at that block. A storage slot: <code>provenStorage(number, account, slot, accountProof, storageProof)</code>. Both revert on any mismatch.</p>
|
||||
</section>
|
||||
|
||||
<h2 id="checked">What the contract checks</h2>
|
||||
<ol>
|
||||
<li>The certificate, through the shared verifier: the aggregate BLS signature over the checkpoint under the installed voter table and the weight rule.</li>
|
||||
<li>The header path from the carrier block up to the certified checkpoint: BLAKE2b-256 keyed BlockHash through the precompile, every parent link.</li>
|
||||
<li>The coinbase transaction under the carrier's <code>hash_merkle_root</code>, and the segment record parsed out of its extra data: the record's <code>post_root</code> for its block is stored under the certificate's index.</li>
|
||||
<li>Every read: a keccak-keyed Merkle Patricia proof against the stored root, verified on chain.</li>
|
||||
</ol>
|
||||
<p class="note">Said plainly, on the contract too (<code>trust()</code>): the aggregator's BLS signature on the record is not checked on chain in this slice, and while the stand-in verifier is installed no certificate signature is checked on chain either; the voter table the shared verifier holds is installed by its deployer. Gas on Sepolia, measured 8 October 2026: a 62-header path 13.3 million (about 215,000 per header, 15 precompile blocks each), a 10-header path about 2.2 million, the state-root store 177,000, a balance read 153,000. The negative cases in <code>test.mjs</code> are a flipped proof node, a wrong block number, a header removed from the path, a merkle sibling altered, a record with its <code>post_root</code> altered, a header with its nonce altered: each reverts.</p>
|
||||
<p class="asof">Devnet 3, no value. Sepolia, no value. A demonstration of the verification path, not a product.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -34,6 +34,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -27,8 +28,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -39,18 +38,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -62,8 +73,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -72,15 +81,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ table{min-width:560px}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -104,8 +105,6 @@ table{min-width:560px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -116,18 +115,30 @@ table{min-width:560px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance" aria-current="page"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -139,8 +150,6 @@ table{min-width:560px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -149,15 +158,25 @@ table{min-width:560px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance" aria-current="page"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -271,7 +290,7 @@ table{min-width:560px}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -286,6 +305,9 @@ table{min-width:560px}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
406
site/proving.html
Normal file
406
site/proving.html
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum Devnet 3 proving</title>
|
||||
<meta name="description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<link rel="canonical" href="https://igneum.network/proving">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum Devnet 3 proving">
|
||||
<meta property="og:description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<meta property="og:url" content="https://igneum.network/proving">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
<meta property="og:image:height" content="256">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 proving">
|
||||
<meta name="twitter:description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* page block; tokens, type and components are in /site.css */
|
||||
/* the explorer pages share this block with block.html and address.html; same tokens as live.html */
|
||||
--card-pad:clamp(18px,3vw,28px);--card-r:18px;--tile-pad:18px 20px;--tile-r:14px;--gap:24px;--gap-tile:12px;
|
||||
--fs-h1:clamp(32px,5.5vw,56px);--fs-h3:clamp(18px,2vw,22px);--fs-tile:clamp(20px,2.2vw,26px)}
|
||||
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px}
|
||||
.mono{font-family:var(--f-mono)}
|
||||
h1,h2{font-family:var(--f-display);margin:0;line-height:1.08;text-wrap:balance}
|
||||
.head{padding:65px 0 45px;display:flex;flex-direction:column;gap:14px}
|
||||
.head p{color:var(--ink-2);max-width:67ch;font-size:18px;line-height:1.65}
|
||||
.search{display:flex;gap:10px;max-width:760px;margin-top:4px;align-items:center;padding:12px 16px;border:1px solid var(--line-2);border-radius:8px;background:var(--row)}
|
||||
.search input{flex:1;min-width:0;border:0;outline:none;background:transparent;color:var(--bone);font-size:14px}
|
||||
.search input::placeholder{color:var(--ash)}
|
||||
.btn.primary:hover{background:#FF6A2B;border-color:#FF6A2B;color:var(--ember-ink)}
|
||||
.msg{font-family:var(--f-mono);font-size:13px;color:var(--molten);min-height:18px}
|
||||
.strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:24px;background:var(--row)}
|
||||
@media (max-width:700px){.strip{grid-template-columns:repeat(2,minmax(0,1fr))}.cell{border-right:1px solid var(--line)!important}.cell:nth-child(2n){border-right:0!important}.cell:nth-last-child(-n+4){border-bottom:1px solid var(--line)}.cell:nth-last-child(-n+2){border-bottom:0}}
|
||||
.cell{padding:22px 25px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:6px;min-width:0}.cell:nth-child(4n){border-right:0}.cell:nth-last-child(-n+4){border-bottom:0}
|
||||
.cell .k{font:10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin-bottom:5px}
|
||||
.cell .v{font:700 clamp(21px,2.2vw,29px)/1.1 var(--display);letter-spacing:-.04em;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.cell .v small{font-family:var(--f-mono);font-weight:500;font-size:13px;color:var(--ash);margin-left:4px;letter-spacing:.04em}
|
||||
@media (max-width:700px){.cell .v{font-size:19px}}
|
||||
.cell .s{font:10px/1.5 var(--mono);color:var(--ash);text-wrap:balance;margin-top:4px}
|
||||
.cell.status .v{display:flex;align-items:center;gap:10px}
|
||||
.off .dot{background:var(--ash);animation:none}.off .cell.status .v{color:var(--ash)}.on .cell.status .v{color:var(--molten)}
|
||||
@media (prefers-reduced-motion:reduce){.dot{animation:none}}
|
||||
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
|
||||
tbody tr:hover td{background:rgba(255,255,255,.025)}
|
||||
.id{font-family:var(--f-mono);color:var(--molten)}
|
||||
.hash{font-family:var(--f-mono)}
|
||||
.sw.chain{background:var(--ember);border-color:var(--blue)}.sw.blue{background:rgba(92,184,255,.7);border-color:var(--blue)}.sw.red{background:linear-gradient(45deg,transparent 44%,var(--ash) 44%,var(--ash) 56%,transparent 56%) center/8px 8px no-repeat}
|
||||
.chip{display:inline-block;font-family:var(--f-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 8px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin-right:6px}
|
||||
.chip.hot{border-color:var(--molten);color:var(--molten)}.chip.ok{border-color:var(--green);color:var(--green)}
|
||||
dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 20px;margin:12px 0 0;font-size:14px}
|
||||
dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash);padding-top:3px}
|
||||
dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
||||
@media (max-width:640px){dl{grid-template-columns:1fr;gap:2px 0}dd{margin-bottom:8px}}
|
||||
.two{display:grid;gap:var(--gap);grid-template-columns:1fr}
|
||||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Proving</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · proving</div>
|
||||
<h1>Proving on Devnet 3<span class="accent">.</span></h1>
|
||||
<p>Every chain block's execution is split into shards. Miners prove them, the node verifies the proofs, and a later coinbase pays the prover. This page reads the observer's record of that cycle: the plan per block, who proved what, and how long a block waits to be paid.</p>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
</div>
|
||||
<div class="strip" aria-live="polite">
|
||||
<div class="cell status"><div class="k">Proving</div><div class="v"><span class="dot"></span><span id="p-status">OFFLINE</span></div><div class="s" id="p-status-s">the node's proving layer</div></div>
|
||||
<div class="cell"><div class="k">Paid, 10 min</div><div class="v" id="p-paid10">0</div><div class="s" id="p-paid10-s">shards, for blocks of any age</div></div>
|
||||
<div class="cell"><div class="k">Paid, 24 h</div><div class="v" id="p-paid24">0</div><div class="s" id="p-paid24-s">shards, IGN to provers</div></div>
|
||||
<div class="cell"><div class="k">Open blocks</div><div class="v" id="p-open">0</div><div class="s" id="p-open-s">chain blocks with unpaid shards</div></div>
|
||||
<div class="cell"><div class="k">Provers, 24 h</div><div class="v" id="p-provers">0</div><div class="s" id="p-provers-s">vote keys paid for a shard</div></div>
|
||||
<div class="cell"><div class="k">Latency, 1 h</div><div class="v" id="p-lat">n/a</div><div class="s" id="p-lat-s">median DAA from block to payment</div></div>
|
||||
<div class="cell"><div class="k">Pool</div><div class="v" id="p-pool">0</div><div class="s" id="p-pool-s">records in the node's pool</div></div>
|
||||
<div class="cell"><div class="k">Shard budget</div><div class="v" id="p-budget">0<small>pgas</small></div><div class="s">proving gas per shard</div></div>
|
||||
</div>
|
||||
<div class="card" aria-label="Chain blocks and their shards">
|
||||
<div class="viz-head"><h2>Chain blocks</h2><div class="eyebrow" id="b-eyebrow">newest 60, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th class="n">Number</th><th>Block</th><th class="n">DAA</th><th>Class</th><th>Miner</th><th class="n">Txs</th><th class="n">pgas</th><th>Shards paid</th><th>States</th><th class="n">Median lag, DAA</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="11" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="note">States count the block's shards as planned (the node published the plan), proving (a record is in the pool), verified (the node's verifier accepted the proof) and paid (a later coinbase carried the record). Lag is the DAA score of the paying block minus the block's own; Devnet 3 targets one DAA step per second.</p>
|
||||
</div>
|
||||
<div class="two two-wrap">
|
||||
<div class="card" aria-label="Provers">
|
||||
<div class="viz-head"><h2>Provers, 24 h</h2><div class="eyebrow" id="pr-eyebrow">by shards paid</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Prover</th><th class="n">Shards</th><th class="n">Paid, IGN</th><th class="n">Median lag</th><th class="n">Last hour</th><th>Last paid</th></tr></thead><tbody id="provers"></tbody></table></div>
|
||||
<p class="note">A prover is a vote key (its first 8 hex characters). A card runs several keys, so one machine can be several rows.</p>
|
||||
</div>
|
||||
<div class="card" aria-label="Latency">
|
||||
<div class="viz-head"><h2>Block to paid</h2><div class="eyebrow" id="l-eyebrow">the last hour</div></div>
|
||||
<dl id="latency"></dl>
|
||||
<p class="note">Measured on the shards paid in the window, from the proven block's DAA score to the paying block's. The 24-hour totals by state are below the hour.</p>
|
||||
<dl id="totals"></dl>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script type="module">
|
||||
import { ignFromWei, shortHash, rel, int } from '/lib/explorer.mjs';
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const stamp = iso => iso ? new Date(iso).toISOString().slice(11, 19) + ' UTC' : '';
|
||||
function bar(s) { if (!s || !s.total) return '<span class="kv">no plan yet</span>'; const pct = Math.round(s.paid / s.total * 100); return `<span class="bar"><i class="${s.paid === s.total ? '' : 'part'}" style="width:${pct}%"></i></span>${s.paid} of ${s.total}`; }
|
||||
async function load() {
|
||||
const j = await fetch('/api/explorer?proving=1').then(r => r.json()); if (!j.ok) throw new Error(j.error);
|
||||
const now = new Date(j.now).getTime(), p = j.proving || {}, l = j.latency_1h || {}, t = j.totals_24h || {};
|
||||
const on = p.supported !== false && !j.stale;
|
||||
document.body.classList.toggle('on', on); document.body.classList.toggle('off', !on);
|
||||
$('p-status').textContent = j.stale ? 'OFFLINE' : (p.supported === false ? 'NO LAYER' : (p.active ? 'ACTIVE' : 'INACTIVE'));
|
||||
$('p-status-s').textContent = j.stale ? 'observer stale' : `read ${stamp(j.now)}, tip DAA ${int(p.tip_daa)}${p.paused_since_ms ? ', paused' : ''}`;
|
||||
const pa = j.paid_10m_any_age || {};
|
||||
$('p-paid10').textContent = int(pa.shards ?? 0); $('p-paid10-s').textContent = `shards paid in the last 10 min for blocks of any age, ${ignFromWei(pa.payout_wei || '0', 2)} IGN; ${int(p.blocks_fully_proven_10m ?? 0)} of ${int(p.blocks_10m ?? 0)} blocks of the window fully proven`;
|
||||
$('p-paid24').textContent = int(t.paid ? t.paid.shards : 0); $('p-paid24-s').textContent = `shards, ${ignFromWei(t.paid ? t.paid.payout_wei : '0', 2)} IGN to provers`;
|
||||
$('p-open').textContent = int(p.open_blocks ?? 0); $('p-open-s').textContent = `chain blocks with unpaid shards, ${int(p.pending_plans ?? 0)} plans not read yet`;
|
||||
$('p-provers').textContent = int(j.provers.length); $('p-provers-s').textContent = `vote keys paid for a shard; ${int(p.provers_10m ?? 0)} in the last 10 min`;
|
||||
$('p-lat').textContent = l.paid ? int(l.p50_daa) : 'n/a'; $('p-lat-s').textContent = l.paid ? `median DAA from block to payment over ${int(l.paid)} shards, p90 ${int(l.p90_daa)}` : 'no shard paid in the last hour';
|
||||
const pool = p.pool || {}; $('p-pool').textContent = int(pool.entries ?? 0); $('p-pool-s').textContent = `records in the node's pool: ${int(pool.pending ?? 0)} pending, ${int(pool.verified ?? 0)} verified, ${int(pool.failed ?? 0)} failed`;
|
||||
$('p-budget').innerHTML = esc(int(p.shard_budget_pgas ?? 0)) + '<small>pgas</small>';
|
||||
$('b-eyebrow').textContent = `newest ${j.blocks.length}, every 5 s, read ${stamp(j.now)}`;
|
||||
$('blocks').innerHTML = j.blocks.length ? j.blocks.map(b => `<tr data-href="/block/${b.hash}"><td class="n">${int(b.number)}</td><td><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a></td><td class="n">${int(b.daa)}</td><td><span class="chip">${esc(b.class)}</span></td><td>${b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : ''} <span class="id" style="font-size:12px">${esc(b.miner_id || '')}</span></td><td class="n">${int(b.tx_count)}</td><td class="n">${int(b.pgas)}</td><td>${bar(b.shards)}</td><td class="kv" style="font-size:12px">${b.shards && b.shards.total ? `${b.shards.planned} planned, ${b.shards.proving} proving, ${b.shards.verified} verified, ${b.shards.paid} paid` : ''}</td><td class="n">${b.shards && b.shards.median_lag !== null && b.shards.median_lag !== undefined ? int(b.shards.median_lag) : ''}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="11" class="empty">No chain block in the last 24 hours.</td></tr>';
|
||||
$('pr-eyebrow').textContent = `${int(j.provers.length)} keys, by shards paid`;
|
||||
$('provers').innerHTML = j.provers.length ? j.provers.map(x => `<tr><td class="id">${esc(x.id)}</td><td class="n">${int(x.shards_24h)}</td><td class="n">${ignFromWei(x.payout_wei_24h, 2)}</td><td class="n">${x.median_lag_24h === null ? '' : int(x.median_lag_24h)}</td><td class="n">${int(x.shards_1h)}</td><td title="${x.last_paid ? new Date(x.last_paid).toISOString() : ''}">${x.last_paid ? rel(now - new Date(x.last_paid).getTime()) : ''}</td></tr>`).join('') : '<tr><td colspan="6" class="empty">No shard paid in the last 24 hours.</td></tr>';
|
||||
$('l-eyebrow').textContent = `the last hour, read ${stamp(j.now)}`;
|
||||
$('latency').innerHTML = l.paid ? dl([['Shards paid', int(l.paid)], ['Median', `${int(l.p50_daa)} DAA`], ['p90', `${int(l.p90_daa)} DAA`], ['Fastest', `${int(l.min_daa)} DAA`], ['Slowest', `${int(l.max_daa)} DAA`]]) : '<div class="empty">No shard paid in the last hour.</div>';
|
||||
$('totals').innerHTML = dl(Object.entries(t).sort().map(([k, v]) => [`${k}, 24 h`, `${int(v.shards)} shards${k === 'paid' ? `, ${ignFromWei(v.payout_wei, 2)} IGN` : ''}`]));
|
||||
}
|
||||
$('blocks').addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
setInterval(() => { load().catch(() => {}); }, 5000);
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,8 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,18 +114,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx" aria-current="page"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -138,8 +149,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -148,15 +157,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx" aria-current="page"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -221,7 +240,7 @@
|
|||
</section>
|
||||
<section class="section compact">
|
||||
<div class="container">
|
||||
<div class="derived"><p>RandomX has kept chips off Monero since 2019 (approximate) by making the mining program random, so the hardware that runs it well is the hardware everyone already owns. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="derived"><p>RandomX has kept Monero on commodity hardware since 2019 by making the mining program random, so the hardware that runs it well is close to the hardware everyone already owns: the one chip that shipped, Bitmain’s Antminer X5 (September 2023), is a board of RISC-V chips at 1.46x per joule over a desktop CPU. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 with its mainnet activation pending (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Property</th><th>RandomX, Monero</th><th>Igneum</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -232,7 +251,7 @@
|
|||
<tr><td>Changes over time</td><td>None. A fixed design, unchanged for seven years</td><td>A new program every hour, its memory pattern with it; era draws and reserved families on a schedule fixed at genesis. Nobody touches it</td></tr>
|
||||
<tr><td>Seed grinding</td><td>Not applicable, the program comes from the hash input</td><td>Closed by a verifiable delay between seed and program</td></tr>
|
||||
<tr><td>Useful work</td><td>None. Hashing only</td><td>Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years without a shipped chip; the one announced, Bitmain’s Antminer X9, was withdrawn in May 2026 before launch</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years with one shipped chip, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, Bitmain’s Antminer X9, was withdrawn in May 2026 with zero units; RandomX v2 released 25 March 2026, activation pending</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Measured so far: the same hourly program, generated on an Apple M5 Max, compiled by Apple's Metal and NVIDIA's CUDA on an RTX 5090, produced identical hashes on both, 192 of 192 across two programs. On a 1 GB dataset the 5090 ran at about 228 million hashes a second and the Mac at about 45 million, both bound by random memory access rather than arithmetic. Those are prototype figures, not mining rates. The first prototype dataset was a closed-form function, and a miner could compute items instead of loading them: measured 111x faster that way on the Mac. The 256 MB cache construction replaced it on 3 October 2026. With the cache, computing items on the fly runs 4.8x slower than loading them, measured on the Mac, and the honest rate is unchanged on both vendors. Open: the same shortcut ratio on NVIDIA and on a discrete AMD card, and the time-memory trade-off between the two measured points. Inside the 5090's 96 MB cache the same program ran nearly six times faster, which is why the dataset starts at 2 GB and grows. On 4 October 2026 the live devnet crossed an hourly program change on all three vendors with no pause and no rejected block: a Mac at 26.7 million hashes a second, an RTX 5090 at 123 million and an integrated AMD chip at 2.7 million, every hash doing 128 distinct reads of the memory-hard dataset.</p></div>
|
||||
|
|
@ -262,7 +281,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -277,6 +296,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
365
site/receipt.html
Normal file
365
site/receipt.html
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum payment receipt</title>
|
||||
<meta name="description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/receipt">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum payment receipt">
|
||||
<meta property="og:description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/receipt">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum payment receipt">
|
||||
<meta name="twitter:description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt" aria-current="page"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt" aria-current="page"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Payment receipt</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 2 · Devnet 3, no value</div>
|
||||
<h1>A receipt any third party re-verifies<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">Paste a Devnet 3 transaction hash. This tab fetches the raw transaction, the including block's merkle path, every header up to the certified checkpoint and the certificate, then proves inclusion and finality itself. Download the receipt as JSON. Anyone checks it later with a one-file verifier, offline, with no node and no network.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> A merchant's receipt is only worth something if the payment cannot be undone and the proof of that fits in a file: here the certificate is a weighted BLS signature by the miners over a checkpoint, and the block holding the payment hashes into that checkpoint's past. On a chain with probabilistic finality a receipt is a guess that ages well; here it is a fact that a file carries.</p>
|
||||
<p>Source: <code>site/lc/core.js</code> (the checks), <code>site/lc/app.js</code> (this page), <code>tools/reference-apps/receipt/verify-receipt.src.mjs</code> (the one-file verifier, bundled to <code>/lc/verify-receipt.js</code>). Test with the negative cases: <a href="/lc/test">/lc/test</a> in the browser, <code>tools/reference-apps/light-service/verify.test.mjs</code> under Node.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="verify">
|
||||
<h2 id="verify">Get a receipt</h2>
|
||||
<form class="vform" data-form="receipt" novalidate>
|
||||
<label for="tx">Transaction hash</label>
|
||||
<div class="row"><input id="tx" name="tx" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" pattern="^0x[0-9a-fA-F]{64}$"><button class="btn primary" type="submit">Prove it in this tab</button></div>
|
||||
<div class="vstatus" data-status role="status" aria-live="polite">Devnet 3, no value. A transaction is final once a certified checkpoint has it in its past, about 30 to 90 s after it executes.</div>
|
||||
</form>
|
||||
<div data-result></div>
|
||||
</section>
|
||||
|
||||
<h2 id="offline">Re-verify offline</h2>
|
||||
<p class="note">The verifier is one file of plain JavaScript with the hashing and curve code inside it: <a href="/lc/verify-receipt.js" download>verify-receipt.js</a>. It runs under Node 18 or later (<code>node verify-receipt.js receipt.json</code>) and prints each check, then <code>VERIFIED</code> or <code>REFUSED</code> with the reason. It fetches nothing. Flip one byte of the file and it is refused: <code>node verify-receipt.js receipt.json --tamper</code> runs that case first so you see the refusal before the verdict.</p>
|
||||
<h2 id="checked">What the receipt proves</h2>
|
||||
<ol>
|
||||
<li>The transaction hash is keccak256 of the raw signed transaction in the file, so the recipient, the amount and the data are the signed ones.</li>
|
||||
<li>The transaction is a leaf of the including block's <code>hash_merkle_root</code> (BLAKE2b-256 keyed MerkleBranchHash up the path).</li>
|
||||
<li>Every header from the including block to the certified checkpoint recomputes and links to the next by a direct parent.</li>
|
||||
<li>The certificate over that checkpoint verifies: the aggregate BLS signature of the signers, the voter order, two thirds of active weight and 17/30 of total.</li>
|
||||
</ol>
|
||||
<p class="note">Not proven by the file: the execution result (status, gas) is carried as the node reported it and labelled so; the voter table with weights comes from the node (spec 10.1). Both are named on the result.</p>
|
||||
<p class="asof">Devnet 3, no value. The chain may reset. A demonstration of the verification path, not a product.</p>
|
||||
</main>
|
||||
<script type="module" src="/lc/app.js"></script>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -64,6 +64,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -81,8 +82,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -93,18 +92,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -116,8 +127,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -126,15 +135,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -249,7 +268,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -264,6 +283,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -564,3 +564,15 @@ main.wrap>.grid{align-items:start}
|
|||
main.wrap{padding-bottom:72px}
|
||||
@media (max-width:560px){main.wrap{padding-bottom:48px}}
|
||||
main.wrap>.grid{margin-bottom:40px}
|
||||
|
||||
/* the /income calculator (8 October 2026) */
|
||||
.calc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--s-4);margin:var(--s-4) 0}
|
||||
.calc-grid .field{display:flex;flex-direction:column;gap:6px;min-width:0}
|
||||
.calc-grid .field>span{font:500 13px/1.4 var(--f-mono);color:var(--ash);text-transform:uppercase;letter-spacing:.04em}
|
||||
.calc-grid .field select,.calc-grid .field input{width:100%;max-width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r-row);background:var(--row);color:var(--bone);font:400 15px/1.4 var(--f-sans)}
|
||||
.calc-grid .field small{font:400 13px/1.5 var(--f-sans);color:var(--ink-2)}
|
||||
.calc-out{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--s-4) var(--s-5);margin:var(--s-5) 0 var(--s-2);padding:var(--s-4) var(--s-5);border:1px solid var(--line);border-radius:var(--r-row);background:var(--row)}
|
||||
.calc-out .k{grid-column:1/-1;font:500 13px/1.4 var(--f-mono);color:var(--ash);text-transform:uppercase;letter-spacing:.04em;margin-top:var(--s-2)}
|
||||
.calc-out .v{font:600 var(--t-h3)/1.2 var(--f-sans);color:var(--bone);overflow-wrap:anywhere}
|
||||
.calc-out .d{font:400 14px/1.5 var(--f-sans);color:var(--ink-2);overflow-wrap:anywhere}
|
||||
@media (min-width:861px){.calc-out{grid-template-columns:200px 1fr}.calc-out .k{grid-column:1;margin-top:0;align-self:baseline}.calc-out .v{grid-column:2}.calc-out .d{grid-column:2;margin-bottom:var(--s-2)}}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url><loc>https://igneum.network/</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>
|
||||
<url><loc>https://igneum.network/litepaper</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.9</priority></url>
|
||||
<url><loc>https://igneum.network/litepaper</loc></url><url><loc>https://igneum.network/economics</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.9</priority></url>
|
||||
<url><loc>https://igneum.network/miner</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
|
||||
<url><loc>https://igneum.network/app</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
|
||||
<url><loc>https://igneum.network/wallet</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/live</loc><lastmod>2026-10-07</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://igneum.network/explorer</loc><lastmod>2026-10-07</lastmod><changefreq>daily</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/explorer</loc><lastmod>2026-10-08</lastmod><changefreq>daily</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/proving</loc><lastmod>2026-10-08</lastmod><changefreq>daily</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/ledger</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/bench</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/evidence</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/light</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/receipt</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/oracle</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/miners</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/journey</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/claims</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.5</priority></url>
|
||||
|
|
@ -17,5 +21,8 @@
|
|||
<url><loc>https://igneum.network/provenance</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/dev-fee</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/metamask</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/faucet</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/faucet</loc><lastmod>2026-10-08</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/build</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
|
||||
<url><loc>https://igneum.network/swap</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/grants</loc><lastmod>2026-10-08</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>
|
||||
</urlset>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -112,8 +113,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -124,18 +123,30 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap" aria-current="page"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -147,8 +158,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -157,15 +166,25 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap" aria-current="page"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -232,7 +251,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<h2 id="swap-h">Swap</h2>
|
||||
<div class="wallet-row">
|
||||
<button class="btn" id="connect" type="button">Connect wallet</button>
|
||||
<span class="status" id="wallet" role="status" aria-live="polite">No wallet connected. MetaMask or the Igneum Wallet, pointed at chain id 4463.</span>
|
||||
<span class="status" id="wallet" role="status" aria-live="polite">No wallet connected. The Igneum Wallet open on this machine, or MetaMask, on chain id 4463.</span>
|
||||
</div>
|
||||
<form id="swap-form" novalidate>
|
||||
<label for="amount-in">You send</label>
|
||||
|
|
@ -318,7 +337,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -333,6 +352,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -363,9 +385,12 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script src="/wallet-provider.js"></script>
|
||||
<script>
|
||||
(function(){
|
||||
// Devnet 3, test tokens, no value. Addresses: docs/contracts/devnet-3.json. Reads go to the public RPC; sends go
|
||||
// Devnet 3, test tokens, no value. Addresses: docs/contracts/devnet-3.json. /wallet-provider.js (the wallet lane's page
|
||||
// bridge) gives the page an EIP-1193 provider for the Igneum Wallet running on this machine: window.ethereum when no
|
||||
// extension injects one, window.igneum beside MetaMask, announced through EIP-6963. Reads go to the public RPC; sends go
|
||||
// through the connected wallet (EIP-1193: MetaMask and any wallet that injects window.ethereum), which asks the node
|
||||
// for the gas limit itself (Devnet 3 charges proving gas inside execution gas, so a local estimate runs out).
|
||||
var RPC='https://rpc.devnet.igneum.network', CHAIN_ID=4463, CHAIN_HEX='0x116f';
|
||||
|
|
@ -394,7 +419,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
// ---- the wallet ----
|
||||
function connect(){
|
||||
var eth=window.ethereum;
|
||||
if(!eth){say($('wallet'),'No wallet found in this browser. Install MetaMask, or use the Igneum Wallet (its page connection comes in a later build; until then watch an address below).','bad');return;}
|
||||
if(!eth){say($('wallet'),'No wallet found. Open the Igneum Wallet on this machine (0.1.6 or later; the page finds it by itself) or install MetaMask, then tap Connect again.','bad');return;}
|
||||
eth.request({method:'eth_requestAccounts'}).then(function(acc){
|
||||
account=acc[0];provider=eth;
|
||||
return eth.request({method:'eth_chainId'});
|
||||
|
|
@ -524,7 +549,11 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:13px;overflo
|
|||
document.querySelectorAll('.addr').forEach(function(el){el.textContent=A[el.getAttribute('data-addr')];});
|
||||
}
|
||||
fillSelects();refreshPools();setInterval(refreshPools,30000);
|
||||
$('connect').addEventListener('click',connect);
|
||||
// a wallet picker when both are present: the Igneum Wallet by EIP-6963, else whatever window.ethereum is
|
||||
var igneumProvider=null;
|
||||
window.addEventListener('eip6963:announceProvider',function(e){if(e.detail&&e.detail.info&&e.detail.info.rdns==='network.igneum.wallet')igneumProvider=e.detail.provider;});
|
||||
try{window.dispatchEvent(new Event('eip6963:requestProvider'));}catch(e){}
|
||||
$('connect').addEventListener('click',function(){if(igneumProvider&&window.ethereum!==igneumProvider&&window.confirm('Connect the Igneum Wallet? Cancel connects the browser extension instead.'))window.ethereum=igneumProvider;connect();});
|
||||
$('swap-form').addEventListener('submit',doSwap);
|
||||
$('amount-in').addEventListener('input',function(){clearTimeout(quoteTimer);quoteTimer=setTimeout(quote,300);});
|
||||
$('token-in').addEventListener('change',quote);$('token-out').addEventListener('change',quote);
|
||||
|
|
|
|||
408
site/tx.html
Normal file
408
site/tx.html
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum Devnet 3 transaction</title>
|
||||
<meta name="description" content="One Devnet 3 transaction: status, value, fees and their split, the block that executed it, its proof state and finality, its logs.">
|
||||
<link rel="canonical" href="https://igneum.network/tx">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum Devnet 3 transaction">
|
||||
<meta property="og:description" content="One Devnet 3 transaction: status, value, fees and their split, the block that executed it, its proof state and finality, its logs.">
|
||||
<meta property="og:url" content="https://igneum.network/tx">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
<meta property="og:image:height" content="256">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 transaction">
|
||||
<meta name="twitter:description" content="One Devnet 3 transaction: status, value, fees and their split, the block that executed it, its proof state and finality, its logs.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* page block; tokens, type and components are in /site.css */
|
||||
/* the explorer pages share this block with block.html and address.html; same tokens as live.html */
|
||||
--card-pad:clamp(18px,3vw,28px);--card-r:18px;--tile-pad:18px 20px;--tile-r:14px;--gap:24px;--gap-tile:12px;
|
||||
--fs-h1:clamp(32px,5.5vw,56px);--fs-h3:clamp(18px,2vw,22px);--fs-tile:clamp(20px,2.2vw,26px)}
|
||||
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px}
|
||||
.mono{font-family:var(--f-mono)}
|
||||
h1,h2{font-family:var(--f-display);margin:0;line-height:1.08;text-wrap:balance}
|
||||
.head{padding:65px 0 45px;display:flex;flex-direction:column;gap:14px}
|
||||
.head p{color:var(--ink-2);max-width:67ch;font-size:18px;line-height:1.65}
|
||||
.search{display:flex;gap:10px;max-width:760px;margin-top:4px;align-items:center;padding:12px 16px;border:1px solid var(--line-2);border-radius:8px;background:var(--row)}
|
||||
.search input{flex:1;min-width:0;border:0;outline:none;background:transparent;color:var(--bone);font-size:14px}
|
||||
.search input::placeholder{color:var(--ash)}
|
||||
.btn.primary:hover{background:#FF6A2B;border-color:#FF6A2B;color:var(--ember-ink)}
|
||||
.msg{font-family:var(--f-mono);font-size:13px;color:var(--molten);min-height:18px}
|
||||
.strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:24px;background:var(--row)}
|
||||
@media (max-width:700px){.strip{grid-template-columns:repeat(2,minmax(0,1fr))}.cell{border-right:1px solid var(--line)!important}.cell:nth-child(2n){border-right:0!important}.cell:nth-last-child(-n+4){border-bottom:1px solid var(--line)}.cell:nth-last-child(-n+2){border-bottom:0}}
|
||||
.cell{padding:22px 25px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:6px;min-width:0}.cell:nth-child(4n){border-right:0}.cell:nth-last-child(-n+4){border-bottom:0}
|
||||
.cell .k{font:10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin-bottom:5px}
|
||||
.cell .v{font:700 clamp(21px,2.2vw,29px)/1.1 var(--display);letter-spacing:-.04em;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.cell .v small{font-family:var(--f-mono);font-weight:500;font-size:13px;color:var(--ash);margin-left:4px;letter-spacing:.04em}
|
||||
@media (max-width:700px){.cell .v{font-size:19px}}
|
||||
.cell .s{font:10px/1.5 var(--mono);color:var(--ash);text-wrap:balance;margin-top:4px}
|
||||
.cell.status .v{display:flex;align-items:center;gap:10px}
|
||||
.off .dot{background:var(--ash);animation:none}.off .cell.status .v{color:var(--ash)}.on .cell.status .v{color:var(--molten)}
|
||||
@media (prefers-reduced-motion:reduce){.dot{animation:none}}
|
||||
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
|
||||
tbody tr:hover td{background:rgba(255,255,255,.025)}
|
||||
.id{font-family:var(--f-mono);color:var(--molten)}
|
||||
.hash{font-family:var(--f-mono)}
|
||||
.sw.chain{background:var(--ember);border-color:var(--blue)}.sw.blue{background:rgba(92,184,255,.7);border-color:var(--blue)}.sw.red{background:linear-gradient(45deg,transparent 44%,var(--ash) 44%,var(--ash) 56%,transparent 56%) center/8px 8px no-repeat}
|
||||
.chip{display:inline-block;font-family:var(--f-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 8px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin-right:6px}
|
||||
.chip.hot{border-color:var(--molten);color:var(--molten)}.chip.ok{border-color:var(--green);color:var(--green)}
|
||||
dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 20px;margin:12px 0 0;font-size:14px}
|
||||
dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash);padding-top:3px}
|
||||
dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
||||
@media (max-width:640px){dl{grid-template-columns:1fr;gap:2px 0}dd{margin-bottom:8px}}
|
||||
.two{display:grid;gap:var(--gap);grid-template-columns:1fr}
|
||||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Transaction</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · transaction</div>
|
||||
<h1 class="hash" id="title">Transaction</h1>
|
||||
<div id="chips"></div>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
</div>
|
||||
<div id="body" hidden>
|
||||
<div class="two two-wrap">
|
||||
<div class="card"><div class="viz-head"><h2>Summary</h2></div><dl id="summary"></dl></div>
|
||||
<div class="card"><div class="viz-head"><h2>Fees and proving</h2><div class="eyebrow">the receipt's Igneum section</div></div><dl id="fees"></dl><p class="note">Read from the observer node, the chain the finality certificates follow. Both base fees burn in full. The priority fee splits 80/20 between the including miner and the proving pool. Proving gas (pgas) is what the shard that proves this transaction costs; the proving base fee prices it.</p></div>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Block and proof</h2><div class="eyebrow" id="blk-eyebrow"></div></div><dl id="blk"></dl></div>
|
||||
<div class="card"><div class="viz-head"><h2>Logs</h2><div class="eyebrow" id="log-n"></div></div><div class="tbl" id="logs"></div></div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script type="module">
|
||||
import { ignFromWei, shortHash, rel, int, utc } from '/lib/explorer.mjs';
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
const addr = a => a ? `<a class="hash" href="/address/${esc(a)}">${esc(a)}</a>` : '<span class="kv">none</span>';
|
||||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const wei = h => (h === null || h === undefined ? null : BigInt(h).toString());
|
||||
const id = decodeURIComponent(location.pathname.split('/').pop() || '');
|
||||
async function load() {
|
||||
const r = await fetch('/api/explorer?tx=' + encodeURIComponent(id)); const j = await r.json();
|
||||
$('title').textContent = id;
|
||||
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; return; }
|
||||
const t = j.tx, b = j.block, now = new Date(j.now).getTime(), g = t.igneum || {};
|
||||
document.title = `Devnet 3 transaction ${shortHash(t.hash, 8, 6)}`;
|
||||
$('title').textContent = t.hash;
|
||||
const chips = [t.status === 'success' ? '<span class="chip ok">success</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="chip">no receipt</span>'];
|
||||
chips.push(`<span class="chip">chain block ${int(t.number)}</span>`);
|
||||
if (b && b.in_observer) { chips.push(b.lock && b.lock.final ? `<span class="chip ok">final under lock ${int(b.lock.index)}</span>` : '<span class="chip">not under a lock yet</span>'); if (b.shards && b.shards.total) chips.push(`<span class="chip ${b.shards.paid === b.shards.total ? 'ok' : ''}">${b.shards.paid} of ${b.shards.total} shards paid</span>`); chips.push(`<span class="chip">class ${esc(b.class || 'v4')}</span>`); }
|
||||
if (t.contract_address) chips.push('<span class="chip hot">contract creation</span>');
|
||||
$('chips').innerHTML = chips.join('');
|
||||
const fee = t.gas_used !== null && t.effective_gas_price !== null ? (BigInt(t.gas_used) * BigInt(t.effective_gas_price)).toString() : null;
|
||||
$('summary').innerHTML = dl([
|
||||
['Network', 'Devnet 3, chain id ' + esc(j.chain_id ?? 4463)],
|
||||
['Hash', `<span class="hash">${esc(t.hash)}</span>`],
|
||||
['Status', t.status || 'no receipt'],
|
||||
['Block', `<a class="hash" href="/block/${esc(t.block_hash)}">${esc(shortHash(t.block_hash, 12, 8))}</a> <span class="kv">chain block ${int(t.number)}, index ${int(t.index)}</span>`],
|
||||
['Time', t.ts ? `${utc(t.ts)} <span class="kv">(${rel(now - t.ts)})</span>` : 'n/a'],
|
||||
['From', addr(t.from)], ['To', t.to ? addr(t.to) + (t.contracts && t.contracts[t.to] !== undefined ? ' <span class="chip">contract</span>' : '') : (t.contract_address ? `<span class="kv">created</span> ${addr(t.contract_address)}` : '<span class="kv">none</span>')],
|
||||
['Value', `${ignFromWei(t.value_wei, 8)} IGN`],
|
||||
['Fee', fee ? `${ignFromWei(fee, 8)} IGN <span class="kv">${int(t.gas_used)} gas at ${ignFromWei(t.effective_gas_price, 10)} IGN per gas</span>` : 'n/a'],
|
||||
['Gas', `${int(t.gas_used)} used of ${int(t.gas)} limit`],
|
||||
['Nonce', int(t.nonce)], ['Type', `${t.type} <span class="kv">${t.type === 2 ? 'EIP-1559' : t.type === 1 ? 'access list' : 'legacy'}</span>`],
|
||||
['Input', `${int(t.input_bytes)} bytes${t.selector ? `, selector <span class="hash">${esc(t.selector)}</span>` : ''}`],
|
||||
]);
|
||||
$('fees').innerHTML = t.igneum ? dl([
|
||||
['Miner tip', g.minerTip ? `${ignFromWei(wei(g.minerTip), 8)} IGN <span class="kv">to the including miner</span>` : 'n/a'],
|
||||
['Execution base fee burned', g.burnedExecutionBaseFee ? `${ignFromWei(wei(g.burnedExecutionBaseFee), 8)} IGN` : 'n/a'],
|
||||
['Proving fee burned', g.burnedProvingFee ? `${ignFromWei(wei(g.burnedProvingFee), 8)} IGN` : 'n/a'],
|
||||
['Proving gas', g.pgasUsed ? `${int(Number(BigInt(g.pgasUsed)))} pgas${g.provingBaseFeePerGas ? ` at ${ignFromWei(wei(g.provingBaseFeePerGas), 10)} IGN per pgas` : ''}${g.overBudget ? ', over budget' : ''}${g.pgasAborted ? ', aborted' : ''}` : 'n/a'],
|
||||
g.developerShares && g.developerShares.length ? ['App share', g.developerShares.map(s => `${ignFromWei(wei(s.wei), 8)} IGN ${s.payee ? 'to ' + addr(s.payee) : '<span class="kv">unregistered, burned</span>'}`).join('<br>')] : null,
|
||||
['Including block', g.includingBlock ? `<a class="hash" href="/block/${esc(String(g.includingBlock).replace(/^0x/, ''))}">${esc(shortHash(String(g.includingBlock).replace(/^0x/, ''), 12, 8))}</a> <span class="kv">the first block that carried it; executed under chain block ${int(t.number)}</span>` : 'n/a'],
|
||||
['Including miner', g.includingMiner ? addr(g.includingMiner) : 'n/a'],
|
||||
]) : '<div class="empty">No receipt yet.</div>';
|
||||
if (b && b.in_observer) {
|
||||
$('blk-eyebrow').textContent = `chain block ${int(b.number)}`;
|
||||
$('blk').innerHTML = dl([
|
||||
['Block', `<a class="hash" href="/block/${esc(b.hash)}">${esc(b.hash)}</a>`],
|
||||
['Blue score', int(b.blue_score)], ['DAA score', int(b.daa)], ['Class', esc(b.class || 'v4')],
|
||||
['Miner', addr(b.evm_miner)],
|
||||
['Lock state', b.lock ? `${b.lock.final ? 'final' : 'not final'} <span class="kv">${esc(b.lock.reason)}</span>` : 'n/a'],
|
||||
['Proof', b.shards && b.shards.total ? `${b.shards.paid} of ${b.shards.total} shards paid${b.shards.median_lag !== null ? `, median lag ${int(b.shards.median_lag)} DAA` : ''} <span class="kv">${b.shards.proving} proving, ${b.shards.verified} verified, ${b.shards.planned} planned</span>` : '<span class="kv">plan not read yet</span>'],
|
||||
]);
|
||||
} else { $('blk-eyebrow').textContent = 'outside the observer window'; $('blk').innerHTML = dl([['Block', `<a class="hash" href="/block/${esc(t.block_hash)}">${esc(t.block_hash)}</a>`], ['Note', esc(b && b.note ? b.note : 'the observer keeps one day of blocks')]]); }
|
||||
const logs = t.logs || [];
|
||||
$('log-n').textContent = `${logs.length} log${logs.length === 1 ? '' : 's'}`;
|
||||
$('logs').innerHTML = logs.length ? `<table><thead><tr><th class="n">Index</th><th>Address</th><th>Topics</th><th>Data</th></tr></thead><tbody>${logs.map(l => `<tr><td class="n">${int(l.i)}</td><td>${addr(l.address)}</td><td class="hash" style="font-size:12px">${(l.topics || []).map(x => esc(x)).join('<br>')}</td><td class="hash" style="font-size:12px;overflow-wrap:anywhere">${esc(l.data)}</td></tr>`).join('')}</tbody></table>` : '<div class="empty">This transaction emitted no logs.</div>';
|
||||
$('body').hidden = false;
|
||||
}
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
145
site/vercel.json
145
site/vercel.json
|
|
@ -1,17 +1,140 @@
|
|||
{
|
||||
"cleanUrls": true,
|
||||
"trailingSlash": false,
|
||||
"redirects": [{"source": "/connect", "destination": "/metamask", "permanent": true}, {"source": "/gpu-benchmarks", "destination": "/miners", "permanent": true}],
|
||||
"rewrites": [{"source": "/block/:id", "destination": "/block"}, {"source": "/address/:addr", "destination": "/address"}, {"source": "/benchmarks", "destination": "/miners"}],
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/",
|
||||
"has": [
|
||||
{
|
||||
"type": "host",
|
||||
"value": "explorer.igneum.network"
|
||||
}
|
||||
],
|
||||
"destination": "/explorer",
|
||||
"permanent": false
|
||||
},
|
||||
{
|
||||
"source": "/connect",
|
||||
"destination": "/metamask",
|
||||
"permanent": true
|
||||
},
|
||||
{
|
||||
"source": "/gpu-benchmarks",
|
||||
"destination": "/miners",
|
||||
"permanent": true
|
||||
}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/tx/:hash",
|
||||
"destination": "/tx"
|
||||
},
|
||||
{
|
||||
"source": "/block/:id",
|
||||
"destination": "/block"
|
||||
},
|
||||
{
|
||||
"source": "/address/:addr",
|
||||
"destination": "/address"
|
||||
},
|
||||
{
|
||||
"source": "/benchmarks",
|
||||
"destination": "/miners"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{"source": "/(.*)", "headers": [{"key": "X-Content-Type-Options", "value": "nosniff"}, {"key": "X-Frame-Options", "value": "DENY"}, {"key": "Referrer-Policy", "value": "strict-origin-when-cross-origin"}, {"key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload"}]},
|
||||
{"source": "/fonts/(.*)", "headers": [{"key": "Cache-Control", "value": "public, max-age=31536000, immutable"}]},
|
||||
{"source": "/(.*)\\.(png|ico)", "headers": [{"key": "Cache-Control", "value": "public, max-age=86400, stale-while-revalidate=604800"}]},
|
||||
{"source": "/site.webmanifest", "headers": [{"key": "Cache-Control", "value": "public, max-age=86400, stale-while-revalidate=604800"}]},
|
||||
{"source": "/journey.json", "headers": [{"key": "Cache-Control", "value": "public, max-age=300"}]},
|
||||
{"source": "/api/live", "headers": [{"key": "Cache-Control", "value": "public, max-age=1"}]},
|
||||
{"source": "/api/stats", "headers": [{"key": "Cache-Control", "value": "public, max-age=10, s-maxage=10"}]},
|
||||
{"source": "/api/supply", "headers": [{"key": "Cache-Control", "value": "public, max-age=10, s-maxage=10"}]},
|
||||
{"source": "/api/explorer", "headers": [{"key": "Cache-Control", "value": "public, max-age=5, s-maxage=5"}]}
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "X-Content-Type-Options",
|
||||
"value": "nosniff"
|
||||
},
|
||||
{
|
||||
"key": "X-Frame-Options",
|
||||
"value": "DENY"
|
||||
},
|
||||
{
|
||||
"key": "Referrer-Policy",
|
||||
"value": "strict-origin-when-cross-origin"
|
||||
},
|
||||
{
|
||||
"key": "Strict-Transport-Security",
|
||||
"value": "max-age=63072000; includeSubDomains; preload"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/fonts/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=31536000, immutable"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/(.*)\\.(png|ico)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=86400, stale-while-revalidate=604800"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/site.webmanifest",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=86400, stale-while-revalidate=604800"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/journey.json",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/api/live",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/api/stats",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=10, s-maxage=10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/api/supply",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=10, s-maxage=10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/api/explorer",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=5, s-maxage=5"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
94
site/wallet-provider.js
Normal file
94
site/wallet-provider.js
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* The Igneum Wallet's page provider (8 October 2026): an EIP-1193 provider for a page when the Igneum Wallet runs on
|
||||
* the same machine. The wallet's engine listens on 127.0.0.1:26811 (its page bridge, app/igneum-wallet/src/bridge.rs);
|
||||
* this file POSTs JSON-RPC there with the X-Igneum-Bridge header (so the browser sends a CORS preflight the bridge
|
||||
* answers for the page's origin) and polls a request the wallet window has to answer (connect, send, sign) until the
|
||||
* person decides there. Nothing is signed on the page; the wallet shows the facts and asks in its own window.
|
||||
*
|
||||
* <script src="/wallet-provider.js"></script> before the page's own script
|
||||
*
|
||||
* Rules: a page that already has window.ethereum (MetaMask) keeps it; the Igneum provider is then window.igneum and is
|
||||
* announced through EIP-6963 (rdns network.igneum.wallet) so a wallet picker can list it. Without an injected wallet,
|
||||
* the Igneum provider is window.ethereum. A request while the wallet is not open rejects with code 4900. Errors come
|
||||
* back as {code, message} (EIP-1193 codes: 4001 declined, 4100 not connected, 4200 not offered, 4902 another chain).
|
||||
* Tests: site/wallet-provider.test.mjs. */
|
||||
(function (win) {
|
||||
var BASE = 'http://127.0.0.1:26811', POLL_MS = 800, TICK_MS = 4000;
|
||||
var seq = 0, hello = null, helloAt = 0, listeners = {}, lastAccounts = '', lastChain = '';
|
||||
function err(code, message) { var e = new Error(message); e.code = code; return e; }
|
||||
function emit(ev, arg) { (listeners[ev] || []).slice().forEach(function (f) { try { f(arg); } catch (e) { } }); }
|
||||
function probe() {
|
||||
var now = Date.now();
|
||||
if (hello && now - helloAt < 10000) return Promise.resolve(hello);
|
||||
return fetch(BASE + '/bridge/hello', { method: 'GET', cache: 'no-store' }).then(function (r) { return r.json(); }).then(function (j) {
|
||||
if (!j || !j.ok || j.wallet !== 'igneum') throw err(4900, 'The Igneum Wallet is not open on this computer');
|
||||
hello = j; helloAt = Date.now(); return j;
|
||||
}).catch(function (e) { hello = null; throw e.code ? e : err(4900, 'The Igneum Wallet is not open on this computer. Open it, then try again.'); });
|
||||
}
|
||||
function rpc(method, params) {
|
||||
var id = ++seq;
|
||||
return fetch(BASE + '/bridge/rpc', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Igneum-Bridge': '1' }, body: JSON.stringify({ jsonrpc: '2.0', id: id, method: method, params: params || [] }), cache: 'no-store' })
|
||||
.then(function (r) { return r.json(); }, function () { throw err(4900, 'The Igneum Wallet stopped answering. Open it, then try again.'); });
|
||||
}
|
||||
function settle(j) {
|
||||
if (j && j.error) throw err(typeof j.error.code === 'number' ? j.error.code : -32603, j.error.message || 'the wallet refused');
|
||||
return j ? j.result : null;
|
||||
}
|
||||
function wait(id) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
function again() {
|
||||
rpc('igneum_poll', [id]).then(function (j) {
|
||||
if (j && j.pending) { win.setTimeout(again, POLL_MS); return; }
|
||||
try { resolve(settle(j)); } catch (e) { reject(e); }
|
||||
}, reject);
|
||||
}
|
||||
win.setTimeout(again, POLL_MS);
|
||||
});
|
||||
}
|
||||
var provider = {
|
||||
isIgneum: true,
|
||||
isConnected: function () { return !!hello; },
|
||||
selectedAddress: null,
|
||||
chainId: null,
|
||||
request: function (args) {
|
||||
if (!args || typeof args.method !== 'string') return Promise.reject(err(-32602, 'request({method, params})'));
|
||||
var method = args.method, params = args.params || [];
|
||||
return probe().then(function () { return rpc(method, params); }).then(function (j) {
|
||||
if (j && j.pending) return wait(j.pending);
|
||||
return settle(j);
|
||||
}).then(function (result) {
|
||||
if (method === 'eth_requestAccounts' || method === 'eth_accounts') { provider.selectedAddress = Array.isArray(result) && result.length ? result[0] : null; }
|
||||
if (method === 'eth_chainId' && typeof result === 'string') provider.chainId = result;
|
||||
return result;
|
||||
});
|
||||
},
|
||||
on: function (ev, f) { (listeners[ev] = listeners[ev] || []).push(f); return provider; },
|
||||
removeListener: function (ev, f) { listeners[ev] = (listeners[ev] || []).filter(function (g) { return g !== f; }); return provider; },
|
||||
// the poll behind accountsChanged and chainChanged (tests call it directly)
|
||||
_tick: function () {
|
||||
return (hello ? Promise.resolve() : probe()).then(function () { return rpc('eth_accounts', []); }).then(function (j) {
|
||||
var acc = (j && !j.error && Array.isArray(j.result)) ? j.result : [];
|
||||
var key = acc.join(',');
|
||||
if (lastAccounts !== '' || key !== '') { if (key !== lastAccounts) { lastAccounts = key; provider.selectedAddress = acc[0] || null; emit('accountsChanged', acc); } } else lastAccounts = key;
|
||||
return rpc('eth_chainId', []);
|
||||
}).then(function (j) {
|
||||
var c = j && !j.error && typeof j.result === 'string' ? j.result : '';
|
||||
if (c && lastChain && c !== lastChain) emit('chainChanged', c);
|
||||
if (c) { lastChain = c; provider.chainId = c; }
|
||||
}).catch(function () { });
|
||||
},
|
||||
// legacy shapes some libraries still call
|
||||
enable: function () { return provider.request({ method: 'eth_requestAccounts' }); },
|
||||
send: function (method, params) { return provider.request(typeof method === 'string' ? { method: method, params: params } : method); },
|
||||
sendAsync: function (payload, cb) { provider.request(payload).then(function (r) { cb(null, { id: payload.id, jsonrpc: '2.0', result: r }); }, function (e) { cb(e); }); }
|
||||
};
|
||||
var ICON = 'data:image/svg+xml;utf8,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100" rx="22" fill="#0C0C0E"/><path d="M50 10 L78 50 L50 90 L22 50 Z M50 36 L61 50 L50 64 L39 50 Z" fill="#F2541B" fill-rule="evenodd"/></svg>');
|
||||
var info = { uuid: 'c0b3a5a6-6b2e-4a0a-9d0e-igneumwallet1', name: 'Igneum Wallet', icon: ICON, rdns: 'network.igneum.wallet' };
|
||||
function announce() { try { win.dispatchEvent(new CustomEvent('eip6963:announceProvider', { detail: Object.freeze({ info: info, provider: provider }) })); } catch (e) { } }
|
||||
win.igneum = provider;
|
||||
if (!win.ethereum) win.ethereum = provider;
|
||||
announce();
|
||||
win.addEventListener('eip6963:requestProvider', announce);
|
||||
// the first probe tells the page whether the wallet is here; the tick keeps accountsChanged honest
|
||||
probe().then(function () { provider._tick(); }, function () { });
|
||||
win.setInterval(function () { if (hello) provider._tick(); else probe().catch(function () { }); }, TICK_MS);
|
||||
})(typeof window !== 'undefined' ? window : this);
|
||||
90
site/wallet-provider.test.mjs
Normal file
90
site/wallet-provider.test.mjs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// node --test site/wallet-provider.test.mjs
|
||||
// The Igneum Wallet's page provider (site/wallet-provider.js): an EIP-1193 provider a page gets when the wallet runs on
|
||||
// the same machine (its page bridge on 127.0.0.1:26811). Known-failed first on 8 October 2026: the file did not exist,
|
||||
// so igneum.network/swap could connect only an injected wallet. The rules: a page that already has window.ethereum
|
||||
// keeps it (the Igneum provider is announced through EIP-6963 and sits at window.igneum); without one, the Igneum
|
||||
// provider is window.ethereum; a request while the wallet is not open rejects with 4900; a pending answer is polled
|
||||
// until the wallet decides; errors come back as {code, message}; accountsChanged and chainChanged fire from polling.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const src = readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'wallet-provider.js'), 'utf8');
|
||||
|
||||
function boot(opts = {}) {
|
||||
const calls = [];
|
||||
const win = { location: { origin: 'https://igneum.network' }, dispatched: [], listeners: {}, setTimeout: (f) => { f(); return 1; }, clearTimeout() {}, setInterval: () => 1, clearInterval() {} };
|
||||
win.addEventListener = (n, f) => { (win.listeners[n] = win.listeners[n] || []).push(f); };
|
||||
win.dispatchEvent = (e) => { win.dispatched.push(e); (win.listeners[e.type] || []).forEach((f) => f(e)); return true; };
|
||||
if (opts.existing) win.ethereum = opts.existing;
|
||||
const fetch = async (url, init) => {
|
||||
calls.push({ url, init });
|
||||
if (opts.down) throw new Error('connection refused');
|
||||
const body = init && init.body ? JSON.parse(init.body) : null;
|
||||
if (url.endsWith('/bridge/hello')) return { ok: true, json: async () => ({ ok: true, wallet: 'igneum', version: '0.1.6', chain_id: 4463, chain_id_hex: '0x116f', bridge: 1 }) };
|
||||
const r = opts.reply(body, calls.length);
|
||||
return { ok: true, json: async () => r };
|
||||
};
|
||||
const Event = class { constructor(type, init) { this.type = type; this.detail = init && init.detail; } };
|
||||
new Function('window', 'fetch', 'CustomEvent', 'Event', 'document', src)(win, fetch, Event, Event, { readyState: 'complete', addEventListener() {} });
|
||||
return { win, calls };
|
||||
}
|
||||
|
||||
test('without an injected wallet the Igneum provider is window.ethereum and is announced through EIP-6963', () => {
|
||||
const { win } = boot({ reply: () => ({ result: [] }) });
|
||||
assert.ok(win.ethereum && win.ethereum.isIgneum === true);
|
||||
assert.equal(win.igneum, win.ethereum);
|
||||
const ann = win.dispatched.filter((e) => e.type === 'eip6963:announceProvider');
|
||||
assert.equal(ann.length, 1);
|
||||
assert.equal(ann[0].detail.info.rdns, 'network.igneum.wallet');
|
||||
assert.equal(ann[0].detail.provider, win.ethereum);
|
||||
});
|
||||
test('an injected wallet keeps window.ethereum; the Igneum provider sits at window.igneum and is still announced', () => {
|
||||
const mm = { isMetaMask: true };
|
||||
const { win } = boot({ existing: mm, reply: () => ({ result: [] }) });
|
||||
assert.equal(win.ethereum, mm);
|
||||
assert.ok(win.igneum && win.igneum.isIgneum);
|
||||
assert.equal(win.dispatched.filter((e) => e.type === 'eip6963:announceProvider').length, 1);
|
||||
});
|
||||
test('a request while the wallet is not open rejects with 4900 and the words a person can act on', async () => {
|
||||
const { win } = boot({ down: true });
|
||||
await assert.rejects(win.igneum.request({ method: 'eth_requestAccounts' }), (e) => e.code === 4900 && /Igneum Wallet is not open/.test(e.message));
|
||||
});
|
||||
test('a direct result comes back; an error comes back as {code, message}; a pending answer is polled until decided', async () => {
|
||||
let polls = 0;
|
||||
const { win, calls } = boot({ reply: (body) => {
|
||||
if (body.method === 'eth_chainId') return { result: '0x116f' };
|
||||
if (body.method === 'eth_requestAccounts') return { pending: '1-ab' };
|
||||
if (body.method === 'igneum_poll') { polls++; return polls < 3 ? { pending: '1-ab' } : { result: ['0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826'] }; }
|
||||
if (body.method === 'wallet_switchEthereumChain') return { error: { code: 4902, message: 'one chain' } };
|
||||
return { result: null };
|
||||
} });
|
||||
assert.equal(await win.igneum.request({ method: 'eth_chainId' }), '0x116f');
|
||||
const acc = await win.igneum.request({ method: 'eth_requestAccounts' });
|
||||
assert.deepEqual(acc, ['0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826']);
|
||||
assert.equal(polls, 3);
|
||||
assert.equal(win.igneum.selectedAddress, '0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826');
|
||||
assert.equal(win.igneum.chainId, '0x116f');
|
||||
await assert.rejects(win.igneum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x1' }] }), (e) => e.code === 4902 && e.message === 'one chain');
|
||||
const rpc = calls.filter((c) => c.url.endsWith('/bridge/rpc'));
|
||||
assert.ok(rpc.every((c) => c.init.headers['X-Igneum-Bridge'] === '1' && c.init.method === 'POST'), 'every call carries the bridge header');
|
||||
assert.ok(rpc.every((c) => c.url.startsWith('http://127.0.0.1:26811/')), 'the fixed loopback port');
|
||||
});
|
||||
test('accountsChanged and chainChanged fire from the poll when they differ; on() and removeListener() work', async () => {
|
||||
let accounts = [];
|
||||
const { win } = boot({ reply: (body) => body.method === 'eth_accounts' ? { result: accounts } : body.method === 'eth_chainId' ? { result: '0x116f' } : { result: null } });
|
||||
const seen = [];
|
||||
const h = (a) => seen.push(a);
|
||||
win.igneum.on('accountsChanged', h);
|
||||
await win.igneum._tick();
|
||||
assert.deepEqual(seen, []);
|
||||
accounts = ['0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826'];
|
||||
await win.igneum._tick();
|
||||
assert.deepEqual(seen, [accounts]);
|
||||
win.igneum.removeListener('accountsChanged', h);
|
||||
accounts = [];
|
||||
await win.igneum._tick();
|
||||
assert.equal(seen.length, 1);
|
||||
});
|
||||
|
|
@ -96,6 +96,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -113,8 +114,6 @@
|
|||
<a href="/wallet" data-nav="wallet" aria-current="page"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -125,18 +124,30 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -148,8 +159,6 @@
|
|||
<a href="/wallet" data-nav="wallet" aria-current="page"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -158,15 +167,25 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income</b><span>What your card would mine, from the live network.</span></a>
|
||||
<a href="/economics" data-nav="economics"><b>Economics</b><span>The emission, the split and the fees, each with its line in the node.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -397,7 +416,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -412,6 +431,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ chain scene: a push paints with the document hidden and no animation frame (the
|
|||
chain scene: the live feed contract (the recorded reply validates; a rewritten miner, a float now, a stray key refused)
|
||||
chain scene parity: one recorded feed through the home fold, /live and the app's Inspect view on build-2, three frames each pixel-equal apart from the app's own-key overlay (a changed token fails first; skipped with no box and no Playwright; one retry)
|
||||
no text overlaps: every served page at 390 to 1600 px, light and dark, the hero at each step (self-test first; IGNEUM_OVERLAP_APPS=1 adds the miner and wallet UIs)
|
||||
explorer, emission and public stats unit tests
|
||||
explorer, emission, income calculator and public stats unit tests
|
||||
ship tool self-test
|
||||
relay unit tests
|
||||
miner app notice strip and update card tests
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const REQUIRED = {
|
|||
['G4', 'admin keys in consensus'],
|
||||
['X8', 'No listing is arranged, promised or sought by the project'],
|
||||
['X31', 'The public testnet is armed: three seed nodes and the public RPC are up, and it opens on the go word.'],
|
||||
['C2', '2019 (approximate)'],
|
||||
['C2', 'Monero has run on RandomX since November 2019'],
|
||||
['X34', 'was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026'],
|
||||
['X36', 'Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked.'],
|
||||
['X35', 'so the launch number is the class v4 row'],
|
||||
|
|
@ -61,7 +61,7 @@ const REQUIRED = {
|
|||
['G3', 'there is no team page'],
|
||||
['G4', 'no admin keys in consensus'],
|
||||
['G6', 'Pools can be bypassed on transaction choice'],
|
||||
['X34', 'About seven years without a shipped chip; the one announced, Bitmain'],
|
||||
['X34', 'About seven years with one shipped chip, Bitmain'],
|
||||
['C3', 'Chips arrived, as on Kaspa, whose hash was designed to welcome them'],
|
||||
['C3', 'Kaspa has run in production since 2021 (approximate)'],
|
||||
['C5', 'Inclusion is not confirmation on either chain'],
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ tree_checks() {
|
|||
run "chain scene: the live feed contract (the recorded reply validates; a rewritten miner, a float now, a stray key refused)" node --test tools/scene/feed-contract.test.mjs tools/scene/legend.test.mjs tools/scene/shard-words.test.mjs
|
||||
run "chain scene parity: one recorded feed through the home fold, /live and the app's Inspect view on build-2, three frames each pixel-equal apart from the app's own-key overlay (a changed token fails first; skipped with no box and no Playwright; one retry)" bash tools/ci/retry-once.sh scene-parity bash tools/scene/parity-remote.sh
|
||||
run "no text overlaps: every served page at 390 to 1600 px, light and dark, the hero at each step (self-test first; IGNEUM_OVERLAP_APPS=1 adds the miner and wallet UIs)" overlap_sweep
|
||||
run "explorer, emission and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/lib/money.test.mjs site/lib/leaderboard.test.mjs site/api/public-stats.test.mjs site/lib/proving-health.test.mjs
|
||||
run "explorer, emission, income calculator and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/lib/income-calc.test.mjs site/lib/money.test.mjs site/lib/leaderboard.test.mjs site/api/public-stats.test.mjs site/lib/proving-health.test.mjs
|
||||
run "ship tool self-test" node tools/ship-app.mjs --self-test
|
||||
run "relay unit tests" node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs relay/test/ember.test.mjs
|
||||
run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
// Every served page carries the slim bar (site-ui-5, the owner's rule of 7 October 2026: "easy access to all of our pages
|
||||
// without a header that is crazy"): the mark and wordmark, the three groups (Mine, Network, Learn) as buttons with their
|
||||
// without a header that is crazy"): the mark and wordmark, the four groups (Mine, Network, Learn, Build) as buttons with their
|
||||
// aria, the Download button, and every route of the site reachable from the group panels AND from the phone sheet, each with
|
||||
// its one-line description. A page with a shorter nav, a panel missing a route, or a route the panels do not name fails the
|
||||
// build and the gate. The route list below is the contract: a new page adds its line here and in site/partials/nav.html in
|
||||
|
|
@ -13,13 +13,14 @@ import { tmpdir } from 'node:os';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const GROUPS = {
|
||||
mine: ['/miner', '/download', '/app', '/wallet', '/miners', '/dev-fee', '/faucet', '/swap', '/metamask'],
|
||||
network: ['/live', '/explorer', '/journey', '/bench', '/evidence'],
|
||||
learn: ['/litepaper', '/income', '/ledger', '/claims', '/randomx', '/provenance'],
|
||||
mine: ['/miner', '/download', '/app', '/wallet', '/miners', '/dev-fee', '/metamask'],
|
||||
network: ['/live', '/explorer', '/journey', '/bench', '/evidence', '/light', '/receipt', '/oracle'],
|
||||
learn: ['/litepaper', '/income', '/economics', '/ledger', '/claims', '/randomx', '/provenance'],
|
||||
build: ['/build', '/faucet', '/swap', '/grants'], // the builder programme (8 October 2026): the developer entry page, the Devnet 3 faucet, the swap, the grants
|
||||
};
|
||||
const ROUTES = Object.values(GROUPS).flat();
|
||||
// pages served without their own panel entry: the explorer's two rewrites, the 404 and the unlinked scenes lab
|
||||
const UNLISTED = new Set(['block.html', 'address.html', '404.html', 'scenes.html']);
|
||||
// pages served without their own panel entry: the explorer's three rewrites (block, address, tx), its proving view, the 404 and the unlinked scenes lab
|
||||
const UNLISTED = new Set(['block.html', 'address.html', 'tx.html', 'proving.html', '404.html', 'scenes.html']);
|
||||
|
||||
export function check(site) {
|
||||
const pages = readdirSync(site).filter(f => f.endsWith('.html'));
|
||||
|
|
@ -74,5 +75,5 @@ if (args[0] === '--self-test') {
|
|||
const site = args[0] || join(here, '..', '..', 'site');
|
||||
const { pages, bad } = check(site);
|
||||
if (bad.length) { console.error('site nav check: ' + bad.length + ' problems\n' + bad.join('\n')); process.exit(1); }
|
||||
console.log(`site nav check: ${pages} pages carry the slim bar: the mark, three groups with ${ROUTES.length} routes in the panels and the sheet, Download, the burger`);
|
||||
console.log(`site nav check: ${pages} pages carry the slim bar: the mark, four groups with ${ROUTES.length} routes in the panels and the sheet, Download, the burger`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ const html = `<!doctype html>
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Mining income per tier</title>
|
||||
<meta name="description" content="What one card, a rig and a pool user mine on Igneum: IGN a day at three network sizes from measured cards, and the electricity a day at three tariffs. Labels on every number, no price of IGN.">
|
||||
<title>Igneum income: what your card would mine</title>
|
||||
<meta name="description" content="Pick a card, set your electricity price and read IGN a day from the live network; type a price for IGN to see money a day at that price. Devnet and testnet IGN have no value.">
|
||||
<link rel="canonical" href="https://igneum.network/income">
|
||||
<!-- head:start -->
|
||||
<!-- head:end -->
|
||||
|
|
@ -32,12 +32,21 @@ const html = `<!doctype html>
|
|||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero"><div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Income per tier</span></div>
|
||||
<h1>What a card mines, by tier.</h1>
|
||||
<p class="lead">One 8, 12, 16, 24 or 32 GB card, a rig and a pool user: IGN a day at three network sizes from measured cards, and the electricity a day at three tariffs. Every number carries its label. No price of IGN appears here: nobody sells IGN and the project quotes none.</p>
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Income</span></div>
|
||||
<h1>What your card would mine.</h1>
|
||||
<p class="lead">Pick a card, set your electricity price, and read IGN a day from the live network. Type a price for IGN to see money a day at that price. Nobody sells IGN and the project quotes none: devnet and testnet IGN have no value, and the figure is arithmetic on the number you typed.</p>
|
||||
</div></section>
|
||||
<section class="section"><div class="container">
|
||||
<h2>The schedule the figures use</h2>
|
||||
<h2>The calculator</h2>
|
||||
<p>Every card is a measured row of the <a href="/miners">bench table</a>: stock rows as bought, tuned rows at a measured lock or an Ember Tune point, never mixed. The network’s hash rate and the newest block’s DAA score come from the observer every 15 s; the block reward is the chain’s own emission rule at that score (<a href="/economics">the economics page</a> has the rule with its source), and the miner’s share is 80 percent of a block. One block a second.</p>
|
||||
<div id="income-calc"><p>The calculator needs JavaScript. The tables below carry the same arithmetic at three network sizes.</p></div>
|
||||
<!-- income-data:start -->
|
||||
<!-- income-data:end -->
|
||||
<p class="note">A solo card’s expected income is its share of the network’s hash rate times 86,400 blocks a day times the block reward times 0.8; a pool user gets the same expected amount minus the pool’s fee, with the variance taken out. The electricity line is watts times 24 hours at your price; the money line is IGN a day at the price you typed, electricity taken off. Nothing here is a forecast.</p>
|
||||
</div></section>
|
||||
<section class="section"><div class="container">
|
||||
<h2>The schedule the tables below use</h2>
|
||||
<p>The tables below are the public testnet’s arithmetic from measured cards; the calculator above reads the live chain, which runs the spec 2.5 schedule the <a href="/economics">economics page</a> states.</p>
|
||||
${paras(sched)}
|
||||
${table(sched)}
|
||||
</div></section>
|
||||
|
|
@ -68,10 +77,12 @@ const html = `<!doctype html>
|
|||
</main>
|
||||
<!-- footer:start -->
|
||||
<!-- footer:end -->
|
||||
<script src="/money.js"></script>
|
||||
<script src="/income-calc.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
const out = join(root, 'site/income.html');
|
||||
// --check: the build decorates card names with the GPU marks; the words are what the document owns, so they are compared bare
|
||||
if (process.argv.includes('--check')) { let cur = ''; try { cur = readFileSync(out, 'utf8'); } catch (e) { } const main = (s) => { const m = /<main id="main">[\s\S]*?<\/main>/.exec(s); return (m ? m[0] : '').replace(/<span class="cardname">(?:<div class="badge[\s\S]*?<\/div>)([\s\S]*?)<\/span>/g, '$1'); }; if (main(cur) !== main(html)) { console.error('site/income.html is not the generator\'s output: node tools/launch/income-page.mjs'); process.exit(1); } console.log('income page: equals the document'); }
|
||||
if (process.argv.includes('--check')) { let cur = ''; try { cur = readFileSync(out, 'utf8'); } catch (e) { } const main = (s) => { const m = /<main id="main">[\s\S]*?<\/main>/.exec(s); return (m ? m[0] : '').replace(/<!-- income-data:start -->[\s\S]*?<!-- income-data:end -->/, '<!-- income-data -->').replace(/<span class="cardname">(?:<div class="badge[\s\S]*?<\/div>)([\s\S]*?)<\/span>/g, '$1'); }; if (main(cur) !== main(html)) { console.error('site/income.html is not the generator\'s output: node tools/launch/income-page.mjs'); process.exit(1); } console.log('income page: equals the document'); }
|
||||
else { writeFileSync(out, html); console.log('wrote site/income.html'); }
|
||||
|
|
|
|||
|
|
@ -118,3 +118,7 @@ Three readings the coordinator raised, reproduced read-only and answered:
|
|||
Under the null (independent residuals, n = 6 epochs) one pair reads r over 0.8 with p about 0.028 (t = 2.67 on 4 degrees of freedom) and over 0.9 with p about 0.007; chance 3-cliques per window are about C(m, 3) p^3: 0.09 at m = 30 ids, about 100 at m = 300. So the clique alone is never the alert; the candidate also needs a design flag on a member (chance per id: `nonce` about 0.002, `late_start` about 1e-6, `spread` unknown until the per-model baseline exists; the devnet's maximum excess is 5.2% against the 10% line) and 6 net windows. At n = 12 (`DETECTOR_WINDOW_EPOCHS=12`) p(r over 0.8) is about 0.001 and chance 3-cliques at m = 300 are about 0.005 per window: set 12 once the testnet has over 100 ids. The first week must add: (1) the excess spread per card model over 12 or more epochs (the devnet has three models over 6); (2) the nonce layout of third-party miners and pools (a stratum extranonce in the high word is honest and non-uniform, so until each software is baselined a `nonce` flag is evidence, not an alert); (3) bands for cards the project does not own, which needs the card model in the coinbase tag; (4) the `machine_group` count, to see what an 8-key card looks like at scale.
|
||||
|
||||
Consequences per tier: the detector costs a miner nothing (it runs on the observer; one `UPDATE` a minute, two epochs re-read a minute, two regexp scans of the intake every 30 minutes). A home card under 8 keys appears as a `machine_group`, never an alert by itself. A pool's key trips `band_high`, which is informational; a pool that publishes its card mix clears it. The alert's action is the signal of epoch-length.md section 11, whose cost per tier is that document's section 7.
|
||||
|
||||
## Explorer indexer (8 October 2026)
|
||||
|
||||
`tools/observer/explorer-indexer.mjs` runs beside the observer against the same node's EVM RPC and writes the EVM side the explorer needs: `<prefix>live_txs` (every transaction with its receipt, logs and the Igneum fee split), `<prefix>live_accounts` (balance, nonce, code, sent and received counts, miner flag), `<prefix>explorer_blocks` (number to hash, for the three-deep reorg re-read) and `<prefix>explorer_state` (progress, `igneum_getNodeInfo`). It never writes the observer's tables. Env: `DATABASE_URL`, `LIVE_TABLE_PREFIX` (default `dn3_`), `IGNEUM_EVM_RPC` (default `http://127.0.0.1:26850`), `EXPLORER_NETWORK` (default `igneum-devnet-3`; a node reporting another network is refused), `EXPLORER_RETAIN_HOURS` (168), `EXPLORER_BACKFILL` (0 = from the first block), `EXPLORER_BATCH` (25). `--once` runs one tick. Tests: `node --test tools/observer/explorer-indexer.test.mjs`. On build-1 it is the unit `igneum-explorer-dn3` (docs/plans/explorer.md section 8).
|
||||
|
|
|
|||
282
tools/observer/explorer-indexer.mjs
Normal file
282
tools/observer/explorer-indexer.mjs
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
// Igneum explorer indexer: the sibling of tools/observer/observer.mjs for the EVM side (8 October 2026, the explorer lane).
|
||||
// The observer writes every DAG block, the shard plans, the checkpoints and the certificates. This process reads the
|
||||
// execution layer of the same node (eth_getBlockByNumber with the transactions, eth_getBlockReceipts, eth_getBalance,
|
||||
// eth_getTransactionCount, eth_getCode, igneum_getNodeInfo) and writes what /tx/<hash>, /address/<addr> and the
|
||||
// transaction lists need. It never touches the observer's tables; it creates its own three next to them under the same
|
||||
// prefix, so one LIVE_TABLE_PREFIX names one chain on both sides. Node 22 or newer, no dependencies.
|
||||
//
|
||||
// node tools/observer/explorer-indexer.mjs run (env below)
|
||||
// node tools/observer/explorer-indexer.mjs --once one tick, then exit (the smoke run)
|
||||
//
|
||||
// Environment, every value optional:
|
||||
// DATABASE_URL Neon connection string (read from ~/.config/igneum/env when unset; never in the repo)
|
||||
// LIVE_TABLE_PREFIX table prefix, default dn3_ (Devnet 3, the same prefix the observer unit on the build box writes)
|
||||
// IGNEUM_EVM_RPC the node's execution JSON-RPC, default http://127.0.0.1:26850 (the Devnet 3 observer node's)
|
||||
// EXPLORER_NETWORK the network the node must report in igneum_getNodeInfo, default igneum-devnet-3; another name refuses
|
||||
// to index (8 October 2026, 10:09 UTC: a unit pointed at the first devnet's node for 26 s wrote 4,797 of
|
||||
// that chain's blocks into the dn3_ tables; the tables were wiped and re-filled)
|
||||
// EXPLORER_BACKFILL chain blocks to index behind the tip on an empty table, default 0 = from the first block
|
||||
// EXPLORER_RETAIN_HOURS hours of transactions kept, default 168 (7 days); older rows are deleted once an hour
|
||||
// EXPLORER_BATCH chain blocks per round while catching up, default 25
|
||||
// EXPLORER_TICK_MS the idle tick, default 2000
|
||||
//
|
||||
// Tables (created on start if missing; the prefix is written as T below):
|
||||
// T live_txs one row per EVM transaction: hash (0x), block_hash (the DAG block's hash, no 0x, as live_blocks), block_number, tx_index, from_addr, to_addr, value_wei,
|
||||
// nonce, gas, gas_price, gas_used, effective_gas_price, status, contract_address, input_bytes, selector,
|
||||
// logs_count, logs (jsonb), igneum (jsonb: the receipt's igneum section), tx_type, ts_ms, received_at
|
||||
// T live_accounts one row per address seen: balance_wei, nonce, code_bytes, is_contract, sent, received, first_seen_number,
|
||||
// last_seen_number, miner (mined a block in the observer's table), refreshed_at
|
||||
// T explorer_blocks one row per indexed chain block: number, hash, tx_count, gas_used, ts_ms, indexed_at (the reorg check
|
||||
// re-reads the newest three numbers every tick and re-indexes a number whose hash moved)
|
||||
// T explorer_state one row: indexed_number, tip_number, chain_id, node_info (igneum_getNodeInfo: params, digest, genesis),
|
||||
// txs_total, accounts_total, backlog, blocks_per_s, last_error, started_at, updated_at
|
||||
//
|
||||
// Reorgs: Devnet 3's rule is no reorg over depth 3 (release-0.3.22 gates), so three numbers are re-read each tick; a deeper
|
||||
// one shows as a block hash in live_txs that the observer's live_blocks no longer calls a chain block, which the API reports.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
|
||||
const ONCE = process.argv.includes('--once');
|
||||
const T = (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
const EVM = process.env.IGNEUM_EVM_RPC || 'http://127.0.0.1:26850';
|
||||
const BACKFILL = Math.max(0, Number(process.env.EXPLORER_BACKFILL) || 0);
|
||||
const NETWORK = process.env.EXPLORER_NETWORK || 'igneum-devnet-3';
|
||||
const RETAIN_H = Math.max(1, Number(process.env.EXPLORER_RETAIN_HOURS) || 168);
|
||||
const BATCH = Math.max(1, Math.min(100, Number(process.env.EXPLORER_BATCH) || 25));
|
||||
const TICK_MS = Math.max(500, Number(process.env.EXPLORER_TICK_MS) || 2000);
|
||||
const ACCOUNTS_PER_TICK = 20;
|
||||
const RPC_CONCURRENCY = 6;
|
||||
|
||||
// ---- pure helpers (tested by explorer-indexer.test.mjs) --------------------------------------------------------------
|
||||
export const hexInt = h => (h === null || h === undefined ? null : Number(BigInt(h)));
|
||||
export const hexBig = h => (h === null || h === undefined ? null : BigInt(h).toString());
|
||||
export const lower = a => (a ? String(a).toLowerCase() : null);
|
||||
|
||||
/** One live_txs row from the block's transaction object and its receipt (both as the node's JSON-RPC returns them). */
|
||||
export function txRow(tx, rc, block) {
|
||||
const input = String(tx.input || '0x');
|
||||
return {
|
||||
hash: lower(tx.hash), block_hash: lower(block.hash).replace(/^0x/, ''), block_number: hexInt(block.number), tx_index: hexInt(tx.transactionIndex) ?? 0,
|
||||
from_addr: lower(tx.from), to_addr: lower(tx.to), value_wei: hexBig(tx.value) || '0', nonce: hexInt(tx.nonce), gas: hexInt(tx.gas),
|
||||
gas_price: hexBig(tx.gasPrice ?? tx.maxFeePerGas) , gas_used: rc ? hexInt(rc.gasUsed) : null, effective_gas_price: rc ? hexBig(rc.effectiveGasPrice) : null,
|
||||
status: rc && rc.status !== undefined && rc.status !== null ? hexInt(rc.status) : null, contract_address: rc ? lower(rc.contractAddress) : null,
|
||||
input_bytes: Math.max(0, (input.length - 2) / 2), selector: input.length >= 10 ? input.slice(0, 10).toLowerCase() : null,
|
||||
logs_count: rc && rc.logs ? rc.logs.length : 0,
|
||||
logs: rc && rc.logs ? rc.logs.map(l => ({ i: hexInt(l.logIndex), address: lower(l.address), topics: l.topics || [], data: l.data || '0x' })) : [],
|
||||
igneum: rc && rc.igneum ? rc.igneum : null, tx_type: hexInt(tx.type) ?? 0, ts_ms: hexInt(block.timestamp) === null ? null : hexInt(block.timestamp) * 1000,
|
||||
};
|
||||
}
|
||||
|
||||
/** The addresses a block touches, each with why (sender, receiver, contract, miner). */
|
||||
export function touched(rows, block) {
|
||||
const m = new Map();
|
||||
const add = (a, kind) => { if (!a) return; const k = lower(a); if (!m.has(k)) m.set(k, new Set()); m.get(k).add(kind); };
|
||||
for (const r of rows) { add(r.from_addr, 'sender'); add(r.to_addr, 'receiver'); add(r.contract_address, 'contract'); }
|
||||
if (block && block.igneum && Array.isArray(block.igneum.rewards)) for (const r of block.igneum.rewards) add(r.miner, 'miner');
|
||||
if (block && block.miner) add(block.miner, 'miner');
|
||||
return m;
|
||||
}
|
||||
|
||||
// ---- Neon over HTTP, the same pattern as the observer ---------------------------------------------------------------
|
||||
function envFile() {
|
||||
try { return Object.fromEntries(readFileSync(`${homedir()}/.config/igneum/env`, 'utf8').split('\n').filter(l => /^[A-Z_]+=/.test(l)).map(l => { const i = l.indexOf('='); return [l.slice(0, i), l.slice(i + 1).replace(/^"|"$/g, '')]; })); } catch { return {}; }
|
||||
}
|
||||
function neon(url) {
|
||||
if (!url) throw new Error('DATABASE_URL is not set');
|
||||
const host = new URL(url).hostname.replace('-pooler', '');
|
||||
return async (query, params = []) => {
|
||||
const r = await fetch(`https://${host}/sql`, { method: 'POST', headers: { 'Neon-Connection-String': url, 'Content-Type': 'application/json' }, body: JSON.stringify({ query, params }), signal: AbortSignal.timeout(30000) });
|
||||
const j = await r.json();
|
||||
if (!r.ok) throw new Error(j.message || JSON.stringify(j));
|
||||
return j.rows || [];
|
||||
};
|
||||
}
|
||||
|
||||
// ---- JSON-RPC with a small concurrency cap ----------------------------------------------------------------------------
|
||||
let inFlight = 0; const waiters = [];
|
||||
async function rpc(method, params = []) {
|
||||
if (inFlight >= RPC_CONCURRENCY) await new Promise(r => waiters.push(r));
|
||||
inFlight++;
|
||||
try {
|
||||
const r = await fetch(EVM, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(15000) });
|
||||
const j = await r.json();
|
||||
if (j.error) throw new Error(`${method}: ${j.error.message || JSON.stringify(j.error)}`);
|
||||
return j.result;
|
||||
} finally { inFlight--; const w = waiters.shift(); if (w) w(); }
|
||||
}
|
||||
const hex = n => '0x' + Number(n).toString(16);
|
||||
|
||||
// ---- schema ----------------------------------------------------------------------------------------------------------
|
||||
async function schema(sql) {
|
||||
await sql(`CREATE TABLE IF NOT EXISTS ${T}live_txs (
|
||||
hash text PRIMARY KEY, block_hash text NOT NULL, block_number bigint NOT NULL, tx_index integer NOT NULL DEFAULT 0,
|
||||
from_addr text, to_addr text, value_wei text NOT NULL DEFAULT '0', nonce bigint, gas bigint, gas_price text, gas_used bigint,
|
||||
effective_gas_price text, status smallint, contract_address text, input_bytes integer NOT NULL DEFAULT 0, selector text,
|
||||
logs_count integer NOT NULL DEFAULT 0, logs jsonb NOT NULL DEFAULT '[]'::jsonb, igneum jsonb, tx_type smallint NOT NULL DEFAULT 0,
|
||||
ts_ms bigint, received_at timestamptz NOT NULL DEFAULT now())`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_txs_number ON ${T}live_txs (block_number DESC, tx_index)`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_txs_from ON ${T}live_txs (from_addr, block_number DESC)`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_txs_to ON ${T}live_txs (to_addr, block_number DESC)`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_txs_block ON ${T}live_txs (block_hash)`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_txs_ts ON ${T}live_txs (ts_ms)`);
|
||||
await sql(`CREATE TABLE IF NOT EXISTS ${T}live_accounts (
|
||||
address text PRIMARY KEY, balance_wei text, nonce bigint, code_bytes integer, is_contract boolean, sent integer NOT NULL DEFAULT 0,
|
||||
received integer NOT NULL DEFAULT 0, first_seen_number bigint, last_seen_number bigint, miner boolean NOT NULL DEFAULT false,
|
||||
refreshed_at timestamptz, updated_at timestamptz NOT NULL DEFAULT now())`);
|
||||
await sql(`CREATE INDEX IF NOT EXISTS ${T}live_accounts_seen ON ${T}live_accounts (last_seen_number DESC)`);
|
||||
await sql(`CREATE TABLE IF NOT EXISTS ${T}explorer_blocks (number bigint PRIMARY KEY, hash text NOT NULL, tx_count integer NOT NULL DEFAULT 0,
|
||||
gas_used bigint, ts_ms bigint, indexed_at timestamptz NOT NULL DEFAULT now())`);
|
||||
await sql(`CREATE TABLE IF NOT EXISTS ${T}explorer_state (id integer PRIMARY KEY, indexed_number bigint, tip_number bigint, chain_id integer,
|
||||
node_info jsonb, txs_total bigint, accounts_total bigint, backlog integer, blocks_per_s double precision, last_error text,
|
||||
rpc text, started_at timestamptz, updated_at timestamptz)`);
|
||||
await sql(`INSERT INTO ${T}explorer_state (id, started_at, updated_at, rpc) VALUES (1, now(), now(), $1) ON CONFLICT (id) DO UPDATE SET started_at = now(), rpc = $1`, [EVM]);
|
||||
}
|
||||
|
||||
// ---- the work ----------------------------------------------------------------------------------------------------------
|
||||
const log = (...a) => console.log(new Date().toISOString(), ...a);
|
||||
const accountQueue = new Map(); // address -> {kinds:Set, number}
|
||||
const contractKnown = new Map(); // address -> is_contract (code fetched once)
|
||||
let txsPerMin = 0, blocksPerMin = 0, accountsPerMin = 0, lastError = null;
|
||||
|
||||
async function indexNumbers(sql, numbers) {
|
||||
const blocks = await Promise.all(numbers.map(n => rpc('eth_getBlockByNumber', [hex(n), true])));
|
||||
const receipts = await Promise.all(numbers.map((n, i) => (blocks[i] && blocks[i].transactions && blocks[i].transactions.length ? rpc('eth_getBlockReceipts', [hex(n)]).catch(() => null) : Promise.resolve([]))));
|
||||
const rows = []; const blockRows = [];
|
||||
for (let i = 0; i < numbers.length; i++) {
|
||||
const b = blocks[i]; if (!b) continue;
|
||||
const byHash = new Map((receipts[i] || []).map(r => [lower(r.transactionHash), r]));
|
||||
const txs = (b.transactions || []).map(t => txRow(t, byHash.get(lower(t.hash)) || null, b));
|
||||
rows.push(...txs);
|
||||
blockRows.push({ number: hexInt(b.number), hash: lower(b.hash).replace(/^0x/, ''), tx_count: txs.length, gas_used: hexInt(b.gasUsed), ts_ms: hexInt(b.timestamp) * 1000 });
|
||||
for (const [a, kinds] of touched(txs, b)) { const q = accountQueue.get(a) || { kinds: new Set(), number: 0 }; for (const k of kinds) q.kinds.add(k); q.number = Math.max(q.number, hexInt(b.number)); accountQueue.set(a, q); }
|
||||
}
|
||||
// a number re-indexed after a reorg drops its old rows first
|
||||
await sql(`DELETE FROM ${T}live_txs WHERE block_number = ANY($1::bigint[])`, [numbers]);
|
||||
for (let off = 0; off < rows.length; off += 200) {
|
||||
const chunk = rows.slice(off, off + 200); const vals = []; const params = [];
|
||||
chunk.forEach((r, k) => {
|
||||
const base = k * 22;
|
||||
vals.push(`(${Array.from({ length: 22 }, (_, j) => '$' + (base + j + 1)).join(',')})`);
|
||||
params.push(r.hash, r.block_hash, r.block_number, r.tx_index, r.from_addr, r.to_addr, r.value_wei, r.nonce, r.gas, r.gas_price, r.gas_used, r.effective_gas_price, r.status, r.contract_address, r.input_bytes, r.selector, r.logs_count, JSON.stringify(r.logs), r.igneum ? JSON.stringify(r.igneum) : null, r.tx_type, r.ts_ms, new Date().toISOString());
|
||||
});
|
||||
await sql(`INSERT INTO ${T}live_txs (hash, block_hash, block_number, tx_index, from_addr, to_addr, value_wei, nonce, gas, gas_price, gas_used, effective_gas_price, status, contract_address, input_bytes, selector, logs_count, logs, igneum, tx_type, ts_ms, received_at)
|
||||
VALUES ${vals.join(',')} ON CONFLICT (hash) DO UPDATE SET block_hash = EXCLUDED.block_hash, block_number = EXCLUDED.block_number, tx_index = EXCLUDED.tx_index, gas_used = EXCLUDED.gas_used,
|
||||
effective_gas_price = EXCLUDED.effective_gas_price, status = EXCLUDED.status, contract_address = EXCLUDED.contract_address, logs_count = EXCLUDED.logs_count, logs = EXCLUDED.logs, igneum = EXCLUDED.igneum, ts_ms = EXCLUDED.ts_ms`, params);
|
||||
}
|
||||
if (blockRows.length) {
|
||||
const vals = []; const params = [];
|
||||
blockRows.forEach((b, k) => { vals.push(`($${k * 5 + 1},$${k * 5 + 2},$${k * 5 + 3},$${k * 5 + 4},$${k * 5 + 5})`); params.push(b.number, b.hash, b.tx_count, b.gas_used, b.ts_ms); });
|
||||
await sql(`INSERT INTO ${T}explorer_blocks (number, hash, tx_count, gas_used, ts_ms) VALUES ${vals.join(',')} ON CONFLICT (number) DO UPDATE SET hash = EXCLUDED.hash, tx_count = EXCLUDED.tx_count, gas_used = EXCLUDED.gas_used, ts_ms = EXCLUDED.ts_ms, indexed_at = now()`, params);
|
||||
}
|
||||
// sent and received counts and first/last seen, in one statement per batch
|
||||
const seen = new Map();
|
||||
for (const r of rows) {
|
||||
if (r.from_addr) { const s = seen.get(r.from_addr) || { sent: 0, received: 0, min: r.block_number, max: r.block_number }; s.sent++; s.min = Math.min(s.min, r.block_number); s.max = Math.max(s.max, r.block_number); seen.set(r.from_addr, s); }
|
||||
if (r.to_addr) { const s = seen.get(r.to_addr) || { sent: 0, received: 0, min: r.block_number, max: r.block_number }; s.received++; s.min = Math.min(s.min, r.block_number); s.max = Math.max(s.max, r.block_number); seen.set(r.to_addr, s); }
|
||||
}
|
||||
const ents = [...seen.entries()];
|
||||
for (let off = 0; off < ents.length; off += 300) {
|
||||
const chunk = ents.slice(off, off + 300); const vals = []; const params = [];
|
||||
chunk.forEach(([a, s], k) => { vals.push(`($${k * 5 + 1},$${k * 5 + 2},$${k * 5 + 3},$${k * 5 + 4},$${k * 5 + 5})`); params.push(a, s.sent, s.received, s.min, s.max); });
|
||||
await sql(`INSERT INTO ${T}live_accounts (address, sent, received, first_seen_number, last_seen_number) VALUES ${vals.join(',')}
|
||||
ON CONFLICT (address) DO UPDATE SET sent = ${T}live_accounts.sent + EXCLUDED.sent, received = ${T}live_accounts.received + EXCLUDED.received,
|
||||
first_seen_number = LEAST(${T}live_accounts.first_seen_number, EXCLUDED.first_seen_number), last_seen_number = GREATEST(${T}live_accounts.last_seen_number, EXCLUDED.last_seen_number), updated_at = now()`, params);
|
||||
}
|
||||
txsPerMin += rows.length; blocksPerMin += blockRows.length;
|
||||
return blockRows;
|
||||
}
|
||||
|
||||
async function refreshAccounts(sql, max) {
|
||||
if (!accountQueue.size) return 0;
|
||||
const picks = [...accountQueue.entries()].sort((a, b) => b[1].number - a[1].number).slice(0, max);
|
||||
for (const [a] of picks) accountQueue.delete(a);
|
||||
const reads = await Promise.all(picks.map(async ([a, q]) => {
|
||||
try {
|
||||
const [bal, nonce] = await Promise.all([rpc('eth_getBalance', [a, 'latest']), rpc('eth_getTransactionCount', [a, 'latest'])]);
|
||||
let code = contractKnown.get(a);
|
||||
if (code === undefined || q.kinds.has('contract')) { const c = await rpc('eth_getCode', [a, 'latest']); code = Math.max(0, (String(c || '0x').length - 2) / 2); contractKnown.set(a, code); }
|
||||
return { a, bal: hexBig(bal), nonce: hexInt(nonce), code, miner: q.kinds.has('miner') };
|
||||
} catch (e) { lastError = String(e.message || e).slice(0, 200); accountQueue.set(a, q); return null; }
|
||||
}));
|
||||
const ok = reads.filter(Boolean);
|
||||
if (ok.length) {
|
||||
const vals = []; const params = [];
|
||||
ok.forEach((r, k) => { vals.push(`($${k * 6 + 1},$${k * 6 + 2},$${k * 6 + 3},$${k * 6 + 4},$${k * 6 + 5},$${k * 6 + 6})`); params.push(r.a, r.bal, r.nonce, r.code, r.code > 0, r.miner); });
|
||||
await sql(`INSERT INTO ${T}live_accounts (address, balance_wei, nonce, code_bytes, is_contract, miner, refreshed_at) VALUES ${vals.map(v => v.replace(/\)$/, ', now())')).join(',')}
|
||||
ON CONFLICT (address) DO UPDATE SET balance_wei = EXCLUDED.balance_wei, nonce = EXCLUDED.nonce, code_bytes = EXCLUDED.code_bytes, is_contract = EXCLUDED.is_contract,
|
||||
miner = ${T}live_accounts.miner OR EXCLUDED.miner, refreshed_at = now(), updated_at = now()`, params);
|
||||
}
|
||||
accountsPerMin += ok.length;
|
||||
return ok.length;
|
||||
}
|
||||
|
||||
async function queueMiners(sql) {
|
||||
// the observer's miners of the last 10 minutes get a balance read every minute, so a miner page is never older than that
|
||||
const rows = await sql(`SELECT DISTINCT evm_miner AS a FROM ${T}live_blocks WHERE received_at > now() - interval '10 minutes' AND evm_miner IS NOT NULL`).catch(() => []);
|
||||
for (const r of rows) { const q = accountQueue.get(lower(r.a)) || { kinds: new Set(), number: 0 }; q.kinds.add('miner'); accountQueue.set(lower(r.a), q); }
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const env = envFile();
|
||||
const sql = neon(process.env.DATABASE_URL || env.DATABASE_URL);
|
||||
await schema(sql);
|
||||
for (const r of await sql(`SELECT address, code_bytes FROM ${T}live_accounts WHERE code_bytes IS NOT NULL`)) contractKnown.set(r.address, Number(r.code_bytes));
|
||||
const st = (await sql(`SELECT indexed_number FROM ${T}explorer_state WHERE id = 1`))[0] || {};
|
||||
let indexed = st.indexed_number === null || st.indexed_number === undefined ? null : Number(st.indexed_number);
|
||||
const chainId = hexInt(await rpc('eth_chainId'));
|
||||
const info0 = await rpc('igneum_getNodeInfo').catch(() => null);
|
||||
if (!info0 || info0.network !== NETWORK) throw new Error(`the node at ${EVM} reports network ${info0 ? info0.network : 'unknown'}, this indexer writes ${NETWORK} (EXPLORER_NETWORK); refusing to index`);
|
||||
log(`explorer indexer: prefix ${T}, rpc ${EVM} (${info0.network}, digest ${String(info0.digest).slice(0, 8)}), chain id ${chainId}, indexed ${indexed === null ? 'nothing yet' : indexed}, batch ${BATCH}, retain ${RETAIN_H} h`);
|
||||
let lastInfo = 0, lastMiners = 0, lastRetain = 0, lastLog = Date.now(), lastRate = Date.now(), rateBlocks = 0;
|
||||
for (;;) {
|
||||
const t0 = Date.now();
|
||||
try {
|
||||
const tip = hexInt(await rpc('eth_blockNumber'));
|
||||
if (indexed === null) { indexed = BACKFILL > 0 ? Math.max(-1, tip - BACKFILL) : -1; log(`starting at chain block ${indexed + 1}, tip ${tip}`); }
|
||||
// the reorg check: the newest three indexed numbers must still carry the hash we stored
|
||||
if (indexed >= 0) {
|
||||
const lo = Math.max(0, indexed - 2);
|
||||
const stored = await sql(`SELECT number, hash FROM ${T}explorer_blocks WHERE number BETWEEN $1 AND $2`, [lo, indexed]);
|
||||
const live = await Promise.all(stored.map(s => rpc('eth_getBlockByNumber', [hex(Number(s.number)), false]).catch(() => null)));
|
||||
const moved = stored.filter((s, i) => live[i] && lower(live[i].hash).replace(/^0x/, '') !== s.hash).map(s => Number(s.number));
|
||||
if (moved.length) { const from = Math.min(...moved); log(`reorg: chain block ${from} moved, re-indexing from it`); indexed = from - 1; }
|
||||
}
|
||||
const behind = tip - indexed;
|
||||
if (behind > 0) {
|
||||
const n = Math.min(BATCH, behind);
|
||||
const numbers = Array.from({ length: n }, (_, i) => indexed + 1 + i);
|
||||
await indexNumbers(sql, numbers);
|
||||
indexed += n; rateBlocks += n;
|
||||
}
|
||||
if (Date.now() - lastMiners > 60000) { await queueMiners(sql); lastMiners = Date.now(); }
|
||||
// while catching up, only the newest addresses are refreshed; the rest wait for the tip
|
||||
await refreshAccounts(sql, behind > BATCH ? 4 : ACCOUNTS_PER_TICK);
|
||||
let info = null;
|
||||
if (Date.now() - lastInfo > 300000) { info = await rpc('igneum_getNodeInfo').catch(() => null); lastInfo = Date.now(); if (info && info.network !== NETWORK) throw new Error(`the node now reports network ${info.network}, not ${NETWORK}; stopping`); }
|
||||
if (indexed > tip + 100) { log(`the node's tip ${tip} is behind the indexed number ${indexed}: a node that moved back; re-indexing from ${tip - 3}`); indexed = Math.max(-1, tip - 3); }
|
||||
if (Date.now() - lastRetain > 3600000) {
|
||||
const cut = Date.now() - RETAIN_H * 3600000;
|
||||
const d = await sql(`WITH d AS (DELETE FROM ${T}live_txs WHERE ts_ms < $1 RETURNING 1) SELECT count(*)::int AS n FROM d`, [cut]);
|
||||
await sql(`DELETE FROM ${T}explorer_blocks WHERE ts_ms < $1`, [cut]);
|
||||
if (d[0] && d[0].n) log(`retention: ${d[0].n} transactions older than ${RETAIN_H} h removed`);
|
||||
lastRetain = Date.now();
|
||||
}
|
||||
const dt = (Date.now() - lastRate) / 1000; let bps = null; if (dt >= 10) { bps = rateBlocks / dt; rateBlocks = 0; lastRate = Date.now(); }
|
||||
await sql(`UPDATE ${T}explorer_state SET indexed_number = $1, tip_number = $2, chain_id = $3, backlog = $4, blocks_per_s = COALESCE($5, blocks_per_s), last_error = $6, updated_at = now(),
|
||||
node_info = COALESCE($7::jsonb, node_info), txs_total = CASE WHEN $8 THEN (SELECT count(*) FROM ${T}live_txs) ELSE txs_total END,
|
||||
accounts_total = CASE WHEN $8 THEN (SELECT count(*) FROM ${T}live_accounts) ELSE accounts_total END WHERE id = 1`,
|
||||
[indexed, tip, chainId, Math.max(0, tip - indexed), bps, lastError, info ? JSON.stringify(info) : null, Date.now() - lastLog > 60000 || ONCE]);
|
||||
if (Date.now() - lastLog > 60000) { log(`indexed ${indexed} of tip ${tip} (behind ${tip - indexed}); last minute: ${blocksPerMin} blocks, ${txsPerMin} txs, ${accountsPerMin} account reads, queue ${accountQueue.size}${lastError ? `, last error: ${lastError}` : ''}`); txsPerMin = blocksPerMin = accountsPerMin = 0; lastError = null; lastLog = Date.now(); }
|
||||
if (ONCE) { log(`once: indexed ${indexed}, tip ${tip}`); return; }
|
||||
if (tip - indexed <= 0) await new Promise(r => setTimeout(r, Math.max(0, TICK_MS - (Date.now() - t0))));
|
||||
} catch (e) {
|
||||
lastError = String(e.message || e).slice(0, 200);
|
||||
log(`tick failed: ${lastError}`);
|
||||
if (ONCE) { process.exitCode = 1; return; }
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] && /explorer-indexer\.mjs$/.test(process.argv[1])) main().catch(e => { console.error(e); process.exit(1); });
|
||||
38
tools/observer/explorer-indexer.test.mjs
Normal file
38
tools/observer/explorer-indexer.test.mjs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// The explorer indexer's pure parts: a transaction row from the node's JSON, the touched-address set, the hex helpers.
|
||||
// node --test tools/observer/explorer-indexer.test.mjs
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { txRow, touched, hexInt, hexBig } from './explorer-indexer.mjs';
|
||||
|
||||
const block = { hash: '0xE61CFFB1D306AD8D3F4F9FEC6D750100517572F54A14A82B40EBFD393531320A', number: '0x654d', timestamp: '0x6acd', miner: '0x8DB0505bbb03dffb58875897eeedc4e790a68d18', igneum: { rewards: [{ miner: '0x78fb14e43d3170dcf9abfdc70f15685c8ea31678', wei: '0x1' }] } };
|
||||
const tx = { hash: '0x4E7C2A9D54208B70A557184CB35E5847CDA4E90FFCA9578C6FC05B9C0DC4EF25', from: '0xE617a7f966fc009934e943fe0453821ff0c8716f', to: '0x7fe2f74b45dd8f0a739c906817f197631fdeff85', value: '0x0', nonce: '0x1a', gas: '0x38936', gasPrice: '0x178411b200', input: '0xa9059cbb000000000000000000000000', transactionIndex: '0x3', type: '0x2' };
|
||||
const rc = { transactionHash: tx.hash, gasUsed: '0x6e5e', effectiveGasPrice: '0x178411b200', status: '0x1', contractAddress: null, logs: [{ logIndex: '0x0', address: '0x7FE2f74b45dd8f0a739c906817f197631fdeff85', topics: ['0xaa'], data: '0x01' }], igneum: { minerTip: '0x148eb7b4f000', pgasUsed: '0x56c' } };
|
||||
|
||||
test('hex helpers: null stays null, big values keep every digit', () => {
|
||||
assert.equal(hexInt(null), null); assert.equal(hexInt('0x654d'), 25933);
|
||||
assert.equal(hexBig('0x18c55612df9b9f9a3600'), '116977006436888600000000'); assert.equal(hexBig(undefined), null);
|
||||
});
|
||||
|
||||
test('txRow: lower-case addresses and hashes, numbers decoded, the receipt folded in, the selector and the log list', () => {
|
||||
const r = txRow(tx, rc, block);
|
||||
assert.equal(r.hash, tx.hash.toLowerCase()); assert.equal(r.block_hash, block.hash.toLowerCase().slice(2)); assert.equal(r.block_number, 25933); assert.equal(r.tx_index, 3);
|
||||
assert.equal(r.from_addr, '0xe617a7f966fc009934e943fe0453821ff0c8716f'); assert.equal(r.to_addr, '0x7fe2f74b45dd8f0a739c906817f197631fdeff85');
|
||||
assert.equal(r.value_wei, '0'); assert.equal(r.nonce, 26); assert.equal(r.gas, 231734); assert.equal(r.gas_used, 28254); assert.equal(r.status, 1);
|
||||
assert.equal(r.selector, '0xa9059cbb'); assert.equal(r.input_bytes, 16); assert.equal(r.logs_count, 1); assert.equal(r.logs[0].address, '0x7fe2f74b45dd8f0a739c906817f197631fdeff85');
|
||||
assert.equal(r.igneum.minerTip, '0x148eb7b4f000'); assert.equal(r.tx_type, 2); assert.equal(r.ts_ms, 0x6acd * 1000);
|
||||
});
|
||||
|
||||
test('txRow without a receipt: the receipt fields are null, nothing throws', () => {
|
||||
const r = txRow({ ...tx, input: '0x', to: null }, null, block);
|
||||
assert.equal(r.gas_used, null); assert.equal(r.status, null); assert.equal(r.selector, null); assert.equal(r.to_addr, null); assert.deepEqual(r.logs, []); assert.equal(r.igneum, null);
|
||||
});
|
||||
|
||||
test('touched: senders, receivers, the created contract and the rewarded miners, each lower case with its reasons', () => {
|
||||
const rows = [txRow(tx, { ...rc, contractAddress: '0xABCDEF0000000000000000000000000000000001' }, block)];
|
||||
const m = touched(rows, block);
|
||||
assert.deepEqual([...m.get('0xe617a7f966fc009934e943fe0453821ff0c8716f')], ['sender']);
|
||||
assert.deepEqual([...m.get('0x7fe2f74b45dd8f0a739c906817f197631fdeff85')], ['receiver']);
|
||||
assert.deepEqual([...m.get('0xabcdef0000000000000000000000000000000001')], ['contract']);
|
||||
assert.deepEqual([...m.get('0x78fb14e43d3170dcf9abfdc70f15685c8ea31678')], ['miner']);
|
||||
assert.deepEqual([...m.get('0x8db0505bbb03dffb58875897eeedc4e790a68d18')], ['miner']);
|
||||
});
|
||||
1
tools/reference-apps/fixtures/dn3-balance.json
Normal file
1
tools/reference-apps/fixtures/dn3-balance.json
Normal file
File diff suppressed because one or more lines are too long
1
tools/reference-apps/fixtures/dn3-checkpoint.json
Normal file
1
tools/reference-apps/fixtures/dn3-checkpoint.json
Normal file
File diff suppressed because one or more lines are too long
1
tools/reference-apps/fixtures/dn3-receipt.json
Normal file
1
tools/reference-apps/fixtures/dn3-receipt.json
Normal file
File diff suppressed because one or more lines are too long
1
tools/reference-apps/light-service/.gitignore
vendored
Normal file
1
tools/reference-apps/light-service/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
43
tools/reference-apps/light-service/package-lock.json
generated
Normal file
43
tools/reference-apps/light-service/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "igneum-light-service",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "igneum-light-service",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@noble/curves": "2.4.0",
|
||||
"@noble/hashes": "2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz",
|
||||
"integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
|
||||
"integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
tools/reference-apps/light-service/package.json
Normal file
8
tools/reference-apps/light-service/package.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "igneum-light-service",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Igneum reference apps: the read service behind rpc.devnet.igneum.network/light (runs on build-1)",
|
||||
"dependencies": { "@noble/curves": "2.4.0", "@noble/hashes": "2.4.0" }
|
||||
}
|
||||
276
tools/reference-apps/light-service/serve.mjs
Normal file
276
tools/reference-apps/light-service/serve.mjs
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
// Igneum reference apps, the read service (8 October 2026). Runs on build-1 at 127.0.0.1:26890 behind
|
||||
// https://rpc.devnet.igneum.network/light/ (the build-server lane's Caddy route, prefix stripped). GET only, CORS open,
|
||||
// answers JSON that a browser verifies by itself with site/lc/core.js: nothing here is a verdict, everything is data
|
||||
// the page recomputes. Reads a Devnet 3 node that executes (the exec JSON-RPC for records, receipts and eth_getProof;
|
||||
// the wRPC JSON websocket for block bodies and headers).
|
||||
//
|
||||
// /checkpoint the latest certified checkpoint (proxied from the site's /api/checkpoint?source=dn3)
|
||||
// /balance?address=0x..&checkpoint=<hash>&index=<n>
|
||||
// the newest paid segment record under that checkpoint, the carrier block's coinbase and
|
||||
// merkle path, the header path carrier..checkpoint, and eth_getProof at the record's block
|
||||
// /receipt?tx=0x..&checkpoint=<hash>&index=<n>
|
||||
// the raw transaction, its including block's merkle path, the header path to the checkpoint
|
||||
// /health
|
||||
//
|
||||
// Env: LIGHT_PORT (26890), EXEC_RPC (http://127.0.0.1:26881), WRPC (ws://127.0.0.1:28880), DATABASE_URL (the Devnet 3
|
||||
// observer's Neon string: /checkpoint reads the dn3_ rows directly), else CHECKPOINT_URL (the site's API). Zero npm dependencies beyond @noble/hashes
|
||||
// (blake2b, keccak) installed beside this file on the box.
|
||||
import { createServer } from 'node:http';
|
||||
import { blake2b } from '@noble/hashes/blake2.js';
|
||||
import { keccak_256 } from '@noble/hashes/sha3.js';
|
||||
import { coinbaseTxHash, merkleRoot, merklePath, hexToBytes, bytesToHex, segmentRecordsOf } from '../../../site/lc/core.js';
|
||||
import { readCheckpoint, earliestCheckpointAbove, neon } from '../../../site/api/checkpoint.mjs';
|
||||
|
||||
const PORT = Number(process.env.LIGHT_PORT || 26890);
|
||||
const EXEC = process.env.EXEC_RPC || 'http://127.0.0.1:26881';
|
||||
const WRPC = process.env.WRPC || 'ws://127.0.0.1:28880';
|
||||
const CHECKPOINT_URL = process.env.CHECKPOINT_URL || 'https://igneum.network/api/checkpoint?source=dn3';
|
||||
const SEGMENT_BLOCKS = 8;
|
||||
const strip = s => String(s).replace(/^0x/i, '').toLowerCase();
|
||||
const log = (...a) => console.log(new Date().toISOString(), ...a);
|
||||
|
||||
// ---- the exec JSON-RPC -------------------------------------------------------------------------------------------
|
||||
async function exec(method, params) {
|
||||
const r = await fetch(EXEC, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(20000) });
|
||||
const j = await r.json();
|
||||
if (j.error) throw new Error(`${method}: ${j.error.message || JSON.stringify(j.error)}`);
|
||||
return j.result;
|
||||
}
|
||||
|
||||
// ---- the wRPC JSON websocket, one connection, reopened on loss; u64 nonces kept as strings ---------------------------
|
||||
let ws = null, wsOpen = null, nextId = 1; const pending = new Map();
|
||||
function wrpcConnect() {
|
||||
if (wsOpen) return wsOpen;
|
||||
wsOpen = new Promise((resolve, reject) => {
|
||||
const s = new WebSocket(WRPC);
|
||||
s.addEventListener('open', () => { ws = s; resolve(s); });
|
||||
s.addEventListener('error', e => { wsOpen = null; reject(new Error('wrpc: ' + (e.message || 'socket error'))); });
|
||||
s.addEventListener('close', () => { ws = null; wsOpen = null; for (const [, p] of pending) p.reject(new Error('wrpc: closed')); pending.clear(); });
|
||||
s.addEventListener('message', e => {
|
||||
let m; try { m = JSON.parse(String(e.data).replace(/"nonce":(\d+)/g, '"nonce":"$1"')); } catch { return; }
|
||||
const p = pending.get(m.id); if (!p) return; pending.delete(m.id);
|
||||
if (m.error) p.reject(new Error('wrpc ' + p.method + ': ' + (m.error.message || JSON.stringify(m.error)))); else p.resolve(m.params);
|
||||
});
|
||||
});
|
||||
return wsOpen;
|
||||
}
|
||||
async function wrpc(method, params) {
|
||||
const s = await wrpcConnect();
|
||||
const id = nextId++;
|
||||
return new Promise((resolve, reject) => {
|
||||
pending.set(id, { resolve, reject, method });
|
||||
s.send(JSON.stringify({ id, method, params }));
|
||||
setTimeout(() => { if (pending.has(id)) { pending.delete(id); reject(new Error('wrpc ' + method + ': timeout')); } }, 20000);
|
||||
});
|
||||
}
|
||||
|
||||
// ---- headers: the verifier's shape (site/verify/core.js headerHash), cached by hash ---------------------------------
|
||||
const headerCache = new Map();
|
||||
function shapeHeader(h) {
|
||||
return {
|
||||
hash: h.hash, version: h.version, parents_by_level: h.parentsByLevel, hash_merkle_root: h.hashMerkleRoot, accepted_id_merkle_root: h.acceptedIdMerkleRoot,
|
||||
utxo_commitment: h.utxoCommitment, timestamp: String(h.timestamp), bits: h.bits, nonce: String(h.nonce), daa_score: String(h.daaScore),
|
||||
blue_work: h.blueWork, blue_score: String(h.blueScore), pruning_point: h.pruningPoint, vote_key_hash: h.voteKeyHash,
|
||||
};
|
||||
}
|
||||
async function header(hash) {
|
||||
const k = strip(hash);
|
||||
if (headerCache.has(k)) return headerCache.get(k);
|
||||
const b = (await wrpc('getBlock', { hash: k, includeTransactions: false })).block;
|
||||
const h = shapeHeader(b.header);
|
||||
if (headerCache.size > 20000) headerCache.clear();
|
||||
headerCache.set(k, h);
|
||||
return h;
|
||||
}
|
||||
async function body(hash) {
|
||||
return (await wrpc('getBlock', { hash: strip(hash), includeTransactions: true })).block;
|
||||
}
|
||||
|
||||
// The header path from `from` (a block in the past of chain block `chainNumber`) up to the checkpoint (chain block
|
||||
// `cpNumber`): [from, ..., chain block chainNumber, ..., checkpoint]; every next header names the previous as a direct parent.
|
||||
async function headerPath(fromHash, chainNumber, cpNumber, cpHash) {
|
||||
const chainHashes = [];
|
||||
for (let n = chainNumber; n <= cpNumber; n++) {
|
||||
const b = await exec('eth_getBlockByNumber', ['0x' + n.toString(16), false]);
|
||||
if (!b) throw new Error(`chain block ${n} is not executed on this node`);
|
||||
chainHashes.push(strip(b.hash));
|
||||
}
|
||||
if (chainHashes[chainHashes.length - 1] !== strip(cpHash)) throw new Error(`chain block ${cpNumber} on this node is ${chainHashes[chainHashes.length - 1].slice(0, 12)}, not the certified checkpoint ${strip(cpHash).slice(0, 12)}`);
|
||||
// down from the chain block to `from` through direct parents (a merged block sits a few parents below)
|
||||
const start = chainHashes[0];
|
||||
let down = [];
|
||||
if (strip(fromHash) !== start) {
|
||||
const target = strip(fromHash);
|
||||
const prev = new Map([[start, null]]);
|
||||
let frontier = [start]; let found = false;
|
||||
for (let depth = 0; depth < 80 && frontier.length && !found; depth++) {
|
||||
const next = [];
|
||||
for (const h of frontier) {
|
||||
const hd = await header(h);
|
||||
for (const p of (hd.parents_by_level[0] || [])) {
|
||||
const ps = strip(p);
|
||||
if (prev.has(ps)) continue;
|
||||
prev.set(ps, h);
|
||||
if (ps === target) { found = true; break; }
|
||||
next.push(ps);
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
frontier = next;
|
||||
}
|
||||
if (!found) throw new Error(`block ${target.slice(0, 12)} is not within 80 parents below chain block ${chainNumber}`);
|
||||
for (let h = target; h !== null; h = prev.get(h)) down.push(h);
|
||||
down = down.slice(0, -1); // ends with the chain block, which chainHashes carries
|
||||
}
|
||||
const order = [...down, ...chainHashes];
|
||||
const out = [];
|
||||
for (const h of order) out.push(await header(h));
|
||||
for (let i = 1; i < out.length; i++) if (!(out[i].parents_by_level[0] || []).map(strip).includes(strip(out[i - 1].hash))) throw new Error(`header ${i} of the path does not name header ${i - 1} as a direct parent`);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ---- the checkpoint -----------------------------------------------------------------------------------------------
|
||||
async function checkpoint() {
|
||||
if (process.env.DATABASE_URL) {
|
||||
// the Devnet 3 observer's rows, read the way the site's /api/checkpoint reads them (DATABASE_URL from the box's observer env)
|
||||
const cp = await readCheckpoint(neon(), 'dn3');
|
||||
if (!cp) throw httpError(404, 'no certified Devnet 3 checkpoint stored yet');
|
||||
return { ok: true, now: new Date().toISOString(), ...cp };
|
||||
}
|
||||
const r = await fetch(CHECKPOINT_URL, { signal: AbortSignal.timeout(15000), cache: 'no-store' });
|
||||
const j = await r.json();
|
||||
if (!j.ok) throw new Error('checkpoint: ' + (j.error || r.status));
|
||||
return j;
|
||||
}
|
||||
async function chainNumberOf(hash) {
|
||||
const b = await exec('eth_getBlockByHash', ['0x' + strip(hash), false]);
|
||||
if (!b) throw new Error(`the checkpoint ${strip(hash).slice(0, 12)} is not an executed chain block on this node yet`);
|
||||
return Number(b.number);
|
||||
}
|
||||
|
||||
// ---- /balance -------------------------------------------------------------------------------------------------------
|
||||
async function balance(q) {
|
||||
const address = q.get('address') || '';
|
||||
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) throw httpError(400, 'address: 0x and 40 hex digits');
|
||||
const cpHash = q.get('checkpoint'), cpIndex = Number(q.get('index'));
|
||||
if (!cpHash || !(cpIndex >= 0)) throw httpError(400, 'checkpoint and index are required (from /api/checkpoint?source=dn3)');
|
||||
const cpNumber = await chainNumberOf(cpHash);
|
||||
// the newest paid segment record carried at or below the checkpoint
|
||||
let chosen = null;
|
||||
for (let first = Math.floor(cpNumber / SEGMENT_BLOCKS) * SEGMENT_BLOCKS, k = 0; first >= 0 && k < 400; first -= SEGMENT_BLOCKS, k++) {
|
||||
const s = await exec('igneum_getSegmentRecords', ['0x' + first.toString(16)]);
|
||||
if (!s || !s.paid) continue;
|
||||
const carrierNumber = Number(s.paid.carrierNumber);
|
||||
if (carrierNumber > cpNumber) continue;
|
||||
const c = (s.carried || []).find(x => x.valid && Number(x.carrierNumber) === carrierNumber && strip(x.keyHash) === strip(s.paid.keyHash));
|
||||
if (!c) continue;
|
||||
chosen = { first, last: Number(c.last), carrier: strip(c.carrier), carrierNumber, keyHash: c.keyHash, statement: c.statement, paidWei: s.paid.wei };
|
||||
break;
|
||||
}
|
||||
if (!chosen) throw httpError(503, `no paid segment record carried at or below chain block ${cpNumber} within 400 segments`);
|
||||
const carrier = await body(chosen.carrier);
|
||||
const coinbase = carrier.transactions[0];
|
||||
const evmHashes = (carrier.evmTransactions || []).map(raw => keccak_256(hexToBytes(strip(raw))));
|
||||
const leaves = [coinbaseTxHash(coinbase, blake2b), ...evmHashes];
|
||||
const root = bytesToHex(merkleRoot(leaves, blake2b));
|
||||
if (root !== strip(carrier.header.hashMerkleRoot)) throw httpError(500, `the carrier's body root recomputes to ${root.slice(0, 12)}, the header says ${strip(carrier.header.hashMerkleRoot).slice(0, 12)}: the serialisation here is wrong, not the chain`);
|
||||
const records = segmentRecordsOf(hexToBytes(strip(coinbase.payload)));
|
||||
const rec = records.find(r => Number(r.first) === chosen.first && Number(r.last) === chosen.last);
|
||||
if (!rec) throw httpError(500, `the carrier's coinbase holds ${records.length} segment record(s), none for segment ${chosen.first}`);
|
||||
// the smallest proof: the earliest certified checkpoint at or above the carrier (the certificate used travels in the answer)
|
||||
let certificate = null;
|
||||
if (process.env.DATABASE_URL) certificate = await earliestCheckpointAbove(neon(), chosen.carrierNumber, chainNumberOf).catch(() => null);
|
||||
let cpN = cpNumber, cpH = cpHash, cpI = cpIndex;
|
||||
if (certificate) { cpH = certificate.hash; cpI = Number(certificate.index); cpN = await chainNumberOf(cpH); }
|
||||
const headers = await headerPath(chosen.carrier, chosen.carrierNumber, cpN, cpH);
|
||||
const account = await exec('eth_getProof', [address, [], '0x' + chosen.last.toString(16)]);
|
||||
const chainId = await exec('eth_chainId', []);
|
||||
return {
|
||||
ok: true, now: new Date().toISOString(), chain_id: 'igneum-devnet-3', address,
|
||||
checkpoint: { hash: strip(cpH), index: cpI, chain_block: cpN },
|
||||
checkpoint_certificate: certificate ? { ok: true, ...certificate } : undefined,
|
||||
segment: { first: chosen.first, last: chosen.last, carrier: chosen.carrier, carrier_chain_block: chosen.carrierNumber, aggregator_key_hash: chosen.keyHash, paid_wei: chosen.paidWei, statement: chosen.statement },
|
||||
headers,
|
||||
carrier: { coinbase, evm_tx_hashes: evmHashes.map(bytesToHex), leaf_index: 0, merkle_siblings: siblings(leaves, 0), amount_wire_len: 8 },
|
||||
segment_record_hex: bytesToHex(rec.bytes),
|
||||
account: { ...account, evm_chain_id: Number(chainId) },
|
||||
};
|
||||
}
|
||||
function siblings(leaves, index) {
|
||||
// recompute the actual sibling hashes level by level (merklePath only gives the shape)
|
||||
const H = d => blake2b(d, { dkLen: 32, key: new TextEncoder().encode('MerkleBranchHash') });
|
||||
const Z = new Uint8Array(32); const out = []; let level = leaves.slice(); let i = index;
|
||||
while (level.length > 1) {
|
||||
out.push(bytesToHex(i % 2 === 0 ? (level[i + 1] || Z) : level[i - 1]));
|
||||
const next = []; for (let k = 0; k < level.length; k += 2) { const l = level[k], r = level[k + 1] || Z; const m = new Uint8Array(64); m.set(l); m.set(r, 32); next.push(H(m)); }
|
||||
level = next; i = i >> 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
void merklePath;
|
||||
|
||||
// ---- /receipt -------------------------------------------------------------------------------------------------------
|
||||
async function receipt(q) {
|
||||
const tx = q.get('tx') || '';
|
||||
if (!/^0x[0-9a-fA-F]{64}$/.test(tx)) throw httpError(400, 'tx: 0x and 64 hex digits');
|
||||
let cpHash = q.get('checkpoint'), cpIndex = Number(q.get('index'));
|
||||
if (!cpHash || !(cpIndex >= 0)) throw httpError(400, 'checkpoint and index are required (from /checkpoint)');
|
||||
const t = await exec('eth_getTransactionByHash', [tx]);
|
||||
if (!t) throw httpError(404, 'the node has not executed a transaction with that hash (unknown, or not yet in a block)');
|
||||
const rcpt = await exec('eth_getTransactionReceipt', [tx]);
|
||||
const chainNumber = Number(t.blockNumber);
|
||||
// the smallest proof: the earliest certified checkpoint at or above the block (from the Devnet 3 observer's rows), else
|
||||
// the checkpoint the caller named; the certificate used is returned so the page verifies against that one
|
||||
let certificate = null;
|
||||
if (process.env.DATABASE_URL) certificate = await earliestCheckpointAbove(neon(), chainNumber, chainNumberOf).catch(() => null);
|
||||
if (certificate) { cpHash = certificate.hash; cpIndex = Number(certificate.index); }
|
||||
const cpNumber = await chainNumberOf(cpHash);
|
||||
if (chainNumber > cpNumber) throw httpError(409, `not final yet: executed at chain block ${chainNumber}, the latest certified checkpoint is chain block ${cpNumber}; try again in about ${chainNumber - cpNumber + 30} s`);
|
||||
const including = strip(t.igneum.includingBlock);
|
||||
const b = await body(including);
|
||||
const raws = b.evmTransactions || [];
|
||||
const idx = raws.findIndex(raw => bytesToHex(keccak_256(hexToBytes(strip(raw)))) === strip(tx));
|
||||
if (idx < 0) throw httpError(500, 'the including block\'s body does not carry the transaction');
|
||||
const leaves = [coinbaseTxHash(b.transactions[0], blake2b), ...raws.map(raw => keccak_256(hexToBytes(strip(raw))))];
|
||||
const root = bytesToHex(merkleRoot(leaves, blake2b));
|
||||
if (root !== strip(b.header.hashMerkleRoot)) throw httpError(500, `the including block's body root recomputes to ${root.slice(0, 12)}, the header says ${strip(b.header.hashMerkleRoot).slice(0, 12)}`);
|
||||
const headers = await headerPath(including, chainNumber, cpNumber, cpHash);
|
||||
return {
|
||||
ok: true, now: new Date().toISOString(), chain_id: 'igneum-devnet-3', tx_hash: strip(tx), raw_tx_hex: strip(raws[idx]),
|
||||
checkpoint: { hash: strip(cpHash), index: cpIndex, chain_block: cpNumber, certificate: certificate ? { ok: true, ...certificate } : undefined },
|
||||
including_block: { header: headers[0], leaf_index: idx + 1, leaf_count: leaves.length, merkle_siblings: siblings(leaves, idx + 1) },
|
||||
headers,
|
||||
execution: rcpt ? { chain_block: chainNumber, chain_block_hash: strip(rcpt.blockHash), status: rcpt.status, gas_used: rcpt.gasUsed, from: rcpt.from, to: rcpt.to, contract_address: rcpt.contractAddress, logs: (rcpt.logs || []).length, effective_gas_price: rcpt.effectiveGasPrice, as_reported_by: 'the node (not proven here)' } : null,
|
||||
tx_as_reported: { from: t.from, to: t.to, value: t.value, nonce: t.nonce, type: t.type, chain_id: t.chainId },
|
||||
};
|
||||
}
|
||||
|
||||
// ---- the server -----------------------------------------------------------------------------------------------------
|
||||
function httpError(status, message) { const e = new Error(message); e.status = status; return e; }
|
||||
const server = createServer(async (req, res) => {
|
||||
const u = new URL(req.url || '/', 'http://x');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'content-type');
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
if (req.method === 'OPTIONS') { res.writeHead(204); return res.end(); }
|
||||
if (req.method !== 'GET') { res.writeHead(405, { 'content-type': 'application/json' }); return res.end('{"ok":false,"error":"GET only"}'); }
|
||||
const t0 = Date.now();
|
||||
try {
|
||||
let out;
|
||||
if (u.pathname === '/health') out = { ok: true, exec: EXEC, wrpc: WRPC, status: await exec('igneum_getExecStatus', []).catch(e => String(e.message)) };
|
||||
else if (u.pathname === '/checkpoint') out = await checkpoint();
|
||||
else if (u.pathname === '/balance') out = await balance(u.searchParams);
|
||||
else if (u.pathname === '/receipt') out = await receipt(u.searchParams);
|
||||
else throw httpError(404, 'no such endpoint: /checkpoint, /balance, /receipt, /health');
|
||||
res.writeHead(200, { 'content-type': 'application/json' });
|
||||
res.end(JSON.stringify(out));
|
||||
log(req.method, u.pathname, 200, Date.now() - t0, 'ms');
|
||||
} catch (e) {
|
||||
const status = e.status || 500;
|
||||
res.writeHead(status, { 'content-type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: String(e.message || e) }));
|
||||
log(req.method, u.pathname + u.search, status, Date.now() - t0, 'ms', String(e.message || e).slice(0, 200));
|
||||
}
|
||||
});
|
||||
server.listen(PORT, '127.0.0.1', () => log(`light service on 127.0.0.1:${PORT}, exec ${EXEC}, wrpc ${WRPC}`));
|
||||
64
tools/reference-apps/light-service/verify.test.mjs
Normal file
64
tools/reference-apps/light-service/verify.test.mjs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// The reference apps' checks against real Devnet 3 data: the genuine case verifies, every tampered case is refused.
|
||||
// Known-failed first. Runs under Node 22 with the two noble libraries installed beside this file (npm install here):
|
||||
// node verify.test.mjs [receipt.json] [balance.json] [checkpoint.json] default: ../fixtures/dn3-*.json
|
||||
// Exits 1 on the first case that does not behave. The same core.js runs in the browser pages and in the one-file
|
||||
// offline receipt verifier, so this is the test that proves their negative cases.
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { blake2b } from '@noble/hashes/blake2.js';
|
||||
import { keccak_256 } from '@noble/hashes/sha3.js';
|
||||
import { bls12_381 } from '@noble/curves/bls12-381.js';
|
||||
import { verifyReceipt, verifyBalance } from '../../../site/lc/core.js';
|
||||
|
||||
const deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
|
||||
const here = new URL('.', import.meta.url).pathname;
|
||||
const load = p => JSON.parse(readFileSync(p, 'utf8'));
|
||||
const clone = x => JSON.parse(JSON.stringify(x));
|
||||
const flipHex = (s, at) => { const h = s.replace(/^0x/, ''); const i = Math.min(at, h.length - 1); const d = (parseInt(h[i], 16) ^ 1).toString(16); return (s.startsWith('0x') ? '0x' : '') + h.slice(0, i) + d + h.slice(i + 1); };
|
||||
let failed = 0;
|
||||
function expect(name, result, want) {
|
||||
const ok = result.verified === want;
|
||||
const line = `${ok ? 'ok ' : 'FAIL'} ${want ? 'verifies' : 'refused '} ${name}${result.verified ? '' : ' :: ' + result.reason}`;
|
||||
console.log(line); if (!ok) failed++;
|
||||
}
|
||||
|
||||
const receiptPath = process.argv[2] || here + '../fixtures/dn3-receipt.json';
|
||||
const receipt = load(receiptPath);
|
||||
console.log(`receipt ${receipt.tx_hash.slice(0, 12)} on ${receipt.chain_id}, checkpoint ${receipt.checkpoint.index}, ${receipt.headers.length} headers`);
|
||||
// the known-failed cases first
|
||||
{ const d = clone(receipt); d.raw_tx_hex = flipHex(d.raw_tx_hex, 40); expect('raw transaction altered by one nibble', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); d.tx_hash = flipHex(d.tx_hash, 10); expect('transaction hash altered', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); d.including_block.leaf_index = d.including_block.leaf_index === 1 ? 2 : 1; expect('merkle leaf index moved', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); d.including_block.merkle_siblings[0] = flipHex(d.including_block.merkle_siblings[0], 3); expect('a merkle sibling altered', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); if (d.headers.length > 2) { d.headers.splice(Math.floor(d.headers.length / 2), 1); expect('a header removed from the path', verifyReceipt(d, deps), false); } }
|
||||
{ const d = clone(receipt); const h = d.headers[Math.floor(d.headers.length / 2)]; h.nonce = String(BigInt(h.nonce) ^ 1n); expect('a header nonce altered', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); d.headers[0].hash_merkle_root = flipHex(d.headers[0].hash_merkle_root, 5); expect('the including block\'s body root altered', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); const c = d.checkpoint.certificate; c.certificate.aggregate_signature_hex = flipHex(c.certificate.aggregate_signature_hex, 20); expect('certificate signature altered', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); d.checkpoint.hash = flipHex(d.checkpoint.hash, 60); expect('receipt points at another checkpoint than its certificate', verifyReceipt(d, deps), false); }
|
||||
{ const d = clone(receipt); const c = d.checkpoint.certificate; const bm = parseInt(c.certificate.bitmap_hex.slice(0, 2), 16); let p = 0; while (!(bm & (1 << p))) p++; c.certificate.bitmap_hex = (bm & ~(1 << p)).toString(16).padStart(2, '0') + c.certificate.bitmap_hex.slice(2); expect(`a signer dropped from the certificate bitmap (position ${p})`, verifyReceipt(d, deps), false); }
|
||||
// then the genuine one
|
||||
const r = verifyReceipt(receipt, deps);
|
||||
expect(`genuine receipt (${r.ms} ms)`, r, true);
|
||||
if (r.verified) console.log(` ${r.tx.type === 2 ? 'EIP-1559' : 'type ' + r.tx.type} tx to ${r.tx.to}, value ${r.tx.value} wei, in block ${r.block.slice(0, 12)} at DAA ${r.block_daa}, ${r.headers} headers to checkpoint ${r.checkpoint}`);
|
||||
|
||||
const balancePath = process.argv[3] || here + '../fixtures/dn3-balance.json';
|
||||
let balance = null; try { balance = load(balancePath); } catch { console.log('no balance fixture yet (' + balancePath + '), skipping the balance cases'); }
|
||||
if (balance) {
|
||||
const cp = balance.checkpoint_certificate || load(process.argv[4] || here + '../fixtures/dn3-checkpoint.json'); // the certificate the service answered with
|
||||
console.log(`balance of ${balance.address} at chain block ${balance.segment.last}, checkpoint ${balance.checkpoint.index}, ${balance.headers.length} headers`);
|
||||
{ const d = clone(balance); d.account.accountProof[d.account.accountProof.length - 1] = flipHex(d.account.accountProof[d.account.accountProof.length - 1], 30); expect('account proof: a node altered', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); d.account.balance = '0x' + (BigInt(d.account.balance) + 1n).toString(16); expect('reported balance raised by one wei', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); d.account.stateRoot = flipHex(d.account.stateRoot, 8); expect('state root altered', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); d.segment_record_hex = flipHex(d.segment_record_hex, 2 * (2 + 8 + 8 + 32 + 48 + 20 + 148) + 3); expect('post_root altered inside the segment record', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); d.segment_record_hex = flipHex(d.segment_record_hex, d.segment_record_hex.length - 10); expect('aggregator signature altered', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); d.carrier.coinbase.payload = flipHex(d.carrier.coinbase.payload, 30); expect('coinbase payload altered', verifyBalance(cp, d, deps), false); }
|
||||
{ const d = clone(balance); if (d.carrier.merkle_siblings.length) { d.carrier.merkle_siblings[0] = flipHex(d.carrier.merkle_siblings[0], 1); expect('a merkle sibling altered', verifyBalance(cp, d, deps), false); } else { d.carrier.merkle_siblings.push('00'.repeat(32)); expect('a merkle sibling added to a one-leaf body', verifyBalance(cp, d, deps), false); } }
|
||||
{ const d = clone(balance); if (d.headers.length > 2) { d.headers.splice(1, 1); expect('a header removed from the path', verifyBalance(cp, d, deps), false); } }
|
||||
{ const d = clone(balance); d.checkpoint.hash = flipHex(d.checkpoint.hash, 1); expect('proof names another checkpoint than the certificate', verifyBalance(cp, d, deps), false); }
|
||||
{ const c = clone(cp); c.certificate.aggregate_signature_hex = flipHex(c.certificate.aggregate_signature_hex, 20); expect('certificate signature altered', verifyBalance(c, balance, deps), false); }
|
||||
{ const d = clone(balance); d.address = '0x' + '11'.repeat(20); expect('another address with this proof', verifyBalance(cp, d, deps), false); }
|
||||
const b = verifyBalance(cp, balance, deps);
|
||||
expect(`genuine balance (${b.ms} ms)`, b, true);
|
||||
if (b.verified) { console.log(` ${b.balance_wei} wei at chain block ${b.block}, ${b.headers} headers, ${b.aggregator}`); for (const s of b.steps) console.log(' ' + (s.ok ? 'ok ' : 'no ') + s.name + ': ' + s.detail); }
|
||||
}
|
||||
console.log(failed ? `FAILED ${failed}` : 'RESULT every case behaved');
|
||||
process.exit(failed ? 1 : 0);
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue