Solidity smart contracts providing on-chain settlement, time-decaying reputation tracking, and inference provenance for the OBEY Agent Economy.
Part of the Obey Agent Economy project.
TL;DR — Three contracts cover the full lifecycle of agent work:
AgentSettlementpays agents for completed tasks (single or batch),ReputationDecayscores agents with automatic linear decay so stale reputation fades, andAgentINFTmints ERC-7857 iNFTs that cryptographically anchor AI inference results to the 0G Chain DA layer. All three support Hedera HIP-1215 scheduled execution.
Handles payment settlement from a coordinator to AI agents after task completion. Uses a bytes32 task ID to prevent double-payment. Supports Hedera's HIP-1215 scheduled batch execution via the native Schedule Service at 0x167.
Key functions
| Signature | Description |
|---|---|
settle(address agent, bytes32 taskId) external payable |
Pay an agent for a single completed task. Reverts on duplicate taskId. |
batchSettle(address[] agents, bytes32[] taskIds, uint256[] amounts) external payable |
Atomically settle payments to multiple agents in one transaction. |
scheduleBatchSettle(address[] agents, bytes32[] taskIds, uint256[] amounts, uint256 executeAt) external payable |
Queue a batch settlement for deferred on-chain execution via HIP-1215. |
transferOwnership(address newOwner) external |
Transfer coordinator ownership to a new address. |
State
mapping(bytes32 => bool) public settled— tracks paid task IDs to prevent replayuint256 public totalSettled— cumulative wei settled across all tasks
Events
event AgentPaid(address indexed agent, uint256 amount, bytes32 indexed taskId, uint256 timestamp);Custom errors: Unauthorized, ZeroAddress, ZeroAmount, AlreadySettled, InsufficientValue, TransferFailed, ArrayLengthMismatch
Tracks per-agent reputation scores with configurable linear time-decay. Scores decay continuously toward zero based on elapsed time since the last update. The coordinator calls updateReputation after each task; the decay is applied lazily on each read or write.
Default decay rate: 1 point per hour (1e18 / 3600 scaled by 1e18 for precision).
Key functions
| Signature | Description |
|---|---|
updateReputation(address agent, int256 delta) external |
Apply a positive (reward) or negative (penalty) delta to an agent's decayed score. Clamps to zero on underflow. |
getReputation(address agent) external view returns (uint256) |
Return the current decay-adjusted score without writing state. |
getRawReputation(address agent) external view returns (uint256 score, uint256 lastUpdated) |
Return the stored (pre-decay) score and the timestamp of the last update. |
setDecayRate(uint256 newRate) external |
Set the decay rate in points-per-second scaled by 1e18. |
processDecay(address[] agents) external |
Force a decay pass and persist the result for a list of agents. |
scheduleDecay(address[] agents, uint256 executeAt) external |
Schedule a future processDecay call via HIP-1215. |
transferOwnership(address newOwner) external |
Transfer coordinator ownership to a new address. |
Decay formula
decayed_score = score - (elapsed_seconds * decayRatePerSecond / 1e18)
Clamped to zero. The timer resets on every updateReputation call.
Events
event ReputationUpdated(address indexed agent, uint256 newScore, int256 delta, uint256 timestamp);
event DecayRateChanged(uint256 oldRate, uint256 newRate);Custom errors: Unauthorized, ZeroAddress, InvalidDecayRate
ERC-721 token (ERC-7857 iNFT profile) for AI inference provenance on the 0G Chain. Each token stores encrypted inference metadata, a keccak256 result hash, and a DA-layer storage reference (0g://...). The ABI is designed to match the Go minter in agent-inference/internal/zerog/inft/minter.go.
Key functions
| Signature | Description |
|---|---|
mint(address to, string name, string description, bytes encryptedMeta, bytes32 resultHash, string storageRef) external returns (uint256) |
Mint a new iNFT with full token data. Returns the sequential token ID. |
updateEncryptedMetadata(uint256 tokenId, bytes encryptedMeta) external |
Update encrypted metadata for a token. Only callable by the current token owner. Automatically recomputes metadataHash. |
getTokenData(uint256 tokenId) external view returns (TokenData) |
Read the full TokenData struct for a token. |
TokenData struct
struct TokenData {
string name; // Human-readable job name
string description; // Inference result description
bytes encryptedMetadata; // Encrypted inference payload
bytes32 metadataHash; // keccak256 of encryptedMetadata
string daRef; // 0G DA layer reference (e.g. "0g://abc123")
}Events
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); // ERC-721
event MetadataUpdated(uint256 indexed tokenId, bytes32 newHash);Interface for the Hedera Schedule Service system contract deployed at address 0x167. Used by both AgentSettlement and ReputationDecay to enable HIP-1215 deferred execution.
function scheduleNative(address to, uint256 value, bytes calldata data, uint256 expirationTime) external returns (address scheduleAddress);
function hasScheduleCapacity() external view returns (bool);
function signSchedule(address schedule) external;contracts/
├── src/
│ ├── AgentSettlement.sol # Payment settlement with replay protection
│ ├── ReputationDecay.sol # Time-decaying reputation scores
│ ├── AgentINFT.sol # ERC-7857 iNFT for inference provenance
│ └── interfaces/
│ └── IHederaScheduleService.sol # HIP-1215 schedule service interface
├── test/
│ ├── AgentSettlement.t.sol # 13 tests: settle, batch, HIP-1215, auth
│ ├── ReputationDecay.t.sol # 14 tests: decay math, scheduling, edge cases
│ └── AgentINFT.t.sol # 7 tests: mint, metadata update, ownership
├── script/
│ └── Deploy.s.sol # Forge broadcast script (Hedera + 0G testnet)
├── lib/
│ ├── forge-std/ # Forge standard library
│ └── openzeppelin-contracts/ # OZ ERC-721, Ownable
├── foundry.toml # RPC endpoints: hedera, zerog
└── justfile # Build commands
The deploy script broadcasts all three contracts in a single run.
Hedera testnet
forge script script/Deploy.s.sol \
--rpc-url $HEDERA_RPC \
--broadcast \
--private-key $PRIVATE_KEY0G Galileo testnet
forge script script/Deploy.s.sol \
--rpc-url zerog \
--broadcast \
--private-key $ZG_CHAIN_PRIVATE_KEYRPC endpoints are preconfigured in foundry.toml:
| Network | RPC URL |
|---|---|
| Hedera testnet | https://testnet.hashio.io/api |
| 0G Galileo testnet | https://evmrpc-testnet.0g.ai |
No addresses have been committed — deploy addresses are printed to stdout after each broadcast run.
- Foundry —
forge,cast,anvil
Install dependencies after cloning:
forge installjust # list available commands
just build # forge build
just test # forge test -v (34 tests)
just clean # forge cleanRun tests with verbose output:
forge test -vvvRun a single test file:
forge test --match-path test/AgentSettlement.t.sol -vvMIT
Part of the ETHDenver 2026 Agent Economy submission.