Home → Token-bound accounts
Chain 4663 · ERC-6551
The pog
owns things.
"What does it mean to add NFTs to a token? You would think it's the other way around?"
You would, and for almost everything on a blockchain you would be right. A wallet owns things; the things do not own anything. That sentence only stops sounding backwards once you know about one specific standard, and the standard is genuinely the strange part here — not the reading of it.
The model you already have
An ERC-721 contract is a ledger of who owns which number. RHPogs is one row per pog: token id 64 belongs to some address, token id 2 belongs to some address. An ERC-20 contract is a ledger of balances, keyed the same way. Your wallet address appears in both ledgers, independently.
So your pog and your POGS are siblings. They have a parent in common — your wallet — and no relationship to each other at all. Sell the pog and the POGS do not move, because nothing ever connected them. Every marketplace, every explorer and every wallet UI is built on that assumption.
What ERC-6551 actually does
ERC-6551 does not change the ERC-721 contract. RHPogs does not implement it, and could not opt out of it if it wanted to. What the standard says is roughly this:
That account is a contract like any other. It can hold ETH. It can hold ERC-20s. It can hold other NFTs. It can call functions on other contracts. The only unusual thing about it is the question it asks before doing any of that: instead of "did the private key sign this?", it asks who does ownerOf() say holds my token right now? — and it takes orders from that address.
So the container is the pog. Not because the pog is magic, but because a contract somewhere is willing to treat holding the pog as the credential. Move the pog and you have moved the credential, and everything the account holds goes with it. Nothing is transferred out; the account never changes address. What changed is who ownerOf returns.
It is not a wallet you make
There is no create step required before it exists as an address. The address is arithmetic. Deploying code there is optional and can happen years later, or never.
It is not custody
No third party holds anything. The account answers to ownerOf, and ownerOf answers to the RHPogs contract.
It is not per-collection
RHPogs did not have to add anything. The same registry serves every ERC-721 on the chain, which is why this works for a collection that was already deployed.
Why anybody wants the inversion
Because it makes a bundle atomic, and bundles are otherwise one of the sharpest edges in this whole space.
Selling a pog plus the things that belong with it, without 6551, means a sequence: send the pog, send the tokens, send the second pog, receive payment. Every step is a separate transaction with its own opportunity for one side to stop halfway. Escrow contracts exist to fix that, and they are extra code, extra trust and extra gas.
With the account, there is no sequence. One transferFrom of one NFT hands over the whole contents, because the contents were never separately owned. The bundle cannot half-arrive. A marketplace that knows nothing about ERC-6551 — including the RHPogs market — moves the whole thing correctly, by accident, because all it ever did was move one token id.
Inventory that travels
A pog that has been somewhere can carry the proof: a badge NFT, a receipt, a balance it earned. Sell the pog, sell the history with it, in one action.
An address per item
Each pog has its own address, so you can pay a specific pog rather than a person. Anything sent there is bound to the item from that moment on.
Nothing to re-list
No unbundling before a sale, no re-bundling after. The listing is the same single-token listing every marketplace already understands.
It composes downwards
An account can hold an NFT that has its own account. Depth is free — which is also, later on this page, the part that bites.
Worked example: RHPOG #64 Basalt Boar
Basalt Boar is a Holographic pog from the Tiki series, rarity rank 499 of 794. Its airdrop entitlement is 1,804,859.23 POGS, paid in three tranches measured from the moment the airdrop is armed:
| Tranche | Unlocks | Share of the drop | POGS to this pog |
|---|---|---|---|
| Tranche 1 | T+0 days | 20% | 360,971.84 |
| Tranche 2 | T+45 days | 30% | 541,457.77 |
| Tranche 3 | T+90 days | 50% | 902,429.61 |
Every figure in that table is derived rather than typed — the arithmetic behind it is on the transparency page.
Step 1 — the entitlement is already bound to the token
This part needs no ERC-6551 at all, and it is worth being precise about it. The distributor pays ownerOf(tokenId) at claim time. So an unclaimed tranche follows the pog: buy pog 64 before tranche 3 unlocks and the 902,429.61 POGS of that tranche will be paid to you, not to the person who sold it. The entitlement is attached to the number, not to a person.
Step 2 — claiming breaks the binding
The moment tranche 1 is claimed, 360,971.84 POGS land in the holder's wallet. They are now siblings again — ordinary ERC-20 balance next to an ordinary NFT. Sell the pog now and those POGS stay behind. The pog on the listing and the pog you imagined are no longer the same asset.
Step 3 — put them back into the pog
Send those 360,971.84 POGS to pog 64's token-bound account instead of leaving them loose, and the pog is a container holding its own airdrop. Now a single sale hands over the artwork, the two unclaimed tranches and the claimed balance, atomically.
Step 4 — nest a second pog inside the first
Transfer pog 2 (Board Shorts Bull) into pog 64's account and something quietly useful happens: because the distributor pays ownerOf, and ownerOf(#2) is now that account, pog 2's tranches — starting at 138,835.32 POGS — are paid into the parent pog without anyone routing them there. Claiming is permissionless, so a stranger can even pay the gas to do it for you.
How it works, mechanically
Three moving parts: a registry, an address, and an account contract.
The registry
One contract, at 0x000000006551c19487814612e58fe06813775758, at that same address on every EVM chain — it was deployed through a deterministic deployer, so the address is a consequence of the bytecode rather than of who deployed it or when. It is live on Robinhood Chain mainnet (4663) and on the testnet. It has essentially two functions:
account(implementation, salt, chainId, tokenContract, tokenId) view returns (address)
createAccount(implementation, salt, chainId, tokenContract, tokenId) returns (address)
The first tells you the address. The second deploys code at it. Both are permissionless: anybody can ask, and anybody can deploy your pog's account for you, because the code that lands there is fixed by the address maths and cannot be substituted.
The address
The registry deploys an ERC-1167 minimal proxy with four extra words glued on the end — salt, chain id, token contract, token id — so that the account can read its own identity out of its own code:
creationCode = 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73
‖ 0x41c8f39463a868d3a88af00cd0fe7102f30e44ec
‖ 5af43d82803e903d91602b57fd5bf3
‖ abi.encode(salt, chainId, tokenContract, tokenId) // 128 bytes
address = keccak256(0xff ‖ registry ‖ salt ‖ keccak256(creationCode))[12:]
That is the whole derivation: a CREATE2 address, computable offline, with no network access and no permission. Every byte of that proxy is normative — change one and every token-bound account address in the world changes.
Two consequences worth holding on to. First, the address exists before the account does, so assets can be sent to a pog whose account has never been deployed; the code can be added later and the assets are still there. Second, the implementation and the salt are inputs. A different implementation, or a salt that is not zero, is a different address for the same pog. Sending to the wrong one is not recoverable by trying again.
The account
The implementation this platform uses is Tokenbound's AccountV3 at 0x41c8f39463a868d3a88af00cd0fe7102f30e44ec. The surface that matters:
| Function | What it is for |
|---|---|
| token() | Returns (chainId, tokenContract, tokenId) — the account states which NFT it belongs to. |
| owner() | Reads ownerOf on that NFT. This is the entire permission model. |
| execute(to, value, data, operation) | The account acts: send ETH, call a contract, transfer a token out. Only a valid signer may call it. |
| state() | A counter that changes on every execution, so an old signed message cannot be replayed after the account has moved on. |
| isValidSignature() | ERC-1271, so the pog itself can be a signer that other contracts accept. |
The operation argument takes 0 for CALL, 1 for DELEGATECALL, 2 for CREATE and 3 for CREATE2. The platform's own tooling only ever emits 0. DELEGATECALL runs somebody else's code in the account's own storage, which is a clean way to hand an account's contents to a contract you did not read.
The honest risks
This is a young standard doing something the rest of the stack was not designed for. Three real problems, and none of them are theoretical.
1 · The nested ownership trap
Nesting is free, so it is easy to build a shape nobody can undo. The simplest is a cycle: put pog 64 into pog 2's account and pog 2 into pog 64's account. Each is now owned by an account controlled by the other. There is no wallet at the top of the chain, so there is no address that can authorise anything, ever again.
Depth is the softer version of the same problem. A pog four levels down is controlled by whoever holds the token at the top, and finding that out means walking the chain by hand. Anything that takes custody of the top-level NFT — a lending contract, a staking vault, a marketplace that escrows rather than approves — takes control of every account below it too, usually without either side thinking about it. That is one reason the RHPogs market is approval-based and never holds the token.
2 · Support is uneven, and silence looks like emptiness
Most marketplaces show you ownerOf and the metadata. They do not show what the token's account holds, because until recently there was nothing to show. A loaded pog and an empty one look identical on a listing. That cuts both ways: a seller may not realise what they are handing over, and a buyer has no interface telling them what they are buying. Explorers, portfolio trackers and tax tools mostly do not walk into token-bound accounts either, so the balance is not missing — it is just invisible to the tool you are looking at.
3 · The contents can leave one block before you buy
This is the one to take seriously. The account answers to the current holder, and the current holder is the seller right up until settlement. Nothing binds the contents you inspected to the sale you signed. A seller can list a loaded pog, watch a purchase enter the mempool, empty the account in the block before, and still collect the full price. The NFT delivered is exactly the one advertised; only the invisible part changed.
RHPogs has the same hazard in its own airdrop, and it is pinned by a test in this repository rather than left as folklore: claim() is permissionless and pays the holder at claim time, so a seller with a listing up can empty an already-unlocked tranche in the block before the sale settles, and the sale still completes at the agreed price. The rule that falls out of it is the same rule as above:
If you want to pay for the contents, the fix is atomicity, not trust: buy through a contract that checks the account's balances — or its state() counter — inside the same transaction as the transfer, and reverts if anything moved. Short of that, price the pog as if the account were empty and treat whatever is inside it as a bonus that may not survive the trip.
Why this platform already speaks 6551
None of this was built for RHPogs. It was already here, because the wallet and the operator dashboard on this chain were written with token-bound accounts in them from the start — which is why a loaded pog is inspectable today rather than after a tooling project.
RH Wallet
The holder's side. It shows any NFT's account, what is inside it, creates the account when it does not exist yet, and spends from it — non-custodially, with the keys never leaving the device.
The operator dashboard
The issuer's side: computing and deploying accounts for a collection, on the same registry, from the same derivation.
One detail from that code is worth copying anywhere you touch this standard. Both sides derive the account address twice — once locally with CREATE2 arithmetic and once by asking the on-chain registry — and refuse to return an address at all if the two disagree. An address that is wrong by one bit is a hole in the ground with funds in it, and this is the one number on the page that funds get sent to.
One live caveat, measured on this chain: the registry is deployed on both Robinhood Chain networks, but the AccountV3 implementation is on mainnet (4663) only. On testnet you can compute an account address and fund it, and it will still be there later — but there is no code at it yet, so it cannot send anything out.
So: which way round is it?
Both, and that is the honest answer. Your wallet owns the pog — that never stopped being true, and the RHPogs contract has no idea any of this exists. The pog owns an account, and the account owns whatever has been put in it. The inversion is one layer deep, it is opt-in per token, and it is worth understanding for exactly one reason: it changes what you are buying without changing what the listing says.
Browse the 794 pogs See RHPOG 64 Open RH Wallet
Airdrop total 800,000,000 POGS · Mythic allocation 80,000,000 POGS · registry 0x000000006551c19487814612e58fe06813775758