skills/bap578-logic-contracts/SKILL.md
Use this skill when designing, building, deploying, binding, or reviewing logic contracts that define autonomous on-chain behavior for BAP-578 Non-Fungible Agents.
npx skillsauth add chatandbuild/skills-repo BAP-578 Logic ContractsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill to design, build, deploy, and bind logic contracts that define on-chain agent behavior for BAP-578 Non-Fungible Agents. Logic contracts are the behavioral extension layer — they give agents the ability to perform autonomous actions, execute strategies, respond to events, and interact with other contracts.
The logic contract is the behavioral layer of a BAP-578 agent. While the main NFA contract defines identity (who the agent is) and state (what it remembers), the logic contract defines action (what it does). A logic contract is a separate smart contract deployed independently, then bound to an agent via the logicAddress field.
The binding creates a relationship:
Think of it as: the NFA contract is the agent's brain (memory and identity), and the logic contract is the agent's hands (actions and capabilities).
Logic contracts can maintain their own state variables, giving agents additional memory beyond what the NFA contract stores. This could include:
The logic contract can also read the agent's on-chain state from the NFA contract by calling view functions like getAgentState and getAgentMetadata.
Logic contracts enable agents to perform actions autonomously. Capabilities depend entirely on what the logic contract implements:
Logic contract trust must be established independently of the NFA contract:
┌──────────────────────────┐
│ NFA Contract │
│ │
│ Agent #17 │
│ ├── owner: 0xABC │
│ ├── balance: 1.5 BNB │
│ ├── active: true │
│ ├── metadata: {...} │
│ └── logicAddress: 0xDEF │◄──── binding
│ │
└──────────────────────────┘
│
│ calls / reads
▼
┌──────────────────────────┐
│ Logic Contract (0xDEF) │
│ │
│ - execute() │
│ - getStatus() │
│ - configure() │
│ │
│ Can read NFA state via: │
│ - nfa.getAgentState(17) │
│ - nfa.getAgentMetadata() │
│ │
└──────────────────────────┘
address.code.length > 0.address(0) unbinds the logic contract (removes behavior).// Token owner binds a logic contract
nfa.setLogicAddress(tokenId, logicContractAddress);
// Emits event for tracking
// event LogicAddressChanged(uint256 indexed tokenId, address logicAddress);
// Token owner unbinds
nfa.setLogicAddress(tokenId, address(0));
Logic contracts don't need to implement a specific interface, but a recommended pattern is:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface INonFungibleAgents {
struct AgentState {
uint256 balance;
bool active;
address logicAddress;
uint256 createdAt;
address owner;
}
struct AgentMetadata {
string persona;
string experience;
string voiceHash;
string animationURI;
string vaultURI;
bytes32 vaultHash;
}
function getAgentState(uint256 tokenId) external view returns (AgentState memory);
function getAgentMetadata(uint256 tokenId) external view returns (AgentMetadata memory);
}
A minimal logic contract that reads agent metadata and returns a greeting:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./INonFungibleAgents.sol";
contract GreeterLogic {
INonFungibleAgents public immutable nfa;
event GreetingGenerated(uint256 indexed tokenId, string greeting);
constructor(address _nfa) {
nfa = INonFungibleAgents(_nfa);
}
function greet(uint256 tokenId) external view returns (string memory) {
INonFungibleAgents.AgentMetadata memory meta = nfa.getAgentMetadata(tokenId);
return string(abi.encodePacked(
"Hello! I am an agent with experience in: ",
meta.experience
));
}
function getAgentInfo(uint256 tokenId) external view returns (
bool active,
uint256 balance,
string memory experience
) {
INonFungibleAgents.AgentState memory state = nfa.getAgentState(tokenId);
INonFungibleAgents.AgentMetadata memory meta = nfa.getAgentMetadata(tokenId);
return (state.active, state.balance, meta.experience);
}
}
A logic contract that executes a defined action when triggered by a keeper or automation service:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./INonFungibleAgents.sol";
contract StrategyLogic {
INonFungibleAgents public immutable nfa;
struct StrategyConfig {
uint256 threshold;
uint256 lastExecuted;
uint256 executionCount;
bool enabled;
}
mapping(uint256 => StrategyConfig) public strategies;
event StrategyExecuted(uint256 indexed tokenId, uint256 timestamp);
event StrategyConfigured(uint256 indexed tokenId, uint256 threshold);
constructor(address _nfa) {
nfa = INonFungibleAgents(_nfa);
}
modifier onlyAgentOwner(uint256 tokenId) {
INonFungibleAgents.AgentState memory state = nfa.getAgentState(tokenId);
require(msg.sender == state.owner, "Not agent owner");
_;
}
function configure(uint256 tokenId, uint256 threshold) external onlyAgentOwner(tokenId) {
strategies[tokenId] = StrategyConfig({
threshold: threshold,
lastExecuted: 0,
executionCount: 0,
enabled: true
});
emit StrategyConfigured(tokenId, threshold);
}
function execute(uint256 tokenId) external {
INonFungibleAgents.AgentState memory state = nfa.getAgentState(tokenId);
require(state.active, "Agent not active");
StrategyConfig storage config = strategies[tokenId];
require(config.enabled, "Strategy not enabled");
require(
block.timestamp >= config.lastExecuted + config.threshold,
"Too soon"
);
// Execute strategy logic here
// This is where you'd interact with DeFi protocols, oracles, etc.
config.lastExecuted = block.timestamp;
config.executionCount++;
emit StrategyExecuted(tokenId, block.timestamp);
}
function disable(uint256 tokenId) external onlyAgentOwner(tokenId) {
strategies[tokenId].enabled = false;
}
}
A logic contract that forwards incoming requests to specialized handlers:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./INonFungibleAgents.sol";
contract RouterLogic {
INonFungibleAgents public immutable nfa;
mapping(bytes4 => address) public handlers;
address public admin;
event RequestRouted(uint256 indexed tokenId, bytes4 selector, address handler);
constructor(address _nfa) {
nfa = INonFungibleAgents(_nfa);
admin = msg.sender;
}
function registerHandler(bytes4 selector, address handler) external {
require(msg.sender == admin, "Not admin");
require(handler.code.length > 0, "Handler must be contract");
handlers[selector] = handler;
}
function route(uint256 tokenId, bytes4 selector, bytes calldata data) external returns (bytes memory) {
INonFungibleAgents.AgentState memory state = nfa.getAgentState(tokenId);
require(state.active, "Agent not active");
address handler = handlers[selector];
require(handler != address(0), "No handler registered");
(bool success, bytes memory result) = handler.call(data);
require(success, "Handler execution failed");
emit RequestRouted(tokenId, selector, handler);
return result;
}
}
Write the logic contract in Solidity. Test thoroughly using Hardhat.
cd non-fungible-agents-BAP-578
# Create logic contract in contracts/logic/
# Write tests in test/logic/
npm test
Deploy separately from the NFA contract:
const GreeterLogic = await ethers.getContractFactory("GreeterLogic");
const logic = await GreeterLogic.deploy(NFA_CONTRACT_ADDRESS);
await logic.waitForDeployment();
console.log("Logic deployed at:", await logic.getAddress());
Verify the logic contract source code so anyone can review it:
npx hardhat verify --network bscTestnet LOGIC_ADDRESS NFA_CONTRACT_ADDRESS
The token owner calls setLogicAddress:
const nfa = await ethers.getContractAt("NonFungibleAgents", NFA_ADDRESS);
await nfa.setLogicAddress(tokenId, LOGIC_ADDRESS);
const logic = await ethers.getContractAt("GreeterLogic", LOGIC_ADDRESS);
const greeting = await logic.greet(tokenId);
console.log(greeting);
Before binding a logic contract, evaluate:
A marketplace for logic contracts would allow:
Categories:
Logic contracts that only read state are inherently safe. They cannot modify anything and carry minimal risk.
modifier onlyAgentOwner(uint256 tokenId) {
require(msg.sender == nfa.getAgentState(tokenId).owner, "Not owner");
_;
}
// DANGEROUS — allows calling any contract with any data
function execute(address target, bytes calldata data) external {
target.call(data);
}
Agent funds should stay in the NFA contract. If the logic contract holds funds, a bug or exploit in the logic contract could cause loss.
Events are the audit trail. Every meaningful action in the logic contract should emit an event with relevant parameters.
BAP-578's specification defines logic contracts as the learning module layer — the interface through which agents connect to AI systems. The standard provides infrastructure without prescribing specific implementations:
The logic contract queries the agent's vault content to provide context for AI generation:
interface IRAGLogic {
function retrieveContext(uint256 tokenId, string calldata query) external view returns (string memory);
function generateWithContext(uint256 tokenId, string calldata query) external returns (string memory);
}
Implementation: Logic contract reads vaultURI from agent metadata, fetches relevant documents, and passes them as context to an AI model via oracle or off-chain service.
The logic contract routes agent interactions to different AI providers:
interface IMCPLogic {
function routeToProvider(uint256 tokenId, string calldata input, string calldata provider) external returns (bytes memory);
function getAvailableProviders() external view returns (string[] memory);
}
Implementation: Logic contract acts as a router, forwarding requests to registered AI service endpoints and returning structured responses.
The logic contract manages the agent's learning tree and updates the on-chain Merkle root:
interface ILearningLogic {
function processInteraction(uint256 tokenId, bytes calldata interactionData) external returns (bytes32 newLearningNode);
function updateMerkleRoot(uint256 tokenId, bytes32 newRoot, bytes32[] calldata proof) external;
function verifyLearning(uint256 tokenId, bytes32 leaf, bytes32[] calldata proof) external view returns (bool);
function queryKnowledge(uint256 tokenId, string calldata query) external view returns (bytes memory);
}
The learning pipeline: interaction → learning extraction → tree building → Merkle root → on-chain update via updateAgentMetadata.
The logic contract stores reward signals and outcome data:
interface IRLLogic {
function recordOutcome(uint256 tokenId, bytes32 actionId, int256 reward) external;
function getRecommendation(uint256 tokenId, bytes calldata context) external view returns (bytes memory);
}
Combine multiple approaches in a single logic contract:
contract HybridLearningLogic is IRAGLogic, ILearningLogic, IRLLogic {
// RAG for knowledge retrieval
// Merkle tree for verifiable learning state
// RL for action optimization
// All behind the single logicAddress binding
}
When asked for logic contract help, respond with:
bap578bap578-security-auditbap578-upgradedocumentation
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.
development
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
devops
Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare.
tools
Use this skill when designing and building durable command-line tools from API docs, OpenAPI specs, SDKs, curl examples, admin tools, web apps, or local scripts, especially when the CLI should expose composable commands, stable JSON output, auth/config handling, install-on-PATH behavior, and a companion skill.