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

hicommonwealth / commonwealth / 13788382186

11 Mar 2025 12:47PM UTC coverage: 44.952% (-0.8%) from 45.755%
13788382186

Pull #11259

github

web-flow
Merge 3caab1019 into 21da2f698
Pull Request #11259: Added in async count cache

1333 of 3320 branches covered (40.15%)

Branch coverage included in aggregate %.

4 of 13 new or added lines in 4 files covered. (30.77%)

172 existing lines in 18 files now uncovered.

2554 of 5327 relevant lines covered (47.94%)

37.99 hits per line

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

2.04
/libs/model/src/bot/CreateBotContest.command.ts
1
import {
2
  InvalidState,
3
  logger,
4
  ServerError,
5
  type Command,
6
} from '@hicommonwealth/core';
7
import {
8
  commonProtocol as cp,
9
  deployERC20Contest,
10
  getTokenAttributes,
11
} from '@hicommonwealth/evm-protocols';
12
import { config, publishCast } from '@hicommonwealth/model';
13
import * as schemas from '@hicommonwealth/schemas';
14
import { buildFarcasterContestFrameUrl } from '@hicommonwealth/shared';
15
import { models } from '../database';
16
import { mustExist } from '../middleware/guards';
17
import { TokenAttributes } from '../services';
18
import {
19
  ContestMetadataResponse,
20
  parseBotCommand,
21
  ParseBotCommandError,
22
} from '../services/openai/parseBotCommand';
23

24
const log = logger(import.meta);
30✔
25

26
export function CreateBotContest(): Command<typeof schemas.CreateBotContest> {
27
  return {
×
28
    ...schemas.CreateBotContest,
29
    auth: [],
30
    body: async ({ payload }) => {
31
      const { prompt } = payload;
×
32
      let contestMetadata: ContestMetadataResponse | null = null;
×
33
      try {
×
34
        contestMetadata = await parseBotCommand(prompt);
×
35
      } catch (err) {
36
        log.warn(`failed to parse bot command: ${(err as Error).message}`);
×
37
        if (payload.castHash) {
×
38
          const prettyError =
39
            err instanceof ParseBotCommandError
×
40
              ? err.getPrettyError()
41
              : 'Failed to create contest. Please check your prompt and try again.';
42
          await publishCast(
×
43
            payload.castHash,
44
            ({ username }) => `Hey @${username}. ${prettyError}`,
×
45
          );
46
        }
47
        return;
×
48
      }
49
      mustExist('Parsed Contest Metadata', contestMetadata);
×
50

51
      const botNamespace = config.BOT.CONTEST_BOT_NAMESPACE;
×
52

53
      if (!botNamespace || botNamespace === '') {
×
54
        new InvalidState('bot not enabled on given chain');
×
55
      }
56

57
      const community = await models.Community.findOne({
×
58
        where: {
59
          namespace: botNamespace as string,
60
        },
61
        include: [
62
          {
63
            model: models.ChainNode.scope('withPrivateData'),
64
            required: true,
65
          },
66
        ],
67
      });
68

69
      mustExist('Community', community);
×
70

71
      let tokenMetadata: TokenAttributes;
72
      try {
×
73
        tokenMetadata = await getTokenAttributes(
×
74
          contestMetadata.tokenAddress,
75
          community!.ChainNode!.private_url!,
76
          false,
77
        );
78
      } catch (err) {
79
        if (payload.castHash) {
×
80
          await publishCast(
×
81
            payload.castHash,
82
            ({ username }) =>
83
              // eslint-disable-next-line max-len
84
              `Hey @${username}. Failed to create contest. Unable to fetch the correct token. Check the address of the token and try again.`,
×
85
          );
86
        }
87
        log.warn(`token validation failed: ${(err as Error).message}`);
×
88
        return;
×
89
      }
90

91
      // use short duration for testnet contests
92
      const contestDurationSecs =
93
        community.ChainNode!.eth_chain_id === cp.ValidChains.SepoliaBase
×
94
          ? 60 * 60
95
          : 60 * 60 * 24 * 7;
96

97
      const namespaceFactory =
98
        cp.factoryContracts[
×
99
          community!.ChainNode!.eth_chain_id as cp.ValidChains
100
        ].factory;
101

102
      if (!config.WEB3.CONTEST_BOT_PRIVATE_KEY)
×
103
        throw new ServerError('Contest bot private key not set!');
×
104

105
      const contestAddress = await deployERC20Contest({
×
106
        privateKey: config.WEB3.CONTEST_BOT_PRIVATE_KEY,
107
        namespaceName: botNamespace!,
108
        contestInterval: contestDurationSecs,
109
        winnerShares: contestMetadata.payoutStructure,
110
        voteToken: contestMetadata.tokenAddress,
111
        voterShare: contestMetadata.voterShare,
112
        exchangeToken: contestMetadata.tokenAddress,
113
        namespaceFactory,
114
        rpc: community!.ChainNode!.private_url!,
115
      });
116
      mustExist('Deployed Contest', contestAddress);
×
117

118
      await models.sequelize.transaction(async (transaction) => {
×
119
        const manager = await models.ContestManager.create(
×
120
          {
121
            name: contestMetadata.contestName,
122
            community_id: community!.id,
123
            created_at: new Date(),
124
            cancelled: false,
125
            farcaster_frame_url: buildFarcasterContestFrameUrl(contestAddress),
126
            is_farcaster_contest: true,
127
            image_url: contestMetadata.image_url,
128
            interval: contestDurationSecs,
129
            funding_token_address: contestMetadata.tokenAddress,
130
            payout_structure: contestMetadata.payoutStructure,
131
            ticker: tokenMetadata.ticker,
132
            decimals: tokenMetadata.decimals,
133
            contest_address: contestAddress,
134
            environment: config.APP_ENV,
135
            farcaster_author_cast_hash: payload.castHash,
136
          },
137
          { transaction },
138
        );
UNCOV
139
        return manager;
×
140
      });
UNCOV
141
      return contestAddress;
×
142
    },
143
  };
144
}
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