diff --git a/src/bot/features/dice.ts b/src/bot/features/dice.ts index 711c48b..258cf15 100644 --- a/src/bot/features/dice.ts +++ b/src/bot/features/dice.ts @@ -1,7 +1,7 @@ import { Composer } from "grammy"; import type { Context } from "#root/bot/context.js"; import { logHandle } from "#root/bot/helpers/logging.js"; -import { placeInLine } from "#root/bot/models/user"; +import { placeInLine } from "#root/bot/models/user.js"; function timeUnitsBetween(startDate: Date, endDate: Date) { let delta = Math.abs(endDate.getTime() - startDate.getTime()) / 1000; diff --git a/src/bot/features/queue.ts b/src/bot/features/queue.ts index a008ba9..18268ba 100644 --- a/src/bot/features/queue.ts +++ b/src/bot/features/queue.ts @@ -16,7 +16,7 @@ import { SelectImageButton, photoKeyboard } from "#root/bot/keyboards/photo.js"; import { NftCollection } from "#root/bot/models/nft-collection.js"; import { openWallet, waitSeqno } from "#root/bot/helpers/ton.js"; import { NftItem, nftMintParameters } from "#root/bot/models/nft-item.js"; -import { pinFileToIPFS, pinJSONToIPFS } from "#root/bot/helpers/ipfs.js"; +import { pinImageURLToIPFS, pinJSONToIPFS } from "#root/bot/helpers/ipfs.js"; import { generate } from "#root/bot/helpers/generation.js"; import { randomAttributes } from "#root/bot/helpers/attributes.js"; import { findUserById } from "#root/bot/models/user.js"; @@ -109,7 +109,7 @@ feature.callbackQuery( return ctx.reply("Empty image"); } const nextItemIndex = await NftCollection.fetchNextItemIndex(); - const ipfsImageHash = await pinFileToIPFS( + const ipfsImageHash = await pinImageURLToIPFS( nextItemIndex, selectedUser.image ?? "", ); @@ -151,13 +151,21 @@ feature.callbackQuery( commonContentUrl: `ipfs://${selectedUser.nftJson}`, }; ctx.logger.info(parameters); + + selectedUser.minted = true; + await selectedUser.save(); + const seqno = await item.deploy(wallet, parameters); await waitSeqno(seqno, wallet); const nft = await NftCollection.getNftAddressByIndex(nextItemIndex); - await ctx.reply( - `https://${config.TESTNET ? "testnet." : ""}getgems.io/collection/${config.COLLECTION_ADDRESS}/${nft.toString()}`, - { link_preview_options: { is_disabled: true } }, - ); + + const nftUrl = `https://${config.TESTNET ? "testnet." : ""}getgems.io/collection/${config.COLLECTION_ADDRESS}/${nft.toString()}`; + selectedUser.nftUrl = nftUrl; + await selectedUser.save(); + + await ctx.reply(nftUrl, { + link_preview_options: { is_disabled: true }, + }); break; } default: { diff --git a/src/bot/features/start.ts b/src/bot/features/start.ts index a7df3fd..1cbb4ad 100644 --- a/src/bot/features/start.ts +++ b/src/bot/features/start.ts @@ -1,8 +1,8 @@ import { Composer } from "grammy"; import type { Context } from "#root/bot/context.js"; import { logHandle } from "#root/bot/helpers/logging.js"; -import { VoteModel, isUserAlreadyVoted } from "#root/bot/models/vote"; -import { findUserById } from "#root/bot/models/user"; +import { findUserById } from "#root/bot/models/user.js"; +import { VoteModel, isUserAlreadyVoted } from "#root/bot/models/vote.js"; const composer = new Composer(); diff --git a/src/bot/helpers/files.ts b/src/bot/helpers/files.ts index 1258eb7..65bb050 100644 --- a/src/bot/helpers/files.ts +++ b/src/bot/helpers/files.ts @@ -35,11 +35,8 @@ export async function saveImageFromUrl( return saveImage(index, newFileName, buffer); } -export function saveJSON(index: number, json: object) { - const fp = folderPath(index); - fs.writeFile( - path.join(fp, `${index}.json`), - JSON.stringify(json), - (_error) => {}, - ); +export function saveJSON(index: number, json: object): string { + const jsonPath = path.join(folderPath(index), `${index}.json`); + fs.writeFile(jsonPath, JSON.stringify(json), (_error) => {}); + return jsonPath; } diff --git a/src/bot/helpers/generation.ts b/src/bot/helpers/generation.ts index 8b60c40..0766be4 100644 --- a/src/bot/helpers/generation.ts +++ b/src/bot/helpers/generation.ts @@ -1,7 +1,7 @@ import fetch from "node-fetch"; import FormData from "form-data"; import fs from "node:fs"; -import { config } from "#root/config"; +import { config } from "#root/config.js"; export async function generate( filePath: string, diff --git a/src/bot/helpers/ipfs.ts b/src/bot/helpers/ipfs.ts index b66b76c..a490dda 100644 --- a/src/bot/helpers/ipfs.ts +++ b/src/bot/helpers/ipfs.ts @@ -3,16 +3,16 @@ import pinataSDK from "@pinata/sdk"; import { Readable } from "node:stream"; import { saveImage, saveJSON } from "./files"; -export async function pinFileToIPFS( +// eslint-disable-next-line new-cap +const pinata = new pinataSDK({ + pinataApiKey: config.PINATA_API_KEY, + pinataSecretApiKey: config.PINATA_API_SECRET, +}); + +export async function pinImageURLToIPFS( index: number, imageURL: string, ): Promise { - // eslint-disable-next-line new-cap - const pinata = new pinataSDK({ - pinataApiKey: config.PINATA_API_KEY, - pinataSecretApiKey: config.PINATA_API_SECRET, - }); - const image = await fetch(imageURL); const arrayBuffer = await image.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); @@ -33,13 +33,8 @@ export async function pinJSONToIPFS( index: number, json: object, ): Promise { - // eslint-disable-next-line new-cap - const pinata = new pinataSDK({ - pinataApiKey: config.PINATA_API_KEY, - pinataSecretApiKey: config.PINATA_API_SECRET, - }); - saveJSON(index, json); - const response = await pinata.pinJSONToIPFS(json, { + const jsonPath = saveJSON(index, json); + const response = await pinata.pinFromFS(jsonPath, { pinataMetadata: { name: `${index}.json` }, }); return response.IpfsHash; diff --git a/src/bot/helpers/ton.ts b/src/bot/helpers/ton.ts index 874813a..6feeb00 100644 --- a/src/bot/helpers/ton.ts +++ b/src/bot/helpers/ton.ts @@ -11,7 +11,7 @@ import { Transaction, WalletContractV4, } from "@ton/ton"; -import { config } from "#root/config"; +import { config } from "#root/config.js"; export type OpenedWallet = { contract: OpenedContract; @@ -29,9 +29,15 @@ export const tonClient = new TonClient({ export async function getTransactions( address: Address, - afterLT: string, + lt: string, + hash: string, ): Promise { - return tonClient.getTransactions(address, { lt: afterLT, limit: 100 }); + return tonClient.getTransactions(address, { + lt, + hash, + limit: 100, + archival: true, + }); } export async function openWallet(mnemonic: string[]) { diff --git a/src/bot/keyboards/queue-menu.ts b/src/bot/keyboards/queue-menu.ts index 72de53b..484d37d 100644 --- a/src/bot/keyboards/queue-menu.ts +++ b/src/bot/keyboards/queue-menu.ts @@ -11,14 +11,10 @@ import { photoKeyboard } from "#root/bot/keyboards/photo.js"; export function photoCaption(user: User) { return `[${user.name}](tg://user?id=${user.id}) - Comment: \`${user.description?.slice(0, 1000) ?? ""}\` - Description: \`${user.nftDescription ?? ""}\` - -Image: ${user.nftImage ? `[ipfs](https://ipfs.io/ipfs/${user.nftImage})` : ""} - -JSON: ${user.nftJson ? `[ipfs](https://ipfs.io/ipfs/${user.nftJson})` : ""} +${user.nftImage ? `[Image](https://ipfs.io/ipfs/${user.nftImage}) | ` : ""} ${user.nftJson ? `[JSON](https://ipfs.io/ipfs/${user.nftJson})` : ""} +Minted: ${user.minted ? "✅" : "❌"} ${user.nftUrl ?? ""} `; } diff --git a/src/bot/models/nft-collection.ts b/src/bot/models/nft-collection.ts index 8c6fb62..bab8850 100644 --- a/src/bot/models/nft-collection.ts +++ b/src/bot/models/nft-collection.ts @@ -12,7 +12,7 @@ import { OpenedWallet, tonClient, } from "#root/bot/helpers/ton.js"; -import { config } from "#root/config"; +import { config } from "#root/config.js"; export type collectionData = { ownerAddress: Address; diff --git a/src/bot/models/nft-item.ts b/src/bot/models/nft-item.ts index 5bfd6be..870d878 100644 --- a/src/bot/models/nft-item.ts +++ b/src/bot/models/nft-item.ts @@ -1,6 +1,6 @@ import { Address, beginCell, Cell, internal, SendMode } from "@ton/core"; import { OpenedWallet } from "#root/bot/helpers/ton.js"; -import { config } from "#root/config"; +import { config } from "#root/config.js"; export type nftMintParameters = { queryId: number; diff --git a/src/bot/models/user.ts b/src/bot/models/user.ts index ea4db21..6486886 100644 --- a/src/bot/models/user.ts +++ b/src/bot/models/user.ts @@ -62,6 +62,9 @@ export class User extends TimeStamps { @prop({ type: String }) nftJson?: string; + + @prop({ type: String }) + nftUrl?: string; } const UserModel = getModelForClass(User); diff --git a/src/bot/models/vote.ts b/src/bot/models/vote.ts index cd88887..bee42a0 100644 --- a/src/bot/models/vote.ts +++ b/src/bot/models/vote.ts @@ -1,5 +1,5 @@ import { modelOptions, prop, getModelForClass } from "@typegoose/typegoose"; -import { TimeStamps } from "@typegoose/typegoose/lib/defaultClasses"; +import { TimeStamps } from "@typegoose/typegoose/lib/defaultClasses.js"; @modelOptions({ schemaOptions: { timestamps: true }, diff --git a/src/bot/subscription.ts b/src/bot/subscription.ts index 323769c..6ef7b7c 100644 --- a/src/bot/subscription.ts +++ b/src/bot/subscription.ts @@ -1,13 +1,15 @@ import { i18n } from "#root/bot/i18n.js"; -/* eslint-disable class-methods-use-this */ -import { logger } from "#root/logger"; +import { logger } from "#root/logger.js"; import { Address, fromNano } from "@ton/core"; -import { config } from "#root/config"; -import TonWeb from "tonweb"; +import { config } from "#root/config.js"; import { Api, Bot, RawApi } from "grammy"; -import { TransactionModel, getLastestTransaction } from "./models/transaction"; -import { findUserByAddress, placeInLine } from "./models/user"; -import { Context } from "./context"; +import TonWeb from "tonweb"; +import { Context } from "#root/bot/context.js"; +import { findUserByAddress, placeInLine } from "#root/bot/models/user.js"; +import { + TransactionModel, + getLastestTransaction, +} from "#root/bot/models/transaction.js"; export class Subscription { bot: Bot>; diff --git a/src/main.ts b/src/main.ts index 241996e..b3bd73a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,7 +5,7 @@ import { config } from "#root/config.js"; import { logger } from "#root/logger.js"; import { createServer } from "#root/server/index.js"; import mongoose from "mongoose"; -import { Subscription } from "#root/bot/subscription"; +import { Subscription } from "#root/bot/subscription.js"; try { await mongoose.connect(config.MONGO);