mint, burn, burnFrom, pause, unpause, setEmissionCapcontracts/bitchicken-token.sol, contracts/interfaces/i-bitchicken-token.solemissionCap: mint reverte EmissionCapExceeded se totalMinted + amount > emissionCap.totalMinted e monotonicamente crescente — queimas nao o decrementam.MINTER_ROLE concedido apenas ao Staking (yield); revogado do deployer apos bootstrap. O NFT nao precisa do papel (indicacao paga em BNB; rename so usa burnFrom).PAUSER_ROLE pausa/despausa transferencias como kill-switch de emergencia.burnFrom (NFT chama para queimar BCKN no rename).setEmissionCap reverte CapBelowTotalMinted se novo cap < totalMinted.setEmissionCap antes de qualquer mint.registerEdition, setEditionActive, setEditionWindow (so owner do NFT)contracts/catalog-management.sol, contracts/bitchicken-nft.sol| Cada edicao tem: nome (1-64 bytes), artURI (IPFS), stats fixos (health/skill/morale > 0), rarity, maxSupply (0=ilimitado), janela de mint (mintStart/mintEnd), distribution (Gacha | DirectSale), pesos por tier (array de 10 uint16). |
active e janela de tempo podem ser alterados pos-registro.pickEdition(tier, randomWord): selecao ponderada cumulativa em memoria (O(n) leituras de storage); se a edicao sorteada estiver esgotada por corrida, avanca linearmente para a proxima elegivel.tierHasAvailable(tier): retorna true se ao menos uma edicao Gacha elegivel existe para o tier.maxSupply != 0 && minted >= maxSupply → EditionSoldOut.mintEnd <= mintStart (ambos != 0) → InvalidEditionWindow.InvalidEditionStats.totalWeight == 0 (nenhuma edicao elegivel) → NoAvailableEdition.updateTierPrices (so owner do NFT), tierPrice(index), getTierPrices()contracts/mint-tier-management.sol, contracts/bitchicken-nft.solupdateTierPrices substitui o array inteiro atomicamente.prices[0] == 0 ou prices[i] <= prices[i-1] → InvalidTierPrices(index, value).index >= 10 → TierOutOfRange(index).requestObtain(tier, referrerCode, name) payablecontracts/bitchicken-forge.soltierPrice(tier) BNB; contrato cria um ForgeRequest e chama s_vrfCoordinator.requestRandomWords.fulfillRandomWords) chama nft.pickEdition(tier, word) + nft.forgeMint(buyer, editionId, gender, name, referrerCode).uint8(word & 1).forgeMint (ex.: edicao esgotou por corrida), o BNB e enfileirado em pendingRefund[buyer] e totalPendingRefunds e incrementado.cancelStaleRequest.claimRefund (pull-payment, CEI).withdraw() — drena apenas balance - totalPendingRefunds.msg.value != tierPrice(tier) → IncorrectPayment.!nft.tierHasAvailable(tier) → NothingAvailable (verificado antes de gastar gas VRF).block.number < req.blockNumber + 256 → RequestNotStale.STALE_BLOCKS = 256, MIN_CALLBACK_GAS = 50_000, MAX_CALLBACK_GAS = 2_500_000.forgeMint(to, editionId, gender, name, referrerCode) — so o Forge autorizadocontracts/bitchicken-nft.soledition.minted, atribui dados per-token (editionId, gender, nome sanitizado), processa o vinculo de indicacao (retorna referrer/rateBps), chama _safeMint.tokenURI e puro-view: constroi JSON on-chain com stats da edicao + dados do token; retorna data:application/json;base64,.... Sem SSTORE de URI por token.rename(tokenId, newName): so o dono; queima renamePrice BCKN via burnFrom; nome sanitizado on-chain (alphanumerico ASCII + espaco, 1-24 chars).msg.sender != $.forge → CallerNotForge.whenNotPaused).InvalidName.rename: ownerOf(tokenId) != msg.sender → NotTokenOwner.registerReferrer(), setReferralLevels (owner) no NFT; claimReferralBnb() no Forge.contracts/referral-tree-management.sol, contracts/bitchicken-nft.sol, contracts/bitchicken-forge.solReferralLinked.paid * rateBps / 10000), paga uma vez (no vinculo).
forgeMint retorna (tokenId, referrer, rateBps); o Forge acumula em pendingReferralBnb[referrer].referredCount (indicados que abriram ≥1 ovo), avaliada
antes de contar o novo indicado. Tabela padrao [0,3,6,8,10] → [2%,4%,6%,8%,10%].claimReferralBnb() (CEI); withdraw() reserva o pool de indicacao.setReferralLevels; teto MAX_REFERRAL_BPS = 1000 (10%); thresholds[0]==0,
crescente, lengths iguais → senao InvalidLevels.pendingReferralBnb == 0 em claimReferralBnb → NothingToClaim.registerReferrer por endereco ja registrado → AlreadyRegistered.MINTER_ROLE (a recompensa e BNB, nao mint de BCKN).stakePair(maleId, femaleId), claim(pairId), claimRange(start, count), unstakePair(pairId)contracts/bitchicken-staking.solscore = Σ(wHealth*H + wSkill*S + wMorale*M) sobre os dois NFTs; rewardPerCycle = baseRate * score / SCALE.idealPairMultiplierBps aplicado (padrao 20000 = 2x).lastClaimAt avanca por multiplos exatos de CYCLE = 168h (sem drift).taxed = gross * claimBurnBps / 10000; porcao taxada nao e mintada (nao e queimada — apenas nao entra em circulacao). net = gross - taxed e mintado ao staker.unstakePair: auto-claim de ciclos inteiros pendentes antes de devolver NFTs.claimRange: pula pares com 0 ciclos (sem revert), processa os demais.genderBit do male != 0 ou do female != 1 → GendersNotComplementary.AlreadyStaked.claim com 0 ciclos → CycleNotElapsed(pairId, nextUnlock).claimRange com start >= total → RangeOutOfBounds.baseRate > MAX_BASE_RATE (1e27) → BaseRateTooHigh.weight > MAX_WEIGHT (1e36) → WeightTooHigh.claimBurnBps > 10000 → InvalidBasisPoints.onERC721Received → UnauthorizedNFT.baseRate = 1e17, weights = 1e18 cada, claimBurnBps = 500 (5%), idealPairMultiplierBps = 20000.list(tokenId, price), cancel(tokenId), obtain(tokenId) payable, proposeSwap(offeredId, wantedId) payable, cancelSwap(swapId), acceptSwap(swapId)contracts/bitchicken-marketplace.solobtain ser chamado.list exige aprovacao previa (falha-rapida: garante que o listing nao seja “morto”).obtain: split de receitas — platformFee → feeSink, royalty EIP-2981 → receiver, restante → vendedor; excesso de BNB devolvido ao comprador.offeredId + BNB opcional (bnbLeg travado no contrato) em troca de wantedId; aceitor chama acceptSwap; ambos NFTs trocam atomicamente; bnbLeg vai ao aceitor. Sem taxa de plataforma em swaps.cancelSwap devolve bnbLeg ao proposer.price == 0 → ZeroPrice.AlreadyListed.msg.value < price → InsufficientPayment.platformFee + royaltyAmt > price → FeesExceedPrice (evita underflow aritmetico).obtain → NotTokenOwner.obtain → NotApproved.platformFeeBps = 250 (2.5%).npm run deploy:<rede> / npm run upgrade:<rede>scripts/deploy.ts, scripts/upgrade.tssetForge, grantRole(MINTER_ROLE) só para Staking, setEmissionCap, updateTierPrices, registra 5 edicoes de exemplo, configura staking e a tabela de niveis da indicacao (setReferralLevels).upgradesApi.upgradeProxy com validacao de compatibilidade de storage..openzeppelin/{bsc,bsc-testnet}.json devem ser commitados.