Skip to content
Contract reference View as Markdown

SqueekTokenLink to this section

TL;DRLink to this section

  • SQK is a standard ERC-20 with EIP-2612 permit, 18 decimals and zero starting supply.
  • Only SqueekMining can mint, always to itself, and total supply can never exceed 2.1 billion SQK.
  • The token itself does not check for work; that rule lives in SqueekMining.

OverviewLink to this section

In active development

The Squeekchain contracts are in active development and are likely to change. Functions, events, errors, limits and behavior described here may change before a mainnet release, and the Sepolia deployment may be upgraded or replaced. Pin the ABI you integrate against, and re-verify the deployment before relying on it.

SqueekToken holds SQK balances and allowances. It has no owner, no burn, no pause and no upgrade path. mintForCheckpoint is the only way supply grows, and only the fixed SqueekMining proxy can call it.

Network Address Kind
Sepolia 0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76 Immutable; not a proxy

FunctionsLink to this section

PermissionlessLink to this section

Standard ERC-20 and EIP-2612Link to this section

function name() external view returns (string);                 // "Squeek"
function symbol() external view returns (string);               // "SQK"
function decimals() external view returns (uint8);              // 18
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function eip712Domain() external view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions);

These are OpenZeppelin 5.6.1's ERC20, ERC20Capped and ERC20Permit, unmodified. Amounts are SQK base units (10^-18 SQK). The permit domain is name Squeek, version 1, this chain and this token. A permit sets an allowance only; it does not authorize claims or merges.

ViewsLink to this section

capLink to this section

function cap() external view returns (uint256);

The lifetime supply cap in SQK base units: 2,100,000,000 × 10^18 on Sepolia, fixed at construction. SqueekMining refuses to bootstrap against any other cap.

miningLink to this section

function mining() external view returns (address);

The SqueekMining proxy: the only minter and the only mint recipient. Verify the deployment checks it.

AdminLink to this section

mintForCheckpointLink to this section

function mintForCheckpoint(uint64 throughRound, uint256 amount) external returns (uint256);

SqueekMining only. Mints amount SQK base units to SqueekMining and emits CheckpointMinted. A zero amount mints nothing but still emits the event.

Name Type Unit Meaning
throughRound uint64 round Last SqueekCore round the checkpoint processed; attribution only
amount uint256 SQK base units Amount to mint

Reverts with UnauthorizedMining for any other caller and ERC20ExceededCap when supply would pass the cap.

EventsLink to this section

event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event CheckpointMinted(uint64 indexed throughRound, uint256 amount, uint256 totalMinted);
event EIP712DomainChanged();
Event Emitted when
Transfer Any transfer; a mint is a Transfer from the zero address to SqueekMining
Approval approve, permit, or an allowance spent by transferFrom
CheckpointMinted Every checkpoint mint, including zero; totalMinted is supply afterwards
EIP712DomainChanged Declared by the inherited interface; never emitted, since the domain is fixed

ErrorsLink to this section

Error Cause Fix
UnauthorizedMining A caller other than SqueekMining tried to mint Only SqueekMining mints
ERC20ExceededCap(increasedSupply, cap) A mint would pass the cap SqueekMining clips issuance at the cap
ERC20InsufficientBalance(sender, balance, needed) Transfer larger than the balance Transfer less
ERC20InsufficientAllowance(spender, allowance, needed) transferFrom beyond the allowance Approve or permit more
ERC20InvalidSender(sender), ERC20InvalidReceiver(receiver), ERC20InvalidApprover(approver), ERC20InvalidSpender(spender) A zero address where one is not allowed Use a real address
ERC2612ExpiredSignature(deadline) Permit after its deadline Sign a new permit
ERC2612InvalidSigner(signer, owner), ECDSAInvalidSignature, ECDSAInvalidSignatureLength(length), ECDSAInvalidSignatureS(s) Permit not signed by owner over these fields, or malformed Sign with the owner's key for the current nonce
InvalidAccountNonce(account, currentNonce) Permit nonce already used Read nonces(owner) and sign again
InvalidMining, ERC20InvalidCap(cap) Invalid constructor arguments Setup only
InvalidShortString, StringTooLong(str) Inherited EIP-712 name or version encoding failure Setup only

Integrator patternsLink to this section

  • Use base units. Keep amounts as bigint base units and format with 18 decimals; never convert to number.
  • Count supply once. A checkpoint mint emits both CheckpointMinted and a Transfer; count one.
  • Supply equals what SqueekMining funded. totalSupply() equals SqueekMining state().minted, whether or not owners have claimed. Unclaimed SQK sits in SqueekMining's balance.
  • Do not infer work from the token. The cap limits supply, but the work-backed issuance rule lives in SqueekMining's code, which governance can upgrade.
  • Treat it as a plain ERC-20 otherwise. There are no transfer hooks, fees, pauses or blocklists.

Usage exampleLink to this section

Check that SQK supply matches what SqueekMining has funded and what it still holds for owners.

// sqk-supply.ts
import { formatUnits, parseAbi } from "viem";
import { blockNumber, client } from "./setup";
import { verifyGraph } from "./verify";

const { mining, token } = await verifyGraph();
const tokenAbi = parseAbi([
  "function totalSupply() view returns (uint256)",
  "function cap() view returns (uint256)",
  "function balanceOf(address account) view returns (uint256)",
]);
const miningAbi = parseAbi([
  "function state() view returns ((uint256 minted, uint256 paid, uint256 totalWeight, uint256 rewardIndex, uint64 closedThroughBlock, uint64 lastActivationRound, uint256 weightActivationCursor, uint256 weightActivationCount, bool bootstrapped, uint64 processedThroughRound, uint64 closedCumulativeWork, uint96 closedCumulativeBlockUnits, uint32 closedWorkPerThousandBlocks))",
]);
const read = { address: token, abi: tokenAbi, blockNumber } as const;
const [supply, cap, held, state] = await Promise.all([
  client.readContract({ ...read, functionName: "totalSupply" }),
  client.readContract({ ...read, functionName: "cap" }),
  client.readContract({ ...read, functionName: "balanceOf", args: [mining] }),
  client.readContract({ address: mining, abi: miningAbi, functionName: "state", blockNumber }),
]);
if (supply !== state.minted) throw new Error("Supply differs from SqueekMining's funded total");
if (held < state.minted - state.paid) throw new Error("SqueekMining holds less than it owes");
console.log({
  supplySQK: formatUnits(supply, 18),
  remainingToCapSQK: formatUnits(cap - supply, 18),
  unclaimedSQK: formatUnits(state.minted - state.paid, 18),
});

ABILink to this section

SqueekToken.json. Any ERC-20 ABI also works for transfers and balances.