{
  "schema": "yieldshield-arc/agent-manifest/v1",
  "name": "YieldShield Arc",
  "summary": "USDC-backed split-risk protection markets on Arc testnet. A holder deposits EURC or cirBTC for a fixed USDC entry claim reserved at 150% by capital providers. Before maturity the holder either keeps the asset minus fees on realized gains (10% providers, 1% creator, 1% protocol) or surrenders it for the fixed USDC claim. After maturity anyone may settle remaining positions into pull claims.",
  "site": "https://arc.yieldshield.ai",
  "llms": "https://arc.yieldshield.ai/llms.txt",
  "status": {
    "deployment": "deployed-and-verified",
    "writesEnabled": true,
    "deploymentId": "arc-testnet-2026-10-19T13-33-11Z-5929f2",
    "verifiedAt": "2026-10-20T06:35:30.637Z",
    "sourceCommit": "d48ec2656cbb07c83efa5a2d1402647175c2b01f",
    "testnetOnly": true,
    "audited": false,
    "verificationMethod": "runtime-bytecode-configuration-and-receipts",
    "explorerSourceVerified": false,
    "testTokensHaveMonetaryValue": false,
    "note": "Arc testnet deployment checked against runtime bytecode, configuration and receipts. Source is not published as verified on the explorer. Unaudited prototype; test tokens only."
  },
  "agentPolicy": {
    "signing": "never",
    "custody": "none",
    "output": "unsigned EVM transactions { chainId, to, data, value: '0x0' } for the user's own wallet to review and sign",
    "mustNotDo": [
      "sign or broadcast transactions",
      "request or store private keys or seed phrases",
      "describe a position as loss-proof, as cover against loss, or as earning a promised return",
      "present the scenario market's synthetic price as a market price",
      "treat testnet activity as adoption or value"
    ]
  },
  "network": {
    "name": "Arc Testnet",
    "chainId": 5042002,
    "rpcUrl": "https://rpc.blockdaemon.testnet.arc.io",
    "explorer": "https://explorer.testnet.arc.io",
    "multicall3": "0xcA11bde05977b3631167028862bE2a173976CA11",
    "faucet": "https://faucet.circle.com",
    "nativeCurrency": {
      "symbol": "USDC",
      "decimals": 18
    },
    "notes": [
      "USDC is Arc's gas token. Native balance (18 decimals) and the USDC ERC-20 interface (6 decimals) are one balance; contracts here use only the ERC-20 interface.",
      "Keep about 0.1 USDC unspent for network fees when preparing USDC deposits.",
      "Minimum base fee 20 gwei; transactions with a lower maxFeePerGas are dropped silently.",
      "Blocks are final on inclusion; block timestamps are non-decreasing, not strictly increasing."
    ]
  },
  "assets": [
    {
      "symbol": "USDC",
      "role": "backing and gas",
      "address": "0x3600000000000000000000000000000000000000",
      "decimals": 6,
      "issuer": "Circle (testnet, no monetary value)"
    },
    {
      "symbol": "EURC",
      "role": "protected asset",
      "address": "0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a",
      "decimals": 6,
      "issuer": "Circle (testnet, no monetary value)"
    },
    {
      "symbol": "cirBTC",
      "role": "protected asset",
      "address": "0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF",
      "decimals": 8,
      "issuer": "Circle (testnet, no monetary value)"
    }
  ],
  "contracts": {
    "factory": "0x77dd612d711c5c3328c6a0eebcb9719955895e1c",
    "deployer": "0x10D42586A65a98BCa4baFAa1bF5DCB10c820f50a",
    "abis": {
      "pool": "https://arc.yieldshield.ai/abi/ShieldPool.json",
      "factory": "https://arc.yieldshield.ai/abi/ShieldFactory.json",
      "chronicleOracle": "https://arc.yieldshield.ai/abi/ShieldChronicleOracle.json",
      "erc20": "https://arc.yieldshield.ai/abi/IERC20Metadata.json"
    },
    "signatures": {
      "pool": [
        "function protect(uint256 amount, uint256 minFloor, uint256 deadline) returns (uint256 id)",
        "function exitAsset(uint256 id, uint256 minAsset)",
        "function partialExitAsset(uint256 id, uint256 amount, uint256 minAsset, uint256 deadline)",
        "function exitBacking(uint256 id)",
        "function partialExitBacking(uint256 id, uint256 amount, uint256 minBacking, uint256 deadline)",
        "function transferPosition(uint256 id, address recipient)",
        "function settleExpired(uint256 id)",
        "function claimBacking()",
        "function depositJuniorBounded(uint256 amount, uint256 minShares, uint256 deadline) returns (uint256)",
        "function requestJuniorWithdrawal()",
        "function cancelJuniorWithdrawal()",
        "function withdrawJuniorBounded(uint256 burn, uint256 minBacking, uint256 minAsset, uint256 deadline)",
        "function claimRewards(address recipient)",
        "function claimFees(address recipient)",
        "function previewPartialExit(uint256 id, uint256 amount) view returns (uint256 assetOut, uint256 fee, uint256 floorOut)",
        "function previewJuniorWithdrawal(address owner, uint256 burn) view returns (uint256 backingOut, uint256 assetOut)",
        "function positions(uint256 id) view returns (address owner, uint256 amount, uint256 floor, uint256 openedAt)",
        "function openPositionIds() view returns (uint256[])",
        "function capacity() view returns (uint256)",
        "function juniorValue() view returns (uint256)",
        "function totalShares() view returns (uint256)",
        "function reservedBacking() view returns (uint256)",
        "function maturity() view returns (uint256)",
        "function terms() view returns (uint16 collateralBps, uint16 juniorFeeBps, uint16 creatorFeeBps, uint32 epochSeconds, uint32 exitDelay, uint32 juniorNotice)",
        "function assetUnit() view returns (uint256)",
        "function oracle() view returns (address)",
        "function protectedToken() view returns (address)",
        "function backing() view returns (address)"
      ],
      "factory": [
        "function allPools() view returns (address[])",
        "function isPool(address) view returns (bool)",
        "function allowed(address asset, address oracle) view returns (bool)",
        "function createPool(address asset, address oracle, (uint16,uint16,uint16,uint32,uint32,uint32) terms, uint256 deadline) returns (address)",
        "function CREATION_SEED() view returns (uint256)"
      ],
      "oracle": [
        "function price() view returns (uint256)",
        "function age() view returns (uint256)",
        "function maxAge() view returns (uint256)"
      ],
      "erc20": [
        "function approve(address spender, uint256 value) returns (bool)",
        "function allowance(address owner, address spender) view returns (uint256)",
        "function balanceOf(address) view returns (uint256)",
        "function decimals() view returns (uint8)"
      ]
    }
  },
  "oracles": {
    "eurc": {
      "adapter": "0xbe38abae66175ce0a86f529b5d564f43186b1b0a",
      "kind": "chronicle",
      "price": "USDC base units (6 decimals) per 1 EURC = Chronicle EURC/USD ÷ Chronicle USDC/USD",
      "feeds": {
        "EURC/USD": "0x4640b2AF58f6Efc32b524C61e59C99d3845aD7C1",
        "USDC/USD": "0x7fBe79354160a1C618015aa77c193CdE0FB29099"
      },
      "maxAgeSeconds": 10800,
      "synthetic": false
    },
    "cirbtc": {
      "adapter": "0x7a460202e1f8b94f44ca92dfbc2421e2ae3749b6",
      "kind": "chronicle",
      "price": "USDC base units (6 decimals) per 1 cirBTC = Chronicle CIRBTC/USDC",
      "feeds": {
        "CIRBTC/USDC": "0xAd1C417C4bc9f037Fc61DC3fbDc999e501155960"
      },
      "maxAgeSeconds": 10800,
      "synthetic": false
    },
    "scenario": {
      "adapter": "0x23adba2644297979fcb943d1d54fb1f4deeb871a",
      "kind": "synthetic",
      "price": "Deterministic public cycle: 1.10 → 1.20 → 1.00 USDC per EURC, changing every 120 seconds from deployment",
      "feeds": {},
      "maxAgeSeconds": null,
      "synthetic": true
    }
  },
  "oracleFreshnessRules": [
    "Reference adapters reject any feed value older than maxAgeSeconds (10800 s), zero, future-dated or unavailable: price() reverts with INVALID_OR_STALE_PRICE.",
    "Read age() on a reference adapter for the age in seconds of its oldest feed value; treat age() > maxAgeSeconds, or any revert, as stale.",
    "While stale, protect, exitAsset, partialExitAsset, provider deposits into pools holding surrendered assets and market creation revert. exitBacking, partialExitBacking, settleExpired and claimBacking need no price and keep working.",
    "No reference market ever falls back to the scenario price.",
    "Chronicle's Arc testnet feeds updated about every 52 minutes between 19 September and 18 October 2026, with outages of about 34 hours (7–8 October) and from 18 October 09:08 UTC. Check freshness on every request."
  ],
  "markets": [
    {
      "key": "eurc",
      "name": "EURC reference",
      "address": "0x583EcBBf94C2B978A9f02d32BF629846e9b0626C",
      "protectedAsset": "EURC",
      "backing": "USDC",
      "oracle": "eurc",
      "synthetic": false,
      "terms": {
        "collateralBps": 15000,
        "juniorFeeBps": 1000,
        "creatorFeeBps": 100,
        "epochSeconds": 2592000,
        "exitDelay": 60,
        "juniorNotice": 120
      }
    },
    {
      "key": "cirbtc",
      "name": "cirBTC reference",
      "address": "0x0B62Acf3cF6BAa9501e01cBeE0aB1D3E74654837",
      "protectedAsset": "cirBTC",
      "backing": "USDC",
      "oracle": "cirbtc",
      "synthetic": false,
      "terms": {
        "collateralBps": 15000,
        "juniorFeeBps": 1000,
        "creatorFeeBps": 100,
        "epochSeconds": 2592000,
        "exitDelay": 60,
        "juniorNotice": 120
      }
    },
    {
      "key": "scenario",
      "name": "EURC scenario lab",
      "address": "0xA18279CfC93F71d808Cb8864D52427B51666EC5e",
      "protectedAsset": "EURC",
      "backing": "USDC",
      "oracle": "scenario",
      "synthetic": true,
      "terms": {
        "collateralBps": 15000,
        "juniorFeeBps": 1000,
        "creatorFeeBps": 100,
        "epochSeconds": 2592000,
        "exitDelay": 60,
        "juniorNotice": 120
      }
    }
  ],
  "discovery": "Featured markets are listed above. Community markets: call factory.allPools(), keep addresses where factory.isPool(address) is true, and read protectedToken() and oracle() to classify them (an oracle equal to the scenario adapter is synthetic).",
  "economics": {
    "entryClaim": "floor = amount × price() ÷ 10^assetDecimals, in USDC base units, fixed at entry",
    "reserve": "a new claim is admitted only while totalBacking ≥ ceil((reserved + floor) × collateralBps ÷ 10000)",
    "gainFees": "on an asset exit, gain = max(0, value − floorOut) ÷ price in asset units; fees = gain × (juniorFeeBps + creatorFeeBps + 100) ÷ 10000",
    "exits": "after exitDelay seconds and before maturity: keep the asset (minus fees on realized gains) or surrender it for the fixed USDC claim; partial exits are proportional",
    "maturity": "at maturity asset exits close; anyone may call settleExpired(id), which credits the owner's fixed claim for claimBacking() and gives the asset to providers",
    "providers": "provider deposits and redemptions are frozen while any position is open; redemption needs requestJuniorWithdrawal() and juniorNotice seconds",
    "limits": {
      "minimumEntryClaimUsdcBaseUnits": "10000",
      "maximumOpenPositionsPerMarket": 100,
      "maximumProtectionWholeUnits": 100000,
      "protocolFeeBps": 100
    }
  },
  "safetyChecks": [
    "eth_chainId equals the manifest chainId (5042002); refuse any other chain.",
    "status.writesEnabled is true; otherwise prepare nothing.",
    "factory.isPool(market) is true and market.protectedToken(), backing() and oracle() match this manifest.",
    "Chain time + terms.exitDelay < maturity() for new protection; chain time < maturity() for provider deposits and asset exits.",
    "For reference markets: price() succeeds and age() ≤ maxAge(). Never substitute the scenario price.",
    "floor ≥ 10000 (0.01 USDC) and floor ≤ capacity(); openPositionIds().length < 100.",
    "Provider deposits: reservedBacking() == 0; user's USDC balance minus the deposit leaves ≥ 0.1 USDC for gas.",
    "User holds the token amount and has enough allowance, or prepend an exact approve(pool, amount).",
    "Simulate every prepared call with eth_call from the user's address before handing it over."
  ],
  "unsignedTransactions": {
    "conventions": {
      "format": "{ chainId: 5042002, to, data, value }",
      "value": "always 0: no function is payable and native USDC is never sent to these contracts",
      "gas": "estimate, then add 30%: a mined oracle read can cost more than its estimate",
      "order": "one transaction per action",
      "deadline": "latest block timestamp + 600 seconds",
      "slippage": "minimum outputs = ceil(quote × 0.995); quote with previewPartialExit or previewJuniorWithdrawal at the latest block",
      "approvals": "exact-amount approve(spender, amount) on the token, never unlimited"
    },
    "recipes": [
      {
        "intent": "protect",
        "plannedMcpTool": "yieldshield_prepare_deposit_shielded",
        "steps": [
          "asset.approve(market, amount)",
          "market.protect(amount, minFloor = ceil(amount × price ÷ 10^decimals × 0.995), deadline)"
        ]
      },
      {
        "intent": "asset exit (keep the asset)",
        "plannedMcpTool": "yieldshield_prepare_partial_withdraw_shielded",
        "steps": [
          "(assetOut,,) = market.previewPartialExit(id, amount)",
          "market.partialExitAsset(id, amount, minAsset = ceil(assetOut × 0.995), deadline)"
        ]
      },
      {
        "intent": "backing exit (take the fixed USDC claim)",
        "plannedMcpTool": "yieldshield_prepare_withdraw",
        "steps": [
          "floorOut = amount == position.amount ? position.floor : position.floor × amount ÷ position.amount",
          "market.partialExitBacking(id, amount, minBacking = floorOut, deadline)"
        ]
      },
      {
        "intent": "settle after maturity (anyone) and claim (owner)",
        "plannedMcpTool": "yieldshield_prepare_withdraw",
        "steps": [
          "market.settleExpired(id)",
          "market.claimBacking() from the owner"
        ]
      },
      {
        "intent": "provide USDC",
        "plannedMcpTool": "yieldshield_prepare_deposit_backing",
        "steps": [
          "usdc.approve(market, amount)",
          "market.depositJuniorBounded(amount, minShares = ceil(expectedShares × 0.995), deadline)"
        ]
      },
      {
        "intent": "provider redemption",
        "plannedMcpTool": "yieldshield_prepare_unlock / yieldshield_prepare_protector_withdraw",
        "steps": [
          "market.requestJuniorWithdrawal(); wait terms.juniorNotice seconds and until reservedBacking() == 0",
          "(backingOut, assetOut) = market.previewJuniorWithdrawal(owner, shares)",
          "market.withdrawJuniorBounded(shares, ceil(backingOut × 0.995), ceil(assetOut × 0.995), deadline)"
        ]
      },
      {
        "intent": "claim fees",
        "plannedMcpTool": "yieldshield_prepare_claim_rewards / yieldshield_prepare_claim_commission",
        "steps": [
          "market.claimRewards(recipient) for provider gain fees",
          "market.claimFees(recipient) for creator or protocol fees"
        ]
      }
    ]
  },
  "roadmap": {
    "mcp": "Planned (grant milestone): expose these reads and recipes as YieldShield MCP tools (list pools, pool safety, oracle freshness, unsigned transaction preparation) using the main repository's agent-core.",
    "cctp": "Planned, not implemented: App Kit Bridge exits from Arc Testnet (domain 26) to Ethereum Sepolia (0) and Base Sepolia (6). USDC uses TokenMessengerV2.depositForBurn; EURC uses CrossChainTokenService.crossChainTransfer with per-token TokenManager approval. Separate user-reviewed transfers; four completed token/route combinations required for the grant milestone."
  }
}
