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()] } } }