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
bigintbase units and format with 18 decimals; never convert tonumber. - Count supply once. A checkpoint mint emits both
CheckpointMintedand aTransfer; count one. - Supply equals what SqueekMining funded.
totalSupply()equals SqueekMiningstate().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.