add some script for data parser
This commit is contained in:
parent
3e60f3282c
commit
fd9ffce88b
33035
configs/address_part1.txt
Normal file
33035
configs/address_part1.txt
Normal file
File diff suppressed because it is too large
Load Diff
33178
configs/address_part2.txt
Normal file
33178
configs/address_part2.txt
Normal file
File diff suppressed because it is too large
Load Diff
34785
configs/address_part3.txt
Normal file
34785
configs/address_part3.txt
Normal file
File diff suppressed because it is too large
Load Diff
15493
configs/sybil.txt
Normal file
15493
configs/sybil.txt
Normal file
File diff suppressed because it is too large
Load Diff
0
outdatas/releation.txt
Normal file
0
outdatas/releation.txt
Normal file
19741
outdatas/scorelist.txt
Normal file
19741
outdatas/scorelist.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,13 @@
|
|||||||
"checkredis": "ts-node -r tsconfig-paths/register src/checkredis.ts",
|
"checkredis": "ts-node -r tsconfig-paths/register src/checkredis.ts",
|
||||||
"additem": "ts-node -r tsconfig-paths/register src/addboxdata.ts",
|
"additem": "ts-node -r tsconfig-paths/register src/addboxdata.ts",
|
||||||
"fixdata": "ts-node -r tsconfig-paths/register src/fixdata.ts",
|
"fixdata": "ts-node -r tsconfig-paths/register src/fixdata.ts",
|
||||||
|
"nochain": "ts-node -r tsconfig-paths/register src/removeNoChain.ts",
|
||||||
|
"out": "ts-node -r tsconfig-paths/register src/queryScoreList.ts",
|
||||||
|
"sybil": "ts-node -r tsconfig-paths/register src/removeSybil.ts",
|
||||||
|
"releation": "ts-node -r tsconfig-paths/register src/updateReleation.ts",
|
||||||
"rankquery": "ts-node -r tsconfig-paths/register src/rankquery2.ts",
|
"rankquery": "ts-node -r tsconfig-paths/register src/rankquery2.ts",
|
||||||
|
"mail": "ts-node -r tsconfig-paths/register src/batchMail.ts",
|
||||||
|
"eth": "ts-node -r tsconfig-paths/register src/queryEthTx.ts -s 0 -l 10000 -k TC7Y76AS4AMQ468XXNKKF2R3TI7V844HUC",
|
||||||
"taskid": "ts-node -r tsconfig-paths/register src/generateTaskId.ts",
|
"taskid": "ts-node -r tsconfig-paths/register src/generateTaskId.ts",
|
||||||
"token": "ts-node -r tsconfig-paths/register src/generateToken.ts",
|
"token": "ts-node -r tsconfig-paths/register src/generateToken.ts",
|
||||||
"ingame": "ts-node -r tsconfig-paths/register src/fixIngame.ts",
|
"ingame": "ts-node -r tsconfig-paths/register src/fixIngame.ts",
|
||||||
|
153
src/fixdata.ts
153
src/fixdata.ts
@ -16,9 +16,9 @@ import { randomIp, randomUserAgent } from 'common/Utils'
|
|||||||
import { ScoreRecord } from 'models/ScoreRecord'
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
import { INVITE_REBATE, SCORE_INVITE_REBATE, SCORE_OPEN_CHEST } from 'common/Constants'
|
import { INVITE_REBATE, SCORE_INVITE_REBATE, SCORE_OPEN_CHEST } from 'common/Constants'
|
||||||
import { ActivityChest } from 'models/ActivityChest'
|
import { ActivityChest } from 'models/ActivityChest'
|
||||||
import { generateChestCfg } from 'services/game.svr'
|
import { generateChestCfg, generateChestLevel } from 'services/game.svr'
|
||||||
|
|
||||||
mongoose.set('debug', true)
|
mongoose.set('debug', false)
|
||||||
const sourceList = require('../configs/ingame_tasks.json')
|
const sourceList = require('../configs/ingame_tasks.json')
|
||||||
|
|
||||||
const dbMain = mongoose.createConnection(process.env.DB_MAIN)
|
const dbMain = mongoose.createConnection(process.env.DB_MAIN)
|
||||||
@ -32,20 +32,20 @@ const initEnv = async () => {
|
|||||||
activity = await ActivityInfo.findById(ACTIVITY)
|
activity = await ActivityInfo.findById(ACTIVITY)
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseOneRecord = async (record: any) => {
|
// const parseOneRecord = async (record: any) => {
|
||||||
if (!FixAddress.checkExist(record.from)) {
|
// if (!FixAddress.checkExist(record.from)) {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let addressEip55 = toEIP55(record.from)
|
// let addressEip55 = toEIP55(record.from)
|
||||||
console.log('parseOneRecord', addressEip55)
|
// console.log('parseOneRecord', addressEip55)
|
||||||
const user = await dbCtrl.collection('users_test').findOne({ address: addressEip55 })
|
// const user = await dbCtrl.collection('users_test').findOne({ address: addressEip55 })
|
||||||
if (!user) {
|
// if (!user) {
|
||||||
// 如果没有用户记录,插入用户记录, 并插入一条钱包登录记录(在插入用户记录之前)
|
// // 如果没有用户记录,插入用户记录, 并插入一条钱包登录记录(在插入用户记录之前)
|
||||||
const { uid, timestamp } = await inertUser(dbCtrl, addressEip55, record.blockTime)
|
// const { uid, timestamp } = await inertUser(dbCtrl, addressEip55, record.blockTime)
|
||||||
await insertWalletLoginLog(dbCtrl, addressEip55, uid, timestamp - Math.floor(Math.random() * 2))
|
// await insertWalletLoginLog(dbCtrl, addressEip55, uid, timestamp - Math.floor(Math.random() * 2))
|
||||||
}
|
// }
|
||||||
// 插入签到记录
|
// // 插入签到记录
|
||||||
}
|
// }
|
||||||
// generate fake ObjectId from timestamp
|
// generate fake ObjectId from timestamp
|
||||||
const generateObjectId = (oid: string, fixSeconds: number) => {
|
const generateObjectId = (oid: string, fixSeconds: number) => {
|
||||||
let timestamp = parseInt(oid.slice(0, 8), 16) + fixSeconds
|
let timestamp = parseInt(oid.slice(0, 8), 16) + fixSeconds
|
||||||
@ -126,13 +126,15 @@ const updateTaskProgress = async (user: any) => {
|
|||||||
modifiedTasks.push({ id: task.id, task: task.task, status: TaskStatusEnum.NOT_START })
|
modifiedTasks.push({ id: task.id, task: task.task, status: TaskStatusEnum.NOT_START })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const loginRecord = await LoginRecord.findOne({ user: user.id }).sort({ _id: -1 })
|
||||||
if (modifiedTasks.length > 0) {
|
if (modifiedTasks.length > 0) {
|
||||||
let result = await dbMain.collection('activity_user').updateOne(
|
let result = await dbMain.collection('activity_user').updateOne(
|
||||||
{ _id: user._id },
|
{ _id: user._id },
|
||||||
{
|
{
|
||||||
$push: { taskProgress: { $each: modifiedTasks } },
|
$push: { taskProgress: { $each: modifiedTasks } },
|
||||||
// TODO:: 根据实际情况更新updatedAt
|
// TODO:: 根据实际情况更新updatedAt
|
||||||
$set: { updatedAt: new Date('2024-05-15T12:31:19.860Z') },
|
// @ts-ignore
|
||||||
|
$set: { updatedAt: loginRecord.createdAt },
|
||||||
$inc: { __v: 1 },
|
$inc: { __v: 1 },
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
@ -150,42 +152,108 @@ const updateTaskProgress = async (user: any) => {
|
|||||||
*/
|
*/
|
||||||
const updateChestRecord = async (addressRecord: any) => {
|
const updateChestRecord = async (addressRecord: any) => {
|
||||||
const records = await ScoreRecord.find({ user: addressRecord.user, activity: ACTIVITY, type: SCORE_OPEN_CHEST })
|
const records = await ScoreRecord.find({ user: addressRecord.user, activity: ACTIVITY, type: SCORE_OPEN_CHEST })
|
||||||
|
const user = await ActivityUser.findById(addressRecord.user)
|
||||||
|
let actionsBox = []
|
||||||
|
let actionsScore = []
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
let { level, chestId } = record.data
|
let { level, chestId } = record.data
|
||||||
level = 4
|
if (level === 1) {
|
||||||
|
level = 3
|
||||||
|
} else if (level === 2) {
|
||||||
|
level = 4
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
const { scoreInit, bounsCfg, maxBounsCount } = generateChestCfg(level)
|
const { scoreInit, bounsCfg, maxBounsCount } = generateChestCfg(level)
|
||||||
await dbMain
|
actionsBox.push({
|
||||||
.collection('activity_chest')
|
updateOne: {
|
||||||
.updateOne({ _id: new Types.ObjectId(chestId) }, { $set: { level, scoreInit, bounsCfg, maxBounsCount } })
|
filter: { _id: new Types.ObjectId(chestId) },
|
||||||
await dbMain
|
update: { $set: { level, scoreInit, bounsCfg, maxBounsCount } },
|
||||||
.collection('score_record')
|
},
|
||||||
.updateOne({ _id: record._id }, { $set: { score: scoreInit, 'data.level': level } })
|
})
|
||||||
const user = await ActivityUser.findById(addressRecord.user)
|
actionsScore.push({
|
||||||
|
updateOne: {
|
||||||
|
filter: { _id: record._id },
|
||||||
|
update: { $set: { score: scoreInit, 'data.level': level } },
|
||||||
|
},
|
||||||
|
})
|
||||||
if (user.inviteUser) {
|
if (user.inviteUser) {
|
||||||
const fixSeconds = 0
|
const fixSeconds = 0
|
||||||
let oid = generateObjectId(record.id, fixSeconds)
|
let oid = generateObjectId(record.id, fixSeconds)
|
||||||
let time = new Date(user.createdAt.getTime() + fixSeconds * 1000)
|
// @ts-ignore
|
||||||
|
let time = new Date(record.createdAt.getTime() + fixSeconds * 1000)
|
||||||
const score1 = scoreInit * INVITE_REBATE
|
const score1 = scoreInit * INVITE_REBATE
|
||||||
let scoreParams = {
|
let scoreParams = {
|
||||||
fromUser: user,
|
fromUser: user.id,
|
||||||
data: record.data.dateTag,
|
date: record.data.dateTag,
|
||||||
chestId,
|
chestId,
|
||||||
level,
|
level,
|
||||||
items: record.data.items,
|
items: record.data.items,
|
||||||
}
|
}
|
||||||
await dbMain.collection('score_record').insertOne({
|
actionsScore.push({
|
||||||
_id: new Types.ObjectId(oid),
|
insertOne: {
|
||||||
user: user.inviteUser,
|
document: {
|
||||||
score: score1,
|
_id: new Types.ObjectId(oid),
|
||||||
activity: record.activity,
|
user: user.inviteUser,
|
||||||
type: SCORE_INVITE_REBATE,
|
score: score1,
|
||||||
data: scoreParams,
|
activity: record.activity,
|
||||||
createdAt: time,
|
type: SCORE_INVITE_REBATE,
|
||||||
updatedAt: time,
|
data: JSON.parse(JSON.stringify(scoreParams)),
|
||||||
__v: 0.0,
|
createdAt: time,
|
||||||
|
updatedAt: time,
|
||||||
|
__v: 0.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (actionsBox.length > 0) {
|
||||||
|
await dbMain.collection('activity_box').bulkWrite(actionsBox)
|
||||||
|
}
|
||||||
|
if (actionsScore.length > 0) {
|
||||||
|
await dbMain.collection('score_record').bulkWrite(actionsScore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 0607 删除sybil数据后, 调整买量用户的宝箱数据
|
||||||
|
* 所有4级改为2级
|
||||||
|
*/
|
||||||
|
|
||||||
|
const updateChest = async (addressRecord: any) => {
|
||||||
|
const records = await ScoreRecord.find({ user: addressRecord.user, activity: ACTIVITY, type: SCORE_OPEN_CHEST })
|
||||||
|
let actionsBox = []
|
||||||
|
let actionsScore = []
|
||||||
|
for (let record of records) {
|
||||||
|
let { level, chestId } = record.data
|
||||||
|
// if (level === 4) {
|
||||||
|
// level = 2
|
||||||
|
// } else if (level === 3) {
|
||||||
|
// level = 1
|
||||||
|
// } else {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
level = generateChestLevel()
|
||||||
|
const { scoreInit, bounsCfg, maxBounsCount } = generateChestCfg(level)
|
||||||
|
actionsBox.push({
|
||||||
|
updateOne: {
|
||||||
|
filter: { _id: new Types.ObjectId(chestId) },
|
||||||
|
update: { $set: { level, scoreInit, bounsCfg, maxBounsCount } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
actionsScore.push({
|
||||||
|
updateOne: {
|
||||||
|
filter: { _id: record._id },
|
||||||
|
update: { $set: { score: scoreInit, 'data.level': level } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (actionsBox.length > 0) {
|
||||||
|
await dbMain.collection('activity_box').bulkWrite(actionsBox)
|
||||||
|
}
|
||||||
|
if (actionsScore.length > 0) {
|
||||||
|
await dbMain.collection('score_record').bulkWrite(actionsScore)
|
||||||
|
}
|
||||||
|
console.log('updateChest', addressRecord.user, actionsBox.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fixTaskProgree = async (record: any) => {
|
const fixTaskProgree = async (record: any) => {
|
||||||
@ -209,10 +277,11 @@ const updateInGameRecords = async (record: any) => {
|
|||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
await initEnv()
|
await initEnv()
|
||||||
await FixAddress.find().cursor().eachAsync(prepareUser)
|
// await FixAddress.find().cursor().eachAsync(prepareUser)
|
||||||
await FixAddress.find().cursor().eachAsync(fixTaskProgree)
|
// await FixAddress.find().cursor().eachAsync(fixTaskProgree)
|
||||||
await FixAddress.find().cursor().eachAsync(updateChestRecord)
|
// await FixAddress.find().cursor().eachAsync(updateChestRecord)
|
||||||
await FixAddress.find().cursor().eachAsync(updateInGameRecords)
|
await FixAddress.find().cursor().eachAsync(updateChest)
|
||||||
|
// await FixAddress.find().cursor().eachAsync(updateInGameRecords)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { BaseModule } from './Base'
|
|||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ type: 1 }, { unique: false })
|
@index({ type: 1 }, { unique: false })
|
||||||
@modelOptions({
|
@modelOptions({
|
||||||
schemaOptions: { collection: 'delete_record', timestamps: true },
|
schemaOptions: { collection: 'delete_record3', timestamps: true },
|
||||||
options: { allowMixed: Severity.ALLOW },
|
options: { allowMixed: Severity.ALLOW },
|
||||||
})
|
})
|
||||||
export class DeleteRecordClass extends BaseModule {
|
export class DeleteRecordClass extends BaseModule {
|
||||||
|
46
src/models/EthTx.ts
Normal file
46
src/models/EthTx.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
|
||||||
|
import { dbconn } from 'decorators/dbconn'
|
||||||
|
import { BaseModule } from './Base'
|
||||||
|
|
||||||
|
@dbconn()
|
||||||
|
@index({ hash: 1, from: 1, to: 1 }, { unique: true })
|
||||||
|
@index({ from: 1 }, { unique: false })
|
||||||
|
@index({ to: 1 }, { unique: false })
|
||||||
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'eth_txs', timestamps: true },
|
||||||
|
})
|
||||||
|
export class EthTxClass extends BaseModule {
|
||||||
|
@prop({ required: true })
|
||||||
|
public from!: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public to!: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public value: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public hash: string
|
||||||
|
@prop()
|
||||||
|
public blockNumber: number
|
||||||
|
@prop()
|
||||||
|
public blockHash: string
|
||||||
|
@prop()
|
||||||
|
public timeStamp: number
|
||||||
|
@prop()
|
||||||
|
public dateTag: string
|
||||||
|
@prop({ default: 0 })
|
||||||
|
public version: number
|
||||||
|
|
||||||
|
public static async saveEvent(event: any) {
|
||||||
|
let hash = event.hash
|
||||||
|
let data = {
|
||||||
|
$inc: { version: 1 },
|
||||||
|
}
|
||||||
|
data = Object.assign(event)
|
||||||
|
|
||||||
|
let record = await EthTx.insertOrUpdate({ hash }, data)
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EthTx = getModelForClass(EthTxClass, {
|
||||||
|
existingConnection: EthTxClass['db'],
|
||||||
|
})
|
63
src/models/chain/GeneralEvent.ts
Normal file
63
src/models/chain/GeneralEvent.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Severity, getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
|
||||||
|
import { dbconn } from 'decorators/dbconn'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
|
||||||
|
@dbconn('chain')
|
||||||
|
@index({ chain: 1, hash: 1, logIndex: 1 }, { unique: true })
|
||||||
|
@index({ chain: 1, address: 1, blockNumber: 1 }, { unique: false })
|
||||||
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'general_event', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
|
export class GeneralEventClass extends BaseModule {
|
||||||
|
@prop({ required: true })
|
||||||
|
public address!: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public chain: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public logIndex: number
|
||||||
|
@prop()
|
||||||
|
public event: string
|
||||||
|
// event hash
|
||||||
|
@prop({ required: true })
|
||||||
|
public hash: string
|
||||||
|
@prop()
|
||||||
|
public blockNumber: number
|
||||||
|
@prop()
|
||||||
|
public blockHash: string
|
||||||
|
@prop()
|
||||||
|
public dateTag: string
|
||||||
|
@prop()
|
||||||
|
public removed: boolean
|
||||||
|
|
||||||
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
|
public decodedData: any
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public blockTime: number
|
||||||
|
@prop({ default: 0 })
|
||||||
|
public version: number
|
||||||
|
|
||||||
|
public static async saveEvent(event: any) {
|
||||||
|
const logIndex = parseInt(event.logIndex || '0')
|
||||||
|
const hash = event.hash || event.transactionHash
|
||||||
|
const data = {
|
||||||
|
address: event.address.toLowerCase(),
|
||||||
|
blockNumber: parseInt(event.blockNumber),
|
||||||
|
removed: event.removed,
|
||||||
|
decodedData: event.decodedData,
|
||||||
|
blockHash: event.blockHash,
|
||||||
|
blockTime: event.blockTime,
|
||||||
|
dateTag: event.dateTag,
|
||||||
|
event: event.event,
|
||||||
|
$inc: { version: 1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
let record = await GeneralEvent.insertOrUpdate({ hash, logIndex, chain: event.chain }, data)
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GeneralEvent = getModelForClass(GeneralEventClass, {
|
||||||
|
existingConnection: GeneralEventClass['db'],
|
||||||
|
})
|
@ -2,7 +2,7 @@ import { getModelForClass, index, modelOptions, prop, Severity } from '@typegoos
|
|||||||
import { dbconn } from 'decorators/dbconn'
|
import { dbconn } from 'decorators/dbconn'
|
||||||
import { BaseModule } from '../Base'
|
import { BaseModule } from '../Base'
|
||||||
|
|
||||||
@dbconn('ctrl')
|
@dbconn()
|
||||||
// case insensitive unique index
|
// case insensitive unique index
|
||||||
@index({ address: 1 }, { unique: true, collation: { locale: 'en', strength: 2 } })
|
@index({ address: 1 }, { unique: true, collation: { locale: 'en', strength: 2 } })
|
||||||
@index({ user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } })
|
@index({ user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } })
|
||||||
|
135
src/queryEthTx.ts
Normal file
135
src/queryEthTx.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { EthTx } from 'models/EthTx'
|
||||||
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
|
let fs = require('fs')
|
||||||
|
|
||||||
|
import yargs from 'yargs'
|
||||||
|
/**
|
||||||
|
* 查询钱包native交易记录
|
||||||
|
*/
|
||||||
|
|
||||||
|
const cfgs = [
|
||||||
|
['address_part1.txt', '66CEJ462RDC6C7J6KDBWVVEAFJ27XGFAVX'],
|
||||||
|
['address_part2.txt', '18YV8FFRPIZAK1AVPN5ZSNJEYPZVNTW73R'],
|
||||||
|
['address_part3.txt', 'TC7Y76AS4AMQ468XXNKKF2R3TI7V844HUC'],
|
||||||
|
]
|
||||||
|
|
||||||
|
const argv = yargs(process.argv.slice(2)).options({
|
||||||
|
i: { type: 'number', default: 0 },
|
||||||
|
}).argv
|
||||||
|
let count = 0
|
||||||
|
mongoose.set('debug', false)
|
||||||
|
let API_KEY = ''
|
||||||
|
const NO_TX_ERR = 'No transactions found'
|
||||||
|
const fetchNormalTx = async (address: string) => {
|
||||||
|
let res = await fetch(
|
||||||
|
`https://api-opbnb.bscscan.com/api?module=account&action=txlist&address=${address}&startblock=0&endblock=99999999&page=1&offset=10000&sort=asc&apikey=${API_KEY}`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
).then(res => res.json())
|
||||||
|
if (res.status != '1') {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
return res.result
|
||||||
|
}
|
||||||
|
const fetchInternalTx = async (address: string) => {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api-opbnb.bscscan.com/api?module=account&action=txlistinternal&address=${address}&startblock=0&endblock=99999999&page=1&offset=10000&sort=asc&apikey=${API_KEY}`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
).then(res => res.json())
|
||||||
|
if (res.status != '1') {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
return res.result
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseOneUser = async (user: any) => {
|
||||||
|
let actions = []
|
||||||
|
let errNormal = false
|
||||||
|
let errInternal = false
|
||||||
|
try {
|
||||||
|
let res1 = await fetchNormalTx(user.address)
|
||||||
|
for (const sub of res1) {
|
||||||
|
if (sub.value == '0') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let data = {
|
||||||
|
$inc: { version: 1 },
|
||||||
|
}
|
||||||
|
data = Object.assign(sub)
|
||||||
|
actions.push({
|
||||||
|
updateOne: {
|
||||||
|
filter: { hash: sub.hash, from: sub.from, to: sub.to },
|
||||||
|
update: data,
|
||||||
|
upsert: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// await EthTx.saveEvent(sub)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message == NO_TX_ERR) {
|
||||||
|
errNormal = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let res2 = await fetchInternalTx(user.address)
|
||||||
|
for (const sub of res2) {
|
||||||
|
if (sub.value == '0') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let data: any = {
|
||||||
|
$inc: { version: 1 },
|
||||||
|
}
|
||||||
|
data = Object.assign(sub)
|
||||||
|
data.from = sub.from.toLowerCase()
|
||||||
|
data.to = sub.to.toLowerCase()
|
||||||
|
actions.push({
|
||||||
|
updateOne: {
|
||||||
|
filter: { hash: sub.hash, from: sub.from, to: sub.to },
|
||||||
|
update: data,
|
||||||
|
upsert: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// await EthTx.saveEvent(sub)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message == NO_TX_ERR) {
|
||||||
|
errInternal = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errInternal && errNormal) {
|
||||||
|
console.log(user.address)
|
||||||
|
}
|
||||||
|
if (actions.length > 0) {
|
||||||
|
await EthTx.bulkWrite(actions)
|
||||||
|
}
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
const i = argv.i || 0
|
||||||
|
API_KEY = cfgs[i][1]
|
||||||
|
if (!API_KEY) {
|
||||||
|
throw new Error('invalid key')
|
||||||
|
}
|
||||||
|
const file = cfgs[i][0]
|
||||||
|
let list = fs.readFileSync(`configs/${file}`, 'utf-8').split('\n')
|
||||||
|
for (let address of list) {
|
||||||
|
await parseOneUser({ address: address.toLowerCase() })
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
104
src/queryReleation.ts
Normal file
104
src/queryReleation.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
|
import { ZRedisClient } from 'zutils'
|
||||||
|
import { formatNumShow } from 'common/Utils'
|
||||||
|
import { RANK_SCORE_SCALE } from 'common/Constants'
|
||||||
|
let fs = require('fs')
|
||||||
|
/**
|
||||||
|
* 生成积分明细
|
||||||
|
*/
|
||||||
|
|
||||||
|
mongoose.set('debug', false)
|
||||||
|
const ACTIVITY = 'uaw_activity'
|
||||||
|
|
||||||
|
const totalKey = 'uaw_activity:static:score'
|
||||||
|
const minCount = 100
|
||||||
|
|
||||||
|
const updateRedis2 = (key, vals) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
new ZRedisClient().pub.zadd(key, vals, function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveScoreToRedis = async (type: string) => {
|
||||||
|
const key = `uaw_score_${type}`
|
||||||
|
await new ZRedisClient().del(key)
|
||||||
|
let records = await ScoreRecord.aggregate([
|
||||||
|
{ $match: { type } },
|
||||||
|
{ $group: { _id: '$user', count: { $sum: '$score' } } },
|
||||||
|
])
|
||||||
|
let vals = []
|
||||||
|
|
||||||
|
for (let i = 0, l = records.length; i < l; i++) {
|
||||||
|
if (records[i].count == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vals.push((records[i].count * RANK_SCORE_SCALE) | 0)
|
||||||
|
vals.push(records[i]._id)
|
||||||
|
if (i % 1000 === 0) {
|
||||||
|
await updateRedis2(key, vals)
|
||||||
|
vals.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vals.length > 0) {
|
||||||
|
await updateRedis2(key, vals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryList = async () => {
|
||||||
|
let records = await ActivityUser.aggregate([
|
||||||
|
{ $match: { inviteUser: { $exists: true } } },
|
||||||
|
{ $group: { _id: '$inviteUser', count: { $sum: 1 } } },
|
||||||
|
{ $match: { count: { $gte: minCount } } },
|
||||||
|
{ $sort: { count: -1 } },
|
||||||
|
])
|
||||||
|
console.log(records.length)
|
||||||
|
let results = []
|
||||||
|
for (let i = 0, l = records.length; i < l; i++) {
|
||||||
|
const { _id, count } = records[i]
|
||||||
|
const user = await ActivityUser.findById(_id)
|
||||||
|
if (!user) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const totalScore = await new ZRedisClient().zscore(totalKey, _id)
|
||||||
|
const releationKey = `uaw_score_invite_rebate`
|
||||||
|
const releatScore = await new ZRedisClient().zscore(releationKey, _id)
|
||||||
|
const scoreShow = formatNumShow(totalScore ? parseInt(totalScore + '') / RANK_SCORE_SCALE : 0)
|
||||||
|
if (scoreShow == '0') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const releatScoreShow = formatNumShow(releatScore ? parseInt(releatScore + '') / RANK_SCORE_SCALE : 0)
|
||||||
|
results.push(`${_id}\t${user?.address || ''}\t${count}\t${scoreShow}\t${releatScoreShow}`)
|
||||||
|
}
|
||||||
|
fs.writeFileSync('outdatas/releation.txt', results.join('\n') + '\n', { flag: 'a+' })
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
let opts = { url: process.env.REDIS }
|
||||||
|
new ZRedisClient(opts)
|
||||||
|
console.time('update redis')
|
||||||
|
await saveScoreToRedis('invite_rebate')
|
||||||
|
console.timeEnd('update redis')
|
||||||
|
console.time('query')
|
||||||
|
fs.writeFileSync('outdatas/releation.txt', '')
|
||||||
|
await queryList()
|
||||||
|
console.timeEnd('query')
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
244
src/queryScoreList.ts
Normal file
244
src/queryScoreList.ts
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
|
import { ZRedisClient } from 'zutils'
|
||||||
|
import { formatNumShow } from 'common/Utils'
|
||||||
|
import { RANK_SCORE_SCALE } from 'common/Constants'
|
||||||
|
import { InGameScoreRecord } from 'models/InGameScoreRecord'
|
||||||
|
import { DeleteRecord } from 'models/DeleteRecord'
|
||||||
|
import { Types } from 'mongoose'
|
||||||
|
import { InGameStats } from 'models/InGameStats'
|
||||||
|
import { NFTHolderRecord } from 'models/NFTHodlerRecord'
|
||||||
|
let fs = require('fs')
|
||||||
|
/**
|
||||||
|
* 生成积分明细
|
||||||
|
*/
|
||||||
|
|
||||||
|
mongoose.set('debug', false)
|
||||||
|
const ACTIVITY = 'uaw_activity'
|
||||||
|
|
||||||
|
const totalKey = 'uaw_activity:static:score'
|
||||||
|
const gameTotalKey = 'uaw_activity:static:gamescore'
|
||||||
|
const releationKey = `uaw_score_invite_rebate`
|
||||||
|
const pageSize = 100
|
||||||
|
|
||||||
|
const updateRedis2 = (key, vals) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
new ZRedisClient().pub.zadd(key, vals, function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveScoreToRedis = async () => {
|
||||||
|
let records = await ScoreRecord.aggregate([{ $group: { _id: '$user', count: { $sum: '$score' } } }])
|
||||||
|
let vals = []
|
||||||
|
for (let i = 0, l = records.length; i < l; i++) {
|
||||||
|
if (records[i].count == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vals.push((records[i].count * RANK_SCORE_SCALE) | 0)
|
||||||
|
vals.push(records[i]._id)
|
||||||
|
if (i % 1000 === 0) {
|
||||||
|
await updateRedis2(totalKey, vals)
|
||||||
|
vals.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vals.length > 0) {
|
||||||
|
await updateRedis2(totalKey, vals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveTypeScoreToRedis = async (type: string) => {
|
||||||
|
const key = `uaw_score_${type}`
|
||||||
|
await new ZRedisClient().del(key)
|
||||||
|
let records = await ScoreRecord.aggregate([
|
||||||
|
{ $match: { type } },
|
||||||
|
{ $group: { _id: '$user', count: { $sum: '$score' } } },
|
||||||
|
])
|
||||||
|
let vals = []
|
||||||
|
|
||||||
|
for (let i = 0, l = records.length; i < l; i++) {
|
||||||
|
if (records[i].count == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vals.push((records[i].count * RANK_SCORE_SCALE) | 0)
|
||||||
|
vals.push(records[i]._id)
|
||||||
|
if (i % 1000 === 0) {
|
||||||
|
await updateRedis2(key, vals)
|
||||||
|
vals.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vals.length > 0) {
|
||||||
|
await updateRedis2(key, vals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateScoreList = async (start: number) => {
|
||||||
|
let end = start + pageSize
|
||||||
|
const records = await new ZRedisClient().zrevrange(totalKey, start, end)
|
||||||
|
let results = []
|
||||||
|
for (let i = 0; i < records.length; i += 2) {
|
||||||
|
const id = records[i]
|
||||||
|
let score = formatNumShow(parseInt(records[i + 1]) / RANK_SCORE_SCALE)
|
||||||
|
const releatScore = await new ZRedisClient().zscore(releationKey, id)
|
||||||
|
const releatScoreShow = formatNumShow(releatScore ? parseInt(releatScore + '') / RANK_SCORE_SCALE : 0)
|
||||||
|
const user = await ActivityUser.findById(id)
|
||||||
|
const rank = start + i / 2 + 1
|
||||||
|
results.push(
|
||||||
|
`${rank}\t${user?.address}\t${score}\t${releatScoreShow}\t${holderMap.get(user?.address.toLowerCase()) || 1}\t${founderSet.has(user.address) ? 1 : 0}\t${explorerSet.has(user.address) ? 1 : 0}\t${badgeSet.has(user.address) ? 1 : 0}\t${candySet.has(user.address) ? 1 : 0}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fs.writeFileSync('outdatas/scorelist.txt', results.join('\n') + '\n', { flag: 'a+' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveGameScoreToRedis = async () => {
|
||||||
|
let records = await InGameScoreRecord.aggregate([{ $group: { _id: '$user', count: { $sum: '$score' } } }])
|
||||||
|
let vals = []
|
||||||
|
for (let i = 0, l = records.length; i < l; i++) {
|
||||||
|
if (records[i].count == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vals.push((records[i].count * 100) | 0)
|
||||||
|
vals.push(records[i]._id)
|
||||||
|
if (i % 1000 === 0) {
|
||||||
|
await updateRedis2(gameTotalKey, vals)
|
||||||
|
vals.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vals.length > 0) {
|
||||||
|
await updateRedis2(gameTotalKey, vals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateGameScoreList = async (start: number) => {
|
||||||
|
let end = start + pageSize
|
||||||
|
// const records = await new ZRedisClient().zrevrange(gameTotalKey, start, end)
|
||||||
|
const records = await InGameStats.find({ score: { $gt: 0 } })
|
||||||
|
.sort({ score: -1 })
|
||||||
|
.skip(start)
|
||||||
|
.limit(pageSize)
|
||||||
|
let results = []
|
||||||
|
for (let i = 0; i < records.length; i++) {
|
||||||
|
let score = records[i].score
|
||||||
|
if (score === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let address = ''
|
||||||
|
const user = await ActivityUser.findById(records[i].user)
|
||||||
|
if (!user) {
|
||||||
|
const userDel = await DeleteRecord.findOne({ 'data._id': new Types.ObjectId(records[i].user) })
|
||||||
|
if (userDel) {
|
||||||
|
address = userDel.data.address
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
address = user.address
|
||||||
|
}
|
||||||
|
const rank = start + i + 1
|
||||||
|
results.push(`${rank}\t${address}\t${score}`)
|
||||||
|
}
|
||||||
|
fs.writeFileSync('outdatas/gameScorelist.txt', results.join('\n') + '\n', { flag: 'a+' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateWhiteList = async () => {
|
||||||
|
let records = await ActivityUser.find({ whiteListNum: { $gt: 0 } })
|
||||||
|
let results = []
|
||||||
|
for (let i = 0; i < records.length; i++) {
|
||||||
|
results.push(`${records[i].address} \t ${records[i].whiteListNum}`)
|
||||||
|
}
|
||||||
|
let records2 = await DeleteRecord.find({ 'data.whiteListNum': { $gt: 0 } })
|
||||||
|
for (let i = 0; i < records2.length; i++) {
|
||||||
|
results.push(`${records2[i].data.address} \t ${records2[i].data.whiteListNum}`)
|
||||||
|
}
|
||||||
|
fs.writeFileSync('outdatas/whitelist.txt', results.join('\n') + '\n', { flag: 'a+' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const holders = [
|
||||||
|
['explorer', '0x0cee888fa25810ca648d697099bc17a2c9e1dfbf', 1.5],
|
||||||
|
['candy', '0xefd4c863e73e7e9cc33d46fb30ce51510fcfdeb0', 1.5],
|
||||||
|
['badge', '0xd728de3d9ebed90e84abe84539280cbc5b18e304', 2],
|
||||||
|
['founder', '0xec23679653337d4c6390d0eeba682246a6067777', 3],
|
||||||
|
]
|
||||||
|
const holderMap = new Map()
|
||||||
|
let explorerSet = new Set()
|
||||||
|
let candySet = new Set()
|
||||||
|
let badgeSet = new Set()
|
||||||
|
let founderSet = new Set()
|
||||||
|
const queryHolder = async () => {
|
||||||
|
for (let holder of holders) {
|
||||||
|
const [name, contract] = holder
|
||||||
|
let records = await NFTHolderRecord.find({ contract: contract + '' })
|
||||||
|
for (let i = 0; i < records.length; i++) {
|
||||||
|
const uid = records[i].user
|
||||||
|
let user = await ActivityUser.findById(uid)
|
||||||
|
if (!user) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let address = user.address.toLowerCase()
|
||||||
|
if (name === 'explorer') {
|
||||||
|
explorerSet.add(address)
|
||||||
|
} else if (name === 'candy') {
|
||||||
|
candySet.add(address)
|
||||||
|
} else if (name === 'badge') {
|
||||||
|
badgeSet.add(address)
|
||||||
|
} else if (name === 'founder') {
|
||||||
|
founderSet.add(address)
|
||||||
|
}
|
||||||
|
if (!holderMap.has(address)) {
|
||||||
|
holderMap.set(address, 1)
|
||||||
|
}
|
||||||
|
holderMap.set(address, holderMap.get(address) * parseFloat(holder[2] + ''))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
let opts = { url: process.env.REDIS }
|
||||||
|
new ZRedisClient(opts)
|
||||||
|
await new ZRedisClient().del(totalKey)
|
||||||
|
// await new ZRedisClient().del(gameTotalKey)
|
||||||
|
console.time('update redis')
|
||||||
|
await saveScoreToRedis()
|
||||||
|
console.timeEnd('update redis')
|
||||||
|
console.time('query holder info')
|
||||||
|
await queryHolder()
|
||||||
|
console.timeEnd('query holder info')
|
||||||
|
console.time('update releation redis')
|
||||||
|
await saveTypeScoreToRedis('invite_rebate')
|
||||||
|
console.timeEnd('update releation redis')
|
||||||
|
console.time('generate score list')
|
||||||
|
const total = (await new ZRedisClient().zcard(totalKey)) as number
|
||||||
|
for (let i = 0; i < total; i += pageSize) {
|
||||||
|
await generateScoreList(i)
|
||||||
|
}
|
||||||
|
console.timeEnd('generate score list')
|
||||||
|
|
||||||
|
// console.time('update game redis')
|
||||||
|
// await saveGameScoreToRedis()
|
||||||
|
// console.timeEnd('update game redis')
|
||||||
|
// console.time('generate game score list')
|
||||||
|
// const totalGame = (await new ZRedisClient().zcard(gameTotalKey)) as number
|
||||||
|
// const totalGame = await InGameStats.countDocuments({ score: { $gt: 0 } })
|
||||||
|
// for (let i = 0; i < totalGame; i += pageSize) {
|
||||||
|
// await generateGameScoreList(i)
|
||||||
|
// }
|
||||||
|
// console.timeEnd('generate game score list')
|
||||||
|
// console.time('generate white list')
|
||||||
|
// await generateWhiteList()
|
||||||
|
// console.timeEnd('generate white list')
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
39
src/removeNoChain.ts
Normal file
39
src/removeNoChain.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
|
import { GeneralEvent } from 'models/chain/GeneralEvent'
|
||||||
|
import { DeleteRecord } from 'models/DeleteRecord'
|
||||||
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
|
|
||||||
|
mongoose.set('debug', true)
|
||||||
|
const ACTIVITY = 'uaw_activity'
|
||||||
|
|
||||||
|
const parseOneUser = async (record: any) => {
|
||||||
|
const address = record.address
|
||||||
|
let res = await GeneralEvent.findOne({ 'decodedData.user': address }).collation({ locale: 'en', strength: 2 })
|
||||||
|
if (!res) {
|
||||||
|
console.log(`no chain record: `, address)
|
||||||
|
let dRecord = new DeleteRecord({
|
||||||
|
type: 'user_no_chain',
|
||||||
|
data: record,
|
||||||
|
})
|
||||||
|
await ScoreRecord.deleteMany({ user: record.id, activity: ACTIVITY })
|
||||||
|
await ScoreRecord.deleteMany({ 'data.fromUser': record.id, type: 'invite_rebate' })
|
||||||
|
await dRecord.save()
|
||||||
|
await ActivityUser.deleteOne({ _id: record.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
await ActivityUser.find().cursor().eachAsync(parseOneUser)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
91
src/removeSybil.ts
Normal file
91
src/removeSybil.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
|
import { DeleteRecord } from 'models/DeleteRecord'
|
||||||
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
|
import { FixAddress } from 'models/ctrl/FixAddress'
|
||||||
|
|
||||||
|
mongoose.set('debug', false)
|
||||||
|
const dbMain = mongoose.createConnection(process.env.DB_MAIN)
|
||||||
|
const ACTIVITY = 'uaw_activity'
|
||||||
|
let fs = require('fs')
|
||||||
|
|
||||||
|
let sybilSet: Set<string> = new Set()
|
||||||
|
let sybilArr: string[] = []
|
||||||
|
|
||||||
|
// const loadSybils = async () => {
|
||||||
|
// let wallets = fs.readFileSync('configs/sybil.txt', 'utf-8').split('\n')
|
||||||
|
// // let fromSet = new Set(wallets)
|
||||||
|
// let records = await EthTx.find({ from: { $in: wallets } })
|
||||||
|
// for (let record of records) {
|
||||||
|
// sybilSet.add(record.to.toLowerCase())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
const loadSybils = async (index: number) => {
|
||||||
|
sybilArr = fs.readFileSync(`data/address_list${(index + '').padStart(2, '0')}`, 'utf-8').split('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadWhitelist = async () => {
|
||||||
|
let records = await FixAddress.find()
|
||||||
|
for (let record of records) {
|
||||||
|
if (sybilSet.has(record.address.toLowerCase())) {
|
||||||
|
sybilSet.delete(record.address.toLowerCase())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteUser = async () => {
|
||||||
|
let userArr = []
|
||||||
|
let records = await ActivityUser.find({ address: { $in: sybilArr } })
|
||||||
|
for (let record of records) {
|
||||||
|
userArr.push(record.id)
|
||||||
|
}
|
||||||
|
await ActivityUser.aggregate([{ $match: { address: { $in: sybilArr } } }, { $out: 'delete_users2' }])
|
||||||
|
console.log('delete_users: ', userArr.length)
|
||||||
|
const res1 = await ActivityUser.deleteMany({ address: { $in: sybilArr } })
|
||||||
|
console.log(res1)
|
||||||
|
const res2 = await ScoreRecord.deleteMany({ user: { $in: userArr }, activity: ACTIVITY })
|
||||||
|
console.log(res2)
|
||||||
|
const res3 = await ScoreRecord.deleteMany({ 'data.fromUser': { $in: userArr }, type: 'invite_rebate' })
|
||||||
|
console.log(res3)
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseOneUser = async (record: any) => {
|
||||||
|
const address = record.address
|
||||||
|
if (sybilSet.has(address)) {
|
||||||
|
console.log(`no chain record: `, address)
|
||||||
|
let dRecord = new DeleteRecord({
|
||||||
|
type: 'user_no_chain',
|
||||||
|
data: record,
|
||||||
|
})
|
||||||
|
await ScoreRecord.deleteMany({ user: record.id, activity: ACTIVITY })
|
||||||
|
await ScoreRecord.deleteMany({ 'data.fromUser': record.id, type: 'invite_rebate' })
|
||||||
|
await dRecord.save()
|
||||||
|
await ActivityUser.deleteOne({ _id: record.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
for (let i = 0; i < 33; i++) {
|
||||||
|
try {
|
||||||
|
await loadSybils(i)
|
||||||
|
console.log(i, 'sybilArr: ', sybilArr.length)
|
||||||
|
await deleteUser()
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// try {
|
||||||
|
// // await loadWhitelist()
|
||||||
|
// // console.log('sybilSet: ', sybilSet.size)
|
||||||
|
// // await ActivityUser.find().cursor().eachAsync(parseOneUser)
|
||||||
|
// } catch (e) {
|
||||||
|
// console.log(e)
|
||||||
|
// }
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
@ -62,14 +62,18 @@ const MAIL_SVR = process.env.EMAIL_SERVER
|
|||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
export class EmailSvr {
|
export class EmailSvr {
|
||||||
public sendMail(msg: IMailData) {
|
public async sendMail(msg: IMailData) {
|
||||||
let url = MAIL_SVR + '/mail/send'
|
let url = MAIL_SVR + '/mail/send'
|
||||||
Object(DEFAULT_MSG_DATA).zssign(msg)
|
Object(DEFAULT_MSG_DATA).zssign(msg)
|
||||||
|
let headers: any = {
|
||||||
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
|
}
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
headers['Authorization'] = 'Basic bWFpbHNlbmRlcjo3NjU0MzIxY2Yt'
|
||||||
|
}
|
||||||
const options: any = {
|
const options: any = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers,
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ message: msg }),
|
body: JSON.stringify({ message: msg }),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
src/updateReleation.ts
Normal file
31
src/updateReleation.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import * as dotenv from 'dotenv'
|
||||||
|
|
||||||
|
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
|
||||||
|
dotenv.config({ path: envFile })
|
||||||
|
console.log(process.env.DB_MAIN)
|
||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { FixAddress } from 'models/ctrl/FixAddress'
|
||||||
|
|
||||||
|
mongoose.set('debug', false)
|
||||||
|
const dbMain = mongoose.createConnection(process.env.DB_MAIN)
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
let records = await FixAddress.find()
|
||||||
|
let users: string[] = records.map(r => r.user)
|
||||||
|
// let addressList: string[] = records.map(r => r.address)
|
||||||
|
console.log('users', users.length)
|
||||||
|
console.log(users[0])
|
||||||
|
// const res = await dbMain
|
||||||
|
// .collection('activity_user')
|
||||||
|
// .updateMany({ address: { $in: addressList } }, { $set: { star: 1 } })
|
||||||
|
const res = await dbMain.collection('score_record').updateMany({ user: { $in: users } }, { $set: { star: 1 } })
|
||||||
|
console.log(res)
|
||||||
|
const res1 = await dbMain.collection('activity_box').updateMany({ user: { $in: users } }, { $set: { star: 1 } })
|
||||||
|
console.log(res1)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
console.log('end')
|
||||||
|
process.exit(0)
|
||||||
|
})()
|
Loading…
x
Reference in New Issue
Block a user