{"id":16340774,"url":"https://github.com/casey/btcnft","last_synced_at":"2026-01-24T13:20:26.952Z","repository":{"id":81087415,"uuid":"484603220","full_name":"casey/btcnft","owner":"casey","description":null,"archived":false,"fork":false,"pushed_at":"2022-04-24T03:01:21.000Z","size":2,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-14T01:18:24.398Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/casey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-23T00:00:31.000Z","updated_at":"2024-11-24T22:31:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"f2a94157-a7bd-42b3-80b6-2d74f65a3578","html_url":"https://github.com/casey/btcnft","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casey%2Fbtcnft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casey%2Fbtcnft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casey%2Fbtcnft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casey%2Fbtcnft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/casey","download_url":"https://codeload.github.com/casey/btcnft/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239441677,"owners_count":19639122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T23:57:49.771Z","updated_at":"2025-11-04T21:30:25.377Z","avatar_url":"https://github.com/casey.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# BTC NFT\n\nBTC NFT is a bitcoin-native protocol for minting and transferring NFTs.\n\nBTC NFTs are associated with individual satoshis, and are transferred using\nsimple bitcoin transactions.\n\n## Satpoints\n\nThe current location of a BTC NFT is a satpoint. A satpoint consists of a\ntransaction ID, an output index, and a satoshi offset, separated by colons.\n\nThis satpoint:\n\n```\n4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:495716253\n```\n\nHas the following parts:\n\n- Transaction ID:\n  `4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b`\n- Output index: `0`\n- Satoshi offset: `495716253`\n\nA transaction ID and output index, known as an outpoint, identify a particular\noutput. A satpoint identifies a particular satoshi within an outpoint.\n\n## Minting BTC NFTs\n\nBTC NFTs are minted by signing a message containing the NFT metadata, which\nincludes a satpoint. The metadata for an image NFT, represented as JSON, might\nlook like this:\n\n```json\n{\n  \"image\": \"b29933e0cc8490ffd1ba687a684c78fa0d5dd0c1089e39f03b4c4be068abfabc\",\n  \"genesis\": \"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:495716253\",\n}\n```\n\nWhose fields have the following meaning:\n\n- `image`: The SHA-256 hash of the NFTs image data.\n- `genesis`: The initial satpoint to which the NFT is assigned.\n\n## NFT IDs\n\nThe SHA-256 hash of the signature of an NFT, encoded using bech32 with the\n`nft` prefix serves as a compact identifier of a given NFT. For example\n\n```\nnft1zkq28upa9vkd2dlve4lc2cxwnsysu3ff4\n```\n\nThis NFT ID can be used to look up the signature and metadata of an NFT.\n\nLooking up the metadata of an NFT ID is trustless, since NFT ID commits to the\nsignature, and the signature commits to the metadata, so NFT metadata can be\nstored anywhere, for example in distributed P2P networks such as BitTorrent or\nIPFS, or on centralized NFT metadata repositories.\n\n## NFT Storage\n\nNFT metadata can be trustlessly retrieved using an NFT ID, so they can be\nstored anywhere.\n\n## Transferring BTC NFTs\n\nBTC NFTs are transferred when the satpoint holding the NFT is spent, using the\nfollowing algorithm:\n\n```python\ndef transfer(satpoint, transaction):\n  offset = 0\n\n  for input in transaction.inputs:\n    if input == satpoint.output:\n      offset += satpoint.offset\n      break\n    else:\n      offset += input.value\n\n  for output in transaction.outputs:\n    if output.value \u003e offset:\n      return Satpoint(output, offset)\n    else:\n      offset -= output.value\n\n  return None\n```\n\nThis algorithm first calculates the offset, in satoshis, of the satpoint within\nthe inputs of the transaction. It then calculates where that offset places the\nsatpoint within the outputs of the transaction, and returns a new satpoint\npointing to the new offset.\n\nIf the new offset points to the fee range, the `transfer` function returns\n`None`. For simplicity, the meaning of such a transfer is left undefined.\nDepending on future needs, such a transfer may be defined as destroying any\nassociated NFTs, or be defined as assigning any associated NFTs to the miner of\nthe current block.\n\n## Finding the current owner of a BTC NFT\n\nThe current owner of a BTC NFT given by a particular NFT ID can be found by\nretrieving the NFT metadata from a metadata repository using the NFT ID. Then,\nstarting from the genesis satpoint, the transfer algorithm is applied whenever\nthe current satpoint is spent.\n\nIn code:\n\n```\ndef find(nft):\n  current = nft.genesis\n\n  while spent(current):\n    spending_transaction = get_spending_transaction(current.outpoint):\n\n    current = transfer(current, spending_transaction)\n\n  return current\n```\n\nThe owner of the output in which the NFT currently resides is the owner of the\nNFT, and the public key that controls that output maybe be used to sign\nownership challenges related to that NFT.\n\n## Relationship to Ordinals\n\n[Ordinals](https://ordinals.com) is a scheme for collectable satoshis, and\nassociated NFTs, and uses a similar transfer scheme. Ordinals is more fun and\naesthetically appealing than BTC NFT. However, proofs of an ordinal NFTs\nlocation are larger, and building a database over the location of all ordinals\nis resource intensive.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcasey%2Fbtcnft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcasey%2Fbtcnft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcasey%2Fbtcnft/lists"}