@elisym/sdk 0.10.2 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1216,6 +1216,9 @@ var DiscoveryService = class {
1216
1216
  if (typeof meta.picture === "string") {
1217
1217
  agent.picture = meta.picture;
1218
1218
  }
1219
+ if (typeof meta.banner === "string") {
1220
+ agent.banner = meta.banner;
1221
+ }
1219
1222
  if (typeof meta.name === "string") {
1220
1223
  agent.name = meta.name;
1221
1224
  }
@@ -1233,18 +1236,20 @@ var DiscoveryService = class {
1233
1236
  *
1234
1237
  * Ranking algorithm:
1235
1238
  * 1. Bucket each agent into 1-minute slots by `lastPaidJobAt` (newest
1236
- * `payment-completed` feedback timestamp). Cold-start agents go into a
1237
- * sentinel bucket below all populated buckets.
1239
+ * `payment-completed` feedback timestamp, gated by a matching kind:6xxx
1240
+ * result from the provider on the same job event). Cold-start agents go
1241
+ * into a sentinel bucket below all populated buckets.
1238
1242
  * 2. Within a bucket, sort by positive review rate descending.
1239
1243
  * 3. Tiebreak by raw `lastPaidJobAt`, then `lastSeen` (NIP-89 freshness).
1240
1244
  *
1241
- * NOTE: We trust the `payment-completed` feedback timestamp directly; we do
1242
- * not verify the embedded `tx` signature on-chain. Public Solana devnet RPC
1243
- * rate-limits trivially exceed what discovery needs (N agents * up-to-5
1244
- * candidates), and the resulting 429s blocked discovery entirely. This
1245
- * means a malicious customer can publish a fake `payment-completed` to lift
1246
- * an agent's ranking. Acceptable trade-off for devnet / MVP; tighten via
1247
- * recipient-tied checks when the network moves to mainnet with a paid RPC
1245
+ * NOTE: We do not verify the `tx` signature on-chain - public Solana devnet
1246
+ * RPC rate-limits trivially exceed what discovery needs (N agents * up-to-5
1247
+ * candidates), and the resulting 429s blocked discovery entirely. As a
1248
+ * lighter sybil mitigation we cross-check `payment-completed` feedback
1249
+ * against a kind:6xxx result event authored by the provider on the same
1250
+ * job: a customer can publish a fake `payment-completed`, but they cannot
1251
+ * forge a result event signed by the provider. Tighten with recipient-tied
1252
+ * on-chain checks when the network moves to mainnet with a paid RPC
1248
1253
  * provider.
1249
1254
  */
1250
1255
  async fetchAgents(network = "devnet", limit) {
@@ -1287,14 +1292,27 @@ var DiscoveryService = class {
1287
1292
  ),
1288
1293
  this.enrichWithMetadata(agents)
1289
1294
  ]);
1295
+ const deliveredJobsByProvider = /* @__PURE__ */ new Map();
1290
1296
  for (const ev of resultEvents) {
1291
1297
  if (!nostrTools.verifyEvent(ev)) {
1292
1298
  continue;
1293
1299
  }
1294
1300
  const agent = agentMap.get(ev.pubkey);
1295
- if (agent && ev.created_at > agent.lastSeen) {
1301
+ if (!agent) {
1302
+ continue;
1303
+ }
1304
+ if (ev.created_at > agent.lastSeen) {
1296
1305
  agent.lastSeen = ev.created_at;
1297
1306
  }
1307
+ const jobEventId = ev.tags.find((t) => t[0] === "e")?.[1];
1308
+ if (jobEventId) {
1309
+ let delivered = deliveredJobsByProvider.get(ev.pubkey);
1310
+ if (!delivered) {
1311
+ delivered = /* @__PURE__ */ new Set();
1312
+ deliveredJobsByProvider.set(ev.pubkey, delivered);
1313
+ }
1314
+ delivered.add(jobEventId);
1315
+ }
1298
1316
  }
1299
1317
  for (const ev of feedbackEvents) {
1300
1318
  if (!nostrTools.verifyEvent(ev)) {
@@ -1321,7 +1339,9 @@ var DiscoveryService = class {
1321
1339
  const status = ev.tags.find((t) => t[0] === "status")?.[1];
1322
1340
  const txTag = ev.tags.find((t) => t[0] === "tx");
1323
1341
  const txSignature = txTag?.[1];
1324
- if (status === "payment-completed" && typeof txSignature === "string" && txSignature) {
1342
+ const jobEventId = ev.tags.find((t) => t[0] === "e")?.[1];
1343
+ const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1344
+ if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
1325
1345
  if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
1326
1346
  agent.lastPaidJobAt = ev.created_at;
1327
1347
  agent.lastPaidJobTx = txSignature;