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.

Two ownership models side by side On the left, one wallet owns an NFT and some tokens as siblings. On the right, the wallet owns the NFT, the NFT owns an account, and that account owns the tokens and other NFTs. WHAT YOU ALREADY THINK YOUR WALLET A POG TOKENS Siblings. Sell the pog and the tokens stay behind. WHAT ERC-6551 ADDS YOUR WALLET THE POG ITS OWN ACCOUNT TOKENS ETH OTHER NFTS One arrow moves all of this at once.
Left: the pog and the tokens are siblings under one wallet. Right: the pog is the parent, and the account underneath it belongs to the token, not to you.

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:

Every NFT that has ever been minted, on any EVM chain, already has a smart-contract account waiting for it at an address you can compute from three facts: the chain, the NFT's contract address, and the token id. Whoever holds the NFT controls that account.

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:

TrancheUnlocksShare of the drop POGS to this pog
Tranche 1T+0 days20%360,971.84
Tranche 2T+45 days30%541,457.77
Tranche 3T+90 days50%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.

Two listings for RHPOG 64 at the same price are not the same trade. One is a picture. The other is a picture holding 360,971.84 POGS, a whole second pog and that pog's remaining entitlement. There is no price oracle on chain 4663, so nothing on this site can tell you what that difference is worth — only that it is not zero and that the listing page will not mention it.

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.

How the account address is derived Five inputs — implementation, salt, chain id, NFT contract and token id — are packed into a minimal-proxy creation code, hashed, and run through CREATE2 from the registry to produce one deterministic account address. FIVE INPUTS IMPLEMENTATIONwhich account codeSALTusually 0CHAIN ID4663NFT CONTRACTthe RHPogs addressTOKEN IDe.g. 64 CREATION CODE proxy + 4 words CREATE2 from registry ACCOUNT ADDRESS Pure arithmetic. The address exists before the account is deployed, and can hold assets while it is still empty of code. Change any input — including the salt — and it is a different address for the same pog.
No registry lookup is required to know the address — the registry just deploys code at the address the maths already picked.

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:

FunctionWhat 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.

An ownership cycle between two token-bound accounts Pog A's account holds pog B, and pog B's account holds pog A. No wallet is above either of them, so nobody can sign for either one again. POG #64 its account holds #2 POG #2 its account holds #64 NO SIGNER ABOVE EITHER ONE
Both pogs are still perfectly valid tokens. Neither can ever move again, because the only address that could authorise a move is inside the loop.

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:

Only the parts that cannot move are safe to pay for. A still-locked tranche is bound to the token id by the contract's own clock. An unlocked tranche, and anything sitting in a token-bound account, is bound to nothing but the seller's intentions.

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