Appearance
LootSkins (ERC-721)
The token contract. Each tokenId is a redeemable claim on one specific CS2 item held in custody. Address and explorer link: Deployments.
- Standards: ERC-721, ERC-2981 (royalty), ERC-165
name()LootFi Skins·symbol()LOOT- Upgradeable: UUPS proxy, owner-authorized
Token IDs
tokenId = (uint256(category) << 248) | sequenceThe top byte is the item category; the remaining 248 bits are a per-category sequence. Full layout, category ordinals and decode snippets: Token IDs.
solidity
function categoryOf(uint256 tokenId) external pure returns (uint8);A pure bit-shift — no storage read, no revert for a nonexistent token. Minting an id whose category byte is ≥ 8 reverts with InvalidCategory.
Functions anyone can call
deTokenize(uint256[] ids) payable
Burns your tokens and starts the return of the underlying skins.
solidity
function deTokenize(uint256[] calldata ids) external payable;- Direct owner only. An approved operator cannot burn on your behalf, by design — it guarantees the
Detokenizedevent'sowneris the true owner, which is who the physical item is returned to. - Maximum 50 ids per call (
MAX_BATCH). More reverts withBatchTooLarge. An empty array reverts withEmptyBatch. - Payment must be exact. The call requires
withdrawFee() * ids.length.
Excess payment is not refunded
deTokenize keeps whatever you send above the required fee. Always read withdrawFee() immediately before calling and send exactly fee × count. The fee is currently 0, so the correct value to send today is 0.
Burning the token is only half of a withdrawal — the physical return is a Steam trade offer you must accept. See Withdraw your skin and Withdrawal lifecycle.
Views
solidity
function withdrawFee() external view returns (uint256); // wei, per token
function baseURI() external view returns (string); // always ends in "/"
function isMinter(address account) external view returns (bool);
function tokenURI(uint256 tokenId) external view returns (string);
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external view returns (address receiver, uint256 amount);tokenURI is baseURI concatenated with the decimal tokenId, with no separator — which is why baseURI always ends in /. Read it on-chain rather than hardcoding a host; see Metadata format.
tokenURI reverts for a token that does not exist. That is also how you detect a burned token: ownerOf and tokenURI both revert, and the Detokenized event is the authoritative burn record.
Plus the full standard ERC-721 surface: ownerOf, balanceOf, approve, getApproved, setApprovalForAll, isApprovedForAll, transferFrom, safeTransferFrom, supportsInterface.
Not enumerable
LootSkins does not implement ERC-721Enumerable — there is no totalSupply() or tokenByIndex(). Enumerate the collection from Transfer logs starting at the deploy block instead. See Events & indexing.
Minter-gated functions
solidity
function mint(address to, uint256 tokenId) external;
function mintBatch(address to, uint256[] calldata tokenIds) external;Callable only by an address for which isMinter is true. The minter role is separate from ownership and separately transferable, so mint authority can move to a different key or a multisig without moving contract ownership. mintBatch is capped at 50 ids.
Events
solidity
event Detokenized(address indexed owner, uint256[] tokenIds);
event MinterUpdated(address indexed minter, bool allowed);
event BaseURIUpdated(string baseURI);
event WithdrawFeeUpdated(uint256 fee);
event FeesWithdrawn(address indexed to, uint256 amount);Plus standard Transfer, Approval and ApprovalForAll.
Detokenized.tokenIds is in the data field, not indexed
Indexing an array parameter stores only its hash, which would make the ids unrecoverable. They are deliberately non-indexed so any consumer can decode them. You cannot filter by a specific token id in that topic — decode the data.
Errors
| Error | When |
|---|---|
ZeroAddress() | An address argument was address(0) |
NotMinter() | Caller is not on the minter allow-list |
InvalidCategory(uint256 category) | tokenId's category byte is ≥ 8 |
BatchTooLarge(uint256 length) | More than 50 ids in one call |
EmptyBatch() | Zero ids passed |
NotOwner(uint256 tokenId) | Caller is not the direct owner of a token being burned |
InsufficientFee(uint256 required, uint256 provided) | Sent less than withdrawFee × count |
FeeTransferFailed() | Fee sweep to the recipient failed |
Decoding a raw revert selector: Errors.
Royalty
LootSkins implements ERC-2981. royaltyInfo currently reports 500 bps (5%).
ERC-2981 is advisory — the token contract does not enforce payment. LootFi's own marketplace reads it and pays the receiver on every fill; a third-party venue is free to ignore it. See Fees & royalties.
Owner functions
updateMinter, updateBaseURI, setWithdrawFee, setDefaultRoyalty, withdrawFees, and UUPS upgrade authorization. What each can and cannot do: Admin & upgrades.