The Mint

Two immutable Ethereum contracts: ProofOfTime (tWARP) and TimeVault. At deploy, token supply is zero until gatherTWARP mints 1,000,000 tokens once. Only the TimeVault address may call mintTWARP, and only on the fixed 365-day stepped schedule—up to 500,000 additional tokens, hard-capped on-chain.

This is not an exploitable mint

There is no public mint function. No admin withdraw from the vault. Scheduled inflation runs in _accrueGlobal: the vault calls mintTWARP(address(this), …) and credits holders via rewardPerTokenStored (wallet balance weight). claim() only transfers your accrued share—it does not mint at claim time.

Supply model

ProofOfTime: GENESIS_SUPPLY = 1,000,000, MAX_SUPPLY = 1,500,000. TimeVault: VAULT_MINT_CAP = 500,000 over 365 days. Per-block rates are (405 ÷ 7,200), (809 ÷ 7,200), and (1,618 ÷ 7,200) tokens per block in phases 1–3 (~405 / ~809 / ~1,618 tokens per day). Integer math lands just under 500k; the final accrual when relBlock ≥ 2,628,000 tops up to exactly 500,000.

Who can mint?

On-chain source (excerpts)

Copied from contracts/src/ProofOfTime.sol and TimeVault.sol (Solidity 0.8.24). Verify on Etherscan after deploy or read the repo files directly.

One-time genesis mint (1M) to deployer.
ProofOfTime.sol
function gatherTWARP() external {
    require(!genesisMinted, "gathered");
    genesisMinted = true;
    _mint(msg.sender, GENESIS_SUPPLY);
}
Only TimeVault may call mintTWARP after setMintManager.
ProofOfTime.sol
function mintTWARP(address to, uint256 amount) external {
    require(msg.sender == mintManager, "manager");
    require(totalSupply() + amount <= MAX_SUPPLY, "cap");
    _mint(to, amount);
}
Stepped per-block rate by schedule phase.
TimeVault.sol
function _rateAtRelative(uint256 rel) internal pure returns (uint256) {
    if (rel >= PHASE2_BLOCKS) return RATE_P3_PER_BLOCK;
    if (rel >= PHASE1_BLOCKS) return RATE_P2_PER_BLOCK;
    return RATE_P1_PER_BLOCK;
}
Scheduled mint: mintTWARP(vault), split pro-rata to eligible wallet supply. If eligibleSupply == 0, mint deferred. Final window tops up to 500k.
TimeVault.sol
function _eligibleSupply() internal view returns (uint256) {
    uint256 supply = nativeToken.totalSupply();
    if (excludedPool != address(0)) {
        uint256 poolBal = nativeToken.balanceOf(excludedPool);
        if (poolBal >= supply) return 0;
        return supply - poolBal;
    }
    return supply;
}

// inside _accrueGlobal:
uint256 eligible = _eligibleSupply();
if (amount > 0 && eligible > 0) {
    nativeToken.mintTWARP(address(this), amount);
    rewardPerTokenStored += (amount * PRECISION) / eligible;
}
Rewards accrue to wallet balanceOf (LP pool excluded). claim() transfers accrued tokens minted to the vault—not a fresh mint on claim.
TimeVault.sol
function _settle(address account) internal {
    uint256 bal = _rewardBalance(account); // 0 for excludedPool
    uint256 paid = userRewardPerTokenPaid[account];
    uint256 rpt = rewardPerTokenStored;
    if (bal > 0 && rpt > paid) {
        rewards[account] += (bal * (rpt - paid)) / PRECISION;
    }
    userRewardPerTokenPaid[account] = rpt;
}

function claim() external {
    _accrueGlobal();
    _settle(msg.sender);
    uint256 amount = rewards[msg.sender];
    require(amount > 0, "nothing");
    rewards[msg.sender] = 0;
    nativeToken.transfer(msg.sender, amount);
}

What cannot happen

Rates & blocks (verifiable constants)

In TimeVault.sol: BLOCKS_PER_DAY = 7_200, PHASE1_BLOCKS = 100_800, PHASE2_BLOCKS = 756_000, SCHEDULE_BLOCKS = 2_628_000. View functions: getCurrentPhase(), getTokensPerBlock(), getTotalMinted(), getRemainingTokens(), getBlocksUntilHalvening(1|2).

Mechanism & numbers on Home

Audit surface

Inflation is limited to ProofOfTime.mintTWARP (caller = vault, cap checks) and TimeVault._accrueGlobal / _mintAmountForWindow / _tokensForElapsed, plus claim for holders.