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

hicommonwealth / commonwealth / 16301206038

15 Jul 2025 06:23PM UTC coverage: 39.709% (-0.007%) from 39.716%
16301206038

push

github

web-flow
Merge pull request #12624 from hicommonwealth/rotorsoft/refactor-evm-protocols/common-protocol

Remove commonProtocol namespace

1855 of 5044 branches covered (36.78%)

Branch coverage included in aggregate %.

7 of 19 new or added lines in 9 files covered. (36.84%)

4 existing lines in 1 file now uncovered.

3269 of 7860 relevant lines covered (41.59%)

36.2 hits per line

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

0.0
/libs/model/src/aggregates/bot/LaunchTokenBot.command.ts
1
import { LaunchpadAbi } from '@commonxyz/common-protocol-abis';
2
import {
3
  AppError,
4
  command,
5
  InvalidState,
6
  logger,
7
  ServerError,
8
  type Command,
9
} from '@hicommonwealth/core';
10
import {
11
  createPrivateEvmClient,
12
  factoryContracts,
13
  getErc20TokenInfo,
14
  getLaunchpadTokenCreatedTransaction,
15
  getTargetMarketCap,
16
  isValidChain,
17
  launchToken,
18
  ValidChains,
19
} from '@hicommonwealth/evm-protocols';
20
import * as schemas from '@hicommonwealth/schemas';
21
import { ChainBase, ChainType } from '@hicommonwealth/shared';
22
import _ from 'lodash';
23
import { z } from 'zod';
24
import { config } from '../../config';
25
import { models } from '../../database';
26
import { mustExist } from '../../middleware/guards';
27
import { CreateCommunity } from '../community';
28

29
const log = logger(import.meta);
×
30

31
export function LaunchTokenBot(): Command<typeof schemas.LaunchToken> {
32
  return {
×
33
    ...schemas.LaunchToken,
34
    auth: [],
35
    body: async ({ payload, actor }) => {
36
      const { name, symbol, totalSupply, eth_chain_id, icon_url, description } =
37
        payload;
×
38

NEW
39
      if (!isValidChain(eth_chain_id)) {
×
40
        throw new AppError('eth_chain_id is not supported');
×
41
      }
42

43
      if (!config.WEB3.LAUNCHPAD_PRIVATE_KEY)
×
44
        throw new ServerError('Launchpad private key not set!');
×
45

46
      const communityId = _.kebabCase(name.toLowerCase());
×
47
      const existingCommunity = await models.Community.findOne({
×
48
        where: { id: communityId },
49
      });
50

51
      if (existingCommunity) {
×
52
        throw new AppError('Token already exists, choose another name');
×
53
      }
54

55
      const chainNode = await models.ChainNode.scope('withPrivateData').findOne(
×
56
        {
57
          where: { eth_chain_id },
58
          attributes: ['id', 'eth_chain_id', 'url', 'private_url'],
59
        },
60
      );
61

62
      mustExist('Chain Node', chainNode);
×
63

NEW
64
      const web3 = createPrivateEvmClient({
×
65
        rpc: chainNode.private_url!,
66
        privateKey: config.WEB3.LAUNCHPAD_PRIVATE_KEY,
67
      });
68
      const launchpadContract = new web3.eth.Contract(
×
69
        LaunchpadAbi,
70
        factoryContracts[eth_chain_id as ValidChains.SepoliaBase].launchpad,
71
      );
NEW
72
      const receipt = await launchToken(
×
73
        launchpadContract,
74
        name,
75
        symbol,
76
        [],
77
        [],
78
        web3.utils.toWei(totalSupply.toString(), 'ether') as string,
79
        web3.eth.defaultAccount as string,
80
        830000,
81
        factoryContracts[eth_chain_id as ValidChains.SepoliaBase]
82
          .tokenCommunityManager,
83
      );
84

85
      const tokenData = await getLaunchpadTokenCreatedTransaction({
×
86
        rpc: chainNode.private_url! || chainNode.url!,
×
87
        transactionHash: receipt.transactionHash,
88
      });
89

90
      if (!tokenData) {
×
91
        throw new InvalidState('Transaction not found');
×
92
      }
93

94
      let tokenInfo: { name: string; symbol: string; totalSupply: bigint };
95
      try {
×
96
        tokenInfo = await getErc20TokenInfo({
×
97
          rpc: chainNode.private_url || chainNode.url,
×
98
          tokenAddress: tokenData.parsedArgs.tokenAddress,
99
        });
100
      } catch (e) {
101
        log.error(
×
102
          `Failed to get erc20 token properties for token ${tokenData.parsedArgs.tokenAddress}`,
103
          e instanceof Error ? e : undefined,
×
104
          {
105
            e,
106
          },
107
        );
108
        throw new Error(
×
109
          `Failed to get erc20 token properties for token ${tokenData.parsedArgs.tokenAddress}`,
110
        );
111
      }
112

113
      const [token] = await models.LaunchpadToken.findOrCreate({
×
114
        where: {
115
          token_address: tokenData.parsedArgs.tokenAddress.toLowerCase(),
116
          namespace: tokenData.parsedArgs.namespace,
117
        },
118
        defaults: {
119
          token_address: tokenData.parsedArgs.tokenAddress.toLowerCase(),
120
          namespace: tokenData.parsedArgs.namespace,
121
          name: tokenInfo.name,
122
          symbol: tokenInfo.symbol,
123
          initial_supply: Number(tokenInfo.totalSupply / BigInt(1e18)),
124
          liquidity_transferred: false,
125
          launchpad_liquidity: tokenData.parsedArgs.launchpadLiquidity,
126
          eth_market_cap_target: getTargetMarketCap(),
127
          description: description ?? null,
×
128
          icon_url: icon_url ?? null,
×
129
        },
130
      });
131

132
      // Create corresponding community for token
133
      await command(CreateCommunity(), {
×
134
        actor,
135
        payload: {
136
          id: communityId,
137
          name,
138
          default_symbol: symbol,
139
          icon_url,
140
          description,
141
          base: ChainBase.Ethereum,
142
          token_name: name,
143
          chain_node_id: chainNode!.id!,
144
          type: ChainType.Offchain,
145
          social_links: [],
146
          directory_page_enabled: false,
147
          tags: [],
148
        },
149
      });
150

151
      await models.Community.update(
×
152
        { namespace: name },
153
        { where: { id: communityId } },
154
      );
155

156
      const response = {
×
157
        community_url: `${config.SERVER_URL}/${communityId}`,
158
        ...token!.toJSON(),
159
      };
160
      return response as unknown as z.infer<typeof schemas.TokenView> & {
×
161
        community_url: string;
162
      };
163
    },
164
  };
165
}
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