Skip to content

Commit

Permalink
fixes, minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Vishtar committed Jul 8, 2024
1 parent 3b33b7a commit a151e63
Show file tree
Hide file tree
Showing 30 changed files with 272 additions and 143 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ TONAPI_TOKEN=
NOTIFICATION_RATE_UP=2
NOTIFICATION_RATE_DOWN=0.5
LIMIT_WALLETS_FOR_USER=10
SECONDS_FROM_PURCHASE_WITH_ROLLBACK_POSSIBILITY=60
# AMQP
AMQP_ENDPOINT=amqp://localhost:5673
# PostgreSQL
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ It proactively notifies users of their gains via Telegram, making it easy to man

## Tests

All tests are located in the [tests](./tests) directory. Currently, there is one unit test (with 6 scenarios) for the main business function:
All tests are located in the [tests](./tests) directory. Currently, there is one unit test (with 7 scenarios) for the main business function:

- [tests/getNotifications.test.ts](./tests/getNotifications.test.ts)
3 changes: 2 additions & 1 deletion frontend/src/types/TJettonData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export type TJettonData = {
address: string
symbol: string
image?: string
decimals: number
pnlPercentage: number
chart: [timestamp: number, price: number | string][]
chart: [timestamp: number, price: number][]
lastBuyTime: number
}
59 changes: 0 additions & 59 deletions frontend/src/utils.ts

This file was deleted.

10 changes: 10 additions & 0 deletions frontend/src/utils/badgeType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const badgeType = (input: number) => {
if (input < 0) {
return 'moderateDecrease'
}
if (input > 0) {
return 'moderateIncrease'
} else {
return 'unchanged'
}
}
9 changes: 9 additions & 0 deletions frontend/src/utils/chartColor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TChartData } from '../types'

export const chartColor = (arr: TChartData[]) => {
if (Number(arr[0].Price) >= Number(arr.at(-1)!.Price)) {
return ['red']
} else {
return ['emerald']
}
}
12 changes: 12 additions & 0 deletions frontend/src/utils/formatDataToChart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { normalizePrice, timeConverter } from '.'

export const formatDataToChart = (input: {
chart: [number, number][]
decimals: number
}) =>
input.chart.reverse().map(arr => {
return {
date: timeConverter(arr[0]),
Price: normalizePrice(arr[1], input.decimals),
}
})
5 changes: 5 additions & 0 deletions frontend/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { normalizePrice } from './normalizePrice'
export { timeConverter } from './timeConverter'
export { chartColor } from './chartColor'
export { formatDataToChart } from './formatDataToChart'
export { badgeType } from './badgeType'
2 changes: 2 additions & 0 deletions frontend/src/utils/normalizePrice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const normalizePrice = (price: number, decimals?: number) =>
price > 0.01 ? Number(price.toFixed(2)) : price.toFixed(decimals || 20)
26 changes: 26 additions & 0 deletions frontend/src/utils/timeConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export function timeConverter(UNIX_timestamp: number) {
const a = new Date(UNIX_timestamp * 1000)
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
]
const year = a.getFullYear()
const month = months[a.getMonth()]
const date = a.getDate()
const hour = a.getHours()
const min = a.getMinutes()
const sec = a.getSeconds()
const time =
date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec
return time
}
2 changes: 2 additions & 0 deletions src/db/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ export { selectUserWallets } from './selectUserWallets'
export { deleteUserWallets } from './deleteUserWallets'
export { deleteUserWallet } from './deleteUserWallet'
export { selectFirstUserPurchaseByJettonId } from './selectFirstUserPurchaseByJettonId'
export { selectWalletById } from './selectWalletById'
export { selectTokenByAddressAndWalletId } from './selectTokenByAddressAndWalletId'
7 changes: 5 additions & 2 deletions src/db/queries/insertUserAdress.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { wallets } from '../../db/schema'
import type { TDbConnection } from '../../types'
import type { TDbConnection, TDbTransaction } from '../../types'

export const insertUserAdress = (db: TDbConnection, values: typeof wallets.$inferInsert) => {
export const insertUserAdress = (
db: TDbConnection | TDbTransaction,
values: typeof wallets.$inferInsert,
) => {
return db.insert(wallets).values(values).onConflictDoNothing().returning()
}
4 changes: 2 additions & 2 deletions src/db/queries/insertUserPurchase.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { TDbConnection } from '../../types'
import type { TDbConnection, TDbTransaction } from '../../types'
import { userPurchases } from '../schema'

export const insertUserPurchase = (
db: TDbConnection,
db: TDbConnection | TDbTransaction,
values: typeof userPurchases.$inferInsert,
) => {
return db.insert(userPurchases).values(values)
Expand Down
14 changes: 14 additions & 0 deletions src/db/queries/selectTokenByAddressAndWalletId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { and, eq } from 'drizzle-orm'
import type { TDbConnection } from '../../types'
import { tokens } from '../schema'

export const selectTokenByAddressAndWalletId = (
db: TDbConnection,
address: string,
walletId: number,
) => {
return db
.select()
.from(tokens)
.where(and(eq(tokens.token, address), eq(tokens.walletId, walletId)))
}
7 changes: 7 additions & 0 deletions src/db/queries/selectWalletById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { eq } from 'drizzle-orm'
import type { TDbConnection } from '../../types'
import { wallets } from '../schema'

export const selectWalletById = (db: TDbConnection, walletId: number) => {
return db.select().from(wallets).where(eq(wallets.id, walletId))
}
7 changes: 5 additions & 2 deletions src/db/queries/upsertToken.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { TDbConnection } from '../../types'
import type { TDbConnection, TDbTransaction } from '../../types'
import { tokens } from '../schema'

export const upsertToken = (db: TDbConnection, values: typeof tokens.$inferInsert) => {
export const upsertToken = (
db: TDbConnection | TDbTransaction,
values: typeof tokens.$inferInsert,
) => {
return db.insert(tokens).values(values).onConflictDoNothing()
}
9 changes: 6 additions & 3 deletions src/services/bot/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ Send an address you want to watch or connect your own 👇
`,
youNoLongerHaveJetton: (ticker: string) =>
`👋 You no longer hold $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}, notifications for this jetton have been stopped.`,
detectedNewJetton: (ticker: string) =>
`💎 New jetton found: $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}. I will notify you when the price moves up or down by 2x.`,
detectedNewJetton: (ticker: string, wallet: string, price: number | string) => `
💎 New jetton found: $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}. Wallet:
${getEmojiForWallet(wallet)} \`${wallet}\`
💵 Current price: $${price}
📢 I will notify you when the price moves up or down by 2x.`,
notification: {
x2: (ticker: string, wallet: string, price: number | string) => `
📈 $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()} made 2x! Wallet:
🚀 $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()} made 2x! Wallet:
${getEmojiForWallet(wallet)} \`${wallet}\`
💵 Current price: $${price}
`,
Expand Down
10 changes: 7 additions & 3 deletions src/services/bot/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ export const ru = {
`,
youNoLongerHaveJetton: (ticker: string) =>
`👋 Вы больше не холдите $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}, уведомления для этого жетона остановлены.`,
detectedNewJetton: (ticker: string) =>
`💎 Обнаружен новый жетон $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}. Вы получите уведомление, когда его цена сделает 2x или упадёт вдвое.`,
detectedNewJetton: (ticker: string, wallet: string, price: number | string) => `
💎 Обнаружен новый жетон $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()}. Кошелёк:
${getEmojiForWallet(wallet)} \`${wallet}\`
💵 Актуальная цена: $${price}
📢 Вы получите уведомление, когда его цена сделает 2x или упадёт вдвое.
`,
notification: {
x2: (ticker: string, wallet: string, price: number | string) => `
📈 Жетон $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()} сделал x2! Адрес:
🚀 Жетон $${jettonNamesWithSpecialCharacters[ticker] || ticker.toUpperCase()} сделал x2! Адрес:
${getEmojiForWallet(wallet)} \`${wallet}\`
💵 Актуальная цена: $${price}`,
x05: (ticker: string, wallet: string, price: number | string) => `
Expand Down
4 changes: 2 additions & 2 deletions src/services/bot/types/TNotificationHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export type TNotificationHandle = {
>
getLastAddressJettonPurchaseFromDB: (
jettonId: number,
) => Promise<typeof userPurchases.$inferSelect | undefined>
) => Promise<typeof userPurchases.$inferSelect>
getLastAddressNotificationFromDB: (
jettonId: number,
) => Promise<typeof userNotifications.$inferSelect | undefined>
getFirstAddressJettonPurchaseFromDB: (
jettonId: number,
) => Promise<typeof userPurchases.$inferSelect | undefined>
) => Promise<typeof userPurchases.$inferSelect>
}
2 changes: 2 additions & 0 deletions src/services/bot/types/TNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ export type TJettonRateNotification = TBaseNotification & {
decimals: number
action: ENotificationType.UP | ENotificationType.DOWN
}

export type TNewJettonNotification = Omit<TBaseNotification, 'jettonId'> & {
jetton: string
price: number
timestamp: number
decimals: number
action: ENotificationType.NEW_JETTON
}

export type TNotHoldedJettonNotification = TBaseNotification & {
action: ENotificationType.NOT_HOLD_JETTON_ANYMORE
}
Expand Down
23 changes: 9 additions & 14 deletions src/services/bot/utils/getNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ export async function* getNotifications(
for (const jetton of addressJettonsFromDb) {
if (!addressJettonsFromChainObj[jetton.token]) {
const firstPurchase = await getFirstAddressJettonPurchaseFromDB(jetton.id)
if (!firstPurchase) {
continue
}
const secondsFromPurchase = Date.now() / 1000 - firstPurchase.timestamp
// Estimated time to bypass a rollback
if (secondsFromPurchase <= 60) {
if (
secondsFromPurchase <=
Number(process.env.SECONDS_FROM_PURCHASE_WITH_ROLLBACK_POSSIBILITY)
) {
continue
}
yield {
Expand All @@ -49,15 +48,11 @@ export async function* getNotifications(
const lastPurchase = await getLastAddressJettonPurchaseFromDB(jetton.id)
const lastNotification = await getLastAddressNotificationFromDB(jetton.id)
console.log({ lastPurchase, lastNotification })
const newestTransactionInDb =
lastPurchase && lastNotification
? lastPurchase.timestamp > lastNotification.timestamp
? lastPurchase
: lastNotification
: lastPurchase || lastNotification
if (!newestTransactionInDb) {
continue
}
const newestTransactionInDb = lastNotification
? lastPurchase.timestamp > lastNotification.timestamp
? lastPurchase
: lastNotification
: lastPurchase
const decimals = addressJettonsFromChainObj[jetton.token].decimals
delete addressJettonsFromChainObj[jetton.token]
const timestamp = Math.floor(Date.now() / 1000)
Expand Down
1 change: 1 addition & 0 deletions src/services/bot/utils/handleCommandDisconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const handleCommandDisconnect = async (
if (!deletedWallet) {
await ctx.reply(ctx.i18n.message.error())
await handleCommandDisconnect(db, ctx, '')
return
}
const address = new TonWeb.utils.Address(deletedWallet.address)
const userFriendlyAddress = address.toString(true, true, true)
Expand Down
Loading

0 comments on commit a151e63

Please sign in to comment.