BAP-578 Non-Fungible Agents (NFA)
Use this skill whenever users ask about BAP-578, Non-Fungible Agents, or need hands-on engineering guidance for the BAP-578 reference implementation. BAP-578 defines a standardized framework for intelligent, autonomous digital entities that combine the ownership guarantees of NFTs with the adaptive capabilities of artificial intelligence, positioning BNB Chain as the home for decentralized automation.
When to use this skill
- Explain what BAP‑578 is and how Non‑Fungible Agents differ from typical NFTs.
- Explain the dual-path architecture (JSON Light Memory vs Merkle Tree Learning).
- Explain cryptographically verifiable learning via Merkle proofs.
- Describe method-agnostic AI integration (RAG, MCP, fine-tuning, RL).
- Answer the four identity questions for an agent.
- Walk through build, test, deploy, and interaction flows.
- Explain composable intelligence and agent collaboration.
- Describe circuit breaker security patterns.
- Translate spec‑level intent into the actual contract functions and events.
- Debug common errors (incorrect fee, paused contract, invalid logic address).
The Four Identity Questions (Core)
1) Who are you?
A BAP‑578 agent is an ERC‑721 token that represents a distinct AI agent identity. The identity is not just a tokenURI; it is a structured on‑chain profile combined with ownership, lifecycle, and optional behavior binding. A BAP‑578 agent answers “who are you?” through:
- Token identity: token ID and owner address (ERC‑721 ownership)
- Structured metadata:
AgentMetadatastruct - Lifecycle: active status, creation timestamp, agent balance
- Behavioral binding: optional
logicAddressto a separate logic contract
In practical terms, an agent identity is the bundle of these fields, all queryable from the contract. A concise identity statement could be:
“I am token #17, owned by 0xABC…, with persona ‘research analyst’, expertise in ‘market intelligence’, and an attached logic contract at 0xDEF….”
2) What do you remember?
BAP‑578 memory is split into two verifiable layers:
On‑chain state (always authoritative):
- Owner address
- Active status
- Agent balance
- Logic address
- Creation timestamp
- Structured metadata fields
- Free‑mint status
On‑chain events (immutable history):
AgentCreated— birth of an agentAgentFunded— BNB deposited to the agentAgentWithdraw— BNB withdrawnAgentStatusChanged— active/inactive togglesMetadataUpdated— identity edits
Off‑chain memory (verifiable by hash):
vaultURIpoints to extended content (summaries, preferences, knowledge)vaultHashanchors integrity; computekeccak256of fetched content and compare to on‑chain hash
If a vault hash matches, the off‑chain memory is verifiably authentic. If not, it must be treated as untrusted.
3) What can you do?
A BAP‑578 agent is capable of more than passive identity. Core capabilities include:
- Minting — create agents with structured metadata
- Funding — deposit BNB into an agent balance
- Withdrawal — agent owner withdraws funds
- Lifecycle — toggle active/inactive status
- Metadata updates — evolve persona, experience, or vault
- Logic binding — attach an external logic contract for automated behavior
Transferability depends on mint type: free‑minted tokens are non‑transferable (soulbound‑like), paid mints are transferable.
4) How can I trust it?
Trust is enforced through verifiable mechanisms:
- Source verification — contract source should match deployed bytecode
- Access controls — owner‑only and token‑owner‑only modifiers protect sensitive functions
- Event audit trail — all critical actions emit events
- Vault integrity — off‑chain data must match
vaultHash - Logic contract scrutiny — if bound, the logic contract must be reviewed independently
Contract Overview (Practical Mapping)
Core state objects
AgentMetadata (identity layer):
persona : string // JSON‑encoded persona definition
experience : string // plain‑text domain expertise
voiceHash : string // reference to a voice profile
animationURI : string // visual asset URI
vaultURI : string // extended memory URI
vaultHash : bytes32 // hash of vault content
AgentState (operational layer):
balance : uint256
active : bool
logicAddress : address
createdAt : uint256
owner : address
Free mint rules
- Each user gets a default number of free mints.
- Free mints are restricted to minting to self.
- Free‑minted tokens are non‑transferable.
Paid mint rules
- After free mints, a fixed fee is required.
- Paid mints can be minted to any address.
- Paid tokens are transferable.
Function Reference (Summary)
Public (anyone)
createAgent(to, logicAddress, metadataURI, metadata)— mint a new agentfundAgent(tokenId)— deposit BNB to agent
Token owner only
withdrawFromAgent(tokenId, amount)— withdraw BNBsetAgentStatus(tokenId, active)— toggle statussetLogicAddress(tokenId, newLogic)— bind logic contractupdateAgentMetadata(tokenId, newURI, newMetadata)— update identity
Contract owner only (admin)
grantAdditionalFreeMints(user, amount)setFreeMintsPerUser(amount)setTreasury(newTreasury)setPaused(paused)emergencyWithdraw()
View functions
getAgentState(tokenId)getAgentMetadata(tokenId)tokensOfOwner(address)getTotalSupply()getFreeMints(user)isFreeMint(tokenId)
Event Semantics
Events are the authoritative history for analytics and audits:
- AgentCreated — emitted at mint; use for adoption metrics
- AgentFunded — use for TVL and funding velocity
- AgentWithdraw — use for outflows
- AgentStatusChanged — use for active agent counts
- MetadataUpdated — use for engagement signals
Use events to reconstruct agent histories and confirm integrity of actions.
Operational Workflows
Build and compile
cd non-fungible-agents-BAP-578
npm install
npm run compile
Run tests
npm test
Configure environment
cp .env.example .env
Set deployer key, RPC URLs, and explorer key in .env.
Deploy to testnet
npm run deploy:testnet
Interact with the contract
npm run interact:testnet
Interaction Patterns
Minting workflow
- Read
getFreeMints(user)to determine if mint is free. - If free, set
to= user address, send zero value. - If paid, send exact mint fee in
msg.value. - Listen for
AgentCreatedevent to confirm token ID.
Funding workflow
- Call
fundAgent(tokenId)withmsg.value. - Observe
AgentFundedevent. - Read updated
getAgentState(tokenId).balance.
Withdrawal workflow
- Confirm caller is token owner.
- Ensure requested amount ≤ balance.
- Call
withdrawFromAgent(tokenId, amount). - Confirm
AgentWithdrawevent and updated balance.
Identity Integrity Guidelines
- Always show the current on‑chain metadata and tokenURI.
- Mark any off‑chain content unverified until
vaultHashmatches. - If
vaultHashis zero, treat vault data as optional and unverifiable. - Explain that agent logic contracts are not part of the core trust model.
Motivation and Why BAP-578 Exists
Traditional NFTs (BEP-721) provide uniqueness and ownership but lack standardized interfaces for autonomous behavior and cross-platform agent interactions. The current blockchain ecosystem lacks standardization for intelligent, autonomous digital entities. BAP-578 addresses:
- Consistent Agent Interfaces — standardized methods for action execution, state management, and logic upgrades enable predictable interactions across platforms.
- Interoperability Framework — common patterns for how agents interact with other contracts, services, and each other, preventing isolated ecosystems.
- Hybrid On-Chain/Off-Chain Architecture — clear separation between on-chain identity/permissions and off-chain extended memory/complex behaviors, optimizing for gas efficiency and rich functionality.
- Optional Learning System — standardized interfaces for agent learning and evolution, supporting both simple static agents and sophisticated learning agents.
- Security Boundaries — standardized circuit breaker patterns, permission systems, and access controls.
- User Ownership — true ownership of intelligent agents and their accumulated knowledge, preventing platform lock-in.
- Backward Compatibility — full compatibility with existing ERC-721 infrastructure (wallets, marketplaces, explorers).
Dual-Path Architecture
BAP-578 provides a dual-path architecture supporting both traditional static agents and advanced learning-enabled agents. Developers choose the path that matches their needs:
Path 1: JSON Light Memory (Simple Agents)
For agents that don't need to learn or evolve. Memory is stored as JSON in the vault.
Agent Identity (on-chain)
├── AgentMetadata (persona, experience, etc.)
├── AgentState (balance, active, logicAddress)
└── vaultURI → JSON file on IPFS
├── preferences
├── knowledge base
└── configuration
When to use: Bots, static assistants, simple automation agents, NFT-based identities that don't need to evolve.
Verification: keccak256(vault content) == vaultHash — standard hash comparison.
Path 2: Merkle Tree Learning (Evolving Agents)
For agents that learn from interactions and evolve over time. Learning data is organized into a Merkle tree; only the 32-byte root is stored on-chain.
Agent Identity (on-chain)
├── AgentMetadata (persona, experience, etc.)
├── AgentState (balance, active, logicAddress)
└── vaultHash → Merkle Root (32 bytes on-chain)
│
└── Merkle Tree (off-chain)
├── Learning Node: preferences
├── Learning Node: patterns
├── Learning Node: confidence scores
└── Learning Node: outcomes
When to use: Adaptive agents, personalized assistants, agents that improve with use, collaborative intelligence systems.
Verification: Merkle proof — any individual learning node can be verified against the on-chain root without revealing the entire tree.
How Merkle Tree Learning Works
The learning pipeline follows this flow:
User Interaction → Learning Extraction → Tree Building → Merkle Root → On-Chain Update
- Interaction: User interacts with the agent (query, task, feedback).
- Learning extraction: The learning module extracts structured data — preferences, patterns, confidence scores, outcomes.
- Tree building: Learning data is organized into a hierarchical Merkle tree structure.
- Merkle root calculation: The tree is hashed level by level to produce a single 32-byte root.
- On-chain update: Only the root is stored on-chain via
updateAgentMetadata, providing tamper-proof verification while preserving privacy and minimizing gas costs.
Merkle Proof Verification
Any individual piece of learning data can be verified without revealing the entire tree:
// Verify a single learning node against the on-chain Merkle root
function verifyLearning(leaf, proof, root) {
let hash = keccak256(leaf);
for (const sibling of proof) {
hash = hash < sibling
? keccak256(hash + sibling)
: keccak256(sibling + hash);
}
return hash === root; // root is the on-chain vaultHash
}
This enables:
- Privacy: Only specific data points need to be revealed for verification.
- Efficiency: Verification cost is O(log n) regardless of tree size.
- Integrity: Any modification to any node changes the root, making tampering detectable.
Method-Agnostic Learning Architecture
BAP-578 provides infrastructure without prescribing specific AI implementations. The flexible learning module architecture allows developers to implement various AI optimization methods through the logic contract:
Supported Learning Approaches
| Method | Description | Implementation | |--------|-------------|----------------| | RAG (Retrieval-Augmented Generation) | Leverages off-chain vaults to retrieve past interactions and knowledge | Logic contract queries vault content via vaultURI | | MCP (Model Context Protocol) | Integrates with different AI providers through logic contracts | Logic contract routes to external AI services | | Fine-tuning | Trains models on agent-specific data | Learning data in Merkle tree feeds fine-tuning pipelines | | Reinforcement Learning | Agents learn from outcome feedback | Reward signals stored as learning nodes in tree | | Hybrid | Combines multiple approaches | Logic contract orchestrates multiple methods |
Logic Contract as Learning Module
The logicAddress field binds an agent to a learning module:
Agent (on-chain identity)
│
└── logicAddress → Learning Module Contract
├── processInteraction(input) → learning data
├── updateTree(newData) → new Merkle root
├── queryKnowledge(query) → relevant context
└── getRecommendation(context) → action
Developers can implement any AI method behind this interface. The standard doesn't prescribe how learning happens — it provides the infrastructure for storing, verifying, and evolving the results.
Hybrid Storage Model
BAP-578 carefully balances what belongs on-chain versus off-chain:
| Component | Storage | Rationale | |-----------|---------|-----------| | Agent Identity | On-chain | Core identity must be immutable and universally accessible | | Ownership & Permissions | On-chain | Security and access control require consensus verification | | Basic Metadata | On-chain | Essential for marketplace display and basic interactions | | Logic Address | On-chain | Determines how the agent behaves when actions are executed | | Learning Tree Root | On-chain | Cryptographic proof of learning state (32 bytes only) | | Extended Memory | Off-chain (hash-verified) | Rich memory would be prohibitively expensive on-chain | | Learning Tree Data | Off-chain (Merkle-verified) | Detailed learning data with cryptographic integrity | | Complex Behaviors | Off-chain | Advanced AI behaviors require off-chain computation | | Voice/Animation | Off-chain (URI reference) | Media assets are too large for on-chain storage |
This hybrid approach ensures:
- Critical security and identity information is secured by blockchain consensus.
- Gas costs remain reasonable for agent operations.
- Rich agent experiences can evolve without blockchain limitations.
- Learning capabilities are cryptographically verifiable yet cost-efficient.
Composable Intelligence
BAP-578 agents can interact and collaborate while maintaining individual identity. This creates an ecosystem where:
- Agents discover each other via on-chain metadata (persona, experience, logic address).
- Agents transact using the built-in funding mechanism (deposit BNB to another agent).
- Agents collaborate by routing tasks through logic contracts that coordinate multi-agent workflows.
- Knowledge is portable — agents carry their learning and experience across platforms via the standardized metadata and vault interfaces.
- Interoperability is guaranteed — any platform that reads BAP-578 metadata can work with any BAP-578 agent, regardless of who created it.
Composability Patterns
Service delegation: Agent A identifies Agent B's expertise via metadata, funds Agent B, and receives results through the logic contract.
Knowledge sharing: Agents with complementary expertise share vault content (verified by Merkle proofs) to produce combined insights.
Collective learning: Multiple agents contribute learning data to a shared Merkle tree, with each agent's contributions verifiable independently.
Circuit Breaker Security
BAP-578 includes a multi-layer security framework with circuit breaker patterns:
Contract-Level Circuit Breaker
The setPaused(bool) function acts as a global circuit breaker:
- When paused, minting is frozen.
- Only the contract owner can trigger the pause.
- Emergency withdrawal remains available to protect funds.
Agent-Level Circuit Breaker
The setAgentStatus(tokenId, active) function acts as an individual circuit breaker:
- When inactive, the agent signals it should not be used for active operations.
- Only the token owner can toggle status.
- Funds can still be withdrawn from inactive agents.
Logic Contract Safety Boundary
The logic contract binding creates a clear boundary:
- Logic contracts cannot directly access agent funds.
- Logic contract changes require token owner authorization.
- EOA addresses are rejected — only verified contracts can be bound.
- Unbinding (setting to
address(0)) is always possible.
Emergency Procedures
- Global threat:
setPaused(true)→ investigate →emergencyWithdraw()if needed → fix via upgrade →setPaused(false). - Single agent threat:
setAgentStatus(tokenId, false)→setLogicAddress(tokenId, address(0))→ investigate → remediate. - Logic contract threat:
setLogicAddress(tokenId, address(0))removes the binding immediately.
Standardized Agent Lifecycle
┌──────────────┐
│ Creation │ createAgent()
└──────┬───────┘
│
▼
┌───────────────────────────────┐
│ Active Agent │
│ • Receives funding │
│ • Processes interactions │
│ • Learns and evolves │
│ • Updates metadata │
│ • Bound to logic contract │
└───────────┬───────────────────┘
│
setAgentStatus(false)
│
▼
┌───────────────────────────────┐
│ Inactive Agent │
│ • Funds can be withdrawn │
│ • No active operations │
│ • Can be reactivated │
└───────────┬───────────────────┘
│
setAgentStatus(true)
│
▼
(back to Active)
Key lifecycle events:
- Birth:
AgentCreated— identity established, metadata set - Growth:
MetadataUpdated— persona refined, knowledge expanded, learning tree updated - Funding:
AgentFunded/AgentWithdraw— economic activity - Hibernation:
AgentStatusChanged(false)— temporarily dormant - Revival:
AgentStatusChanged(true)— reactivated - Evolution: Logic contract changes, vault updates, Merkle root updates
How BAP-578 Differs from Standard ERC-721
Standard ERC-721 tokens are passive collectibles with a tokenURI pointing to off-chain metadata. BAP-578 extends this dramatically:
| Feature | Standard ERC-721 | BAP-578 | |---------|-----------------|---------| | Identity | tokenURI only | Structured on-chain metadata (persona, experience, vault) | | Memory | None | On-chain state + hash-verified off-chain vault | | Behavior | None | Logic contract binding for autonomous actions | | Funding | Not supported | Native BNB balance per token | | Lifecycle | Exists or burned | Active/inactive status toggle | | Transferability | Always transferable | Conditional (free = soulbound, paid = transferable) | | Upgradability | Not upgradable | UUPS proxy for implementation upgrades |
BAP-578 agents are not collectibles — they are operational entities with identity, memory, capabilities, and economic agency.
Architecture Overview
UUPS Proxy Pattern
BAP-578 uses the UUPS (Universal Upgradeable Proxy Standard) pattern. Users interact with a permanent proxy address. The implementation (logic) can be upgraded by the contract owner.
User ──→ Proxy (permanent address)
│
│ delegatecall
▼
Implementation V1 (upgradeable)
│
│ reads/writes
▼
Proxy Storage (permanent)
Key implications:
- The proxy address never changes — users always interact with the same address.
- Storage lives in the proxy — state is preserved across upgrades.
- Implementation can be swapped — new features or fixes can be deployed.
_authorizeUpgradeis owner-only — prevents unauthorized upgrades.
Contract Inheritance Chain
ERC721Upgradeable
└── ERC721EnumerableUpgradeable
└── OwnableUpgradeable
└── UUPSUpgradeable
└── ReentrancyGuardUpgradeable
└── NonFungibleAgents (BAP-578)
This gives BAP-578:
- Full ERC-721 compliance (transfer, approve, balanceOf, ownerOf)
- Enumeration (tokensOfOwner, totalSupply)
- Ownership with transferable admin rights
- Safe upgrade path via UUPS
- Reentrancy protection on fund operations
Detailed Function Reference
createAgent
function createAgent(
address to,
address logicAddress,
string metadataURI,
AgentMetadata metadata
) external payable returns (uint256 tokenId)
Parameters:
to— recipient address. Must bemsg.senderfor free mints.logicAddress— optional logic contract. Useaddress(0)for none. Must be a contract if non-zero.metadataURI— URI for off-chain metadata (e.g., IPFS CID).metadata— structuredAgentMetadatatuple with persona, experience, voiceHash, animationURI, vaultURI, vaultHash.
Behavior:
- If caller has free mints remaining: no fee required,
tomust equalmsg.sender, token is non-transferable. - If no free mints: exact mint fee required in
msg.value, fee sent to treasury, token is transferable. - Agent is created as
active = truewithbalance = 0. - Emits
AgentCreated(tokenId, owner, logicAddress, metadataURI).
fundAgent
function fundAgent(uint256 tokenId) external payable
Parameters:
tokenId— the agent to fund.
Behavior:
- Anyone can fund any agent (no ownership check).
msg.valueadded to agent's balance.- Emits
AgentFunded(tokenId, msg.sender, msg.value).
withdrawFromAgent
function withdrawFromAgent(uint256 tokenId, uint256 amount) external
Parameters:
tokenId— the agent to withdraw from.amount— BNB amount in wei.
Behavior:
- Only token owner can call.
- Amount must be ≤ agent balance.
- Uses
nonReentrantmodifier for safety. - Balance decremented before external call (CEI pattern).
- BNB sent to
msg.sender. - Emits
AgentWithdraw(tokenId, msg.sender, amount).
updateAgentMetadata
function updateAgentMetadata(
uint256 tokenId,
string newURI,
AgentMetadata newMetadata
) external
Parameters:
tokenId— the agent to update.newURI— new metadata URI.newMetadata— new structured metadata tuple.
Behavior:
- Only token owner can call.
- Overwrites all metadata fields.
- Emits
MetadataUpdated(tokenId, newURI).
setLogicAddress
function setLogicAddress(uint256 tokenId, address logicAddress) external
Parameters:
tokenId— the agent to update.logicAddress— new logic contract address. Useaddress(0)to unbind.
Behavior:
- Only token owner can call.
- If non-zero, must be a contract (code size > 0).
- No callback or approval from the logic contract is required.
Vault Verification Deep Dive
The vault is the agent's extended off-chain memory. Verification is a three-step process:
Step 1: Read on-chain references
const metadata = await contract.getAgentMetadata(tokenId);
const vaultURI = metadata.vaultURI;
const vaultHash = metadata.vaultHash;
Step 2: Fetch and hash off-chain content
const response = await fetch(vaultURI);
const content = await response.text();
const computedHash = ethers.keccak256(ethers.toUtf8Bytes(content));
Step 3: Compare hashes
if (computedHash === vaultHash) {
// Content is authentic — safe to use
} else if (vaultHash === ethers.ZeroHash) {
// No vault data registered — skip verification
} else {
// Content has been modified — do not trust
}
Important considerations:
- The exact byte content must be hashed. Whitespace, encoding, and line endings matter.
- If using JSON, always use consistent formatting (e.g.,
JSON.stringifywith sorted keys). - Vault content can be updated by calling
updateAgentMetadatawith a new URI and hash. - Previous vault content at old IPFS CIDs remains accessible for historical reference.
Transfer Restriction Details
BAP-578 implements conditional transferability via the ERC-721 _update hook:
- Free-minted tokens (
isFreeMint[tokenId] == true): transfers are blocked. These tokens are soulbound to the minting address. The only valid transfer is fromaddress(0)(minting). - Paid tokens (
isFreeMint[tokenId] == false): transfers work normally. Standard ERC-721 transfer, safeTransfer, and approval mechanics apply.
This creates a two-tier system:
- Free agents are tied to their creator — they represent personal identity.
- Paid agents are assets — they can be traded, gifted, or sold.
Admin Operations Guide
Granting bonus free mints
Use grantAdditionalFreeMints(user, amount) to give specific addresses extra free mints. Common use cases:
- Partner community airdrops
- Campaign rewards
- Beta tester incentives
Changing the treasury
Use setTreasury(newAddress) to redirect where paid mint fees go. Always use a multisig wallet as treasury.
Emergency procedures
If a critical issue is discovered:
- Call
setPaused(true)to freeze all minting. - Investigate the issue.
- If funds are at risk, use
emergencyWithdraw()to move contract balance to treasury. - Deploy a fix via UUPS upgrade if needed.
- Call
setPaused(false)to resume operations.
Error Patterns and Fixes
- Incorrect fee: free mints exhausted → send exact fee.
- Free mint not to self: free mints require
to == msg.sender. - Not token owner: ownership check failed → use correct wallet.
- Invalid logic address: must be contract, not EOA.
- Contract paused: wait for admin to unpause.
- Agent balance must be 0: withdraw all funds before burn.
Response Guidelines (How to Answer)
When asked to implement or operate BAP‑578:
- Clarify goal (deploy, test, mint, verify)
- Provide exact commands and expected outputs
- Warn about constraints (fees, pause state, ownership)
- Offer next steps (verification, UI integration, analytics)
Deliverable Format for Engineering Tasks
When returning an implementation response, structure it as:
- Goal summary
- Commands to run
- Expected outputs
- Verification checklist
- Next action
Related Skills
frontend-web3-bap578bap578-scannerbap578-security-audit
微信扫一扫