{"version":3,"sources":["../src/relay-feedback.ts"],"sourcesContent":["// src/relay-feedback.ts\n// Standalone utility for submitting ERC-8004 feedback about third-party APIs.\n// Not a plugin — call directly from your relay/aggregator application code.\n\nimport { ethers } from 'ethers';\n\nexport interface RelayFeedbackConfig {\n  /**\n   * ERC-8004 agentId (NFT tokenId) of the **target API** you are calling.\n   */\n  agentId: string | number;\n  /**\n   * Whether the API call succeeded.\n   */\n  success: boolean;\n  /**\n   * Elapsed milliseconds for the API call.\n   */\n  responseTimeMs?: number;\n  /**\n   * Endpoint path of the called API (e.g. '/v1/data').\n   */\n  endpoint?: string;\n  /**\n   * Private key of the **relay/third-party** wallet that signs feedback.\n   * MUST be different from the API owner's wallet — ReputationRegistry\n   * may restrict self-feedback. Wallet needs CREDIT tokens on SKALE Base.\n   * Default: process.env.FEEDBACK_WALLET_PRIVATE_KEY\n   */\n  feedbackWalletPrivateKey?: string;\n  /**\n   * SKALE Base Sepolia RPC URL.\n   * Default: process.env.ERC8004_RPC_URL or SKALE Base Sepolia public RPC.\n   */\n  rpcUrl?: string;\n  /**\n   * ERC-8004 ReputationRegistry contract address.\n   * Default: process.env.ERC8004_REPUTATION_REGISTRY\n   */\n  reputationRegistryAddress?: string;\n}\n\nconst RELAY_FEEDBACK_REPUTATION_ABI = [\n  'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash) external',\n];\n\n/**\n * Submit ERC-8004 on-chain feedback about a **third-party API** you called.\n *\n * Call this fire-and-forget from your relay/aggregator after every external API call.\n * Uses a separate relay wallet (not the API owner's key) to avoid self-feedback restrictions.\n *\n * Records:\n * - `successRate`: 10000 (= 100%) on success, 0 on failure — 2 decimal places\n * - `responseTime`: elapsed milliseconds\n *\n * @example\n * ```typescript\n * import { submitRelayFeedback } from '@relai-fi/x402/relay-feedback';\n *\n * // after calling an external API:\n * const start = Date.now();\n * const result = await fetch('https://other-api.com/data');\n * submitRelayFeedback({\n *   agentId: '5',\n *   success: result.ok,\n *   responseTimeMs: Date.now() - start,\n *   endpoint: '/data',\n * });\n * ```\n */\nexport function submitRelayFeedback(config: RelayFeedbackConfig): void {\n  const agentId = String(config.agentId);\n  const endpoint = config.endpoint ?? '';\n  const responseTimeMs = config.responseTimeMs ?? 0;\n\n  const privateKey = config.feedbackWalletPrivateKey\n    ?? (typeof process !== 'undefined'\n      ? process.env?.FEEDBACK_WALLET_PRIVATE_KEY ?? process.env?.ERC8004_FEEDBACK_WALLET_PRIVATE_KEY\n      : undefined);\n  const reputationAddress = config.reputationRegistryAddress\n    ?? (typeof process !== 'undefined' ? process.env?.ERC8004_REPUTATION_REGISTRY : undefined);\n  const rpcUrl = config.rpcUrl\n    ?? (typeof process !== 'undefined' ? process.env?.ERC8004_RPC_URL : undefined)\n    ?? 'https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha';\n\n  if (!privateKey || !reputationAddress) {\n    console.warn('[relai:submitRelayFeedback] FEEDBACK_WALLET_PRIVATE_KEY or ERC8004_REPUTATION_REGISTRY not set — skipping');\n    return;\n  }\n\n  const provider = new ethers.JsonRpcProvider(rpcUrl);\n  const signer = new ethers.Wallet(privateKey, provider);\n  const reputation = new ethers.Contract(reputationAddress, RELAY_FEEDBACK_REPUTATION_ABI, signer);\n  const id = BigInt(agentId);\n\n  (async () => {\n    const successValue = config.success ? 10000n : 0n;\n    try {\n      const srTx = await reputation.giveFeedback(\n        id, successValue, 2, 'successRate', '', endpoint, '', ethers.ZeroHash,\n      );\n      await srTx.wait();\n      console.log(`[relai:submitRelayFeedback] successRate confirmed agentId=${agentId} success=${config.success}`);\n    } catch (err: any) {\n      console.warn(`[relai:submitRelayFeedback] successRate failed (non-fatal): ${err?.message}`);\n    }\n\n    if (responseTimeMs > 0) {\n      try {\n        const rtTx = await reputation.giveFeedback(\n          id, BigInt(Math.max(0, Math.round(responseTimeMs))), 0, 'responseTime', '', endpoint, '', ethers.ZeroHash,\n        );\n        console.log(`[relai:submitRelayFeedback] responseTime sent agentId=${agentId} ms=${responseTimeMs} tx=${rtTx.hash}`);\n      } catch (err: any) {\n        console.warn(`[relai:submitRelayFeedback] responseTime failed (non-fatal): ${err?.message}`);\n      }\n    }\n  })();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAAuB;AAsCvB,IAAM,gCAAgC;AAAA,EACpC;AACF;AA2BO,SAAS,oBAAoB,QAAmC;AACrE,QAAM,UAAU,OAAO,OAAO,OAAO;AACrC,QAAM,WAAW,OAAO,YAAY;AACpC,QAAM,iBAAiB,OAAO,kBAAkB;AAEhD,QAAM,aAAa,OAAO,6BACpB,OAAO,YAAY,cACnB,QAAQ,KAAK,+BAA+B,QAAQ,KAAK,sCACzD;AACN,QAAM,oBAAoB,OAAO,8BAC3B,OAAO,YAAY,cAAc,QAAQ,KAAK,8BAA8B;AAClF,QAAM,SAAS,OAAO,WAChB,OAAO,YAAY,cAAc,QAAQ,KAAK,kBAAkB,WACjE;AAEL,MAAI,CAAC,cAAc,CAAC,mBAAmB;AACrC,YAAQ,KAAK,gHAA2G;AACxH;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,qBAAO,gBAAgB,MAAM;AAClD,QAAM,SAAS,IAAI,qBAAO,OAAO,YAAY,QAAQ;AACrD,QAAM,aAAa,IAAI,qBAAO,SAAS,mBAAmB,+BAA+B,MAAM;AAC/F,QAAM,KAAK,OAAO,OAAO;AAEzB,GAAC,YAAY;AACX,UAAM,eAAe,OAAO,UAAU,SAAS;AAC/C,QAAI;AACF,YAAM,OAAO,MAAM,WAAW;AAAA,QAC5B;AAAA,QAAI;AAAA,QAAc;AAAA,QAAG;AAAA,QAAe;AAAA,QAAI;AAAA,QAAU;AAAA,QAAI,qBAAO;AAAA,MAC/D;AACA,YAAM,KAAK,KAAK;AAChB,cAAQ,IAAI,6DAA6D,OAAO,YAAY,OAAO,OAAO,EAAE;AAAA,IAC9G,SAAS,KAAU;AACjB,cAAQ,KAAK,+DAA+D,KAAK,OAAO,EAAE;AAAA,IAC5F;AAEA,QAAI,iBAAiB,GAAG;AACtB,UAAI;AACF,cAAM,OAAO,MAAM,WAAW;AAAA,UAC5B;AAAA,UAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,CAAC,CAAC;AAAA,UAAG;AAAA,UAAG;AAAA,UAAgB;AAAA,UAAI;AAAA,UAAU;AAAA,UAAI,qBAAO;AAAA,QACnG;AACA,gBAAQ,IAAI,yDAAyD,OAAO,OAAO,cAAc,OAAO,KAAK,IAAI,EAAE;AAAA,MACrH,SAAS,KAAU;AACjB,gBAAQ,KAAK,gEAAgE,KAAK,OAAO,EAAE;AAAA,MAC7F;AAAA,IACF;AAAA,EACF,GAAG;AACL;","names":[]}