• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hicommonwealth / commonwealth / 13207538896

07 Feb 2025 08:28PM UTC coverage: 46.309% (-0.05%) from 46.356%
13207538896

push

github

web-flow
Merge pull request #10813 from hicommonwealth/rotorsoft/9991-contest-notifications

Route contest notifications

1359 of 3292 branches covered (41.28%)

Branch coverage included in aggregate %.

49 of 86 new or added lines in 11 files covered. (56.98%)

5 existing lines in 3 files now uncovered.

2643 of 5350 relevant lines covered (49.4%)

36.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.9
/libs/model/src/contest/SetContestEnded.command.ts
1
import { Command, logger } from '@hicommonwealth/core';
2
import {
3
  getContestScore,
4
  rollOverContest,
5
} from '@hicommonwealth/evm-protocols';
6
import * as schemas from '@hicommonwealth/schemas';
7
import { NeynarAPIClient } from '@neynar/nodejs-sdk';
8
import { config } from '../config';
9
import { models } from '../database';
10
import { emitEvent, getChainNodeUrl } from '../utils/utils';
11

12
const log = logger(import.meta);
28✔
13

14
async function cleanNeynarWebhook(
15
  contest_address: string,
16
  neynar_webhook_id: string,
17
) {
NEW
18
  try {
×
NEW
19
    const client = new NeynarAPIClient(config.CONTESTS.NEYNAR_API_KEY!);
×
NEW
20
    await client.deleteWebhook(neynar_webhook_id);
×
NEW
21
    await models.ContestManager.update(
×
22
      {
23
        neynar_webhook_id: null,
24
        neynar_webhook_secret: null,
25
      },
26
      { where: { contest_address } },
27
    );
28
  } catch (err) {
NEW
29
    log.warn(`failed to delete neynar webhook: ${neynar_webhook_id}`);
×
30
  }
31
}
32

33
export function SetContestEnded(): Command<typeof schemas.SetContestEnded> {
34
  return {
1✔
35
    ...schemas.SetContestEnded,
36
    auth: [],
37
    body: async ({ payload }) => {
38
      const {
39
        contest_address,
40
        contest_id,
41
        is_one_off,
42
        prize_percentage,
43
        payout_structure,
44
        chain_url,
45
        chain_private_url,
46
        neynar_webhook_id,
47
      } = payload;
1✔
48

49
      const rpc = getChainNodeUrl({
1✔
50
        url: chain_url,
51
        private_url: chain_private_url,
52
      });
53

54
      await rollOverContest({
1✔
55
        privateKey: config.WEB3.PRIVATE_KEY,
56
        rpc,
57
        contest: contest_address,
58
        oneOff: is_one_off,
59
      });
60

61
      // better to get scores using views to avoid returning unbounded arrays in txs
62
      const score = await getContestScore(
1✔
63
        rpc,
64
        contest_address,
65
        prize_percentage,
66
        payout_structure,
67
        contest_id,
68
        is_one_off,
69
      );
70

71
      await models.sequelize.transaction(async (transaction) => {
1✔
72
        // update final score
73
        await models.Contest.update(
1✔
74
          { score, score_updated_at: new Date() },
75
          { where: { contest_address, contest_id }, transaction },
76
        );
77

78
        // reset end/ending flags - preemptively endeding oneoffs so that rollover stops
79
        await models.ContestManager.update(
1✔
80
          { ending: false, ended: is_one_off },
81
          { where: { contest_address }, transaction },
82
        );
83

84
        await emitEvent(
1✔
85
          models.Outbox,
86
          [
87
            {
88
              event_name: schemas.EventNames.ContestEnded,
89
              event_payload: {
90
                contest_address,
91
                contest_id,
92
                is_one_off,
NEW
93
                winners: score.map((s) => ({
×
94
                  address: s.creator_address,
95
                  content: s.content_id,
96
                  votes: s.votes,
97
                  prize: s.prize,
98
                })),
99
              },
100
            },
101
          ],
102
          transaction,
103
        );
104
      });
105

106
      // clean up neynar webhooks when farcaster contest ends (fire and forget)
107
      if (neynar_webhook_id)
1!
NEW
108
        void cleanNeynarWebhook(contest_address, neynar_webhook_id);
×
109

110
      return {};
1✔
111
    },
112
  };
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc