task-svr/src/controllers/nft.controller.ts
2024-04-18 15:49:21 +08:00

188 lines
5.6 KiB
TypeScript

import { DEFAULT_GUILD } from 'common/Constants'
import logger from 'logger/logger'
import { ChestStatusEnum } from 'models/ActivityChest'
import { NFTHolderRecord } from 'models/NFTHodlerRecord'
import { queryNftBalance } from 'services/chain.svr'
import { generateChestLevel, generateNewChest } from 'services/game.svr'
import { checkDiscordRole } from 'services/oauth.svr'
import { SyncLocker, BaseController, router, role, ROLE_ANON, ZError } from 'zutils'
const sourceList = require('../../configs/partner_nft_list.json')
const nftList = sourceList.map(o => {
return {
contract: o['Contract'],
projectName: o['Project'],
link: o['Twitter'],
collection: o['Collection name'],
group: o['GROUP'],
guild: o['SERVER ID'] || DEFAULT_GUILD,
role: o['ROLE ID'],
tier: o['TIER'] == 'Tier 2' ? 2 : 1,
}
})
if (process.env.NODE_ENV !== 'production') {
nftList.unshift({
projectName: 'Test',
link: 'https://x.com/sparky-chain',
contract: '0x50a8e60041a206acaa5f844a1104896224be6f38',
collection: 'Test Group01',
guild: '1222509817411665920',
role: '1230421511735738409',
tier: 2,
})
nftList.unshift({
projectName: 'Test',
link: 'https://x.com/sparky-chain',
contract: '0x50a8e60041a206acaa5f844a1104896224be6f38',
collection: 'Test Group02',
guild: '1222509817411665920',
role: '1230421511735738409',
tier: 2,
})
nftList.unshift({
projectName: 'Test',
link: 'https://x.com/sparky-chain',
contract: '0x50a8e60041a206acaa5f844a1104896224be6f39',
collection: 'Test Collection',
guild: '1222509817411665920',
role: '1229658972793999391',
tier: 2,
})
}
const nftListStr = JSON.stringify(nftList)
const nftMap = new Map()
const groupMap = new Map()
for (let o of nftList) {
nftMap.set(o.contract.toLowerCase(), o)
if (o.group) {
if (!groupMap.has(o.group)) {
groupMap.set(o.group, [])
}
groupMap.get(o.group).push(o)
}
}
/**
* 合作伙伴相关接口
*/
class NftController extends BaseController {
/**
* NFT 列表
*/
@role(ROLE_ANON)
@router('get /api/partner/nfts')
async fetchNftList(req) {
const user = req.user
let list = JSON.parse(nftListStr)
list.forEach(o => {
o.status = 0
})
if (user) {
let records = await NFTHolderRecord.find({ user: user.id })
let recordSet = new Set()
let groupSet = new Set()
for (let record of records) {
recordSet.add(record.contract.toLowerCase())
if (record.group) {
groupSet.add(record.group)
}
}
for (let sub of list) {
sub.status = recordSet.has(sub.contract.toLowerCase()) || groupSet.has(sub.group) ? 1 : 0
}
}
return list
}
/**
* 领取合作伙伴nft holder奖励, 检查NFT
*/
// @router('post /api/partner/claim')
async claimNftHolderReward(req) {
new SyncLocker().checkLock(req)
const user = req.user
let { contract } = req.params
if (!contract) {
throw new ZError(11, 'contract not found')
}
contract = contract.toLowerCase()
if (!nftMap.has(contract)) {
throw new ZError(12, 'contract not found')
}
let record = await NFTHolderRecord.findOne({ user: user.id, contract })
if (record) {
throw new ZError(13, 'already claimed')
}
let rpcRes = await queryNftBalance(contract, user.address)
console.log('check result:', rpcRes)
if (rpcRes.error) {
throw new ZError(20, `check error: ${rpcRes.error.message}`)
}
let count = parseInt(rpcRes.result)
if (count === 0) {
throw new ZError(14, 'not match claim condition')
}
let randomLevel = generateChestLevel()
let chest = generateNewChest(user.id, user.activity, randomLevel, ChestStatusEnum.NORMAL)
await chest.save()
let recordNew = new NFTHolderRecord({
user: user.id,
contract,
chain: nftMap.get(contract).chain,
holderNum: count,
rewards: [chest.id],
})
await recordNew.save()
return { chests: [chest.toJson()] }
}
@router('post /api/partner/claim')
async claimNftHolderRewardDC(req) {
new SyncLocker().checkLock(req)
logger.db('claim_partner', req)
const user = req.user
if (!user.discordId) {
throw new ZError(10, 'need connect discord first')
}
let { contract } = req.params
if (!contract) {
throw new ZError(11, 'params error')
}
contract = contract.toLowerCase()
if (!nftMap.has(contract)) {
throw new ZError(12, 'cfg not found')
}
let record = await NFTHolderRecord.findOne({ user: user.id, contract })
if (record) {
throw new ZError(13, 'already claimed')
}
const cfg = nftMap.get(contract)
if (cfg.group) {
let groupRecord = await NFTHolderRecord.findOne({ user: user.id, group: cfg.group })
if (groupRecord) {
throw new ZError(16, 'already claimed')
}
}
const guild = cfg.guild || DEFAULT_GUILD
let rpcRes = await checkDiscordRole(user.address.toLowerCase(), guild, cfg.role)
console.log('check result:', rpcRes)
if (rpcRes.errcode) {
throw new ZError(rpcRes.errcode, `rpcRes.errmsg`)
}
if (!rpcRes.data.result) {
throw new ZError(14, 'had no role')
}
let chestLevel = cfg.tier || 1
let chest = generateNewChest(user.id, user.activity, chestLevel, ChestStatusEnum.NORMAL)
await chest.save()
let recordNew = new NFTHolderRecord({
user: user.id,
contract,
chain: nftMap.get(contract).chain,
holderNum: 1,
group: cfg.group,
rewards: [chest.id],
})
await recordNew.save()
return { chests: [chest.toJson()] }
}
}