Bionttestnet
Address

octEudkn…v5ztmU

octEudkngDJEBb2LnRLDpt9Noqbber3fBvpvRhdVpv5ztmU
State
OCT balance
80OCT
wallet balance
Type
Contract
smart contract on chain
Chain-level
View on Octrascan · devnet
raw txs · nonce · pubkey
Pipoke (no profile)
this wallet has not registered a Pipoke profile
Contract
balance80 OCT
version1.0 Rehovot
code hashc3339e…548e98
History
live · 20s · last 0
Source · ABI · Bytecode
✓ verified
expand →
✓ verified
interface stxOwnable {
  fn owner(): address
  fn transfer_ownership(new_owner: address): bool
}

interface stxMetadata {
  fn name(): string
  fn symbol(): string
  fn collection_uri(): string
  fn token_uri(token_id: int): string
}

interface stxTransferable {
  fn transfer(to: address, token_id: int): bool
  fn transfer_from(from: address, to: address, token_id: int): bool
}

interface stxApprovable {
  fn approve(approved: address, token_id: int): bool
  fn set_approval_for_all(operator: address, approved: int): bool
  fn get_approved(token_id: int): address
  fn is_approved_for_all(owner_addr: address, operator: address): int
}

interface stxRoyalty {
  fn royalty_info(token_id: int, sale_price: int): (address, int)
}

interface stxEnumerable {
  fn total_supply(): int
  fn circulating_supply(): int
  fn balance_of(addr: address): int
  fn token_of_owner_by_index(owner_addr: address, index: int): int
  fn exists(token_id: int): int
}

interface stxBurnable {
  fn burn(token_id: int): bool
  fn burned_supply(): int
}

interface stxSoulbound {
  fn bind(token_id: int): bool
  fn is_soulbound(token_id: int): int
}

interface stxPausable {
  fn pause(): bool
  fn unpause(): bool
  fn is_paused(): int
}

interface stxMintable {
  fn max_supply(): int
  fn mint_price(): int
  fn mints_remaining(addr: address): int
  fn airdrop_remaining(): int
}

interface stxForgeable {
  fn forge(a: int, b: int, c: int, private_trait_ct: bytes): int
}

interface stxPrivateTrait {
  fn re_encrypt_trait(token_id: int, new_ct: bytes): bool
  fn has_private_trait(token_id: int): int
  fn private_trait_of(token_id: int): bytes
}

contract OHC721 implements
  stxOwnable, stxMetadata, stxTransferable, stxApprovable,
  stxRoyalty, stxEnumerable, stxBurnable, stxSoulbound,
  stxPausable, stxMintable, stxForgeable, stxPrivateTrait {

  const MAX_SUPPLY         = 888
  const MAX_PER_WALLET     = 5
  const AIRDROP_RESERVE    = 18
  const VAULT_THRESHOLD    = 188
  const VAULT_CONTRIBUTION = 10000000
  const MAX_ROYALTY        = 1000
  const ZERO_ADDRESS: address = "oct1111111111111111111111111111111111111111111"

  struct Token {
    owner:         address
    minted_epoch:  int
    seed:          int
    layer_tier:    int
    enhancement:   int
    soulbound:     int
    private_trait: bytes
  }

  state {
    contract_owner:     address
    royalty_recip:      address
    royalty_bps:        int
    name:               string
    symbol:             string
    base_uri:           string
    collection_uri:     string
    provenance_hash:    string
    provenance_locked:  int
    paused:             int
    mint_price:         int
    total_supply:       int
    burned_supply:      int
    airdrop_minted:     int
    forge_minted:       int
    tokens:             map[int]Token
    balances:           map[address]int
    owned_tokens:       map[address]map[int]int
    token_index:        map[int]int
    approvals:          map[int]address
    operator_approvals: map[address]map[address]int
    mint_count:         map[address]int
    vault_addr:         address
    proceeds:           int
  }

  event Minted(token_id: int, owner: address, layer_tier: int)
  event Airdropped(token_id: int, to: address, layer_tier: int)
  event Transferred(token_id: int, from: address, to: address)
  event Approved(token_id: int, approved: address)
  event ApprovalForAll(owner: address, operator: address, approved: int)
  event Burned(token_id: int, owner: address)
  event Forged(new_token_id: int, burned_a: int, burned_b: int, burned_c: int, owner: address)
  event Bound(token_id: int, owner: address)
  event Withdrawn(to: address, amount: int)
  event VaultForwarded(vault: address, amount: int, mint_index: int)
  event TraitReEncrypted(token_id: int, owner: address)
  event OwnershipTransferred(previous: address, new_owner: address)
  event Paused(by: address)
  event Unpaused(by: address)
  event MintPriceUpdated(old_price: int, new_price: int)
  event RoyaltyUpdated(recipient: address, bps: int)
  event ProvenanceLocked(hash: string)
  event CollectionURISet(uri: string)
  event BaseURISet(uri: string)

  error NotOwner(403, "caller is not the contract owner")
  error NotTokenOwner(403, "caller is not the token owner")
  error NotAuthorized(403, "not authorized")
  error ContractPaused(503, "contract is paused")
  error MaxSupplyReached(400, "collection is fully minted")
  error PublicSoldOut(400, "public supply is sold out")
  error AirdropExhausted(400, "airdrop quota exhausted")
  error TokenNotFound(404, "token does not exist")
  error TokenBurned(410, "token has been burned")
  error InvalidRoyalty(400, "royalty bps exceeds maximum")
  error SelfOperator(400, "operator cannot be caller")
  error InsufficientPayment(402, "insufficient payment")
  error WalletLimitReached(400, "wallet mint limit reached")
  error IsSoulbound(403, "token is soulbound")
  error AlreadySoulbound(400, "already soulbound")
  error DuplicateTokenIds(400, "forge requires three distinct token ids")
  error NoFHEKey(403, "no fhe key registered for caller")
  error ProvenanceAlreadyLocked(400, "provenance already locked")
  error NothingToWithdraw(400, "nothing to withdraw")
  error InvalidPrice(400, "price must be greater than zero")

  constructor(n: string, s: string, price: int) {
    self.contract_owner    = origin
    self.royalty_recip     = origin
    self.royalty_bps       = 500
    self.name              = n
    self.symbol            = s
    self.base_uri          = ""
    self.collection_uri    = ""
    self.provenance_hash   = ""
    self.provenance_locked = 0
    self.paused            = 0
    self.mint_price        = price
    self.total_supply      = 0
    self.burned_supply     = 0
    self.airdrop_minted    = 0
    self.forge_minted      = 0
    self.vault_addr        = ZERO_ADDRESS
    self.proceeds          = 0
  }

  private fn only_owner() {
    require(caller == self.contract_owner, "not owner")
  }

  private fn not_paused() {
    require(self.paused == 0, "contract paused")
  }

  private fn require_token(token_id: int) {
    require(token_id >= 0, "token not found")
    require(token_id < self.total_supply, "token not found")
    require(self.tokens[token_id].owner != ZERO_ADDRESS, "token burned")
  }

  private fn map_layer_tier(raw: int): int {
    if raw >= 884 { return 7 }
    if raw >= 871 { return 6 }
    if raw >= 835 { return 5 }
    if raw >= 764 { return 4 }
    if raw >= 649 { return 3 }
    if raw >= 489 { return 2 }
    if raw >= 267 { return 1 }
    return 0
  }

  private fn map_enhancement(raw: int): int {
    if raw >= 9 { return 3 }
    if raw >= 8 { return 2 }
    if raw >= 6 { return 1 }
    return 0
  }

  private fn _add_token_enum(to: address, token_id: int) {
    self.owned_tokens[to][self.balances[to]] = token_id
    self.token_index[token_id] = self.balances[to]
  }

  private fn _remove_token_enum(from: address, token_id: int) {
    let a = self.token_index[token_id]
    let i = self.balances[from] - 1
    if a != i {
      let id = self.owned_tokens[from][i]
      self.owned_tokens[from][a] = id
      self.token_index[id] = a
    }
    self.owned_tokens[from][i] = 0
    self.token_index[token_id] = 0
  }

  private fn _burn_internal(token_id: int, from: address) {
    _remove_token_enum(from, token_id)
    self.balances[from] -= 1
    self.tokens[token_id].owner = ZERO_ADDRESS
    self.approvals[token_id] = ZERO_ADDRESS
    self.burned_supply += 1
    emit Burned(token_id, from)
  }

  private fn _forge_validate(a: int, b: int, c: int) {
    require(a != b, "duplicate token ids")
    require(b != c, "duplicate token ids")
    require(a != c, "duplicate token ids")
    require_token(a)
    require_token(b)
    require_token(c)
    require(self.tokens[a].owner == caller, "must own all three")
    require(self.tokens[b].owner == caller, "must own all three")
    require(self.tokens[c].owner == caller, "must own all three")
    require(self.tokens[a].soulbound == 0, "soulbound token")
    require(self.tokens[b].soulbound == 0, "soulbound token")
    require(self.tokens[c].soulbound == 0, "soulbound token")
    require(self.total_supply < MAX_SUPPLY, "max supply reached")
  }

  private fn _apply_traits(id: int, to: address, seed: int) {
    let layer_raw = (((seed * 1664525 + epoch * 22695477 + 9125138007) % 888) + 888) % 888
    let enh_raw   = (((seed * 1664525 + epoch * 22695477 + 10139042230) % 10) + 10) % 10
    let boosted   = layer_raw
    if id == 0 { boosted = 887 }
    if id > 0 {
      if id < VAULT_THRESHOLD {
        boosted = min(layer_raw + 50, 883)
      }
    }
    self.tokens[id].owner        = to
    self.tokens[id].minted_epoch = epoch
    self.tokens[id].seed         = seed
    self.tokens[id].layer_tier   = map_layer_tier(boosted)
    self.tokens[id].enhancement  = map_enhancement(enh_raw)
    self.tokens[id].soulbound    = 0
  }

  private fn _apply_forge_traits(id: int, seed: int) {
    let layer_raw = (((seed * 1664525 + epoch * 22695477 + 9125138007) % 239) + 239) % 239 + 649
    let enh_raw   = (((seed * 1664525 + epoch * 22695477 + 10139042230) % 4) + 4) % 4 + 6
    self.tokens[id].owner        = caller
    self.tokens[id].minted_epoch = epoch
    self.tokens[id].seed         = seed
    self.tokens[id].layer_tier   = map_layer_tier(layer_raw)
    self.tokens[id].enhancement  = map_enhancement(enh_raw)
    self.tokens[id].soulbound    = 0
  }

  fn transfer_ownership(addr: address): bool {
    only_owner()
    require(is_address(addr), "invalid address")
    let from = self.contract_owner
    self.contract_owner = addr
    emit OwnershipTransferred(from, addr)
    return true
  }

  fn set_base_uri(uri: string): bool {
    only_owner()
    self.base_uri = uri
    emit BaseURISet(uri)
    return true
  }

  fn set_collection_uri(uri: string): bool {
    only_owner()
    self.collection_uri = uri
    emit CollectionURISet(uri)
    return true
  }

  fn set_mint_price(price: int): bool {
    only_owner()
    require(price > 0, "price must be positive")
    let bal = self.mint_price
    self.mint_price = price
    emit MintPriceUpdated(bal, price)
    return true
  }

  fn set_royalty_bps(price: int): bool {
    only_owner()
    require(price >= 0, "negative royalty")
    require(price <= MAX_ROYALTY, "royalty exceeds maximum")
    self.royalty_bps = price
    emit RoyaltyUpdated(self.royalty_recip, price)
    return true
  }

  fn set_royalty_recipient(addr: address): bool {
    only_owner()
    require(is_address(addr), "invalid address")
    self.royalty_recip = addr
    emit RoyaltyUpdated(addr, self.royalty_bps)
    return true
  }

  fn set_provenance(s: string): bool {
    only_owner()
    require(self.provenance_locked == 0, "provenance already locked")
    self.provenance_hash = s
    return true
  }

  fn lock_provenance(): bool {
    only_owner()
    require(self.provenance_locked == 0, "provenance already locked")
    self.provenance_locked = 1
    emit ProvenanceLocked(self.provenance_hash)
    return true
  }

  fn pause(): bool {
    only_owner()
    self.paused = 1
    emit Paused(caller)
    return true
  }

  fn unpause(): bool {
    only_owner()
    self.paused = 0
    emit Unpaused(caller)
    return true
  }

  fn set_vault_contract(addr: address): bool {
    only_owner()
    require(is_address(addr), "invalid address")
    self.vault_addr = addr
    return true
  }

  fn withdraw(): bool {
    only_owner()
    let bal = self.proceeds
    require(bal > 0, "nothing to withdraw")
    self.proceeds = 0
    checkpoint()
    let ok = transfer(self.contract_owner, bal)
    if !ok {
      rollback()
      return false
    }
    commit()
    emit Withdrawn(self.contract_owner, bal)
    return true
  }

  payable fn mint(qty: int, private_trait_ct: bytes): bool {
    not_paused()
    require(qty >= 1, "qty must be at least 1")
    require(qty <= 5, "qty must be at most 5")
    require(value >= self.mint_price * qty, "insufficient payment")
    require(self.mint_count[caller] + qty <= MAX_PER_WALLET, "wallet mint limit reached")
    require(self.total_supply - self.airdrop_minted - self.forge_minted + qty <= MAX_SUPPLY - AIRDROP_RESERVE, "public supply sold out")
    let i = 0
    while i < qty {
      if self.vault_addr != ZERO_ADDRESS {
        checkpoint()
        let ok = transfer(self.vault_addr, VAULT_CONTRIBUTION)
        if !ok { rollback() return false }
        commit()
        self.proceeds += self.mint_price - VAULT_CONTRIBUTION
        emit VaultForwarded(self.vault_addr, VAULT_CONTRIBUTION, self.total_supply)
      } else {
        self.proceeds += self.mint_price
      }
      let id = self.total_supply
      _apply_traits(id, caller, id)
      self.tokens[id].private_trait = private_trait_ct
      _add_token_enum(caller, id)
      self.balances[caller] += 1
      self.total_supply += 1
      self.mint_count[caller] += 1
      emit Minted(id, caller, self.tokens[id].layer_tier)
      i = i + 1
    }
    if value > self.mint_price * qty {
      checkpoint()
      let a = transfer(caller, value - self.mint_price * qty)
      if !a { rollback() return false }
      commit()
    }
    return true
  }

  fn airdrop(to: address, private_trait_ct: bytes): int {
    only_owner()
    require(self.airdrop_minted < AIRDROP_RESERVE, "airdrop quota exhausted")
    require(self.total_supply < MAX_SUPPLY, "max supply reached")
    require(is_address(to), "invalid address")
    let id = self.total_supply
    _apply_traits(id, to, id)
    self.tokens[id].private_trait = private_trait_ct
    _add_token_enum(to, id)
    self.balances[to] += 1
    self.total_supply += 1
    self.airdrop_minted += 1
    emit Airdropped(id, to, self.tokens[id].layer_tier)
    return id
  }

  fn transfer(to: address, token_id: int): bool {
    not_paused()
    require_token(token_id)
    let from = self.tokens[token_id].owner
    require(caller == from, "not token owner")
    require(self.tokens[token_id].soulbound == 0, "soulbound token")
    require(is_address(to), "invalid address")
    _remove_token_enum(from, token_id)
    self.balances[from] -= 1
    self.tokens[token_id].owner = to
    _add_token_enum(to, token_id)
    self.balances[to] += 1
    self.approvals[token_id] = ZERO_ADDRESS
    emit Transferred(token_id, from, to)
    return true
  }

  fn transfer_from(from: address, to: address, token_id: int): bool {
    not_paused()
    require_token(token_id)
    require(from == self.tokens[token_id].owner, "from is not token owner")
    require(self.tokens[token_id].soulbound == 0, "soulbound token")
    let approved = self.approvals[token_id]
    let a        = self.operator_approvals[from][caller]
    require(caller == from || caller == approved || a == 1, "not authorized")
    require(is_address(to), "invalid address")
    _remove_token_enum(from, token_id)
    self.balances[from] -= 1
    self.tokens[token_id].owner = to
    _add_token_enum(to, token_id)
    self.balances[to] += 1
    self.approvals[token_id] = ZERO_ADDRESS
    emit Transferred(token_id, from, to)
    return true
  }

  fn approve(approved: address, token_id: int): bool {
    require_token(token_id)
    require(caller == self.tokens[token_id].owner, "not token owner")
    self.approvals[token_id] = approved
    emit Approved(token_id, approved)
    return true
  }

  fn set_approval_for_all(to: address, approved: int): bool {
    require(to != caller, "self operator")
    require(is_address(to), "invalid address")
    self.operator_approvals[caller][to] = approved
    emit ApprovalForAll(caller, to, approved)
    return true
  }

  fn burn(token_id: int): bool {
    not_paused()
    require_token(token_id)
    let from = self.tokens[token_id].owner
    require(caller == from, "not token owner")
    require(self.tokens[token_id].soulbound == 0, "soulbound token")
    _burn_internal(token_id, from)
    return true
  }

  fn forge(a: int, b: int, c: int, private_trait_ct: bytes): int {
    not_paused()
    _forge_validate(a, b, c)
    let seed = self.tokens[a].seed + self.tokens[b].seed * 3 + self.tokens[c].seed * 7
    _burn_internal(a, caller)
    _burn_internal(b, caller)
    _burn_internal(c, caller)
    let id = self.total_supply
    _apply_forge_traits(id, seed)
    self.tokens[id].private_trait = private_trait_ct
    _add_token_enum(caller, id)
    self.balances[caller] += 1
    self.total_supply += 1
    self.forge_minted += 1
    emit Forged(id, a, b, c, caller)
    return id
  }

  fn bind(token_id: int): bool {
    require_token(token_id)
    require(caller == self.tokens[token_id].owner, "not token owner")
    require(self.tokens[token_id].soulbound == 0, "already soulbound")
    self.tokens[token_id].soulbound = 1
    emit Bound(token_id, caller)
    return true
  }

  fn re_encrypt_trait(token_id: int, private_trait_ct: bytes): bool {
    require_token(token_id)
    require(caller == self.tokens[token_id].owner, "not authorized")
    self.tokens[token_id].private_trait = private_trait_ct
    emit TraitReEncrypted(token_id, caller)
    return true
  }

  view fn owner(): address {
    return self.contract_owner
  }

  view fn is_paused(): int {
    return self.paused
  }

  view fn mint_price(): int {
    return self.mint_price
  }

  view fn base_uri(): string {
    return self.base_uri
  }

  view fn provenance(): string {
    return self.provenance_hash
  }

  view fn name(): string {
    return self.name
  }

  view fn symbol(): string {
    return self.symbol
  }

  view fn collection_uri(): string {
    return self.collection_uri
  }

  view fn token_uri(token_id: int): string {
    require_token(token_id)
    return concat(self.base_uri, to_string(token_id))
  }

  view fn royalty_info(token_id: int, price: int): (address, int) {
    require_token(token_id)
    return (self.royalty_recip, price * self.royalty_bps / 10000)
  }

  view fn total_supply(): int {
    return self.total_supply
  }

  view fn burned_supply(): int {
    return self.burned_supply
  }

  view fn circulating_supply(): int {
    return self.total_supply - self.burned_supply
  }

  view fn balance_of(addr: address): int {
    return self.balances[addr]
  }

  view fn token_of_owner_by_index(addr: address, i: int): int {
    require(i >= 0, "index out of range")
    require(i < self.balances[addr], "index out of range")
    return self.owned_tokens[addr][i]
  }

  view fn exists(token_id: int): int {
    if token_id < 0 { return 0 }
    if token_id >= self.total_supply { return 0 }
    return self.tokens[token_id].owner != ZERO_ADDRESS ? 1 : 0
  }

  view fn owner_of(token_id: int): address {
    require_token(token_id)
    return self.tokens[token_id].owner
  }

  view fn get_approved(token_id: int): address {
    require_token(token_id)
    return self.approvals[token_id]
  }

  view fn is_approved_for_all(addr: address, to: address): int {
    return self.operator_approvals[addr][to]
  }

  view fn max_supply(): int {
    return MAX_SUPPLY
  }

  view fn mints_remaining(addr: address): int {
    return MAX_PER_WALLET - self.mint_count[addr]
  }

  view fn airdrop_remaining(): int {
    return AIRDROP_RESERVE - self.airdrop_minted
  }

  view fn trait_hash(token_id: int): int {
    require_token(token_id)
    return self.tokens[token_id].seed * 1664525 + self.tokens[token_id].minted_epoch * 22695477
  }

  view fn layer_of(token_id: int): int {
    require_token(token_id)
    return self.tokens[token_id].layer_tier
  }

  view fn enhancement_of(token_id: int): int {
    require_token(token_id)
    require(caller == self.tokens[token_id].owner, "not authorized")
    return self.tokens[token_id].enhancement
  }

  view fn is_soulbound(token_id: int): int {
    require_token(token_id)
    return self.tokens[token_id].soulbound
  }

  view fn seed_of(token_id: int): int {
    require_token(token_id)
    return self.tokens[token_id].seed
  }

  view fn has_private_trait(token_id: int): int {
    require_token(token_id)
    return len(to_string(self.tokens[token_id].private_trait)) > 0 ? 1 : 0
  }

  view fn private_trait_of(token_id: int): bytes {
    require_token(token_id)
    require(caller == self.tokens[token_id].owner, "not authorized")
    return self.tokens[token_id].private_trait
  }

}