reformat code
This commit is contained in:
parent
c68ae1dcb6
commit
7d3cd73afc
@ -162,13 +162,16 @@ export class ApiServer {
|
|||||||
self.setErrHandler()
|
self.setErrHandler()
|
||||||
self.setFormatSend()
|
self.setFormatSend()
|
||||||
self.initSchedules()
|
self.initSchedules()
|
||||||
this.server.listen({ port: parseInt(process.env.API_PORT), host: process.env.API_HOST }, (err: any, address: any) => {
|
this.server.listen(
|
||||||
if (err) {
|
{ port: parseInt(process.env.API_PORT), host: process.env.API_HOST },
|
||||||
logger.log(err)
|
(err: any, address: any) => {
|
||||||
process.exit(0)
|
if (err) {
|
||||||
}
|
logger.log(err)
|
||||||
resolve && resolve(address)
|
process.exit(0)
|
||||||
})
|
}
|
||||||
|
resolve && resolve(address)
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
import { singleton } from "decorators/singleton";
|
import { singleton } from 'decorators/singleton'
|
||||||
import { LotteryStats } from "models/LotteryStats";
|
import { LotteryStats } from 'models/LotteryStats'
|
||||||
import { formatDate } from "utils/date.util";
|
import { formatDate } from 'utils/date.util'
|
||||||
|
|
||||||
const EXPIRE_TIME = 1000 * 60 * 60;
|
const EXPIRE_TIME = 1000 * 60 * 60
|
||||||
@singleton
|
@singleton
|
||||||
export class LotteryCache {
|
export class LotteryCache {
|
||||||
map: Map<string, typeof LotteryStats> = new Map();
|
map: Map<string, typeof LotteryStats> = new Map()
|
||||||
lastUsed: Map<string, number> = new Map();
|
lastUsed: Map<string, number> = new Map()
|
||||||
|
|
||||||
public async getData(user: string, activity: string) {
|
public async getData(user: string, activity: string) {
|
||||||
const dateTag = formatDate(new Date());
|
const dateTag = formatDate(new Date())
|
||||||
if (!this.map.has(user+dateTag)) {
|
if (!this.map.has(user + dateTag)) {
|
||||||
const record = await LotteryStats.insertOrUpdate({user, activity, dateTag}, {})
|
const record = await LotteryStats.insertOrUpdate({ user, activity, dateTag }, {})
|
||||||
this.map.set(user+dateTag, record);
|
this.map.set(user + dateTag, record)
|
||||||
}
|
}
|
||||||
this.lastUsed.set(user+dateTag, Date.now());
|
this.lastUsed.set(user + dateTag, Date.now())
|
||||||
return this.map.get(user+dateTag);
|
return this.map.get(user + dateTag)
|
||||||
}
|
}
|
||||||
public async flush() {
|
public async flush() {
|
||||||
for (let [key, record] of this.map.entries()) {
|
for (let [key, record] of this.map.entries()) {
|
||||||
// record.modifiedPaths()
|
// record.modifiedPaths()
|
||||||
if (record.isModified()) {
|
if (record.isModified()) {
|
||||||
await record.save();
|
await record.save()
|
||||||
}
|
}
|
||||||
if (Date.now() - this.lastUsed.get(key) > EXPIRE_TIME) {
|
if (Date.now() - this.lastUsed.get(key) > EXPIRE_TIME) {
|
||||||
this.map.delete(key);
|
this.map.delete(key)
|
||||||
this.lastUsed.delete(key);
|
this.lastUsed.delete(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,36 @@
|
|||||||
import { singleton } from "decorators/singleton";
|
import { singleton } from 'decorators/singleton'
|
||||||
import { FastifyRequest } from "fastify";
|
import { FastifyRequest } from 'fastify'
|
||||||
import { ZError } from "./ZError";
|
import { ZError } from './ZError'
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
export class SyncLocker {
|
export class SyncLocker {
|
||||||
map: Map<string, boolean> = new Map();
|
map: Map<string, boolean> = new Map()
|
||||||
|
|
||||||
public lock(req: FastifyRequest) {
|
public lock(req: FastifyRequest) {
|
||||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||||
if (this.map.has(key)) {
|
if (this.map.has(key)) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
this.map.set(key, true);
|
this.map.set(key, true)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public unlock(req: FastifyRequest) {
|
public unlock(req: FastifyRequest) {
|
||||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||||
this.map.delete(key);
|
this.map.delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkLock(req: FastifyRequest) {
|
public checkLock(req: FastifyRequest) {
|
||||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||||
if (this.map.has(key)) {
|
if (this.map.has(key)) {
|
||||||
throw new ZError(100, 'request too fast');
|
throw new ZError(100, 'request too fast')
|
||||||
}
|
}
|
||||||
this.lock(req);
|
this.lock(req)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public isLocked(req: FastifyRequest) {
|
public isLocked(req: FastifyRequest) {
|
||||||
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
const key = `${req.method}:${req.url}:${req.user?.id || ''}`
|
||||||
return this.map.has(key);
|
return this.map.has(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +1,20 @@
|
|||||||
const ROUND = 1000000;
|
const ROUND = 1000000
|
||||||
|
|
||||||
export const BOOST_CFG = [
|
export const BOOST_CFG = [
|
||||||
{
|
{
|
||||||
value: 2,
|
value: 2,
|
||||||
probability: 500000
|
probability: 500000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 3,
|
value: 3,
|
||||||
probability: 300000
|
probability: 300000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 4,
|
value: 4,
|
||||||
probability: 150000
|
probability: 150000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 5,
|
value: 5,
|
||||||
probability: 50000
|
probability: 50000,
|
||||||
},
|
},
|
||||||
]
|
]
|
@ -24,5 +24,5 @@ export const FUSION_CFG = {
|
|||||||
id: 'kindle',
|
id: 'kindle',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
@ -35,6 +35,6 @@ export const ALL_ITEMS: IItem[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'torch',
|
id: 'torch',
|
||||||
name: 'Torch'
|
name: 'Torch',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export const LOTTERY_CFG = {
|
export const LOTTERY_CFG = {
|
||||||
start: '2024-01-01 00:00:00',
|
start: '2024-01-01 00:00:00',
|
||||||
end: '2025-01-01 00:00:00',
|
end: '2025-01-01 00:00:00',
|
||||||
@ -6,38 +5,37 @@ export const LOTTERY_CFG = {
|
|||||||
{
|
{
|
||||||
item: 'usdt',
|
item: 'usdt',
|
||||||
amount: 20,
|
amount: 20,
|
||||||
probability: 10000
|
probability: 10000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'flame',
|
item: 'flame',
|
||||||
amount: 30,
|
amount: 30,
|
||||||
probability: 300000
|
probability: 300000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'thunder',
|
item: 'thunder',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
probability: 170000
|
probability: 170000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'light',
|
item: 'light',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
probability: 180000
|
probability: 180000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'spark',
|
item: 'spark',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
probability: 130000
|
probability: 130000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'blaze',
|
item: 'blaze',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
probability: 100000
|
probability: 100000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: 'kindle',
|
item: 'kindle',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
probability: 10000
|
probability: 10000,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
]
|
|
||||||
}
|
}
|
@ -1,16 +1,15 @@
|
|||||||
import { SyncLocker } from "common/SyncLocker";
|
import { SyncLocker } from 'common/SyncLocker'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import BaseController, { ROLE_ANON } from "common/base.controller";
|
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||||
import { role, router } from "decorators/router";
|
import { role, router } from 'decorators/router'
|
||||||
import { ActivityInfo } from "models/ActivityInfo";
|
import { ActivityInfo } from 'models/ActivityInfo'
|
||||||
import { ActivityUser } from "models/ActivityUser";
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
import { RedisClient } from "redis/RedisClient";
|
import { RedisClient } from 'redis/RedisClient'
|
||||||
import { rankKey } from "services/rank.svr";
|
import { rankKey } from 'services/rank.svr'
|
||||||
import { yesterday } from "utils/date.util";
|
import { yesterday } from 'utils/date.util'
|
||||||
|
|
||||||
const MAX_LIMIT = 50
|
const MAX_LIMIT = 50
|
||||||
export default class ActivityController extends BaseController {
|
export default class ActivityController extends BaseController {
|
||||||
|
|
||||||
@role(ROLE_ANON)
|
@role(ROLE_ANON)
|
||||||
@router('get /api/activity/:id')
|
@router('get /api/activity/:id')
|
||||||
async info(req) {
|
async info(req) {
|
||||||
@ -32,9 +31,9 @@ export default class ActivityController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@router('post /api/activity/upload_invite_code')
|
@router('post /api/activity/upload_invite_code')
|
||||||
async uploadInviteCode(req) {
|
async uploadInviteCode(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
let { code } = req.params
|
let { code } = req.params
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
if (user.inviteUser) {
|
if (user.inviteUser) {
|
||||||
throw new ZError(11, 'already set invite user')
|
throw new ZError(11, 'already set invite user')
|
||||||
}
|
}
|
||||||
@ -58,8 +57,8 @@ export default class ActivityController extends BaseController {
|
|||||||
const end = start + limit - 1
|
const end = start + limit - 1
|
||||||
const records = await new RedisClient().zrevrange(`${activity}:score`, start, end)
|
const records = await new RedisClient().zrevrange(`${activity}:score`, start, end)
|
||||||
let results: any = []
|
let results: any = []
|
||||||
const yesterdayKey = rankKey(activity, yesterday());
|
const yesterdayKey = rankKey(activity, yesterday())
|
||||||
for (let i = 0; i < records.length; i+=2) {
|
for (let i = 0; i < records.length; i += 2) {
|
||||||
const id = records[i]
|
const id = records[i]
|
||||||
let score = parseInt(records[i + 1])
|
let score = parseInt(records[i + 1])
|
||||||
const user = await ActivityUser.findById(id)
|
const user = await ActivityUser.findById(id)
|
||||||
@ -76,9 +75,9 @@ export default class ActivityController extends BaseController {
|
|||||||
address: user?.address || 'unknow',
|
address: user?.address || 'unknow',
|
||||||
invite,
|
invite,
|
||||||
score,
|
score,
|
||||||
yesterday: yesterdayScore ? parseInt(yesterdayScore+'') : 0
|
yesterday: yesterdayScore ? parseInt(yesterdayScore + '') : 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return results;
|
return results
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,44 +1,46 @@
|
|||||||
|
import { SyncLocker } from 'common/SyncLocker'
|
||||||
|
import { ZError } from 'common/ZError'
|
||||||
|
import BaseController from 'common/base.controller'
|
||||||
|
import { router } from 'decorators/router'
|
||||||
|
import { FastifyRequest } from 'fastify'
|
||||||
|
import { ActivityItem } from 'models/ActivityItem'
|
||||||
|
import { TokenClaimHistory } from 'models/TokenClaimHistory'
|
||||||
|
import { queryStakeList } from 'services/chain.svr'
|
||||||
|
import { sign } from 'utils/chain.util'
|
||||||
|
|
||||||
import { SyncLocker } from "common/SyncLocker";
|
|
||||||
import { ZError } from "common/ZError";
|
|
||||||
import BaseController from "common/base.controller";
|
|
||||||
import { router } from "decorators/router";
|
|
||||||
import { FastifyRequest } from "fastify";
|
|
||||||
import { ActivityItem } from "models/ActivityItem";
|
|
||||||
import { TokenClaimHistory } from "models/TokenClaimHistory";
|
|
||||||
import { queryStakeList } from "services/chain.svr";
|
|
||||||
import { sign } from "utils/chain.util";
|
|
||||||
|
|
||||||
|
|
||||||
const MAX_LIMIT = 50
|
|
||||||
export default class ChainController extends BaseController {
|
export default class ChainController extends BaseController {
|
||||||
|
|
||||||
@router('get /api/stake/list')
|
@router('get /api/stake/list')
|
||||||
async stakeList(req) {
|
async stakeList(req) {
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
const records = await queryStakeList(user.address)
|
const records = await queryStakeList(user.address)
|
||||||
const result = records.map((r) => r.toJson())
|
const result = records.map(r => r.toJson())
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('post /api/lottery/claim_usdt')
|
@router('post /api/lottery/claim_usdt')
|
||||||
async preClaimUsdt(req: FastifyRequest) {
|
async preClaimUsdt(req: FastifyRequest) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
if (user.address) {
|
if (user.address) {
|
||||||
throw new ZError(11, 'no address')
|
throw new ZError(11, 'no address')
|
||||||
}
|
}
|
||||||
const minClaimNum = +process.env.MINI_CLAIM_USDT
|
const minClaimNum = +process.env.MINI_CLAIM_USDT
|
||||||
const record = await ActivityItem.findOne({user: user.id, activity: user.activity, item: 'usdt'})
|
const record = await ActivityItem.findOne({ user: user.id, activity: user.activity, item: 'usdt' })
|
||||||
if (!record || record.amount < minClaimNum) {
|
if (!record || record.amount < minClaimNum) {
|
||||||
throw new ZError(10, 'no enough usdt')
|
throw new ZError(10, 'no enough usdt')
|
||||||
}
|
}
|
||||||
const amount = record.amount + '';
|
const amount = record.amount + ''
|
||||||
record.amount = 0;
|
record.amount = 0
|
||||||
await record.save()
|
await record.save()
|
||||||
const token = process.env.USDT_CONTRACT;
|
const token = process.env.USDT_CONTRACT
|
||||||
const history = await TokenClaimHistory.addOne({user: user.id, activity: user.activity, address: user.address, token, amount})
|
const history = await TokenClaimHistory.addOne({
|
||||||
const res = await sign({user: user.address, token, amount, saltNonce: history.id})
|
user: user.id,
|
||||||
|
activity: user.activity,
|
||||||
|
address: user.address,
|
||||||
|
token,
|
||||||
|
amount,
|
||||||
|
})
|
||||||
|
const res = await sign({ user: user.address, token, amount, saltNonce: history.id })
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,78 +1,77 @@
|
|||||||
import { EMPTY_REWARD, ITEM_FRAME } from "common/Constants";
|
import { EMPTY_REWARD, ITEM_FRAME } from 'common/Constants'
|
||||||
import { LotteryCache } from "common/LotteryCache";
|
import { LotteryCache } from 'common/LotteryCache'
|
||||||
import { SyncLocker } from "common/SyncLocker";
|
import { SyncLocker } from 'common/SyncLocker'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import BaseController from "common/base.controller";
|
import BaseController from 'common/base.controller'
|
||||||
import { FUSION_CFG } from "configs/fusion";
|
import { FUSION_CFG } from 'configs/fusion'
|
||||||
import { ALL_ITEMS } from "configs/items";
|
import { ALL_ITEMS } from 'configs/items'
|
||||||
import { LOTTERY_CFG } from "configs/lottery";
|
import { LOTTERY_CFG } from 'configs/lottery'
|
||||||
import { router } from "decorators/router";
|
import { router } from 'decorators/router'
|
||||||
import { FastifyRequest } from "fastify";
|
import { FastifyRequest } from 'fastify'
|
||||||
import { ActivityItem } from "models/ActivityItem";
|
import { ActivityItem } from 'models/ActivityItem'
|
||||||
import { LotteryRecord } from "models/LotteryRecord";
|
import { LotteryRecord } from 'models/LotteryRecord'
|
||||||
import { updateRankScore } from "services/rank.svr";
|
import { updateRankScore } from 'services/rank.svr'
|
||||||
import { formatDate } from "utils/date.util";
|
import { formatDate } from 'utils/date.util'
|
||||||
|
|
||||||
const ROUND = 1000000;
|
const ROUND = 1000000
|
||||||
|
|
||||||
// Get random prizes according to the set probability
|
// Get random prizes according to the set probability
|
||||||
const draw = (rewards: {probability: number}[]) => {
|
const draw = (rewards: { probability: number }[]) => {
|
||||||
let total = 0;
|
let total = 0
|
||||||
let random = Math.floor(Math.random() * ROUND);
|
let random = Math.floor(Math.random() * ROUND)
|
||||||
let reward = null;
|
let reward = null
|
||||||
for (let r of rewards) {
|
for (let r of rewards) {
|
||||||
total += r.probability;
|
total += r.probability
|
||||||
if (random < total) {
|
if (random < total) {
|
||||||
reward = r;
|
reward = r
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {id: reward?.item || EMPTY_REWARD, amount: reward?.amount || 1};
|
return { id: reward?.item || EMPTY_REWARD, amount: reward?.amount || 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class LotteryController extends BaseController {
|
export default class LotteryController extends BaseController {
|
||||||
@router('get /api/lottery/stats')
|
@router('get /api/lottery/stats')
|
||||||
async userStats(req) {
|
async userStats(req) {
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
let record = await new LotteryCache().getData(user.id, user.activity);
|
let record = await new LotteryCache().getData(user.id, user.activity)
|
||||||
let result:any = record.toJson();
|
let result: any = record.toJson()
|
||||||
let items = await ActivityItem.find({user: user.id, activity: user.activity});
|
let items = await ActivityItem.find({ user: user.id, activity: user.activity })
|
||||||
result.items = items.map((i) => i.toJson());
|
result.items = items.map(i => i.toJson())
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('post /api/lottery/history')
|
@router('post /api/lottery/history')
|
||||||
async userLotteryHistory(req) {
|
async userLotteryHistory(req) {
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
let { day, page, limit } = req.params;
|
let { day, page, limit } = req.params
|
||||||
const query: any = {user: user.id, activity: user.activity};
|
const query: any = { user: user.id, activity: user.activity }
|
||||||
if (day !== 'all') {
|
if (day !== 'all') {
|
||||||
query.dateTag = day;
|
query.dateTag = day
|
||||||
}
|
}
|
||||||
page = +page || 1
|
page = +page || 1
|
||||||
limit = +limit || 10
|
limit = +limit || 10
|
||||||
let start = page * limit || 0
|
let start = page * limit || 0
|
||||||
|
|
||||||
|
let historys = await LotteryRecord.find(query).skip(start).limit(limit)
|
||||||
let historys = await LotteryRecord.find(query).skip(start).limit(limit);
|
let total = await LotteryRecord.countDocuments(query)
|
||||||
let total = await LotteryRecord.countDocuments(query);
|
|
||||||
return {
|
return {
|
||||||
count: total,
|
count: total,
|
||||||
page: +page,
|
page: +page,
|
||||||
limit,
|
limit,
|
||||||
records: historys.map((h) => h.toJson())
|
records: historys.map(h => h.toJson()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('get /api/lottery/items')
|
@router('get /api/lottery/items')
|
||||||
async items(req) {
|
async items(req) {
|
||||||
const items = ALL_ITEMS;
|
const items = ALL_ITEMS
|
||||||
const cfgs = LOTTERY_CFG;
|
const cfgs = LOTTERY_CFG
|
||||||
const itemMap = new Map();
|
const itemMap = new Map()
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
itemMap.set(item.id, item);
|
itemMap.set(item.id, item)
|
||||||
}
|
}
|
||||||
let result = [];
|
let result = []
|
||||||
for (let cfg of cfgs.rewards) {
|
for (let cfg of cfgs.rewards) {
|
||||||
result.push({
|
result.push({
|
||||||
id: cfg.item,
|
id: cfg.item,
|
||||||
@ -80,47 +79,46 @@ export default class LotteryController extends BaseController {
|
|||||||
name: itemMap.get(cfg.item).name,
|
name: itemMap.get(cfg.item).name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return {items: result, start: cfgs.start, end: cfgs.end};
|
return { items: result, start: cfgs.start, end: cfgs.end }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@router('get /api/lottery/draw')
|
@router('get /api/lottery/draw')
|
||||||
async draw(req) {
|
async draw(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
const { start, end, rewards } = LOTTERY_CFG;
|
const { start, end, rewards } = LOTTERY_CFG
|
||||||
const startTime = new Date(start).getTime();
|
const startTime = new Date(start).getTime()
|
||||||
const endTime = new Date(end).getTime();
|
const endTime = new Date(end).getTime()
|
||||||
const now = Date.now();
|
const now = Date.now()
|
||||||
if (now < startTime) {
|
if (now < startTime) {
|
||||||
throw new ZError(10, 'lottery not start');
|
throw new ZError(10, 'lottery not start')
|
||||||
}
|
}
|
||||||
if (now > endTime) {
|
if (now > endTime) {
|
||||||
throw new ZError(11, 'lottery end');
|
throw new ZError(11, 'lottery end')
|
||||||
}
|
}
|
||||||
let record = await new LotteryCache().getData(user.id, user.activity);
|
let record = await new LotteryCache().getData(user.id, user.activity)
|
||||||
if (record.amount <= 0) {
|
if (record.amount <= 0) {
|
||||||
throw new ZError(12, 'no chance');
|
throw new ZError(12, 'no chance')
|
||||||
}
|
}
|
||||||
record.amount -= 1;
|
record.amount -= 1
|
||||||
record.used += 1;
|
record.used += 1
|
||||||
let reward = draw(rewards);
|
let reward = draw(rewards)
|
||||||
const dateTag = formatDate(new Date());
|
const dateTag = formatDate(new Date())
|
||||||
let history = new LotteryRecord({
|
let history = new LotteryRecord({
|
||||||
user: user.id,
|
user: user.id,
|
||||||
activity: user.activity,
|
activity: user.activity,
|
||||||
dateTag,
|
dateTag,
|
||||||
reward: reward?.id || EMPTY_REWARD,
|
reward: reward?.id || EMPTY_REWARD,
|
||||||
amount: reward.amount || 0,
|
amount: reward.amount || 0,
|
||||||
});
|
})
|
||||||
await history.save();
|
await history.save()
|
||||||
const items = ALL_ITEMS;
|
const items = ALL_ITEMS
|
||||||
const itemMap = new Map();
|
const itemMap = new Map()
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
itemMap.set(item.id, item);
|
itemMap.set(item.id, item)
|
||||||
}
|
}
|
||||||
if (itemMap.get(reward.id)?.score) {
|
if (itemMap.get(reward.id)?.score) {
|
||||||
let score = (reward?.amount || 0) * itemMap.get(reward.id).score;
|
let score = (reward?.amount || 0) * itemMap.get(reward.id).score
|
||||||
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
||||||
score = Math.floor(score * user.boost)
|
score = Math.floor(score * user.boost)
|
||||||
}
|
}
|
||||||
@ -128,67 +126,72 @@ export default class LotteryController extends BaseController {
|
|||||||
user: user.id,
|
user: user.id,
|
||||||
score,
|
score,
|
||||||
activity: user.activity,
|
activity: user.activity,
|
||||||
scoreType: "draw",
|
scoreType: 'draw',
|
||||||
scoreParams: {
|
scoreParams: {
|
||||||
date: dateTag
|
date: dateTag,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
await ActivityItem.insertOrUpdate({
|
await ActivityItem.insertOrUpdate(
|
||||||
user: user.id,
|
{
|
||||||
activity: user.activity,
|
user: user.id,
|
||||||
item: reward.id
|
activity: user.activity,
|
||||||
},
|
item: reward.id,
|
||||||
{
|
},
|
||||||
$inc: {amount: reward.amount},
|
{
|
||||||
last: Date.now()
|
$inc: { amount: reward.amount },
|
||||||
})
|
last: Date.now(),
|
||||||
return reward;
|
},
|
||||||
|
)
|
||||||
|
return reward
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('get /api/lottery/fusion')
|
@router('get /api/lottery/fusion')
|
||||||
async fusion(req) {
|
async fusion(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
let items = await ActivityItem.find({user: user.id, activity: user.activity});
|
let items = await ActivityItem.find({ user: user.id, activity: user.activity })
|
||||||
let itemCountMap = new Map();
|
let itemCountMap = new Map()
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
itemCountMap.set(item.item, item.amount);
|
itemCountMap.set(item.item, item.amount)
|
||||||
}
|
}
|
||||||
for (let item of FUSION_CFG.source) {
|
for (let item of FUSION_CFG.source) {
|
||||||
if (!itemCountMap.has(item.id)) {
|
if (!itemCountMap.has(item.id)) {
|
||||||
throw new ZError(13, 'no enough item');
|
throw new ZError(13, 'no enough item')
|
||||||
}
|
}
|
||||||
if (itemCountMap.get(item.id) < item.amount) {
|
if (itemCountMap.get(item.id) < item.amount) {
|
||||||
throw new ZError(14, 'no enough item');
|
throw new ZError(14, 'no enough item')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let item of FUSION_CFG.source) {
|
for (let item of FUSION_CFG.source) {
|
||||||
await ActivityItem.insertOrUpdate({
|
await ActivityItem.insertOrUpdate(
|
||||||
user: user.id,
|
{
|
||||||
activity: user.activity,
|
user: user.id,
|
||||||
item: item.id
|
activity: user.activity,
|
||||||
},
|
item: item.id,
|
||||||
{
|
},
|
||||||
$inc: {amount: -item.amount},
|
{
|
||||||
last: Date.now()
|
$inc: { amount: -item.amount },
|
||||||
})
|
last: Date.now(),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await ActivityItem.insertOrUpdate({
|
await ActivityItem.insertOrUpdate(
|
||||||
user: user.id,
|
{
|
||||||
activity: user.activity,
|
user: user.id,
|
||||||
item: FUSION_CFG.target.id
|
activity: user.activity,
|
||||||
},
|
item: FUSION_CFG.target.id,
|
||||||
{
|
},
|
||||||
$inc: {amount: FUSION_CFG.target.amount},
|
{
|
||||||
last: Date.now()
|
$inc: { amount: FUSION_CFG.target.amount },
|
||||||
})
|
last: Date.now(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: FUSION_CFG.target.id,
|
id: FUSION_CFG.target.id,
|
||||||
amount: FUSION_CFG.target.amount,
|
amount: FUSION_CFG.target.amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,33 +1,33 @@
|
|||||||
import BaseController, {ROLE_ANON} from 'common/base.controller'
|
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||||
import { SyncLocker } from 'common/SyncLocker'
|
import { SyncLocker } from 'common/SyncLocker'
|
||||||
import {ZError} from 'common/ZError'
|
import { ZError } from 'common/ZError'
|
||||||
import { BOOST_CFG } from 'configs/boost'
|
import { BOOST_CFG } from 'configs/boost'
|
||||||
import { role, router } from 'decorators/router'
|
import { role, router } from 'decorators/router'
|
||||||
import logger from 'logger/logger'
|
import logger from 'logger/logger'
|
||||||
import { ActivityUser } from 'models/ActivityUser'
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
import {DEFAULT_EXPIRED, NonceRecord} from 'models/NonceRecord'
|
import { DEFAULT_EXPIRED, NonceRecord } from 'models/NonceRecord'
|
||||||
import { ScoreRecord } from 'models/ScoreRecord'
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
import { LoginRecordQueue } from 'queue/loginrecord.queue'
|
import { LoginRecordQueue } from 'queue/loginrecord.queue'
|
||||||
import { RedisClient } from 'redis/RedisClient'
|
import { RedisClient } from 'redis/RedisClient'
|
||||||
import { queryCheckInList } from 'services/chain.svr'
|
import { queryCheckInList } from 'services/chain.svr'
|
||||||
import { rankKey } from 'services/rank.svr'
|
import { rankKey } from 'services/rank.svr'
|
||||||
import {SiweMessage} from 'siwe'
|
import { SiweMessage } from 'siwe'
|
||||||
import { nextday, yesterday } from 'utils/date.util'
|
import { nextday, yesterday } from 'utils/date.util'
|
||||||
import { checkParamsNeeded } from 'utils/net.util'
|
import { checkParamsNeeded } from 'utils/net.util'
|
||||||
import { aesDecrypt, base58ToHex } from 'utils/security.util'
|
import { aesDecrypt, base58ToHex } from 'utils/security.util'
|
||||||
|
|
||||||
const LOGIN_TIP = 'This signature is just to verify your identity'
|
const LOGIN_TIP = 'This signature is just to verify your identity'
|
||||||
|
|
||||||
const ROUND = 1000000;
|
const ROUND = 1000000
|
||||||
const generateBoost = (rewards: {probability: number}[]) => {
|
const generateBoost = (rewards: { probability: number }[]) => {
|
||||||
let total = 0;
|
let total = 0
|
||||||
let random = Math.floor(Math.random() * ROUND);
|
let random = Math.floor(Math.random() * ROUND)
|
||||||
let reward = null;
|
let reward = null
|
||||||
for (let r of rewards) {
|
for (let r of rewards) {
|
||||||
total += r.probability;
|
total += r.probability
|
||||||
if (random < total) {
|
if (random < total) {
|
||||||
reward = r;
|
reward = r
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reward.value
|
return reward.value
|
||||||
@ -48,19 +48,19 @@ class SignController extends BaseController {
|
|||||||
const { signature, message, activity } = req.params
|
const { signature, message, activity } = req.params
|
||||||
checkParamsNeeded(signature, message)
|
checkParamsNeeded(signature, message)
|
||||||
if (!message.nonce) {
|
if (!message.nonce) {
|
||||||
throw new ZError(11, 'Invalid nonce');
|
throw new ZError(11, 'Invalid nonce')
|
||||||
}
|
}
|
||||||
let nonce = message.nonce
|
let nonce = message.nonce
|
||||||
let source = 'unknow'
|
let source = 'unknow'
|
||||||
if (nonce.length > 24) {
|
if (nonce.length > 24) {
|
||||||
nonce = base58ToHex(nonce);
|
nonce = base58ToHex(nonce)
|
||||||
let nonceStr = aesDecrypt(nonce, activity);
|
let nonceStr = aesDecrypt(nonce, activity)
|
||||||
if (nonceStr.indexOf('|') >=0 ) {
|
if (nonceStr.indexOf('|') >= 0) {
|
||||||
const split = nonceStr.split('|')
|
const split = nonceStr.split('|')
|
||||||
nonce = split[0];
|
nonce = split[0]
|
||||||
source = split[1];
|
source = split[1]
|
||||||
} else {
|
} else {
|
||||||
nonce = nonceStr;
|
nonce = nonceStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let record = await NonceRecord.findById(nonce)
|
let record = await NonceRecord.findById(nonce)
|
||||||
@ -75,9 +75,9 @@ class SignController extends BaseController {
|
|||||||
}
|
}
|
||||||
record.status = 1
|
record.status = 1
|
||||||
await record.save()
|
await record.save()
|
||||||
const msgSign = new SiweMessage(message);
|
const msgSign = new SiweMessage(message)
|
||||||
try {
|
try {
|
||||||
await msgSign.verify({ signature, nonce: message.nonce });
|
await msgSign.verify({ signature, nonce: message.nonce })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new ZError(15, 'signature invalid')
|
throw new ZError(15, 'signature invalid')
|
||||||
}
|
}
|
||||||
@ -92,16 +92,20 @@ class SignController extends BaseController {
|
|||||||
await accountData.save()
|
await accountData.save()
|
||||||
new LoginRecordQueue().addLog(req, accountData.id, activity, source)
|
new LoginRecordQueue().addLog(req, accountData.id, activity, source)
|
||||||
|
|
||||||
const token = await res.jwtSign({ id: accountData.id, address: accountData.address, activity: accountData.activity })
|
const token = await res.jwtSign({
|
||||||
|
id: accountData.id,
|
||||||
|
address: accountData.address,
|
||||||
|
activity: accountData.activity,
|
||||||
|
})
|
||||||
return { token }
|
return { token }
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('get /api/user/state')
|
@router('get /api/user/state')
|
||||||
async userInfo(req){
|
async userInfo(req) {
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
const todayKey = rankKey(user.activity, new Date());
|
const todayKey = rankKey(user.activity, new Date())
|
||||||
const todayScore = await new RedisClient().zscore(todayKey, user.id)
|
const todayScore = await new RedisClient().zscore(todayKey, user.id)
|
||||||
const totalKey = rankKey(user.activity);
|
const totalKey = rankKey(user.activity)
|
||||||
const totalScore = await new RedisClient().zscore(totalKey, user.id)
|
const totalScore = await new RedisClient().zscore(totalKey, user.id)
|
||||||
const totalRank = await new RedisClient().zrevrank(totalKey, user.id)
|
const totalRank = await new RedisClient().zrevrank(totalKey, user.id)
|
||||||
let invite = ''
|
let invite = ''
|
||||||
@ -112,9 +116,9 @@ class SignController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const records = await ScoreRecord.find({ user: user.id, activity: user.activity, scoreType: 'invite' })
|
const records = await ScoreRecord.find({ user: user.id, activity: user.activity, scoreType: 'invite' })
|
||||||
let score = 0;
|
let score = 0
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
score += record.score;
|
score += record.score
|
||||||
}
|
}
|
||||||
let result = {
|
let result = {
|
||||||
address: user.address,
|
address: user.address,
|
||||||
@ -124,34 +128,34 @@ class SignController extends BaseController {
|
|||||||
twitterName: user.twitterName,
|
twitterName: user.twitterName,
|
||||||
discordId: user.discordId,
|
discordId: user.discordId,
|
||||||
discordName: user.discordName,
|
discordName: user.discordName,
|
||||||
scoreToday: todayScore ? parseInt(todayScore+'') : 0,
|
scoreToday: todayScore ? parseInt(todayScore + '') : 0,
|
||||||
scoreTotal: totalScore ? parseInt(totalScore+'') : 0,
|
scoreTotal: totalScore ? parseInt(totalScore + '') : 0,
|
||||||
rankTotal: totalRank ? totalRank : '-',
|
rankTotal: totalRank ? totalRank : '-',
|
||||||
invite,
|
invite,
|
||||||
inviteCount: records.length,
|
inviteCount: records.length,
|
||||||
inviteScore: score,
|
inviteScore: score,
|
||||||
code: user.inviteCode,
|
code: user.inviteCode,
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
@router('get /api/user/state/boost')
|
@router('get /api/user/state/boost')
|
||||||
async boost(req){
|
async boost(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
if (user.boost > 1 && user.boostExpire && user.boostExpire > Date.now()) {
|
if (user.boost > 1 && user.boostExpire && user.boostExpire > Date.now()) {
|
||||||
throw new ZError(11, 'already boosted')
|
throw new ZError(11, 'already boosted')
|
||||||
}
|
}
|
||||||
user.boost = generateBoost(BOOST_CFG)
|
user.boost = generateBoost(BOOST_CFG)
|
||||||
user.boostExpire = nextday();
|
user.boostExpire = nextday()
|
||||||
await user.save();
|
await user.save()
|
||||||
return { boost: user.boost, boostExpire: user.boostExpire };
|
return { boost: user.boost, boostExpire: user.boostExpire }
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('get /api/user/checkin/list/:tag')
|
@router('get /api/user/checkin/list/:tag')
|
||||||
async checkInList(req){
|
async checkInList(req) {
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
const {tag} = req.params;
|
const { tag } = req.params
|
||||||
let days: any = 1;
|
let days: any = 1
|
||||||
if (tag === '1month') {
|
if (tag === '1month') {
|
||||||
days = '1month'
|
days = '1month'
|
||||||
} else if (tag === 'last') {
|
} else if (tag === 'last') {
|
||||||
@ -161,7 +165,6 @@ class SignController extends BaseController {
|
|||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* regist user by token from wallet-svr
|
* regist user by token from wallet-svr
|
||||||
* TODO::
|
* TODO::
|
||||||
@ -175,5 +178,4 @@ class SignController extends BaseController {
|
|||||||
const { wallet_token } = req.params
|
const { wallet_token } = req.params
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,39 @@
|
|||||||
import { SyncLocker } from "common/SyncLocker";
|
import { SyncLocker } from 'common/SyncLocker'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import BaseController from "common/base.controller";
|
import BaseController from 'common/base.controller'
|
||||||
import { router } from "decorators/router";
|
import { router } from 'decorators/router'
|
||||||
import { TaskCfg, TaskTypeEnum } from "models/ActivityInfo";
|
import { TaskCfg, TaskTypeEnum } from 'models/ActivityInfo'
|
||||||
import { TaskStatus, TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatus, TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { formatDate } from "utils/date.util";
|
import { formatDate } from 'utils/date.util'
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
const prod = process.env.NODE_ENV === 'production'
|
const prod = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
const initTasks = () => {
|
const initTasks = () => {
|
||||||
const tasks = join(__dirname, '../tasks')
|
const tasks = join(__dirname, '../tasks')
|
||||||
const list = new Map();
|
const list = new Map()
|
||||||
fs.readdirSync(tasks)
|
fs.readdirSync(tasks)
|
||||||
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
|
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
|
||||||
.forEach((file: any) => {
|
.forEach((file: any) => {
|
||||||
const Task = require('../tasks/' + file);
|
const Task = require('../tasks/' + file)
|
||||||
list.set(Task.default.name, {
|
list.set(Task.default.name, {
|
||||||
name: Task.default.name,
|
name: Task.default.name,
|
||||||
desc: Task.default.desc,
|
desc: Task.default.desc,
|
||||||
show: Task.default.show})
|
show: Task.default.show,
|
||||||
})
|
})
|
||||||
return list
|
})
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
const allTasks = initTasks();
|
const allTasks = initTasks()
|
||||||
|
|
||||||
|
|
||||||
export default class TasksController extends BaseController {
|
export default class TasksController extends BaseController {
|
||||||
|
|
||||||
@router('post /api/tasks/progress')
|
@router('post /api/tasks/progress')
|
||||||
async taskProgress(req) {
|
async taskProgress(req) {
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
let activity = req.activity;
|
let activity = req.activity
|
||||||
const dateTag = formatDate(new Date());
|
const dateTag = formatDate(new Date())
|
||||||
let taskAddedSet = new Set();
|
let taskAddedSet = new Set()
|
||||||
for (let task of user.taskProgress) {
|
for (let task of user.taskProgress) {
|
||||||
if (task.dateTag) {
|
if (task.dateTag) {
|
||||||
taskAddedSet.add(task.id + ':' + task.dateTag)
|
taskAddedSet.add(task.id + ':' + task.dateTag)
|
||||||
@ -42,52 +41,51 @@ export default class TasksController extends BaseController {
|
|||||||
taskAddedSet.add(task.id)
|
taskAddedSet.add(task.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let modified = false;
|
let modified = false
|
||||||
let visibleTasks = new Set();
|
let visibleTasks = new Set()
|
||||||
for (let task of activity.tasks) {
|
for (let task of activity.tasks) {
|
||||||
if (!allTasks.has(task.task)) {
|
if (!allTasks.has(task.task)) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
if (!task.isVaild()) {
|
if (!task.isVaild()) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
if (task.type === TaskTypeEnum.DAILY ) {
|
if (task.type === TaskTypeEnum.DAILY) {
|
||||||
let id = `${task.id}:${dateTag}`
|
let id = `${task.id}:${dateTag}`
|
||||||
if (!taskAddedSet.has(id)) {
|
if (!taskAddedSet.has(id)) {
|
||||||
modified = true;
|
modified = true
|
||||||
user.taskProgress.push({id, task:task.task ,dateTag: dateTag, status: TaskStatusEnum.NOT_START})
|
user.taskProgress.push({ id, task: task.task, dateTag: dateTag, status: TaskStatusEnum.NOT_START })
|
||||||
}
|
}
|
||||||
if (task.show) visibleTasks.add(id);
|
if (task.show) visibleTasks.add(id)
|
||||||
} else if (task.type === TaskTypeEnum.ONCE ) {
|
} else if (task.type === TaskTypeEnum.ONCE) {
|
||||||
if (!taskAddedSet.has(task.id)) {
|
if (!taskAddedSet.has(task.id)) {
|
||||||
modified = true;
|
modified = true
|
||||||
user.taskProgress.push({id: task.id, task: task.task, status: TaskStatusEnum.NOT_START})
|
user.taskProgress.push({ id: task.id, task: task.task, status: TaskStatusEnum.NOT_START })
|
||||||
}
|
}
|
||||||
if (task.show) visibleTasks.add(task.id);
|
if (task.show) visibleTasks.add(task.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (modified) {
|
if (modified) {
|
||||||
await user.save();
|
await user.save()
|
||||||
}
|
}
|
||||||
return user.taskProgress.filter((t: TaskStatus) => visibleTasks.has(t.id));
|
return user.taskProgress.filter((t: TaskStatus) => visibleTasks.has(t.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@router('post /api/tasks/begin_task')
|
@router('post /api/tasks/begin_task')
|
||||||
async beginTask(req) {
|
async beginTask(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
let user = req.user;
|
let user = req.user
|
||||||
let activity = req.activity;
|
let activity = req.activity
|
||||||
let { task } = req.params;
|
let { task } = req.params
|
||||||
const [taskId, dateTag] = task.split(':');
|
const [taskId, dateTag] = task.split(':')
|
||||||
const currentDateTag = formatDate(new Date());
|
const currentDateTag = formatDate(new Date())
|
||||||
if (dateTag && currentDateTag !== dateTag) {
|
if (dateTag && currentDateTag !== dateTag) {
|
||||||
throw new ZError(11, 'task date not match')
|
throw new ZError(11, 'task date not match')
|
||||||
}
|
}
|
||||||
if (!activity.isVaild()) {
|
if (!activity.isVaild()) {
|
||||||
throw new ZError(15, 'activity not start or end')
|
throw new ZError(15, 'activity not start or end')
|
||||||
}
|
}
|
||||||
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId);
|
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
throw new ZError(12, 'task not found')
|
throw new ZError(12, 'task not found')
|
||||||
}
|
}
|
||||||
@ -105,80 +103,88 @@ export default class TasksController extends BaseController {
|
|||||||
return t.id.indexOf(preTask) > -1
|
return t.id.indexOf(preTask) > -1
|
||||||
}
|
}
|
||||||
return t.id === preTask
|
return t.id === preTask
|
||||||
});
|
})
|
||||||
if (!preTaskData || (preTaskData.status === TaskStatusEnum.NOT_START || preTaskData.status === TaskStatusEnum.RUNNING)) {
|
if (
|
||||||
|
!preTaskData ||
|
||||||
|
preTaskData.status === TaskStatusEnum.NOT_START ||
|
||||||
|
preTaskData.status === TaskStatusEnum.RUNNING
|
||||||
|
) {
|
||||||
throw new ZError(14, 'task previous not finish')
|
throw new ZError(14, 'task previous not finish')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
|
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task)
|
||||||
if (currentTask.status === TaskStatusEnum.PART_SUCCESS || currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
|
if (
|
||||||
|
currentTask.status === TaskStatusEnum.PART_SUCCESS ||
|
||||||
|
currentTask.status === TaskStatusEnum.SUCCESS ||
|
||||||
|
currentTask.status === TaskStatusEnum.CLAIMED
|
||||||
|
) {
|
||||||
throw new ZError(15, 'task already end')
|
throw new ZError(15, 'task already end')
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
||||||
currentTask.timeStart = Date.now();
|
currentTask.timeStart = Date.now()
|
||||||
currentTask.status = TaskStatusEnum.RUNNING;
|
currentTask.status = TaskStatusEnum.RUNNING
|
||||||
}
|
}
|
||||||
await user.save();
|
await user.save()
|
||||||
return currentTask
|
return currentTask
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('post /api/tasks/check_task')
|
@router('post /api/tasks/check_task')
|
||||||
async checkTask(req) {
|
async checkTask(req) {
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
const activity = req.activity;
|
const activity = req.activity
|
||||||
const { task } = req.params;
|
const { task } = req.params
|
||||||
const [taskId, dateTag] = task.split(':');
|
const [taskId, dateTag] = task.split(':')
|
||||||
const currentDateTag = formatDate(new Date());
|
const currentDateTag = formatDate(new Date())
|
||||||
if (dateTag && currentDateTag !== dateTag) {
|
if (dateTag && currentDateTag !== dateTag) {
|
||||||
throw new ZError(11, 'task date not match')
|
throw new ZError(11, 'task date not match')
|
||||||
}
|
}
|
||||||
if (!activity.isVaild()) {
|
if (!activity.isVaild()) {
|
||||||
throw new ZError(15, 'activity not start or end')
|
throw new ZError(15, 'activity not start or end')
|
||||||
}
|
}
|
||||||
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId);
|
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
throw new ZError(12, 'task not found')
|
throw new ZError(12, 'task not found')
|
||||||
}
|
}
|
||||||
if (!cfg.isVaild()) {
|
if (!cfg.isVaild()) {
|
||||||
throw new ZError(16, 'task not start or end')
|
throw new ZError(16, 'task not start or end')
|
||||||
}
|
}
|
||||||
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
|
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task)
|
||||||
if (!currentTask) {
|
if (!currentTask) {
|
||||||
throw new ZError(11, 'task not found')
|
throw new ZError(11, 'task not found')
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.CLAIMED) {
|
if (currentTask.status === TaskStatusEnum.CLAIMED) {
|
||||||
return currentTask;
|
return currentTask
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
||||||
throw new ZError(11, 'task not begin');
|
throw new ZError(11, 'task not begin')
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.RUNNING || currentTask.status === TaskStatusEnum.PART_SUCCESS) {
|
if (currentTask.status === TaskStatusEnum.RUNNING || currentTask.status === TaskStatusEnum.PART_SUCCESS) {
|
||||||
let Task = require('../tasks/' + currentTask.task);
|
let Task = require('../tasks/' + currentTask.task)
|
||||||
let taskInstance = new Task.default({user, activity});
|
let taskInstance = new Task.default({ user, activity })
|
||||||
await taskInstance.execute({task: currentTask});
|
await taskInstance.execute({ task: currentTask })
|
||||||
}
|
}
|
||||||
return currentTask
|
return currentTask
|
||||||
}
|
}
|
||||||
|
|
||||||
@router('post /api/tasks/claim')
|
@router('post /api/tasks/claim')
|
||||||
async claimTask(req) {
|
async claimTask(req) {
|
||||||
new SyncLocker().checkLock(req);
|
new SyncLocker().checkLock(req)
|
||||||
const user = req.user;
|
const user = req.user
|
||||||
const activity = req.activity;
|
const activity = req.activity
|
||||||
const { task } = req.params;
|
const { task } = req.params
|
||||||
const [taskId, dateTag] = task.split(':');
|
const [taskId, dateTag] = task.split(':')
|
||||||
if (!activity.isVaild()) {
|
if (!activity.isVaild()) {
|
||||||
throw new ZError(15, 'activity not start or end')
|
throw new ZError(15, 'activity not start or end')
|
||||||
}
|
}
|
||||||
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId);
|
let cfg = activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
throw new ZError(14, 'task not found')
|
throw new ZError(14, 'task not found')
|
||||||
}
|
}
|
||||||
if (!cfg.isVaild()) {
|
if (!cfg.isVaild()) {
|
||||||
throw new ZError(16, 'task not start or end')
|
throw new ZError(16, 'task not start or end')
|
||||||
}
|
}
|
||||||
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
|
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task)
|
||||||
if (!currentTask) {
|
if (!currentTask) {
|
||||||
throw new ZError(11, 'task not found')
|
throw new ZError(11, 'task not found')
|
||||||
}
|
}
|
||||||
@ -189,10 +195,9 @@ export default class TasksController extends BaseController {
|
|||||||
throw new ZError(13, 'task not end')
|
throw new ZError(13, 'task not end')
|
||||||
}
|
}
|
||||||
|
|
||||||
const Task = require('../tasks/' + currentTask.task);
|
const Task = require('../tasks/' + currentTask.task)
|
||||||
const taskInstance = new Task.default({user, activity});
|
const taskInstance = new Task.default({ user, activity })
|
||||||
await taskInstance.claimReward(currentTask);
|
await taskInstance.claimReward(currentTask)
|
||||||
return currentTask
|
return currentTask
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,7 +7,6 @@ const dir = `${__dirname}/../initdatas`
|
|||||||
const db = mongoose.connection
|
const db = mongoose.connection
|
||||||
var ejson = require('mongodb-extended-json')
|
var ejson = require('mongodb-extended-json')
|
||||||
|
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
await mongoose.connect(process.env.DB_MAIN)
|
await mongoose.connect(process.env.DB_MAIN)
|
||||||
@ -18,7 +17,7 @@ var ejson = require('mongodb-extended-json')
|
|||||||
const collection_name = list[i].replace('.json', '')
|
const collection_name = list[i].replace('.json', '')
|
||||||
const parsedJSON = require(dir + '/' + list[i])
|
const parsedJSON = require(dir + '/' + list[i])
|
||||||
const jsonArry = ejson.deserialize(parsedJSON)
|
const jsonArry = ejson.deserialize(parsedJSON)
|
||||||
await db.collection(collection_name).insertMany(jsonArry);
|
await db.collection(collection_name).insertMany(jsonArry)
|
||||||
console.log('Inserted ' + jsonArry.length + ' documents into the "' + collection_name + '" collection.')
|
console.log('Inserted ' + jsonArry.length + ' documents into the "' + collection_name + '" collection.')
|
||||||
}
|
}
|
||||||
console.log('Finished inserting documents into the database')
|
console.log('Finished inserting documents into the database')
|
||||||
@ -27,4 +26,3 @@ var ejson = require('mongodb-extended-json')
|
|||||||
}
|
}
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
})()
|
})()
|
||||||
|
|
||||||
|
@ -5,12 +5,11 @@ import findOrCreate from 'mongoose-findorcreate'
|
|||||||
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from './Base'
|
||||||
|
|
||||||
|
|
||||||
export enum TaskTypeEnum {
|
export enum TaskTypeEnum {
|
||||||
ONCE = 1,
|
ONCE = 1,
|
||||||
DAILY = 2,
|
DAILY = 2,
|
||||||
}
|
}
|
||||||
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }, })
|
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW } })
|
||||||
export class TaskCfg {
|
export class TaskCfg {
|
||||||
@prop()
|
@prop()
|
||||||
id: string
|
id: string
|
||||||
@ -20,19 +19,19 @@ export class TaskCfg {
|
|||||||
title: string
|
title: string
|
||||||
@prop({ enum: TaskTypeEnum, default: TaskTypeEnum.ONCE })
|
@prop({ enum: TaskTypeEnum, default: TaskTypeEnum.ONCE })
|
||||||
type: TaskTypeEnum
|
type: TaskTypeEnum
|
||||||
@prop({default: 1})
|
@prop({ default: 1 })
|
||||||
repeat: number
|
repeat: number
|
||||||
@prop()
|
@prop()
|
||||||
desc: string
|
desc: string
|
||||||
@prop({ type: mongoose.Schema.Types.Mixed })
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
category: any
|
category: any
|
||||||
@prop({default: false})
|
@prop({ default: false })
|
||||||
autoclaim: boolean
|
autoclaim: boolean
|
||||||
@prop({ type: () => [String], default: [] })
|
@prop({ type: () => [String], default: [] })
|
||||||
pretasks: string[]
|
pretasks: string[]
|
||||||
@prop()
|
@prop()
|
||||||
score: number
|
score: number
|
||||||
@prop({default: true})
|
@prop({ default: true })
|
||||||
show: boolean
|
show: boolean
|
||||||
@prop({ type: mongoose.Schema.Types.Mixed })
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
cfg: any
|
cfg: any
|
||||||
@ -135,7 +134,6 @@ class ActivityInfoClass extends BaseModule {
|
|||||||
result.tasks = tasks
|
result.tasks = tasks
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActivityInfo = getModelForClass(ActivityInfoClass, { existingConnection: ActivityInfoClass.db })
|
export const ActivityInfo = getModelForClass(ActivityInfoClass, { existingConnection: ActivityInfoClass.db })
|
||||||
|
@ -6,9 +6,12 @@ import { BaseModule } from './Base'
|
|||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1, activity: 1}, { unique: false })
|
@index({ user: 1, activity: 1 }, { unique: false })
|
||||||
@index({ user: 1, activity: 1, item: 1 }, { unique: true })
|
@index({ user: 1, activity: 1, item: 1 }, { unique: true })
|
||||||
@modelOptions({ schemaOptions: { collection: 'activity_item', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'activity_item', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class ActivityItemClass extends BaseModule {
|
class ActivityItemClass extends BaseModule {
|
||||||
@prop()
|
@prop()
|
||||||
public user: string
|
public user: string
|
||||||
@ -16,16 +19,16 @@ class ActivityItemClass extends BaseModule {
|
|||||||
public activity: string
|
public activity: string
|
||||||
@prop()
|
@prop()
|
||||||
public item: string
|
public item: string
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public amount: number
|
public amount: number
|
||||||
@prop()
|
@prop()
|
||||||
public last: number
|
public last: number
|
||||||
|
|
||||||
public toJson() {
|
public toJson() {
|
||||||
return {
|
return {
|
||||||
id: this.item,
|
id: this.item,
|
||||||
amount: this.amount
|
amount: this.amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const ActivityItem = getModelForClass(ActivityItemClass, { existingConnection: ActivityItemClass['db'] })
|
export const ActivityItem = getModelForClass(ActivityItemClass, { existingConnection: ActivityItemClass['db'] })
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
import { getModelForClass, index, modelOptions, mongoose, pre, prop, ReturnModelType, Severity } from '@typegoose/typegoose'
|
import {
|
||||||
|
getModelForClass,
|
||||||
|
index,
|
||||||
|
modelOptions,
|
||||||
|
mongoose,
|
||||||
|
pre,
|
||||||
|
prop,
|
||||||
|
ReturnModelType,
|
||||||
|
Severity,
|
||||||
|
} from '@typegoose/typegoose'
|
||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import findOrCreate from 'mongoose-findorcreate'
|
import findOrCreate from 'mongoose-findorcreate'
|
||||||
@ -16,7 +25,7 @@ export enum TaskStatusEnum {
|
|||||||
PART_SUCCESS = 4,
|
PART_SUCCESS = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }})
|
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW } })
|
||||||
export class TaskStatus {
|
export class TaskStatus {
|
||||||
@prop()
|
@prop()
|
||||||
id: string
|
id: string
|
||||||
@ -44,18 +53,21 @@ interface ActivityUserClass extends Base, TimeStamps {}
|
|||||||
@index({ inviteUser: 1, activity: 1 }, { unique: false })
|
@index({ inviteUser: 1, activity: 1 }, { unique: false })
|
||||||
@index({ twitterId: 1 }, { unique: true, partialFilterExpression: { twitterId: { $exists: true } } })
|
@index({ twitterId: 1 }, { unique: true, partialFilterExpression: { twitterId: { $exists: true } } })
|
||||||
@index({ discordId: 1 }, { unique: true, partialFilterExpression: { discordId: { $exists: true } } })
|
@index({ discordId: 1 }, { unique: true, partialFilterExpression: { discordId: { $exists: true } } })
|
||||||
@modelOptions({ schemaOptions: { collection: 'activity_user', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'activity_user', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
@pre<ActivityUserClass>('save', async function () {
|
@pre<ActivityUserClass>('save', async function () {
|
||||||
if (!this.inviteCode) {
|
if (!this.inviteCode) {
|
||||||
// 取ObjectId的time和inc段,
|
// 取ObjectId的time和inc段,
|
||||||
// 将time段倒序(倒序后, 如果以0开始, 则移除0, 随机拼接一个hex字符), 然后拼接inc段, 再转换成52进制
|
// 将time段倒序(倒序后, 如果以0开始, 则移除0, 随机拼接一个hex字符), 然后拼接inc段, 再转换成52进制
|
||||||
let timeStr = this.id.slice(0, 8).split("").reverse().join("");
|
let timeStr = this.id.slice(0, 8).split('').reverse().join('')
|
||||||
if (timeStr.indexOf('0') === 0) {
|
if (timeStr.indexOf('0') === 0) {
|
||||||
let randomStr = convert({ numStr: (Math.random() * 51 | 0 + 1) + '', base:10, to: 52})
|
let randomStr = convert({ numStr: ((Math.random() * 51) | (0 + 1)) + '', base: 10, to: 52 })
|
||||||
timeStr = randomStr + timeStr.slice(1)
|
timeStr = randomStr + timeStr.slice(1)
|
||||||
}
|
}
|
||||||
let shortId = timeStr + this.id.slice(-6)
|
let shortId = timeStr + this.id.slice(-6)
|
||||||
this.inviteCode = convert({numStr: shortId, base: 16, to: 52, alphabet})
|
this.inviteCode = convert({ numStr: shortId, base: 16, to: 52, alphabet })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
class ActivityUserClass extends BaseModule {
|
class ActivityUserClass extends BaseModule {
|
||||||
@ -89,7 +101,7 @@ class ActivityUserClass extends BaseModule {
|
|||||||
@prop()
|
@prop()
|
||||||
public discordName?: string
|
public discordName?: string
|
||||||
|
|
||||||
@prop({default: 1})
|
@prop({ default: 1 })
|
||||||
public boost: number
|
public boost: number
|
||||||
/**
|
/**
|
||||||
* boost过期时间
|
* boost过期时间
|
||||||
@ -104,10 +116,13 @@ class ActivityUserClass extends BaseModule {
|
|||||||
@prop({ type: () => [TaskStatus], default: [] })
|
@prop({ type: () => [TaskStatus], default: [] })
|
||||||
public taskProgress?: TaskStatus[]
|
public taskProgress?: TaskStatus[]
|
||||||
|
|
||||||
public static async findByCode(this: ReturnModelType<typeof ActivityUserClass>, inviteCode: string, activity: string) {
|
public static async findByCode(
|
||||||
|
this: ReturnModelType<typeof ActivityUserClass>,
|
||||||
|
inviteCode: string,
|
||||||
|
activity: string,
|
||||||
|
) {
|
||||||
return this.findOne({ inviteCode, activity }).exec()
|
return this.findOne({ inviteCode, activity }).exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActivityUser = getModelForClass(ActivityUserClass, { existingConnection: ActivityUserClass.db })
|
export const ActivityUser = getModelForClass(ActivityUserClass, { existingConnection: ActivityUserClass.db })
|
||||||
|
@ -102,7 +102,7 @@ export abstract class BaseModule extends FindOrCreate {
|
|||||||
* @return {{opt: any, sort: {_id: number}}}
|
* @return {{opt: any, sort: {_id: number}}}
|
||||||
*/
|
*/
|
||||||
public static parseQueryParam(params: {}, options?: any) {
|
public static parseQueryParam(params: {}, options?: any) {
|
||||||
const opt: any = { deleted: { $ne: true } }
|
const opt: any = { deleted: { $ne: true } }
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let obj = this.schema.paths
|
let obj = this.schema.paths
|
||||||
for (let key in params) {
|
for (let key in params) {
|
||||||
@ -201,6 +201,6 @@ export abstract class BaseModule extends FindOrCreate {
|
|||||||
public getTimestampOfID() {
|
public getTimestampOfID() {
|
||||||
// Extract the timestamp from the ObjectId
|
// Extract the timestamp from the ObjectId
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return this._id.getTimestamp();
|
return this._id.getTimestamp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,10 @@ import { BaseModule } from './Base'
|
|||||||
*/
|
*/
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1, activity: 1, wallet: 1 }, { unique: false })
|
@index({ user: 1, activity: 1, wallet: 1 }, { unique: false })
|
||||||
@modelOptions({ schemaOptions: { collection: 'user_login_record', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'user_login_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class LoginRecordClass extends BaseModule {
|
class LoginRecordClass extends BaseModule {
|
||||||
@prop()
|
@prop()
|
||||||
public user: string
|
public user: string
|
||||||
|
@ -7,9 +7,12 @@ import { BaseModule } from './Base'
|
|||||||
* 用户抽奖记录
|
* 用户抽奖记录
|
||||||
*/
|
*/
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1, activity: 1}, { unique: false })
|
@index({ user: 1, activity: 1 }, { unique: false })
|
||||||
@index({ user: 1, activity: 1, dateTag: 1}, { unique: false })
|
@index({ user: 1, activity: 1, dateTag: 1 }, { unique: false })
|
||||||
@modelOptions({ schemaOptions: { collection: 'lottery_record', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'lottery_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class LotteryRecordClass extends BaseModule {
|
class LotteryRecordClass extends BaseModule {
|
||||||
@prop()
|
@prop()
|
||||||
public user: string
|
public user: string
|
||||||
@ -19,15 +22,15 @@ class LotteryRecordClass extends BaseModule {
|
|||||||
public dateTag: string
|
public dateTag: string
|
||||||
@prop()
|
@prop()
|
||||||
public reward?: string
|
public reward?: string
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public amount: number
|
public amount: number
|
||||||
|
|
||||||
public toJson() {
|
public toJson() {
|
||||||
return {
|
return {
|
||||||
day: this.dateTag,
|
day: this.dateTag,
|
||||||
id: this.reward,
|
id: this.reward,
|
||||||
amount: this.amount,
|
amount: this.amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const LotteryRecord = getModelForClass(LotteryRecordClass, { existingConnection: LotteryRecordClass['db'] })
|
export const LotteryRecord = getModelForClass(LotteryRecordClass, { existingConnection: LotteryRecordClass['db'] })
|
||||||
|
@ -7,35 +7,37 @@ import { BaseModule } from './Base'
|
|||||||
* 用户抽奖状态
|
* 用户抽奖状态
|
||||||
*/
|
*/
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1, activity: 1, dateTag: 1}, { unique: false })
|
@index({ user: 1, activity: 1, dateTag: 1 }, { unique: false })
|
||||||
@modelOptions({ schemaOptions: { collection: 'lottery_stats', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'lottery_stats', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class LotteryStatsClass extends BaseModule {
|
class LotteryStatsClass extends BaseModule {
|
||||||
@prop()
|
@prop()
|
||||||
public user: string
|
public user: string
|
||||||
@prop()
|
@prop()
|
||||||
public activity: string
|
public activity: string
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public amount: number
|
public amount: number
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public daily: number
|
public daily: number
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public gacha: number
|
public gacha: number
|
||||||
@prop({default: 0 })
|
@prop({ default: 0 })
|
||||||
public share: number
|
public share: number
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public used: number
|
public used: number
|
||||||
@prop()
|
@prop()
|
||||||
public dateTag: string
|
public dateTag: string
|
||||||
|
|
||||||
|
|
||||||
public toJson() {
|
public toJson() {
|
||||||
return {
|
return {
|
||||||
amount: this.amount,
|
amount: this.amount,
|
||||||
daily: this.daily,
|
daily: this.daily,
|
||||||
gacha: this.gacha,
|
gacha: this.gacha,
|
||||||
used: this.used,
|
used: this.used,
|
||||||
day: this.dateTag,
|
day: this.dateTag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const LotteryStats = getModelForClass(LotteryStatsClass, { existingConnection: LotteryStatsClass['db'] })
|
export const LotteryStats = getModelForClass(LotteryStatsClass, { existingConnection: LotteryStatsClass['db'] })
|
||||||
|
@ -2,17 +2,19 @@ import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from
|
|||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from './Base'
|
||||||
|
|
||||||
|
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1, chain: 1, address: 1}, { unique: false })
|
@index({ user: 1, chain: 1, address: 1 }, { unique: false })
|
||||||
@index({ user: 1, chain: 1, address: 1, tokenId: 1 }, { unique: true })
|
@index({ user: 1, chain: 1, address: 1, tokenId: 1 }, { unique: true })
|
||||||
@modelOptions({ schemaOptions: { collection: 'nft_burn_record', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'nft_burn_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class NftBurnRecordClass extends BaseModule {
|
class NftBurnRecordClass extends BaseModule {
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public user: string
|
public user: string
|
||||||
@prop()
|
@prop()
|
||||||
public chain: number
|
public chain: number
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public address: string
|
public address: string
|
||||||
@prop()
|
@prop()
|
||||||
public tokenId: string
|
public tokenId: string
|
||||||
@ -20,8 +22,6 @@ class NftBurnRecordClass extends BaseModule {
|
|||||||
public activity: string
|
public activity: string
|
||||||
@prop()
|
@prop()
|
||||||
public task: string
|
public task: string
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NftBurnRecord = getModelForClass(NftBurnRecordClass, { existingConnection: NftBurnRecordClass['db'] })
|
export const NftBurnRecord = getModelForClass(NftBurnRecordClass, { existingConnection: NftBurnRecordClass['db'] })
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@ class NonceRecordClass extends BaseModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const NonceRecord = getModelForClass(NonceRecordClass, { existingConnection: NonceRecordClass['db'] })
|
export const NonceRecord = getModelForClass(NonceRecordClass, { existingConnection: NonceRecordClass['db'] })
|
||||||
|
|
||||||
|
@ -2,17 +2,19 @@ import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from
|
|||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from './Base'
|
||||||
|
|
||||||
|
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1 }, { unique: false })
|
@index({ user: 1 }, { unique: false })
|
||||||
@index({ activity: 1 }, { unique: false })
|
@index({ activity: 1 }, { unique: false })
|
||||||
@index({user: 1, activity: 1, type: 1}, { unique: false })
|
@index({ user: 1, activity: 1, type: 1 }, { unique: false })
|
||||||
@modelOptions({ schemaOptions: { collection: 'score_record', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'score_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class ScoreRecordClass extends BaseModule {
|
class ScoreRecordClass extends BaseModule {
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public user: string
|
public user: string
|
||||||
|
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public activity: string
|
public activity: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
@ -23,8 +25,6 @@ class ScoreRecordClass extends BaseModule {
|
|||||||
|
|
||||||
@prop({ type: mongoose.Schema.Types.Mixed })
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
public data: any
|
public data: any
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScoreRecord = getModelForClass(ScoreRecordClass, { existingConnection: ScoreRecordClass['db'] })
|
export const ScoreRecord = getModelForClass(ScoreRecordClass, { existingConnection: ScoreRecordClass['db'] })
|
||||||
|
|
||||||
|
@ -2,17 +2,19 @@ import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from
|
|||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from './Base'
|
||||||
|
|
||||||
|
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ user: 1 }, { unique: false })
|
@index({ user: 1 }, { unique: false })
|
||||||
@index({ activity: 1 }, { unique: false })
|
@index({ activity: 1 }, { unique: false })
|
||||||
@index({user: 1, activity: 1, type: 1}, { unique: false })
|
@index({ user: 1, activity: 1, type: 1 }, { unique: false })
|
||||||
@modelOptions({ schemaOptions: { collection: 'token_claim_record', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'token_claim_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
class TokenClaimHistoryClass extends BaseModule {
|
class TokenClaimHistoryClass extends BaseModule {
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public user: string
|
public user: string
|
||||||
|
|
||||||
@prop({ required: true})
|
@prop({ required: true })
|
||||||
public activity: string
|
public activity: string
|
||||||
/**
|
/**
|
||||||
* 冗余字段, 方便查找
|
* 冗余字段, 方便查找
|
||||||
@ -31,7 +33,7 @@ class TokenClaimHistoryClass extends BaseModule {
|
|||||||
* 1: 已确认
|
* 1: 已确认
|
||||||
* -1: 已明确失败
|
* -1: 已明确失败
|
||||||
*/
|
*/
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public status: number
|
public status: number
|
||||||
// 转账交易hash
|
// 转账交易hash
|
||||||
@prop()
|
@prop()
|
||||||
@ -44,5 +46,6 @@ class TokenClaimHistoryClass extends BaseModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TokenClaimHistory = getModelForClass(TokenClaimHistoryClass, { existingConnection: TokenClaimHistoryClass['db'] })
|
export const TokenClaimHistory = getModelForClass(TokenClaimHistoryClass, {
|
||||||
|
existingConnection: TokenClaimHistoryClass['db'],
|
||||||
|
})
|
||||||
|
@ -5,8 +5,8 @@ import { formatDate, yesterday } from 'utils/date.util'
|
|||||||
|
|
||||||
@dbconn('chain')
|
@dbconn('chain')
|
||||||
@index({ from: 1 }, { unique: false })
|
@index({ from: 1 }, { unique: false })
|
||||||
@index({ from: 1, dateTag: 1}, { unique: true })
|
@index({ from: 1, dateTag: 1 }, { unique: true })
|
||||||
@index({ from: 1, blockTime: 1}, { unique: false })
|
@index({ from: 1, blockTime: 1 }, { unique: false })
|
||||||
@modelOptions({
|
@modelOptions({
|
||||||
schemaOptions: { collection: 'check_in_event', timestamps: true },
|
schemaOptions: { collection: 'check_in_event', timestamps: true },
|
||||||
})
|
})
|
||||||
@ -26,7 +26,7 @@ export class CheckInClass extends BaseModule {
|
|||||||
@prop()
|
@prop()
|
||||||
public dateTag: string
|
public dateTag: string
|
||||||
// 连签天数
|
// 连签天数
|
||||||
@prop({default: 0})
|
@prop({ default: 0 })
|
||||||
public count: number
|
public count: number
|
||||||
@prop()
|
@prop()
|
||||||
public value: string
|
public value: string
|
||||||
@ -34,7 +34,7 @@ export class CheckInClass extends BaseModule {
|
|||||||
public input: string
|
public input: string
|
||||||
|
|
||||||
public static async saveEvent(event: any) {
|
public static async saveEvent(event: any) {
|
||||||
const preDay = formatDate(yesterday());
|
const preDay = formatDate(yesterday())
|
||||||
const preDayEvent = await CheckIn.findOne({ from: event.from, dateTag: preDay })
|
const preDayEvent = await CheckIn.findOne({ from: event.from, dateTag: preDay })
|
||||||
if (preDayEvent) {
|
if (preDayEvent) {
|
||||||
event.count = preDayEvent.count + 1
|
event.count = preDayEvent.count + 1
|
||||||
@ -43,12 +43,12 @@ export class CheckInClass extends BaseModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public toJson() {
|
public toJson() {
|
||||||
return {
|
return {
|
||||||
address: this.from,
|
address: this.from,
|
||||||
day: this.dateTag,
|
day: this.dateTag,
|
||||||
time: this.blockTime,
|
time: this.blockTime,
|
||||||
count: this.count
|
count: this.count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,15 +20,14 @@ export class NftHolderClass extends BaseModule {
|
|||||||
public blockNumber: number
|
public blockNumber: number
|
||||||
@prop()
|
@prop()
|
||||||
public user: string
|
public user: string
|
||||||
@prop({default: false})
|
@prop({ default: false })
|
||||||
public burn: boolean
|
public burn: boolean
|
||||||
|
|
||||||
|
|
||||||
public static async saveData(event: any) {
|
public static async saveData(event: any) {
|
||||||
const address = event.address;
|
const address = event.address
|
||||||
const chain = event.chain;
|
const chain = event.chain
|
||||||
const tokenId = event.tokenId;
|
const tokenId = event.tokenId
|
||||||
const blockNumer = event.blockNumber;
|
const blockNumer = event.blockNumber
|
||||||
const burn = event.to === ZERO_ADDRESS
|
const burn = event.to === ZERO_ADDRESS
|
||||||
|
|
||||||
let record = await NftHolder.findOne({ address, chain, tokenId })
|
let record = await NftHolder.findOne({ address, chain, tokenId })
|
||||||
@ -44,8 +43,7 @@ export class NftHolderClass extends BaseModule {
|
|||||||
record.blockNumber = blockNumer
|
record.blockNumber = blockNumer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await record.save();
|
await record.save()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@ import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoos
|
|||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
import { BaseModule } from '../Base'
|
import { BaseModule } from '../Base'
|
||||||
|
|
||||||
|
|
||||||
@dbconn('chain')
|
@dbconn('chain')
|
||||||
@index({ chain: 1, nft: 1, tokenId: 1, start: 1 }, { unique: true })
|
@index({ chain: 1, nft: 1, tokenId: 1, start: 1 }, { unique: true })
|
||||||
@index({ chain:1, user: 1, nft: 1}, {unique: false})
|
@index({ chain: 1, user: 1, nft: 1 }, { unique: false })
|
||||||
@modelOptions({
|
@modelOptions({
|
||||||
schemaOptions: { collection: 'nft_stake_info', timestamps: true },
|
schemaOptions: { collection: 'nft_stake_info', timestamps: true },
|
||||||
})
|
})
|
||||||
@ -38,13 +37,13 @@ export class NftStakeClass extends BaseModule {
|
|||||||
public version: number
|
public version: number
|
||||||
|
|
||||||
public toJson() {
|
public toJson() {
|
||||||
return {
|
return {
|
||||||
nft: this.nft,
|
nft: this.nft,
|
||||||
nftid: this.tokenId,
|
nftid: this.tokenId,
|
||||||
start: this.start,
|
start: this.start,
|
||||||
cd: +process.env.STAKE_CD,
|
cd: +process.env.STAKE_CD,
|
||||||
stakeTime: this.stakeTime
|
stakeTime: this.stakeTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { LotteryCache } from 'common/LotteryCache';
|
import { LotteryCache } from 'common/LotteryCache'
|
||||||
import { singleton } from 'decorators/singleton'
|
import { singleton } from 'decorators/singleton'
|
||||||
import logger from 'logger/logger';
|
import logger from 'logger/logger'
|
||||||
import {NonceRecord} from 'models/NonceRecord'
|
|
||||||
import * as schedule from 'node-schedule'
|
import * as schedule from 'node-schedule'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,14 +8,12 @@ import * as schedule from 'node-schedule'
|
|||||||
*/
|
*/
|
||||||
@singleton
|
@singleton
|
||||||
export default class CacheSchedule {
|
export default class CacheSchedule {
|
||||||
|
|
||||||
async updateCache() {
|
async updateCache() {
|
||||||
try {
|
try {
|
||||||
new LotteryCache().flush();
|
new LotteryCache().flush()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn(err)
|
logger.warn(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
scheduleAll() {
|
scheduleAll() {
|
||||||
schedule.scheduleJob('*/10 * * * * *', async () => {
|
schedule.scheduleJob('*/10 * * * * *', async () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { singleton } from 'decorators/singleton'
|
import { singleton } from 'decorators/singleton'
|
||||||
import {NonceRecord} from 'models/NonceRecord'
|
import { NonceRecord } from 'models/NonceRecord'
|
||||||
import * as schedule from 'node-schedule'
|
import * as schedule from 'node-schedule'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,11 +8,11 @@ import * as schedule from 'node-schedule'
|
|||||||
@singleton
|
@singleton
|
||||||
export default class NonceRecordSchedule {
|
export default class NonceRecordSchedule {
|
||||||
async parseAllFinishedRecord() {
|
async parseAllFinishedRecord() {
|
||||||
await NonceRecord.deleteMany({status: 1});
|
await NonceRecord.deleteMany({ status: 1 })
|
||||||
}
|
}
|
||||||
async parseAllExpiredRecord() {
|
async parseAllExpiredRecord() {
|
||||||
let now = Date.now()
|
let now = Date.now()
|
||||||
await NonceRecord.deleteMany({expired: {$lt: now}})
|
await NonceRecord.deleteMany({ expired: { $lt: now } })
|
||||||
}
|
}
|
||||||
scheduleAll() {
|
scheduleAll() {
|
||||||
schedule.scheduleJob('*/1 * * * *', async () => {
|
schedule.scheduleJob('*/1 * * * *', async () => {
|
||||||
|
@ -1,53 +1,53 @@
|
|||||||
import { NftHolder } from "models/chain/NftHolder"
|
import { NftHolder } from 'models/chain/NftHolder'
|
||||||
import { NftStake } from "models/chain/NftStake"
|
import { NftStake } from 'models/chain/NftStake'
|
||||||
|
|
||||||
export const queryCheckInList = async (address: string, days: string | number | string[], limit: number = 0) => {
|
export const queryCheckInList = async (address: string, days: string | number | string[], limit: number = 0) => {
|
||||||
const url = process.env.CHAIN_SVR + '/task/check_in'
|
const url = process.env.CHAIN_SVR + '/task/check_in'
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
address,
|
address,
|
||||||
days,
|
days,
|
||||||
limit
|
limit,
|
||||||
})
|
}),
|
||||||
}).then((res) => res.json())
|
}).then(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryCheckInSeq = async (address: string) =>{
|
export const queryCheckInSeq = async (address: string) => {
|
||||||
const url = process.env.CHAIN_SVR + '/task/check_in/max_seq'
|
const url = process.env.CHAIN_SVR + '/task/check_in/max_seq'
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
address,
|
address,
|
||||||
})
|
}),
|
||||||
}).then((res) => res.json())
|
}).then(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryBurnNftList = async (address: string, user: string, chain: number) => {
|
export const queryBurnNftList = async (address: string, user: string, chain: number) => {
|
||||||
const url = process.env.CHAIN_SVR + '/task/nft/checkburn'
|
const url = process.env.CHAIN_SVR + '/task/nft/checkburn'
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
address,
|
address,
|
||||||
user,
|
user,
|
||||||
chain
|
chain,
|
||||||
})
|
}),
|
||||||
}).then((res) => res.json())
|
}).then(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkHadGacha = async (user: string) => {
|
export const checkHadGacha = async (user: string) => {
|
||||||
const chain = process.env.CHAIN+''
|
const chain = process.env.CHAIN + ''
|
||||||
const address = process.env.GACHA_CONTRACT
|
const address = process.env.GACHA_CONTRACT
|
||||||
const record = await NftHolder.findOne({user, chain, address})
|
const record = await NftHolder.findOne({ user, chain, address })
|
||||||
return !!record
|
return !!record
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryStakeList = async (userAddress: string) => {
|
export const queryStakeList = async (userAddress: string) => {
|
||||||
const chain = process.env.CHAIN+''
|
const chain = process.env.CHAIN + ''
|
||||||
const address = process.env.BADGE_CONTRACT
|
const address = process.env.BADGE_CONTRACT
|
||||||
let records = await NftStake.find({chain, nft: address, user: userAddress.toLowerCase()})
|
let records = await NftStake.find({ chain, nft: address, user: userAddress.toLowerCase() })
|
||||||
return records
|
return records
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { hmacSha256 } from "utils/security.util"
|
import { hmacSha256 } from 'utils/security.util'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
const SECRET_KEY = process.env.HASH_SALT
|
const SECRET_KEY = process.env.HASH_SALT
|
||||||
@ -10,14 +10,13 @@ function createSign(address: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function checkTwitter(address: string) {
|
export function checkTwitter(address: string) {
|
||||||
let sign = createSign(address);
|
let sign = createSign(address)
|
||||||
const url = `${process.env.OAUTH_SVR_URL}/activity/twitter/${address}?sign=${sign}`
|
const url = `${process.env.OAUTH_SVR_URL}/activity/twitter/${address}?sign=${sign}`
|
||||||
return axios.get(url);
|
return axios.get(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function checkDiscord(address: string) {
|
export function checkDiscord(address: string) {
|
||||||
let sign = createSign(address);
|
let sign = createSign(address)
|
||||||
const url = `${process.env.OAUTH_SVR_URL}/activity/discord/${address}?sign=${sign}`;
|
const url = `${process.env.OAUTH_SVR_URL}/activity/discord/${address}?sign=${sign}`
|
||||||
return axios.get(url);
|
return axios.get(url)
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ScoreRecord } from "models/ScoreRecord";
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
import { RedisClient } from "redis/RedisClient";
|
import { RedisClient } from 'redis/RedisClient'
|
||||||
import { formatDate } from "utils/date.util";
|
import { formatDate } from 'utils/date.util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新排行榜
|
* 更新排行榜
|
||||||
@ -16,12 +16,12 @@ export const updateRankScore = async ({
|
|||||||
score,
|
score,
|
||||||
activity,
|
activity,
|
||||||
scoreType,
|
scoreType,
|
||||||
scoreParams
|
scoreParams,
|
||||||
}: {
|
}: {
|
||||||
user: string,
|
user: string
|
||||||
score: number,
|
score: number
|
||||||
activity: string,
|
activity: string
|
||||||
scoreType: string,
|
scoreType: string
|
||||||
scoreParams: any
|
scoreParams: any
|
||||||
}) => {
|
}) => {
|
||||||
let record = new ScoreRecord({
|
let record = new ScoreRecord({
|
||||||
@ -29,14 +29,14 @@ export const updateRankScore = async ({
|
|||||||
activity: activity,
|
activity: activity,
|
||||||
score,
|
score,
|
||||||
type: scoreType,
|
type: scoreType,
|
||||||
data: scoreParams
|
data: scoreParams,
|
||||||
})
|
})
|
||||||
await record.save();
|
await record.save()
|
||||||
const key = rankKey(activity);
|
const key = rankKey(activity)
|
||||||
await updateRank(key, score, user);
|
await updateRank(key, score, user)
|
||||||
// add daily score
|
// add daily score
|
||||||
const dailyKey = rankKey(activity, new Date());
|
const dailyKey = rankKey(activity, new Date())
|
||||||
await updateRank(dailyKey, score, user);
|
await updateRank(dailyKey, score, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,20 +46,20 @@ export const updateRankScore = async ({
|
|||||||
* @param member
|
* @param member
|
||||||
*/
|
*/
|
||||||
const updateRank = async (key: string, score: number, member: string) => {
|
const updateRank = async (key: string, score: number, member: string) => {
|
||||||
let scoreSaved = await new RedisClient().zscore(key, member) + '';
|
let scoreSaved = (await new RedisClient().zscore(key, member)) + ''
|
||||||
if (scoreSaved) {
|
if (scoreSaved) {
|
||||||
scoreSaved = scoreSaved.substring(0, scoreSaved.indexOf('.'))
|
scoreSaved = scoreSaved.substring(0, scoreSaved.indexOf('.'))
|
||||||
}
|
}
|
||||||
let scoreOld = parseInt(scoreSaved || '0');
|
let scoreOld = parseInt(scoreSaved || '0')
|
||||||
score = score + scoreOld;
|
score = score + scoreOld
|
||||||
const scoreToSave = score + 1 - (Date.now() / 1000 / 10000000000)
|
const scoreToSave = score + 1 - Date.now() / 1000 / 10000000000
|
||||||
await new RedisClient().zadd(key, scoreToSave, member);
|
await new RedisClient().zadd(key, scoreToSave, member)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const rankKey = (activity: string, date?: Date) => {
|
export const rankKey = (activity: string, date?: Date) => {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return `${activity}:score`
|
return `${activity}:score`
|
||||||
}
|
}
|
||||||
const dateTag = formatDate(date);
|
const dateTag = formatDate(date)
|
||||||
return `${activity}:score:${dateTag}`
|
return `${activity}:score:${dateTag}`
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
import { queryBurnNftList } from "services/chain.svr";
|
import { queryBurnNftList } from 'services/chain.svr'
|
||||||
import { NftBurnRecord } from "models/NFTBrunRecord";
|
import { NftBurnRecord } from 'models/NFTBrunRecord'
|
||||||
|
|
||||||
export default class BurnNft extends ITask {
|
export default class BurnNft extends ITask {
|
||||||
static desc = 'Butn NFT'
|
static desc = 'Butn NFT'
|
||||||
@ -23,9 +23,9 @@ export default class BurnNft extends ITask {
|
|||||||
chain,
|
chain,
|
||||||
address,
|
address,
|
||||||
})
|
})
|
||||||
const localNftSet = new Set();
|
const localNftSet = new Set()
|
||||||
let finishAmount = 0;
|
let finishAmount = 0
|
||||||
let tmpNftSet = new Set();
|
let tmpNftSet = new Set()
|
||||||
for (let nft of localNft) {
|
for (let nft of localNft) {
|
||||||
localNftSet.add(nft.tokenId)
|
localNftSet.add(nft.tokenId)
|
||||||
if (nft.activity === this.activity.id && nft.task === task.id) {
|
if (nft.activity === this.activity.id && nft.task === task.id) {
|
||||||
@ -33,13 +33,13 @@ export default class BurnNft extends ITask {
|
|||||||
tmpNftSet.add(nft.tokenId)
|
tmpNftSet.add(nft.tokenId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let finishNfts = new Set();
|
let finishNfts = new Set()
|
||||||
for (let nft of nftList) {
|
for (let nft of nftList) {
|
||||||
if (!localNftSet.has(nft.tokenId)) {
|
if (!localNftSet.has(nft.tokenId)) {
|
||||||
finishNfts.add(nft.tokenId)
|
finishNfts.add(nft.tokenId)
|
||||||
finishAmount += 1
|
finishAmount += 1
|
||||||
if (finishAmount >= cfg.repeat) {
|
if (finishAmount >= cfg.repeat) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ export default class BurnNft extends ITask {
|
|||||||
address,
|
address,
|
||||||
tokenId: finishNft,
|
tokenId: finishNft,
|
||||||
activity: this.activity.id,
|
activity: this.activity.id,
|
||||||
task: task.id
|
task: task.id,
|
||||||
})
|
})
|
||||||
await record.save()
|
await record.save()
|
||||||
}
|
}
|
||||||
@ -67,13 +67,13 @@ export default class BurnNft extends ITask {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save failed')
|
throw new ZError(100, 'save failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskStatus, TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatus, TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { TaskCfg, TaskTypeEnum } from "models/ActivityInfo";
|
import { TaskCfg, TaskTypeEnum } from 'models/ActivityInfo'
|
||||||
import { queryCheckInList, queryCheckInSeq } from "services/chain.svr";
|
import { queryCheckInList, queryCheckInSeq } from 'services/chain.svr'
|
||||||
import { updateRankScore } from "services/rank.svr";
|
import { updateRankScore } from 'services/rank.svr'
|
||||||
import { LotteryCache } from "common/LotteryCache";
|
import { LotteryCache } from 'common/LotteryCache'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查每日签到
|
* 检查每日签到
|
||||||
@ -22,27 +22,30 @@ export default class DailyCheckIn extends ITask {
|
|||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
const days = cfg.params.days || 1
|
const days = cfg.params.days || 1
|
||||||
const limit = cfg.params.limit || 0
|
const limit = cfg.params.limit || 0
|
||||||
const res = cfg.type === TaskTypeEnum.DAILY ?
|
const res =
|
||||||
await queryCheckInList(address, days - 1, limit)
|
cfg.type === TaskTypeEnum.DAILY
|
||||||
: await queryCheckInSeq(address)
|
? await queryCheckInList(address, days - 1, limit)
|
||||||
|
: await queryCheckInSeq(address)
|
||||||
if (res.errcode) {
|
if (res.errcode) {
|
||||||
throw new ZError(res.errcode, res.errmsg)
|
throw new ZError(res.errcode, res.errmsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cfg.type === TaskTypeEnum.DAILY && task.status === TaskStatusEnum.RUNNING && res.data.length >= days)
|
if (
|
||||||
|| (cfg.type === TaskTypeEnum.ONCE && task.status === TaskStatusEnum.RUNNING && res.data.count >= days)) {
|
(cfg.type === TaskTypeEnum.DAILY && task.status === TaskStatusEnum.RUNNING && res.data.length >= days) ||
|
||||||
|
(cfg.type === TaskTypeEnum.ONCE && task.status === TaskStatusEnum.RUNNING && res.data.count >= days)
|
||||||
|
) {
|
||||||
task.status = TaskStatusEnum.SUCCESS
|
task.status = TaskStatusEnum.SUCCESS
|
||||||
task.timeFinish = Date.now()
|
task.timeFinish = Date.now()
|
||||||
task.data = res.data
|
task.data = res.data
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save daily checkin failed')
|
throw new ZError(100, 'save daily checkin failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,13 +59,13 @@ export default class DailyCheckIn extends ITask {
|
|||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
if (cfg.type === TaskTypeEnum.DAILY) {
|
if (cfg.type === TaskTypeEnum.DAILY) {
|
||||||
const res = await queryCheckInList(this.user.address, 1, 0)
|
const res = await queryCheckInList(this.user.address, 1, 0)
|
||||||
const [taskId, dateTag] = task.id.split(':');
|
const [taskId, dateTag] = task.id.split(':')
|
||||||
let list: { day: string, time: number, count: number }[] = res.data;
|
let list: { day: string; time: number; count: number }[] = res.data
|
||||||
|
|
||||||
const countCfg = cfg.params.score.length;
|
const countCfg = cfg.params.score.length
|
||||||
let count = list.length > 0 ? list[0].count : 0;
|
let count = list.length > 0 ? list[0].count : 0
|
||||||
let seq = count % countCfg;
|
let seq = count % countCfg
|
||||||
let score = cfg.params.score[seq] || 0 + cfg.score;
|
let score = cfg.params.score[seq] || 0 + cfg.score
|
||||||
const user = this.user
|
const user = this.user
|
||||||
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
||||||
score = Math.floor(score * user.boost)
|
score = Math.floor(score * user.boost)
|
||||||
@ -77,18 +80,17 @@ export default class DailyCheckIn extends ITask {
|
|||||||
date: dateTag,
|
date: dateTag,
|
||||||
bouns: score,
|
bouns: score,
|
||||||
boost: user.boost,
|
boost: user.boost,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
await this.claimItem(cfg)
|
await this.claimItem(cfg)
|
||||||
} else {
|
} else {
|
||||||
await super.claimReward(task);
|
await super.claimReward(task)
|
||||||
}
|
}
|
||||||
// 更新gacha拥有者抽奖次数, 这里写死, 等想到好的方式再处理
|
// 更新gacha拥有者抽奖次数, 这里写死, 等想到好的方式再处理
|
||||||
let record = await new LotteryCache().getData(this.user.id, this.user.activity);
|
let record = await new LotteryCache().getData(this.user.id, this.user.activity)
|
||||||
if (record.daily === 0) {
|
if (record.daily === 0) {
|
||||||
record.daily += 1
|
record.daily += 1
|
||||||
record.amount += 1
|
record.amount += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import { checkDiscord } from "services/oauth.svr";
|
import { checkDiscord } from 'services/oauth.svr'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class DiscordConnect extends ITask {
|
export default class DiscordConnect extends ITask {
|
||||||
static desc = 'join discord'
|
static desc = 'join discord'
|
||||||
@ -28,18 +28,17 @@ export default class DiscordConnect extends ITask {
|
|||||||
this.user.discordName = res.data.data.username
|
this.user.discordName = res.data.data.username
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'discord already binded')
|
throw new ZError(100, 'discord already binded')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class DiscordJoin extends ITask {
|
export default class DiscordJoin extends ITask {
|
||||||
static desc = 'join discord'
|
static desc = 'join discord'
|
||||||
@ -10,7 +10,7 @@ export default class DiscordJoin extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'check discord join failed')
|
throw new ZError(11, 'check discord join failed')
|
||||||
}
|
}
|
||||||
@ -23,17 +23,16 @@ export default class DiscordJoin extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'already join discord')
|
throw new ZError(100, 'already join discord')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class DiscordRole extends ITask {
|
export default class DiscordRole extends ITask {
|
||||||
static desc = 'acquire discord role'
|
static desc = 'acquire discord role'
|
||||||
@ -9,7 +9,7 @@ export default class DiscordRole extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'check discord role failed')
|
throw new ZError(11, 'check discord role failed')
|
||||||
}
|
}
|
||||||
@ -22,17 +22,16 @@ export default class DiscordRole extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'already acquired discord role')
|
throw new ZError(100, 'already acquired discord role')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
import { UserLog } from "models/UserLog";
|
import { LoginRecord } from 'models/LoginRecord'
|
||||||
import { LoginRecord } from "models/LoginRecord";
|
|
||||||
|
|
||||||
export default class OkxLogin extends ITask {
|
export default class OkxLogin extends ITask {
|
||||||
static desc = 'okx wallet login'
|
static desc = 'okx wallet login'
|
||||||
@ -13,22 +12,22 @@ export default class OkxLogin extends ITask {
|
|||||||
const { task } = data
|
const { task } = data
|
||||||
const { activity } = this.user
|
const { activity } = this.user
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let wallet = 'okx';
|
let wallet = 'okx'
|
||||||
let record = LoginRecord.findOne({ user: this.user.id, activity, wallet})
|
let record = LoginRecord.findOne({ user: this.user.id, activity, wallet })
|
||||||
if (!record ) {
|
if (!record) {
|
||||||
throw new ZError(11, 'task not finished')
|
throw new ZError(11, 'task not finished')
|
||||||
}
|
}
|
||||||
task.status = TaskStatusEnum.SUCCESS
|
task.status = TaskStatusEnum.SUCCESS
|
||||||
task.timeFinish = Date.now()
|
task.timeFinish = Date.now()
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'discord already binded')
|
throw new ZError(100, 'discord already binded')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
import { ActivityUser, TaskStatus, TaskStatusEnum } from "models/ActivityUser";
|
import { ActivityUser, TaskStatus, TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
import { updateRankScore } from "services/rank.svr";
|
import { updateRankScore } from 'services/rank.svr'
|
||||||
import { ActivityItem } from "models/ActivityItem";
|
import { ActivityItem } from 'models/ActivityItem'
|
||||||
import { LotteryCache } from "common/LotteryCache";
|
import { LotteryCache } from 'common/LotteryCache'
|
||||||
import { checkHadGacha } from "services/chain.svr";
|
import { checkHadGacha } from 'services/chain.svr'
|
||||||
|
|
||||||
const updateInviteScore = async (user: typeof ActivityUser, scores: number[], items: any[], level: number, reason: string) => {
|
const updateInviteScore = async (
|
||||||
|
user: typeof ActivityUser,
|
||||||
|
scores: number[],
|
||||||
|
items: any[],
|
||||||
|
level: number,
|
||||||
|
reason: string,
|
||||||
|
) => {
|
||||||
if (!user.inviteUser || scores.length <= level) {
|
if (!user.inviteUser || scores.length <= level) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let userSup = await ActivityUser.findById(user.inviteUser)
|
let userSup = await ActivityUser.findById(user.inviteUser)
|
||||||
if (!userSup || !userSup.address) {
|
if (!userSup || !userSup.address) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
await updateRankScore({
|
await updateRankScore({
|
||||||
user: userSup.id,
|
user: userSup.id,
|
||||||
@ -21,22 +27,21 @@ const updateInviteScore = async (user: typeof ActivityUser, scores: number[], it
|
|||||||
scoreType: reason,
|
scoreType: reason,
|
||||||
scoreParams: {
|
scoreParams: {
|
||||||
user: user.id,
|
user: user.id,
|
||||||
level
|
level,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
// 更新gacha拥有者抽奖次数, 这里写死, 等想到好的方式再处理
|
// 更新gacha拥有者抽奖次数, 这里写死, 等想到好的方式再处理
|
||||||
let record = await new LotteryCache().getData(userSup.id, userSup.activity);
|
let record = await new LotteryCache().getData(userSup.id, userSup.activity)
|
||||||
record.share += 1
|
record.share += 1
|
||||||
record.amount += 1
|
record.amount += 1
|
||||||
if (record.gacha ===0 && checkHadGacha(userSup.address)) {
|
if (record.gacha === 0 && checkHadGacha(userSup.address)) {
|
||||||
record.gacha += 1
|
record.gacha += 1
|
||||||
record.amount += 1
|
record.amount += 1
|
||||||
}
|
}
|
||||||
if (items.length > level) {
|
if (items.length > level) {
|
||||||
for (let key in items[level]) {
|
for (let key in items[level]) {
|
||||||
let amount = items[level][key]
|
let amount = items[level][key]
|
||||||
await ActivityItem.insertOrUpdate(
|
await ActivityItem.insertOrUpdate({ user: userSup, activity: userSup.activity, item: key }, { $inc: { amount } })
|
||||||
{user: userSup, activity: userSup.activity, item: key}, {$inc: {amount}})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await updateInviteScore(userSup, scores, items, level + 1, reason)
|
await updateInviteScore(userSup, scores, items, level + 1, reason)
|
||||||
@ -52,18 +57,18 @@ export default class ShareCode extends ITask {
|
|||||||
if (!this.user.inviteUser) {
|
if (!this.user.inviteUser) {
|
||||||
throw new Error('not finished')
|
throw new Error('not finished')
|
||||||
}
|
}
|
||||||
let scores = cfg.params.score;
|
let scores = cfg.params.score
|
||||||
const items = cfg.params.inviteItems || [];
|
const items = cfg.params.inviteItems || []
|
||||||
task.status = TaskStatusEnum.SUCCESS
|
task.status = TaskStatusEnum.SUCCESS
|
||||||
task.timeFinish = Date.now()
|
task.timeFinish = Date.now()
|
||||||
task.data = {}
|
task.data = {}
|
||||||
await this.user.save();
|
await this.user.save()
|
||||||
// According to configuration, add score to user who invite current user
|
// According to configuration, add score to user who invite current user
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await super.claimReward(task);
|
await super.claimReward(task)
|
||||||
await updateInviteScore(this.user, scores, items, 0, task.task)
|
await updateInviteScore(this.user, scores, items, 0, task.task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,10 +76,10 @@ export default class ShareCode extends ITask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async claimReward(task: TaskStatus) {
|
public async claimReward(task: TaskStatus) {
|
||||||
await super.claimReward(task);
|
await super.claimReward(task)
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let scores = cfg.params.score;
|
let scores = cfg.params.score
|
||||||
const items = cfg.params.inviteItems || [];
|
const items = cfg.params.inviteItems || []
|
||||||
await updateInviteScore(this.user, scores, items, 0, "invite")
|
await updateInviteScore(this.user, scores, items, 0, 'invite')
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import { checkTwitter } from "services/oauth.svr";
|
import { checkTwitter } from 'services/oauth.svr'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { ActivityUser, TaskStatusEnum } from "models/ActivityUser";
|
import { ActivityUser, TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class TwitterConnect extends ITask {
|
export default class TwitterConnect extends ITask {
|
||||||
static desc = 'twitter connect'
|
static desc = 'twitter connect'
|
||||||
@ -26,20 +26,18 @@ export default class TwitterConnect extends ITask {
|
|||||||
this.user.twitterName = res.data.data.username
|
this.user.twitterName = res.data.data.username
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'twitter already binded')
|
throw new ZError(100, 'twitter already binded')
|
||||||
}
|
}
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class TwitterFollow extends ITask {
|
export default class TwitterFollow extends ITask {
|
||||||
static desc = 'twitter follow'
|
static desc = 'twitter follow'
|
||||||
@ -9,7 +9,7 @@ export default class TwitterFollow extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'follow failed')
|
throw new ZError(11, 'follow failed')
|
||||||
}
|
}
|
||||||
@ -22,17 +22,16 @@ export default class TwitterFollow extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save failed')
|
throw new ZError(100, 'save failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
|
|
||||||
export default class TwitterRetweet extends ITask {
|
export default class TwitterRetweet extends ITask {
|
||||||
static desc = 'twitter retweet'
|
static desc = 'twitter retweet'
|
||||||
@ -8,7 +8,7 @@ export default class TwitterRetweet extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find(t => t.id === task.id)
|
let cfg = this.activity.tasks.find(t => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'retweet failed')
|
throw new ZError(11, 'retweet failed')
|
||||||
}
|
}
|
||||||
@ -21,17 +21,16 @@ export default class TwitterRetweet extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save failed')
|
throw new ZError(100, 'save failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { TaskCfg } from "models/ActivityInfo";
|
import { TaskCfg } from 'models/ActivityInfo'
|
||||||
|
|
||||||
export default class YoutubeFollow extends ITask {
|
export default class YoutubeFollow extends ITask {
|
||||||
static desc = 'youtube follow'
|
static desc = 'youtube follow'
|
||||||
@ -9,7 +9,7 @@ export default class YoutubeFollow extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'follow failed')
|
throw new ZError(11, 'follow failed')
|
||||||
}
|
}
|
||||||
@ -22,17 +22,16 @@ export default class YoutubeFollow extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save failed')
|
throw new ZError(100, 'save failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ZError } from "common/ZError";
|
import { ZError } from 'common/ZError'
|
||||||
import { ITask } from "./base/ITask";
|
import { ITask } from './base/ITask'
|
||||||
import { TaskStatusEnum } from "models/ActivityUser";
|
import { TaskStatusEnum } from 'models/ActivityUser'
|
||||||
|
|
||||||
export default class YoutubePost extends ITask {
|
export default class YoutubePost extends ITask {
|
||||||
static desc = 'youtube post'
|
static desc = 'youtube post'
|
||||||
@ -8,7 +8,7 @@ export default class YoutubePost extends ITask {
|
|||||||
async execute(data: any) {
|
async execute(data: any) {
|
||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find(t => t.id === task.id)
|
let cfg = this.activity.tasks.find(t => t.id === task.id)
|
||||||
let time = cfg.params.time;
|
let time = cfg.params.time
|
||||||
if (Date.now() - task.timeStart < time * 1000) {
|
if (Date.now() - task.timeStart < time * 1000) {
|
||||||
throw new ZError(11, 'post failed')
|
throw new ZError(11, 'post failed')
|
||||||
}
|
}
|
||||||
@ -21,17 +21,16 @@ export default class YoutubePost extends ITask {
|
|||||||
task.data = {}
|
task.data = {}
|
||||||
try {
|
try {
|
||||||
await this.user.save()
|
await this.user.save()
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
throw new ZError(100, 'save failed')
|
throw new ZError(100, 'save failed')
|
||||||
}
|
}
|
||||||
if (cfg.autoclaim) {
|
if (cfg.autoclaim) {
|
||||||
try {
|
try {
|
||||||
await this.claimReward(task);
|
await this.claimReward(task)
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ActivityInfo, TaskCfg } from "models/ActivityInfo"
|
import { ActivityInfo, TaskCfg } from 'models/ActivityInfo'
|
||||||
import { ActivityItem } from "models/ActivityItem"
|
import { ActivityItem } from 'models/ActivityItem'
|
||||||
import { ActivityUser, TaskStatus, TaskStatusEnum } from "models/ActivityUser"
|
import { ActivityUser, TaskStatus, TaskStatusEnum } from 'models/ActivityUser'
|
||||||
import { updateRankScore } from "services/rank.svr"
|
import { updateRankScore } from 'services/rank.svr'
|
||||||
|
|
||||||
export abstract class ITask {
|
export abstract class ITask {
|
||||||
static desc: string
|
static desc: string
|
||||||
@ -11,8 +11,7 @@ export abstract class ITask {
|
|||||||
user: typeof ActivityUser
|
user: typeof ActivityUser
|
||||||
activity: typeof ActivityInfo
|
activity: typeof ActivityInfo
|
||||||
|
|
||||||
|
constructor({ user, activity }: { user: typeof ActivityUser; activity: typeof ActivityInfo }) {
|
||||||
constructor({user, activity}: {user: typeof ActivityUser, activity: typeof ActivityInfo}) {
|
|
||||||
// do nothing
|
// do nothing
|
||||||
this.user = user
|
this.user = user
|
||||||
this.activity = activity
|
this.activity = activity
|
||||||
@ -21,10 +20,10 @@ export abstract class ITask {
|
|||||||
|
|
||||||
public async claimReward(task: any) {
|
public async claimReward(task: any) {
|
||||||
const user = this.user
|
const user = this.user
|
||||||
const [taskId, dateTag] = task.id.split(':');
|
const [taskId, dateTag] = task.id.split(':')
|
||||||
const cfg = this.activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
const cfg = this.activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
||||||
if (!cfg.score) {
|
if (!cfg.score) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let claimAmount = task.data.claimAmount || 0
|
let claimAmount = task.data.claimAmount || 0
|
||||||
let score = cfg.score
|
let score = cfg.score
|
||||||
@ -41,15 +40,14 @@ export abstract class ITask {
|
|||||||
scoreParams: {
|
scoreParams: {
|
||||||
date: dateTag,
|
date: dateTag,
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
boost: user.boost
|
boost: user.boost,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
claimAmount += 1
|
claimAmount += 1
|
||||||
}
|
}
|
||||||
task.data.claimAmount = claimAmount
|
task.data.claimAmount = claimAmount
|
||||||
task.markModified('data')
|
task.markModified('data')
|
||||||
if ((cfg.repeat > 1 && claimAmount >= cfg.repeat)
|
if ((cfg.repeat > 1 && claimAmount >= cfg.repeat) || (cfg.repeat === 1 && claimAmount >= 1)) {
|
||||||
|| (cfg.repeat === 1 && claimAmount >= 1)) {
|
|
||||||
task.status = TaskStatusEnum.CLAIMED
|
task.status = TaskStatusEnum.CLAIMED
|
||||||
task.timeClaim = Date.now()
|
task.timeClaim = Date.now()
|
||||||
}
|
}
|
||||||
@ -62,7 +60,9 @@ export abstract class ITask {
|
|||||||
for (let key in cfg.params.items) {
|
for (let key in cfg.params.items) {
|
||||||
let amount = cfg.params.items[key]
|
let amount = cfg.params.items[key]
|
||||||
await ActivityItem.insertOrUpdate(
|
await ActivityItem.insertOrUpdate(
|
||||||
{user: this.user.id, activity: this.user.activity, item: key}, {$inc: {amount}, last: Date.now()})
|
{ user: this.user.id, activity: this.user.activity, item: key },
|
||||||
|
{ $inc: { amount }, last: Date.now() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util'
|
import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util'
|
||||||
import { soliditySha3, toWei } from 'web3-utils'
|
import { soliditySha3, toWei } from 'web3-utils'
|
||||||
import Web3 from 'web3';
|
import Web3 from 'web3'
|
||||||
|
|
||||||
export function recoverTypedSignatureV4(signObj: any, signature: string) {
|
export function recoverTypedSignatureV4(signObj: any, signature: string) {
|
||||||
return recoverTypedSignature({
|
return recoverTypedSignature({
|
||||||
@ -46,22 +46,29 @@ export function buildLoginSignMsg(nonce: string, tips: string) {
|
|||||||
return signObj
|
return signObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sign = async ({
|
||||||
export const sign = async ({ user, token, amount, saltNonce }
|
user,
|
||||||
: {user: string, token: string, amount: number | string, saltNonce?: string}) => {
|
token,
|
||||||
const web3 = new Web3();
|
amount,
|
||||||
let privateKey = process.env.SIGN_PRIVATE_KEY;
|
saltNonce,
|
||||||
const acc = web3.eth.accounts.privateKeyToAccount(privateKey);
|
}: {
|
||||||
const account = web3.eth.accounts.wallet.add(acc);
|
user: string
|
||||||
|
token: string
|
||||||
|
amount: number | string
|
||||||
|
saltNonce?: string
|
||||||
|
}) => {
|
||||||
|
const web3 = new Web3()
|
||||||
|
let privateKey = process.env.SIGN_PRIVATE_KEY
|
||||||
|
const acc = web3.eth.accounts.privateKeyToAccount(privateKey)
|
||||||
|
const account = web3.eth.accounts.wallet.add(acc)
|
||||||
const executor = account.address
|
const executor = account.address
|
||||||
const amountBn = toWei(amount+'');
|
const amountBn = toWei(amount + '')
|
||||||
const chainId = process.env.CHAIN;
|
const chainId = process.env.CHAIN
|
||||||
const claimContract = process.env.CLAIM_CONTRACT;
|
const claimContract = process.env.CLAIM_CONTRACT
|
||||||
const startTime = Date.now() / 1000 | 0
|
const startTime = (Date.now() / 1000) | 0
|
||||||
saltNonce = saltNonce || ((Math.random() * 1000) | 0) + '';
|
saltNonce = saltNonce || ((Math.random() * 1000) | 0) + ''
|
||||||
let signStr = soliditySha3.apply(this,
|
let signStr = soliditySha3.apply(this, [user, token, claimContract, chainId, amountBn, startTime, saltNonce])
|
||||||
[user, token, claimContract, chainId, amountBn, startTime, saltNonce]);
|
let signature = await web3.eth.sign(signStr, executor)
|
||||||
let signature = await web3.eth.sign(signStr, executor);
|
signature = signature.replace(/00$/, '1b').replace(/01$/, '1c')
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
return { token, amount: amountBn, startTime, saltNonce, signature }
|
||||||
return {token, amount: amountBn, startTime, saltNonce, signature}
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
// format the date to the format we want
|
// format the date to the format we want
|
||||||
export const formatDate = (date: Date): string => {
|
export const formatDate = (date: Date): string => {
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear()
|
||||||
const month = (date.getMonth() + 1 + '').padStart(2, '0');
|
const month = (date.getMonth() + 1 + '').padStart(2, '0')
|
||||||
const day = (date.getDate() + '').padStart(2, '0');
|
const day = (date.getDate() + '').padStart(2, '0')
|
||||||
return `${year}${month}${day}`;
|
return `${year}${month}${day}`
|
||||||
};
|
}
|
||||||
|
|
||||||
// get formated datestring of yesterday
|
// get formated datestring of yesterday
|
||||||
export const yesterday = (date?: Date) => {
|
export const yesterday = (date?: Date) => {
|
||||||
date = date || new Date();
|
date = date || new Date()
|
||||||
date.setDate(date.getDate() - 1);
|
date.setDate(date.getDate() - 1)
|
||||||
return date;
|
return date
|
||||||
};
|
}
|
||||||
|
|
||||||
export const nextday = (date?: Date) => {
|
export const nextday = (date?: Date) => {
|
||||||
date = date || new Date();
|
date = date || new Date()
|
||||||
date.setDate(date.getDate() + 1);
|
date.setDate(date.getDate() + 1)
|
||||||
return date;
|
return date
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { ZError } from "common/ZError"
|
import { ZError } from 'common/ZError'
|
||||||
|
|
||||||
const TIMEOUT_ERROR = new Error('timeout')
|
const TIMEOUT_ERROR = new Error('timeout')
|
||||||
|
|
||||||
@ -140,7 +140,9 @@ export function generateHeader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const checkParamsNeeded = (...args) => {
|
export const checkParamsNeeded = (...args) => {
|
||||||
args.forEach((arg) => {if (!arg) {
|
args.forEach(arg => {
|
||||||
throw new ZError(10, 'params mismatch');
|
if (!arg) {
|
||||||
}});
|
throw new ZError(10, 'params mismatch')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
export const ONE_DAY = 24 * 60 * 60 * 1000
|
export const ONE_DAY = 24 * 60 * 60 * 1000
|
||||||
export const NFT_BEGIN_DAY = new Date(2023, 4, 8)
|
export const NFT_BEGIN_DAY = new Date(2023, 4, 8)
|
||||||
|
|
||||||
@ -21,5 +19,3 @@ export function daysBetween(date1: Date, date2: Date) {
|
|||||||
const diffInDays = Math.round(diffInMs / ONE_DAY)
|
const diffInDays = Math.round(diffInMs / ONE_DAY)
|
||||||
return diffInDays
|
return diffInDays
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Web3 from 'web3';
|
import Web3 from 'web3'
|
||||||
import { BN } from 'ethereumjs-util';
|
import { BN } from 'ethereumjs-util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts some token minimal unit to render format string, showing 5 decimals
|
* Converts some token minimal unit to render format string, showing 5 decimals
|
||||||
@ -10,23 +10,17 @@ import { BN } from 'ethereumjs-util';
|
|||||||
* @returns {String} - Number of token minimal unit, in render format
|
* @returns {String} - Number of token minimal unit, in render format
|
||||||
* If value is less than 5 precision decimals will show '< 0.00001'
|
* If value is less than 5 precision decimals will show '< 0.00001'
|
||||||
*/
|
*/
|
||||||
export function renderFromTokenMinimalUnit(
|
export function renderFromTokenMinimalUnit(tokenValue, decimals, decimalsToShow = 5) {
|
||||||
tokenValue,
|
const minimalUnit = fromTokenMinimalUnit(tokenValue || 0, decimals)
|
||||||
decimals,
|
const minimalUnitNumber = parseFloat(minimalUnit)
|
||||||
decimalsToShow = 5
|
let renderMinimalUnit
|
||||||
) {
|
|
||||||
const minimalUnit = fromTokenMinimalUnit(tokenValue || 0, decimals);
|
|
||||||
const minimalUnitNumber = parseFloat(minimalUnit);
|
|
||||||
let renderMinimalUnit;
|
|
||||||
if (minimalUnitNumber < 0.00001 && minimalUnitNumber > 0) {
|
if (minimalUnitNumber < 0.00001 && minimalUnitNumber > 0) {
|
||||||
renderMinimalUnit = "< 0.00001";
|
renderMinimalUnit = '< 0.00001'
|
||||||
} else {
|
} else {
|
||||||
const base = Math.pow(10, decimalsToShow);
|
const base = Math.pow(10, decimalsToShow)
|
||||||
renderMinimalUnit = (
|
renderMinimalUnit = (Math.round(minimalUnitNumber * base) / base).toString()
|
||||||
Math.round(minimalUnitNumber * base) / base
|
|
||||||
).toString();
|
|
||||||
}
|
}
|
||||||
return renderMinimalUnit;
|
return renderMinimalUnit
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Converts token minimal unit to readable string value
|
* Converts token minimal unit to readable string value
|
||||||
@ -36,25 +30,25 @@ export function renderFromTokenMinimalUnit(
|
|||||||
* @returns {string} - String containing the new number
|
* @returns {string} - String containing the new number
|
||||||
*/
|
*/
|
||||||
export function fromTokenMinimalUnit(minimalInput, decimals) {
|
export function fromTokenMinimalUnit(minimalInput, decimals) {
|
||||||
minimalInput = addHexPrefix(Number(minimalInput).toString(16));
|
minimalInput = addHexPrefix(Number(minimalInput).toString(16))
|
||||||
let minimal = safeNumberToBN(minimalInput);
|
let minimal = safeNumberToBN(minimalInput)
|
||||||
const negative = minimal.lt(new BN(0));
|
const negative = minimal.lt(new BN(0))
|
||||||
const base = Web3.utils.toBN(Math.pow(10, decimals).toString());
|
const base = Web3.utils.toBN(Math.pow(10, decimals).toString())
|
||||||
|
|
||||||
if (negative) {
|
if (negative) {
|
||||||
minimal = minimal.mul(new BN(-1));
|
minimal = minimal.mul(new BN(-1))
|
||||||
}
|
}
|
||||||
let fraction = minimal.mod(base).toString(10);
|
let fraction = minimal.mod(base).toString(10)
|
||||||
while (fraction.length < decimals) {
|
while (fraction.length < decimals) {
|
||||||
fraction = "0" + fraction;
|
fraction = '0' + fraction
|
||||||
}
|
}
|
||||||
fraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/)[1];
|
fraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/)[1]
|
||||||
const whole = minimal.div(base).toString(10);
|
const whole = minimal.div(base).toString(10)
|
||||||
let value = "" + whole + (fraction === "0" ? "" : "." + fraction);
|
let value = '' + whole + (fraction === '0' ? '' : '.' + fraction)
|
||||||
if (negative) {
|
if (negative) {
|
||||||
value = "-" + value;
|
value = '-' + value
|
||||||
}
|
}
|
||||||
return value;
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,20 +59,20 @@ export function fromTokenMinimalUnit(minimalInput, decimals) {
|
|||||||
* @returns {String} - Number of token minimal unit, in render format
|
* @returns {String} - Number of token minimal unit, in render format
|
||||||
* If value is less than 5 precision decimals will show '< 0.00001'
|
* If value is less than 5 precision decimals will show '< 0.00001'
|
||||||
*/
|
*/
|
||||||
export function renderFromWei(value, decimalsToShow = 5) {
|
export function renderFromWei(value, decimalsToShow = 5) {
|
||||||
let renderWei = '0';
|
let renderWei = '0'
|
||||||
// avoid undefined
|
// avoid undefined
|
||||||
if (value) {
|
if (value) {
|
||||||
const wei = Web3.utils.fromWei(value);
|
const wei = Web3.utils.fromWei(value)
|
||||||
const weiNumber = parseFloat(wei);
|
const weiNumber = parseFloat(wei)
|
||||||
if (weiNumber < 0.00001 && weiNumber > 0) {
|
if (weiNumber < 0.00001 && weiNumber > 0) {
|
||||||
renderWei = '< 0.00001';
|
renderWei = '< 0.00001'
|
||||||
} else {
|
} else {
|
||||||
const base = Math.pow(10, decimalsToShow);
|
const base = Math.pow(10, decimalsToShow)
|
||||||
renderWei = (Math.round(weiNumber * base) / base).toString();
|
renderWei = (Math.round(weiNumber * base) / base).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return renderWei;
|
return renderWei
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +83,7 @@ export function fromTokenMinimalUnit(minimalInput, decimals) {
|
|||||||
* @returns {string} - String of the hex token value
|
* @returns {string} - String of the hex token value
|
||||||
*/
|
*/
|
||||||
export function calcTokenValueToSend(value, decimals) {
|
export function calcTokenValueToSend(value, decimals) {
|
||||||
return value ? (value * Math.pow(10, decimals)).toString(16) : 0;
|
return value ? (value * Math.pow(10, decimals)).toString(16) : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,11 +93,7 @@ export function calcTokenValueToSend(value, decimals) {
|
|||||||
* @returns {boolean} - True if the string is a valid decimal
|
* @returns {boolean} - True if the string is a valid decimal
|
||||||
*/
|
*/
|
||||||
export function isDecimal(value) {
|
export function isDecimal(value) {
|
||||||
return (
|
return Number.isFinite(parseFloat(value)) && !Number.isNaN(parseFloat(value)) && !isNaN(+value)
|
||||||
Number.isFinite(parseFloat(value)) &&
|
|
||||||
!Number.isNaN(parseFloat(value)) &&
|
|
||||||
!isNaN(+value)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +103,7 @@ export function isDecimal(value) {
|
|||||||
* @returns {Object} - BN instance
|
* @returns {Object} - BN instance
|
||||||
*/
|
*/
|
||||||
export function toBN(value) {
|
export function toBN(value) {
|
||||||
return Web3.utils.toBN(value);
|
return Web3.utils.toBN(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,20 +113,20 @@ export function toBN(value) {
|
|||||||
* @returns {string} The prefixed string.
|
* @returns {string} The prefixed string.
|
||||||
*/
|
*/
|
||||||
export const addHexPrefix = (str: string) => {
|
export const addHexPrefix = (str: string) => {
|
||||||
if (typeof str !== "string" || str.match(/^-?0x/u)) {
|
if (typeof str !== 'string' || str.match(/^-?0x/u)) {
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str.match(/^-?0X/u)) {
|
if (str.match(/^-?0X/u)) {
|
||||||
return str.replace("0X", "0x");
|
return str.replace('0X', '0x')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str.startsWith("-")) {
|
if (str.startsWith('-')) {
|
||||||
return str.replace("-", "-0x");
|
return str.replace('-', '-0x')
|
||||||
}
|
}
|
||||||
|
|
||||||
return `0x${str}`;
|
return `0x${str}`
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps 'numberToBN' method to avoid potential undefined and decimal values
|
* Wraps 'numberToBN' method to avoid potential undefined and decimal values
|
||||||
@ -145,8 +135,8 @@ export const addHexPrefix = (str: string) => {
|
|||||||
* @returns {Object} - The converted value as BN instance
|
* @returns {Object} - The converted value as BN instance
|
||||||
*/
|
*/
|
||||||
export function safeNumberToBN(value: number | string) {
|
export function safeNumberToBN(value: number | string) {
|
||||||
const safeValue = fastSplit(value.toString()) || "0";
|
const safeValue = fastSplit(value.toString()) || '0'
|
||||||
return numberToBN(safeValue);
|
return numberToBN(safeValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,66 +147,58 @@ export function safeNumberToBN(value: number | string) {
|
|||||||
* @returns {string} - the selected splitted element
|
* @returns {string} - the selected splitted element
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function fastSplit(value, divider = ".") {
|
export function fastSplit(value, divider = '.') {
|
||||||
value += "";
|
value += ''
|
||||||
const [from, to] = [value.indexOf(divider), 0];
|
const [from, to] = [value.indexOf(divider), 0]
|
||||||
return value.substring(from, to) || value;
|
return value.substring(from, to) || value
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stripHexPrefix(str: string) {
|
export function stripHexPrefix(str: string) {
|
||||||
if (typeof str !== "string") {
|
if (typeof str !== 'string') {
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
return str.slice(0, 2) === "0x" ? str.slice(2) : str;
|
return str.slice(0, 2) === '0x' ? str.slice(2) : str
|
||||||
}
|
}
|
||||||
|
|
||||||
export function numberToBN(arg) {
|
export function numberToBN(arg) {
|
||||||
if (typeof arg === "string" || typeof arg === "number") {
|
if (typeof arg === 'string' || typeof arg === 'number') {
|
||||||
var multiplier = Web3.utils.toBN(1); // eslint-disable-line
|
var multiplier = Web3.utils.toBN(1); // eslint-disable-line
|
||||||
var formattedString = String(arg).toLowerCase().trim();
|
var formattedString = String(arg).toLowerCase().trim()
|
||||||
var isHexPrefixed =
|
var isHexPrefixed = formattedString.substr(0, 2) === '0x' || formattedString.substr(0, 3) === '-0x'
|
||||||
formattedString.substr(0, 2) === "0x" ||
|
|
||||||
formattedString.substr(0, 3) === "-0x";
|
|
||||||
var stringArg = stripHexPrefix(formattedString); // eslint-disable-line
|
var stringArg = stripHexPrefix(formattedString); // eslint-disable-line
|
||||||
if (stringArg.substr(0, 1) === "-") {
|
if (stringArg.substr(0, 1) === '-') {
|
||||||
stringArg = stripHexPrefix(stringArg.slice(1));
|
stringArg = stripHexPrefix(stringArg.slice(1))
|
||||||
multiplier = Web3.utils.toBN(-1);
|
multiplier = Web3.utils.toBN(-1)
|
||||||
}
|
}
|
||||||
stringArg = stringArg === "" ? "0" : stringArg;
|
stringArg = stringArg === '' ? '0' : stringArg
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!stringArg.match(/^-?[0-9]+$/) && stringArg.match(/^[0-9A-Fa-f]+$/)) ||
|
(!stringArg.match(/^-?[0-9]+$/) && stringArg.match(/^[0-9A-Fa-f]+$/)) ||
|
||||||
stringArg.match(/^[a-fA-F]+$/) ||
|
stringArg.match(/^[a-fA-F]+$/) ||
|
||||||
(isHexPrefixed === true && stringArg.match(/^[0-9A-Fa-f]+$/))
|
(isHexPrefixed === true && stringArg.match(/^[0-9A-Fa-f]+$/))
|
||||||
) {
|
) {
|
||||||
return Web3.utils.toBN(stringArg).mul(multiplier);
|
return Web3.utils.toBN(stringArg).mul(multiplier)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if ((stringArg.match(/^-?[0-9]+$/) || stringArg === '') && isHexPrefixed === false) {
|
||||||
(stringArg.match(/^-?[0-9]+$/) || stringArg === "") &&
|
return Web3.utils.toBN(stringArg).mul(multiplier)
|
||||||
isHexPrefixed === false
|
|
||||||
) {
|
|
||||||
return Web3.utils.toBN(stringArg).mul(multiplier);
|
|
||||||
}
|
}
|
||||||
} else if (typeof arg === "object" && arg.toString && !arg.pop && !arg.push) {
|
} else if (typeof arg === 'object' && arg.toString && !arg.pop && !arg.push) {
|
||||||
if (
|
if (arg.toString(10).match(/^-?[0-9]+$/) && (arg.mul || arg.dividedToIntegerBy)) {
|
||||||
arg.toString(10).match(/^-?[0-9]+$/) &&
|
return Web3.utils.toBN(arg.toString(10))
|
||||||
(arg.mul || arg.dividedToIntegerBy)
|
|
||||||
) {
|
|
||||||
return Web3.utils.toBN(arg.toString(10));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"[number-to-bn] while converting number " +
|
'[number-to-bn] while converting number ' +
|
||||||
JSON.stringify(arg) +
|
JSON.stringify(arg) +
|
||||||
" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported."
|
' to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported.',
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkRadixLegal(radix) {
|
function checkRadixLegal(radix) {
|
||||||
return radix >= 2 && radix <= 62;
|
return radix >= 2 && radix <= 62
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,18 +208,18 @@ function checkRadixLegal(radix) {
|
|||||||
*/
|
*/
|
||||||
function transformCharToNum(letter, base) {
|
function transformCharToNum(letter, base) {
|
||||||
if (base <= 36) {
|
if (base <= 36) {
|
||||||
letter = letter.toLowerCase();
|
letter = letter.toLowerCase()
|
||||||
}
|
}
|
||||||
if (letter >= '0' && letter <= '9') {
|
if (letter >= '0' && letter <= '9') {
|
||||||
return parseInt(letter);
|
return parseInt(letter)
|
||||||
}
|
}
|
||||||
if (letter >= 'a' && letter <= 'z') {
|
if (letter >= 'a' && letter <= 'z') {
|
||||||
return letter.charCodeAt(0) - 'a'.charCodeAt(0) + 10;
|
return letter.charCodeAt(0) - 'a'.charCodeAt(0) + 10
|
||||||
}
|
}
|
||||||
if (letter >= 'A' && letter <= 'Z') {
|
if (letter >= 'A' && letter <= 'Z') {
|
||||||
return letter.charCodeAt(0) - 'A'.charCodeAt(0) + 36;
|
return letter.charCodeAt(0) - 'A'.charCodeAt(0) + 36
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,8 +228,8 @@ function transformCharToNum(letter, base) {
|
|||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function transformNumToChar(num, alphabet) {
|
function transformNumToChar(num, alphabet) {
|
||||||
alphabet = alphabet || '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
alphabet = alphabet || '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
return alphabet.charAt(num);
|
return alphabet.charAt(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,30 +239,40 @@ function transformNumToChar(num, alphabet) {
|
|||||||
* @param {number} to 转换后的进制
|
* @param {number} to 转换后的进制
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
export function convert({numStr, base, to, alphabet}: {numStr: string, base: number, to: number, alphabet?: string}): string {
|
export function convert({
|
||||||
|
numStr,
|
||||||
|
base,
|
||||||
|
to,
|
||||||
|
alphabet,
|
||||||
|
}: {
|
||||||
|
numStr: string
|
||||||
|
base: number
|
||||||
|
to: number
|
||||||
|
alphabet?: string
|
||||||
|
}): string {
|
||||||
// 当base和to相等 或 base和to超出转换范围,则原样返回
|
// 当base和to相等 或 base和to超出转换范围,则原样返回
|
||||||
if (base === to || !checkRadixLegal(base) || !checkRadixLegal(to)) {
|
if (base === to || !checkRadixLegal(base) || !checkRadixLegal(to)) {
|
||||||
return numStr;
|
return numStr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先转成10进制
|
// 先转成10进制
|
||||||
let p = 0;
|
let p = 0
|
||||||
let number10 = 0;
|
let number10 = 0
|
||||||
while (p < numStr.length) {
|
while (p < numStr.length) {
|
||||||
number10 *= base;
|
number10 *= base
|
||||||
number10 += transformCharToNum(numStr.charAt(p), base);
|
number10 += transformCharToNum(numStr.charAt(p), base)
|
||||||
p++;
|
p++
|
||||||
}
|
}
|
||||||
// 若要转换的正好是进制,则直接返回
|
// 若要转换的正好是进制,则直接返回
|
||||||
if (to === 10) {
|
if (to === 10) {
|
||||||
return number10.toString();
|
return number10.toString()
|
||||||
}
|
}
|
||||||
let result = '';
|
let result = ''
|
||||||
let cur;
|
let cur
|
||||||
while (number10) {
|
while (number10) {
|
||||||
cur = number10 % to;
|
cur = number10 % to
|
||||||
result = transformNumToChar(cur, alphabet) + result;
|
result = transformNumToChar(cur, alphabet) + result
|
||||||
number10 = Math.floor(number10 / to);
|
number10 = Math.floor(number10 / to)
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
@ -82,73 +82,72 @@ export function checkSign({
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
export const aesEncrypt = (plaintText, key) => {
|
export const aesEncrypt = (plaintText, key) => {
|
||||||
key = CryptoJS.SHA1(key).toString().substring(0,16)
|
key = CryptoJS.SHA1(key).toString().substring(0, 16)
|
||||||
key = CryptoJS.enc.Base64.parse(key)
|
key = CryptoJS.enc.Base64.parse(key)
|
||||||
let encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
|
let encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.Pkcs7
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
});
|
})
|
||||||
|
|
||||||
return encryptedData.toString(CryptoJS.format.Hex);
|
return encryptedData.toString(CryptoJS.format.Hex)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const aesDecrypt = (encryptedDataHexStr, key) => {
|
export const aesDecrypt = (encryptedDataHexStr, key) => {
|
||||||
key = CryptoJS.SHA1(key).toString().substring(0,16)
|
key = CryptoJS.SHA1(key).toString().substring(0, 16)
|
||||||
key = CryptoJS.enc.Base64.parse(key)
|
key = CryptoJS.enc.Base64.parse(key)
|
||||||
let encryptedHex = CryptoJS.enc.Hex.parse(encryptedDataHexStr);
|
let encryptedHex = CryptoJS.enc.Hex.parse(encryptedDataHexStr)
|
||||||
let encryptedBase64 = CryptoJS.enc.Base64.stringify(encryptedHex);
|
let encryptedBase64 = CryptoJS.enc.Base64.stringify(encryptedHex)
|
||||||
|
|
||||||
var decryptedData = CryptoJS.AES.decrypt(encryptedBase64, key, {
|
var decryptedData = CryptoJS.AES.decrypt(encryptedBase64, key, {
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.Pkcs7,
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
});
|
})
|
||||||
|
|
||||||
return decryptedData.toString(CryptoJS.enc.Utf8);
|
return decryptedData.toString(CryptoJS.enc.Utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||||
const base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
||||||
|
|
||||||
export const hexToBase58 = (hexString: string) => {
|
export const hexToBase58 = (hexString: string) => {
|
||||||
const bytes = hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16));
|
const bytes = hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))
|
||||||
let base58String = '';
|
let base58String = ''
|
||||||
|
|
||||||
let num = BigInt('0x' + hexString);
|
let num = BigInt('0x' + hexString)
|
||||||
while (num > BigInt(0)) {
|
while (num > BigInt(0)) {
|
||||||
const remainder = num % BigInt(58);
|
const remainder = num % BigInt(58)
|
||||||
num = num / BigInt(58);
|
num = num / BigInt(58)
|
||||||
base58String = base58Alphabet[Number(remainder)] + base58String;
|
base58String = base58Alphabet[Number(remainder)] + base58String
|
||||||
}
|
}
|
||||||
|
|
||||||
return base58String;
|
return base58String
|
||||||
}
|
}
|
||||||
|
|
||||||
export const base58ToHex = (base58String: string) => {
|
export const base58ToHex = (base58String: string) => {
|
||||||
const base58Length = base58String.length;
|
const base58Length = base58String.length
|
||||||
let num = BigInt(0);
|
let num = BigInt(0)
|
||||||
let leadingZeros = 0;
|
let leadingZeros = 0
|
||||||
for (let i = 0; i < base58Length; i++) {
|
for (let i = 0; i < base58Length; i++) {
|
||||||
const charIndex = base58Alphabet.indexOf(base58String[i]);
|
const charIndex = base58Alphabet.indexOf(base58String[i])
|
||||||
if (charIndex === -1) {
|
if (charIndex === -1) {
|
||||||
throw new Error('Invalid Base58 string');
|
throw new Error('Invalid Base58 string')
|
||||||
}
|
}
|
||||||
|
|
||||||
num = num * BigInt(58) + BigInt(charIndex);
|
num = num * BigInt(58) + BigInt(charIndex)
|
||||||
}
|
}
|
||||||
return num.toString(16);
|
return num.toString(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hexToBase32 = (hexString: string) => {
|
export const hexToBase32 = (hexString: string) => {
|
||||||
const bytes = hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16));
|
const bytes = hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))
|
||||||
const base32Alphabet = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
|
const base32Alphabet = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
|
||||||
let base32String = '';
|
let base32String = ''
|
||||||
|
|
||||||
let num = BigInt('0x' + hexString);
|
let num = BigInt('0x' + hexString)
|
||||||
while (num > BigInt(0)) {
|
while (num > BigInt(0)) {
|
||||||
const remainder = num % BigInt(32);
|
const remainder = num % BigInt(32)
|
||||||
num = num / BigInt(32);
|
num = num / BigInt(32)
|
||||||
base32String = base32Alphabet[Number(remainder)] + base32String;
|
base32String = base32Alphabet[Number(remainder)] + base32String
|
||||||
}
|
}
|
||||||
|
|
||||||
return base32String;
|
return base32String
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user