增加合作方nft相关接口
This commit is contained in:
parent
149a44cc76
commit
db5babe823
7986
configs/partner_nft_list.json
Normal file
7986
configs/partner_nft_list.json
Normal file
File diff suppressed because it is too large
Load Diff
61
docs/uaw.md
61
docs/uaw.md
@ -46,6 +46,11 @@
|
||||
|
||||
1. 宝箱助力列表(17) 增加返回给邀请者的额外积分
|
||||
|
||||
#### 20240413
|
||||
|
||||
1. 用户状态(10) 增加返回是否获得白名单字段
|
||||
2. 增加
|
||||
|
||||
### 1. 钱包预登录
|
||||
|
||||
#### Request
|
||||
@ -349,7 +354,8 @@ body:
|
||||
"scoreSocial": 0, // 社交任务获得的分数
|
||||
"code": "自己的邀请码",
|
||||
"mapopen": 0, // 地图开启状态, 0: 未开启, 1: 已开启
|
||||
"enhanceCount": 1 // 当日剩余助力次数
|
||||
"enhanceCount": 1, // 当日剩余助力次数
|
||||
"inWhiteList": 1, // 是否得到白名单
|
||||
}
|
||||
```
|
||||
|
||||
@ -803,4 +809,55 @@ body:
|
||||
}]
|
||||
```
|
||||
|
||||
###
|
||||
### 28. 合作伙伴NFT列表
|
||||
|
||||
#### Request
|
||||
|
||||
- URL:`/api/partner/nfts`
|
||||
- 方法:GET`
|
||||
- 头部:
|
||||
- Authorization: Bearer JWT_token
|
||||
|
||||
|
||||
#### Response
|
||||
|
||||
```js
|
||||
[{
|
||||
"projectName": "L3E7", // 项目名称
|
||||
"link": "https://twitter.com/L3E7_Official", // 项目方twitter
|
||||
"contract": "0x20577896ea6113ed8c94b2f08f3893bdc08eba22", //合约地址
|
||||
"collection": "l3e7 worlds", // NFT的collection名称
|
||||
"remarks": "600 collection", // 描述
|
||||
"chain": 1, // 链id
|
||||
"status": 1, // 已登录状态下, 1表示已领取
|
||||
}]
|
||||
```
|
||||
|
||||
### 29.\* 领取NFT holder奖励
|
||||
|
||||
#### Request
|
||||
|
||||
- URL:`/api/partner/claim`
|
||||
- 方法:POST
|
||||
- 头部:
|
||||
- Authorization: Bearer JWT_token
|
||||
|
||||
|
||||
#### Response
|
||||
|
||||
```js
|
||||
{
|
||||
chests: [
|
||||
{ // 结构同 18.宝箱列表
|
||||
id: 1, // 箱子id
|
||||
stat: 0, // 0: 锁定, 1: 正常
|
||||
shareCode: '箱子的分享码',
|
||||
level: 1, // 箱子品级
|
||||
maxBonus: 10, // 最大可助力数量
|
||||
scoreInit: 5, // 初始可获得积分
|
||||
scoreBonus: 10, // 助力增加的分数
|
||||
bonusCount: 2, // 已助力次数
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
76
src/controllers/nft.controller.ts
Normal file
76
src/controllers/nft.controller.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { ChestStatusEnum } from 'models/ActivityChest'
|
||||
import { NFTHolderRecord } from 'models/NFTHodlerRecord'
|
||||
import { queryNftBalance } from 'services/chain.svr'
|
||||
import { generateChestLevel, generateNewChest } from 'services/game.svr'
|
||||
import { SyncLocker, BaseController, router, role, ROLE_ANON, ZError } from 'zutils'
|
||||
|
||||
const nftList = require('../../configs/partner_nft_list.json')
|
||||
const nftListStr = JSON.stringify(nftList)
|
||||
const nftMap = new Map()
|
||||
nftList.forEach(o => nftMap.set(o.contract.toLowerCase(), o))
|
||||
/**
|
||||
* 合作伙伴相关接口
|
||||
*/
|
||||
class NftController extends BaseController {
|
||||
/**
|
||||
* NFT 列表
|
||||
*/
|
||||
@role(ROLE_ANON)
|
||||
@router('get /api/partner/nfts')
|
||||
async nftList(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(records.map(o => o.contract.toLowerCase()))
|
||||
for (let sub of list) {
|
||||
list.status = recordSet.has(sub.contract.toLowerCase())
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
/**
|
||||
* 领取合作伙伴nft holder奖励
|
||||
*/
|
||||
@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()] }
|
||||
}
|
||||
}
|
@ -148,6 +148,7 @@ class SignController extends BaseController {
|
||||
code: user.inviteCode,
|
||||
mapopen: gameRecord.status,
|
||||
enhanceCount,
|
||||
inWhiteList: user.inWhiteList ? 1 : 0,
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
33
src/models/NFTHodlerRecord.ts
Normal file
33
src/models/NFTHodlerRecord.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
|
||||
import { dbconn } from 'decorators/dbconn'
|
||||
import { BaseModule } from './Base'
|
||||
|
||||
/**
|
||||
* nft hodler claim record
|
||||
*/
|
||||
|
||||
@dbconn()
|
||||
@index({ user: 1 }, { unique: false })
|
||||
@index({ user: 1, chain: 1, address: 1 }, { unique: true })
|
||||
@modelOptions({
|
||||
schemaOptions: { collection: 'nft_holder_claim_record', timestamps: true },
|
||||
options: { allowMixed: Severity.ALLOW },
|
||||
})
|
||||
class NFTHolderRecordClass extends BaseModule {
|
||||
@prop({ required: true })
|
||||
public user: string
|
||||
@prop()
|
||||
public chain: number
|
||||
@prop({ required: true })
|
||||
public contract: string
|
||||
@prop({ type: () => [String], default: [] })
|
||||
public tokenId?: string[]
|
||||
@prop()
|
||||
public holderNum: number
|
||||
@prop({ type: () => [String], default: [] })
|
||||
public rewards: string[]
|
||||
}
|
||||
|
||||
export const NFTHolderRecord = getModelForClass(NFTHolderRecordClass, {
|
||||
existingConnection: NFTHolderRecordClass['db'],
|
||||
})
|
@ -68,3 +68,24 @@ export const queryStakeList = async (userAddress: string) => {
|
||||
let records = await NftStake.find({ chain, nft: address, user: userAddress.toLowerCase() })
|
||||
return records
|
||||
}
|
||||
|
||||
export const queryNftBalance = async (contract: string, address: string) => {
|
||||
const rpc = 'https://mainnet.infura.io/v3/b6bf7d3508c941499b10025c0776eaf8'
|
||||
const data = {
|
||||
id: (Date.now() / 1000) | 0,
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_call',
|
||||
params: [
|
||||
{
|
||||
data: `0x70a08231000000000000000000000000${address.replace('0x', '')}`,
|
||||
from: address,
|
||||
to: contract,
|
||||
},
|
||||
'latest',
|
||||
],
|
||||
}
|
||||
return fetch(rpc, {
|
||||
body: JSON.stringify(data),
|
||||
method: 'POST',
|
||||
}).then(res => res.json())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user