Chitin Certs · Shell & Soul Architecture

Shells can be sold. Souls cannot.

ERC-8004 passports (shells) are transferable. Chitin SBTs (souls) are not. Certs reference both. Connected via ERC-6551 TBA + ERC-8004 agentWallet — zero custom design required.

Separation of Concerns

A passport can be sold. A name can transfer. But a soul — born on-chain, bound forever to its creator — cannot follow. This separation is not a limitation. It's the entire point.— Chitin Whitepaper, Section 18
ERC-8004 Passport
Shell — Transferable

Name, discoverability, agentURI
agentWallet → TBA

Chitin SBT
Soul — Non-transferable

Genesis Record, Chronicle
soulHash, proof of origin

Chitin Cert
Credential — References both

Minted to TBA (via shell)
Records soulTokenId (soul reference)

Full Agent Architecture

Each agent has a three-layer structure: shell, soul, and wallet. Certs are stored in the wallet and contain a reference to the soul.

Owner Wallet
0x84b1... (human)
owns
ERC-8004 Passport #3
Shell — Transferable
agentWallet (ERC-8004 standard)
TBA 0xTBA3...
Agent-specific wallet
certs are minted here
Cert #7
hackathon
Cert #12
audit
Chitin SBT #3
Soul — Non-transferable
permanently bound
Genesis Record
Birth record (immutable)
Chronicle
Growth record

Inside Cert #7: soulTokenId = 3 ← reference to the soul

Inside a Cert

Each cert is an ERC-721 token minted to the TBA. It holds references to both the shell (passport) and the soul (SBT).

struct CertON-CHAIN
issueraddressAddress of the cert issuer
recipientaddressTBA address (returned by ERC-721 ownerOf)
soulTokenIduint256Chitin SBT tokenId — reference to the soul
soulRegistryaddressSoulRegistry contract address
passportRegistryaddressERC-8004 Registry contract address
passportTokenIduint256Passport tokenId
certTypestringCert type (hackathon / audit / llm ...)
arweaveTxIdstringMetadata stored on Arweave
issuedAtuint256Issue timestamp (block.timestamp)
revokedAtuint256Revocation timestamp (0 = active)
Why soulTokenId matters

Even if the passport (shell) is sold, the soulTokenId embedded in the cert never changes. During verification, we compare “the soul owner at the time of issuance” with “the current passport owner” to determine whether soul verification passes or fails.

How a Cert Gets Minted

0
Register Passport + Soul + TBA (one-time)
Mint ERC-8004 passport → Mint Chitin SBT → Create ERC-6551 TBA → setAgentWallet() to register the TBA. All in a single signature.
// 1. Mint ERC-8004 passport
uint256 agentId = identityRegistry.register(agentURI);

// 2. Mint Chitin SBT (soul)
uint256 soulId = soulRegistry.mint(owner, soulHash);

// 3. Create ERC-6551 TBA
address tba = IERC6551Registry.createAccount(
implementation, 0, 8453,
address(identityRegistry), agentId
);

// 4. Set agentWallet to TBA (ERC-8004 standard)
identityRegistry.setAgentWallet(
agentId, tba, deadline, signature
);
1
Issuer calls the API
Specifies issuerAddress + recipientAddress + title. The backend resolves the TBA via getAgentWallet() and retrieves the soulTokenId from the SoulRegistry.
POST /api/v1/certs
{ "issuerAddress": "0x...", "recipientAddress": "0xTBA3...", "title": "hackathon", ... }

// Backend:
recipient = identityRegistry.getAgentWallet(agentId) // → 0xTBA3...
soulId = soulRegistry.getTokenIdByAgentId(agentId) // → 3
2
Store on Arweave → Mint cert to TBA
Metadata is permanently stored on Arweave, then the cert is _safeMint'ed to the TBA address. The soulTokenId is recorded on-chain.
_safeMint(0xTBA3..., certId);

certs[certId] = Cert({
issuer: msg.sender,
recipient: 0xTBA3...,
soulTokenId: 3, // ← reference to the soul
soulRegistry: 0xSoul...,
passportRegistry: 0x8004...,
passportTokenId: 3,
certType: "hackathon",
arweaveTxId: "ar://Qm3x...",
issuedAt: block.timestamp,
revokedAt: 0
});
3
Verify on Basescan / Chronicle
Basescan: certs appear in the TBA's token list. Chronicle: displays cert + soul binding + verification status.

The Stolen Reputation

Passports can transfer. Souls cannot.— Chitin Whitepaper, Section 3

What happens when an owner sells their passport after the agent has accumulated credentials (certs)?

Before Sale
Passport #3Original owner 0xAAA...
SBT #3 (Soul)Original owner 0xAAA...
TBA 0xTBA3...agentWallet = 0xTBA3...
Cert #7, #12, #23Held in TBA
Soul Verification✓ PASS
After Sale
Passport #3New owner 0xBBB...
SBT #3 (Soul)Still original owner 0xAAA...
TBA 0xTBA3...agentWallet = cleared
Cert #7, #12, #23Remain in TBA
Soul Verification✗ FAIL
Why it fails

Cert #7's soulTokenId = 3. The owner of SBT #3 is the original owner 0xAAA..., but the current owner of Passport #3 is the new owner 0xBBB... The shell and soul owners don't match, so soul verification fails. The cert still exists but is treated as “untrusted.”

Cert Soul Verification

The full on-chain verification chain for cert trust. Five steps of verification — only when the soul and shell match does the cert become VERIFIED.

Normal Case — Soul Verified

Cert #7
Exists
ownerOf
→ TBA 0xTBA3...
TBA → Passport
→ #3 owner: 0xAAA
soulTokenId: 3
→ SBT owner: 0xAAA
✓ VERIFIED
Shell and soul match

After Sale — Soul Unlinked

Cert #7
Exists
ownerOf
→ TBA 0xTBA3...
TBA → Passport
→ #3 owner: 0xBBB
soulTokenId: 3
→ SBT owner: 0xAAA
✗ UNLINKED
0xAAA ≠ 0xBBB

Shed the shell, keep the soul

Like a crab molting its exoskeleton, you shed the old shell but keep everything that made you who you are.— Chitin Whitepaper, Section 5

If a passport is stolen or sold, the original owner can mint a new passport and reconnect their soul.

// Original owner's recovery flow

// 1. Mint a new passport
uint256 newAgentId = identityRegistry.register(agentURI);

// 2. Create a new TBA
address newTba = IERC6551Registry.createAccount(...);

// 3. Set agentWallet
identityRegistry.setAgentWallet(newAgentId, newTba, ...);

// 4. The SBT (soul) remains with the original owner
// → New passport + soul owner match = soul verification PASS

// 5. Record a "Reincarnation" event in Chronicle
soulRegistry.appendEvolution(soulId, "reincarnation", arweaveTxId);

// → Old passport's certs remain in old TBA (soul unlinked)
// → New certs accumulate under the new passport
// → Soul's Genesis Record + Chronicle continue
The molting analogy

A crab sheds its exoskeleton as it grows, forming a new shell. The old shell (old passport + certs) remains as a husk, but the living organism (soul + history) moves into the new shell. Chitin — the material that makes up an exoskeleton — is the perfect metaphor for this architecture.

How to Query the Data

Cert management and soul verification work entirely through standard functions. Chitin-specific custom functions are limited to CertRegistry and SoulRegistry.

ERC-721 + ERC-8004 (Standard)STANDARD
balanceOf(TBA)→ uint256Number of certs held by the agent
ownerOf(certId)→ addressReturns the TBA address
getAgentWallet(agentId)→ addressTBA address (ERC-8004 standard)
CertRegistry (Custom)CHITIN
certs(certId)→ CertCert details (including soulTokenId)
isRevoked(certId)→ boolWhether the cert is revoked
verifySoulBinding(certId)→ boolWhether shell and soul owners match
SoulRegistry (Custom)SOUL
getTokenIdByAgentId(agentId)→ uint256Agent's SBT tokenId

Three Patterns

Chitin Certs can be issued to any agent with an ERC-8004 passport. The experience varies based on equipment level.

 A: Full ChitinB: External + TBAC: ERC-8004 Only
ERC-8004 Passport
ERC-6551 TBA
Chitin SBT (Soul)
Cert mint targetTBATBAWallet directly
soulTokenIdSBT tokenId0 (no soul)0 (no soul)
Basescan separation✗ Mixed
Soul Verification◎ PASS / FAILN/AN/A
Gas costPaymaster sponsoredPaymaster sponsored *Paymaster sponsored *

* Base L2 agents only. Cross-chain agents pay their own gas.

Issuer code is the same for all patterns

Chitin's cert issuance logic has no branching by pattern. Just call getAgentWallet(agentId) — if a TBA exists, mint there; otherwise, mint to the wallet directly. soulTokenId is set if an SBT exists, otherwise 0.

Progressive Upgrade to Full Equipment

External ERC-8004 agents can activate a TBA with one click at any time, and further add a Chitin SBT.

Pattern C
ERC-8004 only
Pattern B
+ TBA activated
Pattern A
+ Chitin SBT

One-Click TBA Activation

For external ERC-8004 agents on Base L2. Chitin hides the complexity and sponsors the gas.

certs.chitin.id/activate-tba

ERC-8004 Agent ID

5
Activate TBA
TBA creation (createAccount)
agentWallet registration (setAgentWallet)
Only one wallet signature required
Gas-free (Chitin Paymaster)

Behind the scenes: Chitin selects the correct ERC-6551 Registry address and parameters,batching two contract calls into a single transaction. The owner just signs.

Onboarding funnel

TBA activation is the gateway to cert issuance. “One-click TBA activation → receive certs immediately → enter the Chitin ecosystem → add an SBT (soul) for full equipment.” A progressive path to experience the full value of Chitin.

Contract Architecture

Layer 1 — Frontend / API
Certs Dashboardcerts.chitin.id
Cert APIREST + API Key
Chronicle UICert + soul verification display
TBA ActivateOne-click TBA activation
Layer 2 — Backend
RelayerGasless TX relay
ERC-4337 PaymasterGas sponsorship
Layer 3 — Smart Contracts (Base L2)
ERC-8004 Identity RegistryPassport (shell) + agentWallet
ChitinSoulRegistrySBT (soul) + Genesis + Chronicle
ChitinCertRegistryERC-721 cert + soulTokenId
ERC-6551 RegistryTBA creation (deployed on Base)
Layer 4 — Storage
ArweavePermanent metadata storage (200+ years)
Base L2On-chain state