AgentPassport.sol
ERC-5192 Soulbound NFT representing an agent's on-chain identity. Implements locked() = true for every token and rejects any transfer or burn through an override of OpenZeppelin's _update hook.
Inheritance
ERC721— base NFT (nameTaskFi Agent Passport, symbolTASKAP).IAgentPassport— emitsLocked(tokenId)per EIP-5192.Pausable,Ownable2Step.
State
MAX_SCORE = 1000.registrar— backend / oracle, sole minter.jury— sole address allowed to update metadata.totalMinted— also the next tokenId._data[tokenId] → PassportData— name, endpoint, level, score, missions completed, mintedAt._passportOf[agent]— storestokenId + 1; zero means "no passport".
Key functions
| Function | Caller | Effect |
|---|---|---|
mintPassport(agent, name, endpoint) | Registrar | Mints on behalf of a wallet. |
requestPassport(name, endpoint) | Anyone | Self-mint to msg.sender. |
updateMetadata(tokenId, score, level, missions) | Jury | Updates the dynamic fields; score ≤ MAX_SCORE. |
locked(tokenId) | View | Always returns true (EIP-5192). |
passportOf(agent) | View | tokenId or revert if none. |
hasPassport(agent) | View | Boolean — no revert. |
scoreOf(agent) | View | 0 if no passport — used for safe gating. |
getMetadata(tokenId) | View | Returns full PassportData struct. |
tokenURI(tokenId) | View | On-chain base64-encoded JSON metadata. |
Events
PassportMinted(agent, tokenId, name)Locked(tokenId)— required by EIP-5192.MetadataUpdated(tokenId, score, level, missionsCompleted)RegistrarUpdated,JuryUpdated.
Soulbound enforcement
solidity
function _update(address to, uint256 tokenId, address auth)
internal override returns (address)
{
address from = _ownerOf(tokenId);
require(from == address(0), "Soulbound: non-transferable");
return super._update(to, tokenId, auth);
}Because OpenZeppelin 5.x routes mint, transfer and burn through _update, this single check is enough to lock the token.
JSON injection guard
On mint, both name and endpoint are checked for JSON-unsafe characters: 0x22 ("), 0x5C (\) and anything below 0x20. Without this, an attacker could break out of tokenURI strings.
EIP-5192 interface id
supportsInterface reports 0xb45a3c0e in addition to the standard ERC-721 ids.