// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {FHE, euint64, ebool, externalEuint64} from "@fhevm/solidity/lib/FHE.sol"; import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol"; interface IReputationBadge { function mintOrUpgrade(uint256 agentId, address operator, uint8 tier) external; function tierOf(uint256 agentId) external view returns (uint8); } interface IInsurancePool { function receivePenalty(uint256 agentId) external payable; function delegateCredit(uint256 agentId, uint256 amount) external; function repayCredit(uint256 agentId) external payable; } /** * @title CipherTrust * @notice Confidential underwriting protocol for autonomous agents & robots. * * Autonomous AI trading bots, delivery robots, drone fleets, and DePIN devices * increasingly hold funds and execute tasks without human supervision. There is * no confidential way today to score their reliability and price the * collateral/insurance they must post -- any naive on-chain reputation system * leaks competitively sensitive operational data (uptime, error rates, routes, * strategy performance) to rivals, because blockchains are public by default. * * CipherTrust computes a rolling trust score and a required collateral bond * entirely under Fully Homomorphic Encryption. Operators, insurers, and task * marketplaces can rely on the *outcome* (bond tier, sufficiency check) * without ever seeing the raw encrypted telemetry that produced it. * * v0.2 additions (see docs/COMPETITIVE_ANALYSIS.md for why these were added): * - Multi-oracle quorum: telemetry only affects the score once N independent * oracles agree within a round, reducing single-oracle trust assumptions. * - Async confidential slashing: an oracle can request a confidential SLA * breach check; the breach flag is decrypted via Zama's public-decrypt + * signature-verification flow before any penalty is applied on-chain. * - Optional composability hooks into a soulbound ReputationBadge (public, * selectively-revealed trust tier) and an InsurancePool (LP yield funded * by slashing penalties), so other protocols can build on CipherTrust's * output without ever touching an agent's raw telemetry. * * NOTE: this is an MVP scaffold. Verify every FHE.* call (especially the * makePubliclyDecryptable / checkSignatures async-decrypt flow) against the * exact current version of fhevm-solidity pinned in package.json before * deploying to a live network -- the FHE Solidity API surface evolves * between releases, and this flow has not yet been compiled/tested. */ contract CipherTrust is SepoliaConfig { address public admin; uint256 public nextAgentId; struct Agent { address operator; bool registered; bool active; uint256 identityId; // optional link into AgentIdentityRegistry, 0 if unset euint64 trustScore; // encrypted, 0-1000 scale euint64 requiredBond; // encrypted, wei uint256 postedBond; // public collateral currently deposited (wei) ebool bondSufficient; // encrypted boolean: postedBond >= requiredBond uint256 breachCount; // public count of confirmed SLA breaches uint256 trustScoreVar; // estimation uncertainty variance, initialized to 100 (public) euint64 liquidationThreshold; // encrypted minimum trust score before liquidation uint256 delegatedBond; // public delegated bond amount borrowed from the pool (wei) uint256 interestAccumulated; // public interest accumulated (wei) uint256 lastInterestUpdateTime; // timestamp of the last yield accrual } struct Task { uint256 agentId; address client; uint256 coverageLimit; // maximum ETH coverage (wei) bool active; } struct Lease { address lessee; uint256 agentId; uint256 hardwareId; uint256 requiredBond; // underwriting bond (wei) uint256 startTimestamp; bool active; } uint256 public nextTaskId = 1; mapping(uint256 => Task) public tasks; uint256 public nextLeaseId = 1; mapping(uint256 => Lease) public leases; mapping(address => uint256) public userActiveLeaseId; mapping(uint256 => uint256) public claimRequestTask; // decryption requestId => taskId mapping(uint256 => uint256) public agentActiveTaskId; // agentId => active taskId (0 if none) struct PendingRound { uint32 count; bool initialized; euint64 sumCompletion; euint64 sumUptime; euint64 sumLatency; euint64 sumError; } mapping(uint256 => Agent) private _agents; mapping(address => bool) public authorizedOracles; mapping(address => bool) public authorizedUnderwriters; // FHE-Stream: Confidential Staking Yields & Payroll Streams struct SalaryStream { euint64 flowRate; uint256 lastClaimBlock; bool active; } mapping(address => SalaryStream) private _salaryStreams; mapping(uint256 => address) public streamRequests; mapping(uint256 => PendingRound) private _pendingRounds; // agentId => in-flight quorum round mapping(uint256 => uint256) public currentRoundId; // agentId => round id mapping(uint256 => mapping(address => uint256)) private _oracleLastRound; // agentId => oracle => last round id + 1 submitted uint32 public quorumThreshold = 1; // number of independent oracles required per round uint256 public nextTierRequestId = 1; mapping(uint256 => uint256) public tierRequestAgent; mapping(uint256 => bytes32) public tierRequestHandle; uint256 public nextSlashRequestId = 1; mapping(uint256 => uint256) public slashRequestAgent; mapping(uint256 => bytes32) public slashRequestHandle; uint256 public nextLiquidationRequestId = 1; mapping(uint256 => uint256) public liquidationRequestAgent; IReputationBadge public reputationBadge; IInsurancePool public insurancePool; // FHE-ML Neural Perceptron Weights (Underwriter Configurable) uint32 public weightCompletion = 40; uint32 public weightUptime = 30; uint32 public weightLatency = 15; uint32 public weightError = 80; uint32 public neuronBias = 200; uint32 public maxNeuralRiskThreshold = 1200; // ReLU risk limit uint64 private constant W_COMPLETION = 40; uint64 private constant W_UPTIME = 30; uint64 private constant W_LATENCY = 15; uint64 private constant W_ERROR = 15; uint64 private constant HIGH_TRUST_THRESHOLD = 750; uint64 private constant MED_TRUST_THRESHOLD = 400; uint64 private constant HIGH_TRUST_BOND = uint64(0.1 ether); uint64 private constant MED_TRUST_BOND = uint64(1 ether); uint64 private constant LOW_TRUST_BOND = uint64(5 ether); uint256 private constant SLASH_BPS = 1000; // 10% of posted bond uint256 private constant ORACLE_VAR = 50; uint256 private constant PREMIUM_PER_VAR_WEI = 0.04 ether; // 0.04 ETH per unit of variance event AgentRegistered(uint256 indexed agentId, address indexed operator, uint256 identityId); event OracleAuthorized(address indexed oracle); event UnderwriterAuthorized(address indexed underwriter); event TelemetrySubmitted(uint256 indexed agentId, address indexed oracle, uint256 roundId); event ScoreUpdated(uint256 indexed agentId, uint256 roundId); event BondDeposited(uint256 indexed agentId, uint256 amount, uint256 totalPosted); event BondWithdrawn(uint256 indexed agentId, uint256 amount); event TierRevealRequested(uint256 indexed agentId, uint256 indexed requestId); event TierRevealed(uint256 indexed agentId, uint64 tierCode); event SlashCheckRequested(uint256 indexed agentId, uint256 indexed requestId); event SlashCheckFulfilled(uint256 indexed agentId, bool breached); event AgentSlashed(uint256 indexed agentId, uint256 penalty); event AgentLiquidated(uint256 indexed agentId, uint256 slashedAmount); event LiquidationCheckRequested(uint256 indexed agentId, uint256 indexed requestId); event TaskRegistered(uint256 indexed taskId, uint256 indexed agentId, address indexed client, uint256 coverageLimit); event ClaimPaid(uint256 indexed taskId, uint256 indexed agentId, address indexed client, uint256 payoutAmount); event NeuronWeightsUpdated(uint32 wComp, uint32 wUpt, uint32 wLat, uint32 wErr, uint32 bias, uint32 threshold); event ReputationBadgeSet(address indexed badge); event InsurancePoolSet(address indexed pool); event LeaseRequested(uint256 indexed leaseId, address indexed lessee, uint256 hardwareId, uint256 requiredBond); event LeaseSettled(uint256 indexed leaseId, address indexed lessee, uint256 hardwareId, bool success, uint256 payout); event SalaryStreamCreated(address indexed recipient); event StreamClaimRequested(address indexed recipient, uint256 indexed requestId); event StreamClaimed(address indexed recipient, uint256 amount); modifier onlyAdmin() { require(msg.sender == admin); _; } modifier onlyOracle() { require(authorizedOracles[msg.sender]); _; } modifier onlyAgentOperator(uint256 agentId) { require(_agents[agentId].operator == msg.sender); _; } constructor() { admin = msg.sender; } function setQuorumThreshold(uint32 threshold) external onlyAdmin { require(threshold >= 1); quorumThreshold = threshold; } function setReputationBadge(address badge) external onlyAdmin { require(address(reputationBadge) == address(0)); reputationBadge = IReputationBadge(badge); emit ReputationBadgeSet(badge); } function setInsurancePool(address pool) external onlyAdmin { require(address(insurancePool) == address(0)); insurancePool = IInsurancePool(pool); emit InsurancePoolSet(pool); } function authorizeOracle(address oracle) external onlyAdmin { authorizedOracles[oracle] = true; emit OracleAuthorized(oracle); } function authorizeUnderwriter(address underwriter) external onlyAdmin { authorizedUnderwriters[underwriter] = true; emit UnderwriterAuthorized(underwriter); } /// @notice Register a new autonomous agent/robot under a given operator. /// @param identityId optional AgentIdentityRegistry id (0 if not using the registry). function registerAgent(address operator, uint256 identityId) external onlyAdmin returns (uint256 agentId) { agentId = nextAgentId++; Agent storage a = _agents[agentId]; a.operator = operator; a.registered = true; a.active = true; a.identityId = identityId; a.trustScore = FHE.asEuint64(500); // neutral starting score a.trustScoreVar = 100; a.liquidationThreshold = FHE.asEuint64(300); a.requiredBond = _deriveBond(a.trustScore, 100); a.delegatedBond = 0; a.interestAccumulated = 0; a.lastInterestUpdateTime = block.timestamp; FHE.allowThis(a.trustScore); FHE.allowThis(a.requiredBond); FHE.allowThis(a.liquidationThreshold); FHE.allow(a.trustScore, operator); FHE.allow(a.requiredBond, operator); FHE.allow(a.liquidationThreshold, operator); emit AgentRegistered(agentId, operator, identityId); } /// @notice Submit fully-encrypted telemetry for a completed task. Only /// authorized oracles may call this. The submission only affects the /// agent's score once `quorumThreshold` independent oracles have /// submitted within the current round. function submitTelemetry( uint256 agentId, externalEuint64 completionScoreA, externalEuint64 completionScoreB, externalEuint64 uptimeScore, externalEuint64 latencyScore, externalEuint64 errorScore, bytes calldata inputProof ) external onlyOracle { Agent storage a = _agents[agentId]; require(a.registered && a.active); uint256 roundId = currentRoundId[agentId]; require(_oracleLastRound[agentId][msg.sender] != roundId + 1); _oracleLastRound[agentId][msg.sender] = roundId + 1; euint64 compA = FHE.fromExternal(completionScoreA, inputProof); euint64 compB = FHE.fromExternal(completionScoreB, inputProof); euint64 uptime = FHE.fromExternal(uptimeScore, inputProof); euint64 latency = FHE.fromExternal(latencyScore, inputProof); euint64 errorP = FHE.fromExternal(errorScore, inputProof); // Compute absolute differences for anomaly detection (Completion only) ebool compAltB = FHE.lt(compA, compB); euint64 compDiff = FHE.select(compAltB, FHE.sub(compB, compA), FHE.sub(compA, compB)); ebool compAnomaly = FHE.gt(compDiff, FHE.asEuint64(2)); // Apply sensor fusion outlier filter euint64 completion = FHE.select(compAnomaly, FHE.asEuint64(0), FHE.div(FHE.add(compA, compB), 2)); uptime = FHE.select(compAnomaly, FHE.asEuint64(0), uptime); latency = FHE.select(compAnomaly, FHE.asEuint64(0), latency); errorP = FHE.select(compAnomaly, FHE.asEuint64(10), errorP); PendingRound storage round = _pendingRounds[agentId]; if (!round.initialized) { round.sumCompletion = completion; round.sumUptime = uptime; round.sumLatency = latency; round.sumError = errorP; round.initialized = true; } else { round.sumCompletion = FHE.add(round.sumCompletion, completion); round.sumUptime = FHE.add(round.sumUptime, uptime); round.sumLatency = FHE.add(round.sumLatency, latency); round.sumError = FHE.add(round.sumError, errorP); } round.count += 1; FHE.allowThis(round.sumCompletion); FHE.allowThis(round.sumUptime); FHE.allowThis(round.sumLatency); FHE.allowThis(round.sumError); emit TelemetrySubmitted(agentId, msg.sender, roundId); if (round.count >= quorumThreshold) { euint64 avgCompletion = FHE.div(round.sumCompletion, quorumThreshold); euint64 avgUptime = FHE.div(round.sumUptime, quorumThreshold); euint64 avgLatency = FHE.div(round.sumLatency, quorumThreshold); euint64 avgError = FHE.div(round.sumError, quorumThreshold); _applyScoreUpdate(agentId, avgCompletion, avgUptime, avgLatency, avgError); delete _pendingRounds[agentId]; currentRoundId[agentId] = roundId + 1; emit ScoreUpdated(agentId, roundId); } } function _applyScoreUpdate( uint256 agentId, euint64 completion, euint64 uptime, euint64 latency, euint64 errorP ) private { Agent storage a = _agents[agentId]; euint64 weightedObs = FHE.add( FHE.add(FHE.mul(completion, W_COMPLETION), FHE.mul(uptime, W_UPTIME)), FHE.mul(latency, W_LATENCY) ); euint64 penalty = FHE.mul(errorP, W_ERROR); ebool obsUnderflow = FHE.lt(weightedObs, penalty); euint64 x_obs = FHE.select(obsUnderflow, FHE.asEuint64(0), FHE.sub(weightedObs, penalty)); // Bayesian Update for variance and weights uint256 oldVar = a.trustScoreVar; uint256 newVar = (oldVar * ORACLE_VAR) / (oldVar + ORACLE_VAR); if (newVar < 10) { newVar = 10; } a.trustScoreVar = newVar; uint256 alpha = (ORACLE_VAR * 100) / (oldVar + ORACLE_VAR); uint256 beta = (oldVar * 100) / (oldVar + ORACLE_VAR); // Weighted FHE score update euint64 term1 = FHE.mul(a.trustScore, uint64(alpha)); euint64 term2 = FHE.mul(x_obs, uint64(beta)); euint64 newScore = FHE.div(FHE.add(term1, term2), 100); a.trustScore = newScore; a.requiredBond = _deriveBond(newScore, newVar); uint256 dt = block.timestamp - a.lastInterestUpdateTime; a.lastInterestUpdateTime = block.timestamp; if (dt > 0 && a.delegatedBond > 0) { uint256 apr = 500; // default 5% APR if (address(reputationBadge) != address(0)) { uint8 tier = reputationBadge.tierOf(agentId); if (tier == 3) apr = 100; else if (tier == 2) apr = 500; else if (tier == 1) apr = 2500; } uint256 interestAcc = (a.delegatedBond * apr * dt) / 8640000000; a.interestAccumulated += interestAcc; } euint64 totalCollateral = FHE.add(FHE.asEuint64(uint64(_clampToU64(a.postedBond))), FHE.asEuint64(uint64(_clampToU64(a.delegatedBond)))); a.bondSufficient = FHE.ge(totalCollateral, a.requiredBond); FHE.allowThis(a.trustScore); FHE.allowThis(a.requiredBond); FHE.allowThis(a.bondSufficient); FHE.allow(a.trustScore, a.operator); FHE.allow(a.requiredBond, a.operator); // On-chain FHE Perceptron (Confidential AI Model Inference) euint64 positiveRisk = FHE.add( FHE.add(FHE.mul(latency, weightLatency), FHE.mul(errorP, weightError)), FHE.asEuint64(neuronBias) ); euint64 negativeRisk = FHE.add( FHE.mul(completion, weightCompletion), FHE.mul(uptime, weightUptime) ); ebool riskUnderflow = FHE.lt(positiveRisk, negativeRisk); euint64 neuralRisk = FHE.select(riskUnderflow, FHE.asEuint64(0), FHE.sub(positiveRisk, negativeRisk)); ebool isNeuralBreach = FHE.gt(neuralRisk, FHE.asEuint64(maxNeuralRiskThreshold)); ebool breachedLimit = FHE.or(FHE.lt(newScore, a.liquidationThreshold), isNeuralBreach); euint64 severity = FHE.sub(FHE.asEuint64(1000), newScore); bytes32[] memory cts = new bytes32[](2); cts[0] = ebool.unwrap(breachedLimit); cts[1] = euint64.unwrap(severity); uint256 reqId = FHE.requestDecryption(cts, this.fulfillLiquidation.selector); liquidationRequestAgent[reqId] = agentId; emit LiquidationCheckRequested(agentId, reqId); } /// @dev Confidential decision-tree: three bond tiers selected entirely /// under encryption via FHE.select, plus a dynamic uncertainty premium. function _deriveBond(euint64 score, uint256 variance) private returns (euint64) { ebool highTrust = FHE.ge(score, FHE.asEuint64(HIGH_TRUST_THRESHOLD)); ebool medTrust = FHE.ge(score, FHE.asEuint64(MED_TRUST_THRESHOLD)); euint64 baseBond = FHE.select(medTrust, FHE.asEuint64(MED_TRUST_BOND), FHE.asEuint64(LOW_TRUST_BOND)); baseBond = FHE.select(highTrust, FHE.asEuint64(HIGH_TRUST_BOND), baseBond); uint256 premium = variance * PREMIUM_PER_VAR_WEI; return FHE.add(baseBond, FHE.asEuint64(uint64(premium))); } function _clampToU64(uint256 value) private pure returns (uint256) { uint256 maxU64 = type(uint64).max; return value > maxU64 ? maxU64 : value; } /// @notice Operator posts native-token collateral for an agent. function depositBond(uint256 agentId) external payable onlyAgentOperator(agentId) { require(msg.value > 0); Agent storage a = _agents[agentId]; a.postedBond += msg.value; a.bondSufficient = FHE.ge(FHE.asEuint64(uint64(_clampToU64(a.postedBond))), a.requiredBond); FHE.allowThis(a.bondSufficient); FHE.allow(a.bondSufficient, a.operator); emit BondDeposited(agentId, msg.value, a.postedBond); } /// @notice Operator withdraws excess collateral. Confidential sufficiency /// should be re-checked off-chain via the relayer SDK before withdrawing, /// since the exact required bond stays encrypted on-chain. function withdrawBond(uint256 agentId, uint256 amount) external onlyAgentOperator(agentId) { Agent storage a = _agents[agentId]; require(amount <= a.postedBond); a.postedBond -= amount; a.bondSufficient = FHE.ge(FHE.asEuint64(uint64(_clampToU64(a.postedBond))), a.requiredBond); FHE.allowThis(a.bondSufficient); FHE.allow(a.bondSufficient, a.operator); payable(msg.sender).transfer(amount); emit BondWithdrawn(agentId, amount); } /// @notice Grant an authorized underwriter/insurer read access to an /// agent's encrypted trust score, required bond, and sufficiency flag -- /// without exposing the raw telemetry that produced them. function grantUnderwriterAccess(uint256 agentId, address underwriter) external onlyAgentOperator(agentId) { require(authorizedUnderwriters[underwriter]); Agent storage a = _agents[agentId]; FHE.allow(a.trustScore, underwriter); FHE.allow(a.requiredBond, underwriter); FHE.allow(a.bondSufficient, underwriter); } /// @notice Operator opts in to publicly reveal only the *tier* (Low/Medium/High) /// of their agent's trust score -- never the exact score -- so a soulbound /// ReputationBadge can be minted/upgraded. This is a selective disclosure, /// not a default: the raw score stays encrypted unless the operator calls this. function requestTierReveal(uint256 agentId) external onlyAgentOperator(agentId) returns (uint256 requestId) { Agent storage a = _agents[agentId]; ebool highTrust = FHE.ge(a.trustScore, FHE.asEuint64(HIGH_TRUST_THRESHOLD)); ebool medTrust = FHE.ge(a.trustScore, FHE.asEuint64(MED_TRUST_THRESHOLD)); euint64 tierCode = FHE.select(highTrust, FHE.asEuint64(3), FHE.select(medTrust, FHE.asEuint64(2), FHE.asEuint64(1))); bytes32[] memory cts = new bytes32[](1); cts[0] = euint64.unwrap(tierCode); requestId = FHE.requestDecryption(cts, this.fulfillTierReveal.selector); tierRequestAgent[requestId] = agentId; emit TierRevealRequested(agentId, requestId); } /// @notice Called with the Zama KMS's decrypted cleartext + proof (via the /// relayer SDK's public-decrypt flow) to finalize a tier reveal. function fulfillTierReveal(uint256 requestId, bytes memory cleartexts, bytes memory decryptionProof) external { FHE.checkSignatures(requestId, cleartexts, decryptionProof); uint64 tierCode = abi.decode(cleartexts, (uint64)); uint256 agentId = tierRequestAgent[requestId]; delete tierRequestAgent[requestId]; if (address(reputationBadge) != address(0)) { reputationBadge.mintOrUpgrade(agentId, _agents[agentId].operator, uint8(tierCode)); } emit TierRevealed(agentId, tierCode); } /// @notice An authorized oracle flags a possible SLA breach with an /// encrypted 0/1 signal. Nothing happens on-chain until the flag is /// confidentially checked and revealed via fulfillSlashCheck. function requestSlashCheck( uint256 agentId, externalEuint64 breachSignal, bytes calldata inputProof ) external onlyOracle returns (uint256 requestId) { Agent storage a = _agents[agentId]; require(a.registered); euint64 signal = FHE.fromExternal(breachSignal, inputProof); ebool breached = FHE.eq(signal, FHE.asEuint64(1)); bytes32[] memory cts = new bytes32[](1); cts[0] = ebool.unwrap(breached); requestId = FHE.requestDecryption(cts, this.fulfillSlashCheck.selector); slashRequestAgent[requestId] = agentId; emit SlashCheckRequested(agentId, requestId); } /// @notice Finalizes a slash check using the Zama KMS's decrypted /// cleartext + proof. If breached, 10% of the posted bond is slashed and /// forwarded to the InsurancePool (if configured) as LP yield. function fulfillSlashCheck(uint256 requestId, bytes memory cleartexts, bytes memory decryptionProof) external { FHE.checkSignatures(requestId, cleartexts, decryptionProof); bool breached = abi.decode(cleartexts, (bool)); uint256 agentId = slashRequestAgent[requestId]; delete slashRequestAgent[requestId]; if (breached) { Agent storage a = _agents[agentId]; uint256 penalty = (a.postedBond * SLASH_BPS) / 10000; if (penalty > 0) { a.postedBond -= penalty; a.breachCount += 1; a.bondSufficient = FHE.ge(FHE.asEuint64(uint64(_clampToU64(a.postedBond))), a.requiredBond); FHE.allowThis(a.bondSufficient); FHE.allow(a.bondSufficient, a.operator); if (address(insurancePool) != address(0)) { insurancePool.receivePenalty{value: penalty}(agentId); } emit AgentSlashed(agentId, penalty); } } emit SlashCheckFulfilled(agentId, breached); } /// @notice Finalizes a liquidation check using the Zama KMS's decrypted /// cleartext + proof. If breached, the agent is deactivated and its remaining /// posted bond is fully slashed to the InsurancePool. function fulfillLiquidation(uint256 requestId, bytes memory cleartexts, bytes memory decryptionProof) external { FHE.checkSignatures(requestId, cleartexts, decryptionProof); (bool breached, uint256 severity) = abi.decode(cleartexts, (bool, uint256)); uint256 agentId = liquidationRequestAgent[requestId]; delete liquidationRequestAgent[requestId]; if (breached) { Agent storage a = _agents[agentId]; a.active = false; uint256 selfBond = a.postedBond; uint256 borrowedBond = a.delegatedBond; a.postedBond = 0; a.delegatedBond = 0; a.bondSufficient = FHE.asEbool(false); FHE.allowThis(a.bondSufficient); FHE.allow(a.bondSufficient, a.operator); uint256 totalBond = selfBond + borrowedBond; uint256 payoutAmount = 0; uint256 taskId = agentActiveTaskId[agentId]; if (taskId > 0 && tasks[taskId].active) { payoutAmount = (tasks[taskId].coverageLimit * severity) / 1000; if (payoutAmount > totalBond) { payoutAmount = totalBond; } Task storage t = tasks[taskId]; t.active = false; agentActiveTaskId[agentId] = 0; if (payoutAmount > 0) { payable(t.client).transfer(payoutAmount); emit ClaimPaid(taskId, agentId, t.client, payoutAmount); } } uint256 remainder = totalBond - payoutAmount; if (remainder > 0) { if (address(insurancePool) != address(0)) { insurancePool.receivePenalty{value: remainder}(agentId); } emit AgentLiquidated(agentId, remainder); } } } function getAgent(uint256 agentId) external view returns (address operator, bool registered, bool active, uint256 postedBond, uint256 breachCount, uint256 identityId, uint256 trustScoreVar) { Agent storage a = _agents[agentId]; return (a.operator, a.registered, a.active, a.postedBond, a.breachCount, a.identityId, a.trustScoreVar); } function getEncryptedTrustScore(uint256 agentId) external view returns (euint64) { return _agents[agentId].trustScore; } function getEncryptedRequiredBond(uint256 agentId) external view returns (euint64) { return _agents[agentId].requiredBond; } function getEncryptedBondSufficiency(uint256 agentId) external view returns (ebool) { return _agents[agentId].bondSufficient; } function getDelegatedBond(uint256 agentId) external view returns (uint256) { return _agents[agentId].delegatedBond; } function getInterestAccumulated(uint256 agentId) external view returns (uint256) { return _agents[agentId].interestAccumulated; } event CreditDelegated(uint256 indexed agentId, uint256 amount); event InterestRepaid(uint256 indexed agentId, uint256 amount); function requestCreditDelegation(uint256 agentId, uint256 amount) external { Agent storage a = _agents[agentId]; require(msg.sender == a.operator); require(a.registered && a.active); require(address(insurancePool) != address(0)); insurancePool.delegateCredit(agentId, amount); a.delegatedBond += amount; euint64 totalCollateral = FHE.add(FHE.asEuint64(uint64(_clampToU64(a.postedBond))), FHE.asEuint64(uint64(_clampToU64(a.delegatedBond)))); a.bondSufficient = FHE.ge(totalCollateral, a.requiredBond); FHE.allowThis(a.bondSufficient); FHE.allow(a.bondSufficient, a.operator); emit CreditDelegated(agentId, amount); } function repayInterest(uint256 agentId) external payable { Agent storage a = _agents[agentId]; require(a.registered && a.active); require(msg.value > 0); if (msg.value >= a.interestAccumulated) { a.interestAccumulated = 0; } else { a.interestAccumulated -= msg.value; } insurancePool.repayCredit{value: msg.value}(agentId); emit InterestRepaid(agentId, msg.value); } function registerUnderwrittenTask(uint256 agentId, address client, uint256 coverageLimit) external returns (uint256 taskId) { Agent storage a = _agents[agentId]; require(msg.sender == a.operator || msg.sender == admin); require(a.registered && a.active); require(agentActiveTaskId[agentId] == 0); uint256 totalCollateral = a.postedBond + a.delegatedBond; require(totalCollateral >= coverageLimit); taskId = nextTaskId++; Task storage t = tasks[taskId]; t.agentId = agentId; t.client = client; t.coverageLimit = coverageLimit; t.active = true; agentActiveTaskId[agentId] = taskId; emit TaskRegistered(taskId, agentId, client, coverageLimit); } function deactivateAgent(uint256 agentId) external onlyAdmin { _agents[agentId].active = false; } function updateNeuronWeights( uint32 wComp, uint32 wUpt, uint32 wLat, uint32 wErr, uint32 bias, uint32 threshold ) external onlyAdmin { weightCompletion = wComp; weightUptime = wUpt; weightLatency = wLat; weightError = wErr; neuronBias = bias; maxNeuralRiskThreshold = threshold; emit NeuronWeightsUpdated(wComp, wUpt, wLat, wErr, bias, threshold); } function requestLeaseHardware( uint256 agentId, uint256 hardwareId, uint256 leaseBond ) external returns (uint256 leaseId) { Agent storage a = _agents[agentId]; require(msg.sender == a.operator); require(a.registered && a.active); require(address(reputationBadge) != address(0)); require(address(insurancePool) != address(0)); require(userActiveLeaseId[msg.sender] == 0); uint8 tier = reputationBadge.tierOf(agentId); require(tier >= 2); insurancePool.delegateCredit(agentId, leaseBond); leaseId = nextLeaseId++; Lease storage l = leases[leaseId]; l.lessee = msg.sender; l.agentId = agentId; l.hardwareId = hardwareId; l.requiredBond = leaseBond; l.startTimestamp = block.timestamp; l.active = true; userActiveLeaseId[msg.sender] = leaseId; emit LeaseRequested(leaseId, msg.sender, hardwareId, leaseBond); } function settleLeaseHardware(uint256 leaseId, bool success) external onlyAdmin { Lease storage l = leases[leaseId]; require(l.active); l.active = false; userActiveLeaseId[l.lessee] = 0; uint256 payout = 0; if (!success) { payout = l.requiredBond; payable(admin).transfer(payout); } else { insurancePool.repayCredit{value: l.requiredBond}(l.agentId); } emit LeaseSettled(leaseId, l.lessee, l.hardwareId, success, payout); } // FHE-Stream: Confidential Salary & Yield Streaming Implementation function createSalaryStream( address recipient, externalEuint64 hRate, bytes calldata inputProof ) external onlyAdmin { require(!_salaryStreams[recipient].active); _salaryStreams[recipient].flowRate = FHE.fromExternal(hRate, inputProof); _salaryStreams[recipient].lastClaimBlock = block.number; _salaryStreams[recipient].active = true; FHE.allow(_salaryStreams[recipient].flowRate, recipient); FHE.allowThis(_salaryStreams[recipient].flowRate); emit SalaryStreamCreated(recipient); } function claimSalaryStream() external returns (uint256 requestId) { address recipient = msg.sender; SalaryStream storage stream = _salaryStreams[recipient]; require(stream.active); require(block.number > stream.lastClaimBlock); uint256 blocksAccrued = block.number - stream.lastClaimBlock; stream.lastClaimBlock = block.number; euint64 accrued = FHE.mul(stream.flowRate, uint64(blocksAccrued)); FHE.allowThis(accrued); bytes32[] memory cts = new bytes32[](1); cts[0] = euint64.unwrap(accrued); requestId = FHE.requestDecryption(cts, this.fulfillStreamClaim.selector); streamRequests[requestId] = recipient; emit StreamClaimRequested(recipient, requestId); } function fulfillStreamClaim( uint256 requestId, bytes memory cleartexts, bytes memory decryptionProof ) external { FHE.checkSignatures(requestId, cleartexts, decryptionProof); uint256 amount = abi.decode(cleartexts, (uint256)); address recipient = streamRequests[requestId]; delete streamRequests[requestId]; if (amount > 0) { payable(recipient).transfer(amount); } emit StreamClaimed(recipient, amount); } receive() external payable {} }