Bionttestnet
Address

octDRue6…qaKABR

octDRue6rfDL9cEhEYiAtcNGTD4qCfsZxxuKxVimmqaKABR
State
OCT balance
0.0002OCT
wallet balance
Type
Token · $SPEC
Spectrum · OCS-01
Chain-level
View on Octrascan · devnet
raw txs · nonce · pubkey
Pipoke (no profile)
this wallet has not registered a Pipoke profile
Contract
OCS-01 · token
nameSpectrum
symbol$SPEC
total supply06 decimals
standardOCS-01fungible token
balance0.0002 OCT
version1.0 Rehovot
code hasha7108c…65adce
History
live · 20s · last 0
Source · ABI · Bytecode
✓ verified
expand →
✓ verified
contract SpectrumNFT {

  struct NFT {
    owner: address
    creator: address
    collection: string
    metadata_uri: string
    royalty_bps: int
    minted_epoch: int
  }

  event Minted(token_id: int, owner: address, collection: string)
  event Transferred(token_id: int, from: address, to: address)
  event Approved(token_id: int, approved: address)
  event ApprovalForAll(owner: address, operator: address, approved: int)

  const MAX_ROYALTY: int = 1000

  state {
    owner: address
    name: string
    symbol: string
    total_supply: int
    tokens: map[int]NFT
    balances: map[address]int
    approvals: map[int]address
    operator_approvals: map[address]map[address]int
  }

  constructor(n: string, s: string) {
    self.owner = origin
    self.name = n
    self.symbol = s
    self.total_supply = 0
  }

  fn mint(
    to: address,
    collection: string,
    metadata_uri: string,
    royalty_bps: int
  ): int {
    require(caller == self.owner, "not authorized")
    require(royalty_bps >= 0, "negative royalty")
    require(royalty_bps <= MAX_ROYALTY, "max royalty 10%")
    let id = self.total_supply
    self.tokens[id].owner = to
    self.tokens[id].creator = caller
    self.tokens[id].collection = collection
    self.tokens[id].metadata_uri = metadata_uri
    self.tokens[id].royalty_bps = royalty_bps
    self.tokens[id].minted_epoch = epoch
    self.balances[to] += 1
    self.total_supply += 1
    emit Minted(id, to, collection)
    return id
  }

  fn transfer(to: address, token_id: int): bool {
    require(token_id >= 0, "invalid id")
    require(token_id < self.total_supply, "token not found")
    let current_owner = self.tokens[token_id].owner
    require(caller == current_owner, "not owner")
    require(to != current_owner, "already owner")
    self.tokens[token_id].owner = to
    self.balances[current_owner] -= 1
    self.balances[to] += 1
    self.approvals[token_id] = to
    emit Transferred(token_id, current_owner, to)
    return true
  }

  fn transfer_from(from: address, to: address, token_id: int): bool {
    require(token_id >= 0, "invalid id")
    require(token_id < self.total_supply, "token not found")
    let current_owner = self.tokens[token_id].owner
    require(from == current_owner, "from is not owner")
    let approved = self.approvals[token_id]
    let is_operator = self.operator_approvals[from][caller]
    require(
      caller == current_owner ||
      caller == approved ||
      is_operator == 1,
      "not authorized"
    )
    self.tokens[token_id].owner = to
    self.balances[from] -= 1
    self.balances[to] += 1
    self.approvals[token_id] = to
    emit Transferred(token_id, from, to)
    return true
  }

  fn approve(approved: address, token_id: int): bool {
    require(token_id >= 0, "invalid id")
    require(token_id < self.total_supply, "token not found")
    require(caller == self.tokens[token_id].owner, "not owner")
    self.approvals[token_id] = approved
    emit Approved(token_id, approved)
    return true
  }

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

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

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

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

  view fn get_token_uri(token_id: int): string {
    return self.tokens[token_id].metadata_uri
  }

  view fn get_collection(token_id: int): string {
    return self.tokens[token_id].collection
  }

  view fn get_creator(token_id: int): address {
    return self.tokens[token_id].creator
  }

  view fn get_royalty(token_id: int): int {
    return self.tokens[token_id].royalty_bps
  }

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

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

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

  view fn get_token_info(token_id: int): string {
    require(token_id >= 0, "invalid id")
    require(token_id < self.total_supply, "token not found")
    let s = to_string(token_id)
    s = concat(s, ",")
    s = concat(s, to_string(self.tokens[token_id].owner))
    s = concat(s, ",")
    s = concat(s, to_string(self.tokens[token_id].creator))
    s = concat(s, ",")
    s = concat(s, self.tokens[token_id].collection)
    s = concat(s, ",")
    s = concat(s, to_string(self.tokens[token_id].royalty_bps))
    s = concat(s, ",")
    s = concat(s, to_string(self.tokens[token_id].minted_epoch))
    return s
  }

  view fn is_approved_or_owner(token_id: int, addr: address): int {
    require(token_id >= 0, "invalid id")
    require(token_id < self.total_supply, "token not found")
    let current_owner = self.tokens[token_id].owner
    if addr == current_owner {
      return 1
    }
    if self.approvals[token_id] == addr {
      return 1
    }
    if self.operator_approvals[current_owner][addr] == 1 {
      return 1
    }
    return 0
  }

  view fn get_contract_info(): string {
    let s = self.name
    s = concat(s, ",")
    s = concat(s, self.symbol)
    s = concat(s, ",")
    s = concat(s, to_string(self.total_supply))
    s = concat(s, ",")
    s = concat(s, to_string(self.owner))
    return s
  }
}