Hartii developer docs

HartiiLabs

Launch token

LaunchToken is cloned once per launch and is the ERC-20 every HartiiLabs token actually is. Source: contracts/contracts/LaunchToken.sol in the hartii-labs repo. Implementation contract live at 0x0059af4b7441e15E06e4686bd2f4CC5dfF5AAA0A — every launch's actual token is a clone at its own address.

Non-standard behavior an integrator must know

  • There is no mint() function anywhere in this contract's ABI. The full fixed supply is minted exactly once, atomically, inside initialize(). Supply can never be inflated after launch; totalSupply can only ever go down, via burn().
  • transfer/transferFrom are the plain textbook ERC-20 implementation — no fee-on-transfer, no blacklist, no pause, no owner-only transfer hook of any kind. A creator cannot quietly disable sells because there is no hook point in the contract to add one.
  • The only non-standard transfer behavior is the creator vesting gate below, which applies only to the creator address.

ERC-20 surface

FunctionSignatureNotes
name()string public nameSet once at initialize().
symbol()string public symbolSet once at initialize().
decimals()uint8 public constant decimalsAlways 18.
totalSupply()uint256 public totalSupplyFixed at mint; only decreases via burn().
balanceOf(address account)external view returns (uint256)Standard.
allowance(address owner_, address spender)external view returns (uint256)Standard.
approve(address spender, uint256 amount)external returns (bool)Standard; no increaseAllowance/decreaseAllowance helpers exist.
transfer(address to, uint256 amount)external returns (bool)Reverts "Zero to" (no burn-via-zero-address — use burn() instead), "Insufficient balance", and the creator vesting gate below if msg.sender == creator.
transferFrom(address from, address to, uint256 amount)external returns (bool)Same reverts as transfer, plus "Insufficient allowance". An allowance of type(uint256).max is treated as infinite and never decremented (standard gas-saving pattern).

burn()

solidity
function burn(uint256 amount) external

Any holder may destroy their own tokens: reduces their balance and totalSupply, emits Transfer(msg.sender, address(0), amount). Reverts "Insufficient balance" if the caller doesn't hold amount. If the caller is the creator, it is subject to the exact same vesting gate as a transfer ("Creator allocation still locked").

Creator vesting

Set once at initialize(), driven by the factory's creatorLockDuration setting at the time of that launch:

FieldMeaning
creator()The launch's creator address.
creatorAllocation()Total tokens allocated to the creator (the locked pool), minted directly to their balance at launch.
creatorClaimed()Unused bookkeeping field — vesting is enforced purely by the transfer gate below, not by a separate claim step.
lockedUntil()block.timestamp + creatorLockDuration at launch time. Before this timestamp, zero of the creator's allocation is transferable.
VESTING_DURATIONConstant, 7 days. Linear release window starting at lockedUntil.
unlockedCreatorAllocation()view — amount of the original allocation unlocked so far. 0 before lockedUntil; linear from 0 to creatorAllocation over the 7 days after; creatorAllocation (fully unlocked) once elapsed >= VESTING_DURATION.
solidity
function unlockedCreatorAllocation() public view returns (uint256) {
    if (block.timestamp < lockedUntil) return 0;
    uint256 elapsed = block.timestamp - lockedUntil;
    if (elapsed >= VESTING_DURATION) return creatorAllocation;
    return (creatorAllocation * elapsed) / VESTING_DURATION;
}

The transfer gate — applied inside _transfer (and inside burn()), on the creator address specifically, gated on the original allocation, not the creator's current balance (so it can't be bypassed by routing through another contract or by having already sold part of the position):

solidity
if (from == creator) {
    uint256 locked = unlockedCreatorAllocation() < creatorAllocation
        ? creatorAllocation - unlockedCreatorAllocation()
        : 0;
    require(fromBalance - amount >= locked, "Creator allocation still locked");
}

In plain terms: the creator can always move tokens down to their currently-locked remainder, never below it. With the live factory default creatorLockDuration = 0, the 7-day linear release starts immediately at launch.

Events

EventIndexed fieldsNon-indexed fieldsEmitted by
Transferfrom, tovalueinitialize() (the two initial mints, from address(0)), transfer, transferFrom, burn (to address(0))
Approvalowner, spendervalueapprove
CreatorAllocationClaimedcreatoramountDeclared in the ABI but never emitted anywhere in this contract's code — see Unverified below.

Provenance fields

FieldMeaning
factory()The TokenFactory that deployed and initialized this clone (msg.sender inside initialize()).
metadataHash()keccak256/CID-derived hash of the off-chain metadata JSON supplied at launch.
Quai Network mainnet · chain 9 · Cyprus-1. Figures marked "read on" a date were read from the chain that day; re-read before relying on them.