-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9408 from hicommonwealth/malik.9371.store-token-info
[ERC20 Launchpad] - Store token info
- Loading branch information
Showing
23 changed files
with
435 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Token } from '@hicommonwealth/schemas'; | ||
import Sequelize from 'sequelize'; // must use "* as" to avoid scope errors | ||
import { z } from 'zod'; | ||
import type { ChainNodeAttributes, ChainNodeInstance } from './chain_node'; | ||
import type { ModelInstance } from './types'; | ||
|
||
export type TokenAttributes = z.infer<typeof Token> & { | ||
// associations | ||
ChainNode?: ChainNodeAttributes; | ||
}; | ||
|
||
export type TokenInstance = ModelInstance<TokenAttributes> & { | ||
// add mixins as needed | ||
getChainNode: Sequelize.BelongsToGetAssociationMixin<ChainNodeInstance>; | ||
}; | ||
|
||
export default ( | ||
sequelize: Sequelize.Sequelize, | ||
): Sequelize.ModelStatic<TokenInstance> => | ||
sequelize.define<TokenInstance>( | ||
'Token', | ||
{ | ||
name: { type: Sequelize.STRING, primaryKey: true }, | ||
icon_url: { type: Sequelize.STRING, allowNull: true }, | ||
description: { type: Sequelize.STRING, allowNull: true }, | ||
symbol: { type: Sequelize.STRING }, | ||
chain_node_id: { type: Sequelize.INTEGER }, | ||
base: { type: Sequelize.STRING, allowNull: false }, | ||
author_address: { type: Sequelize.STRING, allowNull: false }, | ||
community_id: { type: Sequelize.STRING, allowNull: false }, | ||
launchpad_contract_address: { type: Sequelize.STRING, allowNull: false }, | ||
uniswap_pool_address: { type: Sequelize.STRING, allowNull: true }, | ||
}, | ||
{ | ||
tableName: 'Tokens', | ||
timestamps: true, | ||
createdAt: 'created_at', | ||
updatedAt: 'updated_at', | ||
underscored: false, | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { InvalidInput, type Command } from '@hicommonwealth/core'; | ||
import * as schemas from '@hicommonwealth/schemas'; | ||
import { ChainBase } from '@hicommonwealth/shared'; | ||
import { models } from '../database'; | ||
import { AuthContext, isAuthorized } from '../middleware'; | ||
import { mustExist } from '../middleware/guards'; | ||
|
||
export const CreateTokenErrors = { | ||
TokenNameExists: | ||
'The name for this token already exists, please choose another name', | ||
InvalidEthereumChainId: 'Ethereum chain ID not provided or unsupported', | ||
InvalidAddress: 'Address is invalid', | ||
InvalidBase: 'Must provide valid chain base', | ||
MissingNodeUrl: 'Missing node url', | ||
InvalidNode: 'RPC url returned invalid response. Check your node url', | ||
}; | ||
|
||
export function CreateToken(): Command< | ||
typeof schemas.CreateToken, | ||
AuthContext | ||
> { | ||
return { | ||
...schemas.CreateToken, | ||
auth: [isAuthorized({ roles: ['admin'] })], | ||
body: async ({ actor, payload }) => { | ||
const { | ||
base, | ||
chain_node_id, | ||
name, | ||
symbol, | ||
description, | ||
icon_url, | ||
community_id, | ||
launchpad_contract_address, | ||
} = payload; | ||
|
||
const token = await models.Token.findOne({ | ||
where: { name }, | ||
}); | ||
if (token) throw new InvalidInput(CreateTokenErrors.TokenNameExists); | ||
|
||
const baseCommunity = await models.Community.findOne({ | ||
where: { base, id: community_id }, | ||
}); | ||
mustExist('Community Chain Base', baseCommunity); | ||
|
||
const node = await models.ChainNode.findOne({ | ||
where: { id: chain_node_id }, | ||
}); | ||
mustExist(`Chain Node`, node); | ||
|
||
if (base === ChainBase.Ethereum && !node.eth_chain_id) | ||
throw new InvalidInput(CreateTokenErrors.InvalidEthereumChainId); | ||
|
||
const createdToken = await models.Token.create({ | ||
base, | ||
chain_node_id, | ||
name, | ||
symbol, | ||
description, | ||
icon_url, | ||
author_address: actor.address || '', | ||
community_id, | ||
launchpad_contract_address, | ||
// uniswap_pool_address, - TODO: add when uniswap integration is done | ||
}); | ||
|
||
return createdToken!.toJSON(); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { type Query } from '@hicommonwealth/core'; | ||
import * as schemas from '@hicommonwealth/schemas'; | ||
import { QueryTypes } from 'sequelize'; | ||
import { z } from 'zod'; | ||
import { models } from '../database'; | ||
|
||
export function GetTokens(): Query<typeof schemas.GetTokens> { | ||
return { | ||
...schemas.GetTokens, | ||
auth: [], | ||
secure: false, | ||
body: async ({ payload }) => { | ||
const { search = '', cursor, limit, order_by, order_direction } = payload; | ||
|
||
// pagination configuration | ||
const direction = order_direction || 'DESC'; | ||
const order_col = order_by || 'name'; | ||
const offset = limit! * (cursor! - 1); | ||
const replacements: { | ||
search?: string; | ||
offset: number; | ||
order_col: string; | ||
direction: string; | ||
limit: number; | ||
} = { | ||
search: search ? `%${search.toLowerCase()}%` : '', | ||
offset, | ||
order_col, | ||
direction, | ||
limit, | ||
}; | ||
|
||
const sql = ` | ||
SELECT | ||
name, | ||
icon_url, | ||
description, | ||
symbol, | ||
chain_node_id, | ||
base, | ||
created_at, | ||
updated_at, | ||
author_address, | ||
community_id, | ||
launchpad_contract_address, | ||
count(*) OVER() AS total | ||
FROM "Tokens" | ||
${search ? 'WHERE LOWER(name) LIKE :search' : ''} | ||
ORDER BY ${order_col} :direction | ||
LIMIT :limit | ||
OFFSET :offset | ||
`; | ||
|
||
const tokens = await models.sequelize.query< | ||
z.infer<typeof schemas.Token> & { total?: number } | ||
>(sql, { | ||
replacements, | ||
type: QueryTypes.SELECT, | ||
nest: true, | ||
}); | ||
|
||
return schemas.buildPaginatedResponse( | ||
tokens, | ||
+(tokens.at(0)?.total ?? 0), | ||
{ | ||
limit, | ||
offset, | ||
}, | ||
); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './CreateToken.command'; | ||
export * from './GetTokens.query'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ChainBase } from '@hicommonwealth/shared'; | ||
import { z } from 'zod'; | ||
import { Token } from '../entities'; | ||
import { PG_INT } from '../utils'; | ||
|
||
export const CreateToken = { | ||
input: z.object({ | ||
name: z.string(), | ||
symbol: z.string(), | ||
icon_url: z.string().nullish(), | ||
description: z.string().nullish(), | ||
chain_node_id: PG_INT, | ||
base: z.nativeEnum(ChainBase), | ||
community_id: z.string(), | ||
launchpad_contract_address: z.string(), | ||
}), | ||
output: Token, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { ChainBase } from '@hicommonwealth/shared'; | ||
import { z } from 'zod'; | ||
import { PG_INT } from '../utils'; | ||
|
||
export const Token = z.object({ | ||
// 1. Regular fields are nullish when nullable instead of optional | ||
name: z.string(), | ||
icon_url: z.string().nullish(), | ||
description: z.string().nullish(), | ||
symbol: z.string(), | ||
chain_node_id: PG_INT, | ||
base: z.nativeEnum(ChainBase), | ||
author_address: z.string(), | ||
community_id: z.string(), | ||
launchpad_contract_address: z.string(), | ||
uniswap_pool_address: z.string().optional(), | ||
|
||
// 2. Timestamps are managed by sequelize, thus optional | ||
created_at: z.coerce.date().optional(), | ||
updated_at: z.coerce.date().optional(), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { z } from 'zod'; | ||
import { Token } from '../entities'; | ||
import { PaginatedResultSchema, PaginationParamsSchema } from './pagination'; | ||
|
||
export const GetTokens = { | ||
input: PaginationParamsSchema.extend({ | ||
search: z.string().optional(), | ||
order_by: z.enum(['name']).optional(), | ||
}), | ||
output: PaginatedResultSchema.extend({ | ||
results: Token.omit({ uniswap_pool_address: true }).array(), | ||
}), | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/commonwealth/client/scripts/state/api/token/createToken.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { trpc } from 'utils/trpcClient'; | ||
|
||
const useCreateTokenMutation = () => { | ||
return trpc.token.createToken.useMutation(); | ||
}; | ||
|
||
export default useCreateTokenMutation; |
38 changes: 38 additions & 0 deletions
38
packages/commonwealth/client/scripts/state/api/token/fetchTokens.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { GetTokens } from '@hicommonwealth/schemas'; | ||
import { trpc } from 'utils/trpcClient'; | ||
import { z } from 'zod'; | ||
|
||
const FETCH_TOKENS_STALE_TIME = 60 * 3_000; // 3 mins | ||
|
||
type UseFetchTokensProps = z.infer<typeof GetTokens.input> & { | ||
enabled?: boolean; | ||
}; | ||
|
||
const useFetchTokensQuery = ({ | ||
limit, | ||
order_by, | ||
order_direction, | ||
search, | ||
enabled = true, | ||
}: UseFetchTokensProps) => { | ||
return trpc.token.getTokens.useInfiniteQuery( | ||
{ | ||
limit, | ||
order_by, | ||
order_direction, | ||
search, | ||
}, | ||
{ | ||
staleTime: FETCH_TOKENS_STALE_TIME, | ||
enabled, | ||
initialCursor: 1, | ||
getNextPageParam: (lastPage) => { | ||
const nextPageNum = lastPage.page + 1; | ||
if (nextPageNum <= lastPage.totalPages) return nextPageNum; | ||
return undefined; | ||
}, | ||
}, | ||
); | ||
}; | ||
|
||
export default useFetchTokensQuery; |
4 changes: 4 additions & 0 deletions
4
packages/commonwealth/client/scripts/state/api/token/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import useCreateTokenMutation from './createToken'; | ||
import useFetchTokensQuery from './fetchTokens'; | ||
|
||
export { useCreateTokenMutation, useFetchTokensQuery }; |
Oops, something went wrong.