make earning more tangible

This commit is contained in:
keyan 2022-07-07 14:14:22 -05:00
parent 9581160944
commit 7aa6a02a08
3 changed files with 61 additions and 80 deletions

View File

@ -1,25 +0,0 @@
// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function
// const z = 1.281551565545 // 80% confidence
// const z = 1.644853626951 // 90% confidence
// const z = 1.959963984540 // 95% confidence
const z = 3.090232306168 // 98% confidence
function confidence (s, n) {
if (n === 0) {
return 0
}
const p = s / n
const left = p + 1 / (2 * n) * z * z
const right = z * Math.sqrt(p * (1 - p) / n + z * z / (4 * n * n))
const under = 1 + 1 / n * z * z
return (left - right) / under
}
console.log(confidence(process.argv[2], process.argv[3]))
/*
Need to describe how they'll earn
If we trust upvotes how can we use that to determine the best
*/

View File

@ -1,5 +1,10 @@
const serialize = require('../api/resolvers/serial') const serialize = require('../api/resolvers/serial')
const ITEM_EACH_REWARD = 3.0
const UPVOTE_EACH_REWARD = 6.0
const TOP_ITEMS = 21
const EARLY_MULTIPLIER_MAX = 100.0
// TODO: use a weekly trust measure or make trust decay // TODO: use a weekly trust measure or make trust decay
function earn ({ models }) { function earn ({ models }) {
return async function ({ name }) { return async function ({ name }) {
@ -14,18 +19,63 @@ function earn ({ models }) {
OR ("ItemAct".act = 'VOTE' AND "Item"."userId" = "ItemAct"."userId")) OR ("ItemAct".act = 'VOTE' AND "Item"."userId" = "ItemAct"."userId"))
AND "ItemAct".created_at > now_utc() - INTERVAL '1 day'` AND "ItemAct".created_at > now_utc() - INTERVAL '1 day'`
// calculate the total trust /*
const { sum: { trust } } = await models.user.aggregate({ How earnings work:
sum: { 1/3: top 21 posts over last 36 hours, scored on a relative basis
trust: true 1/3: top 21 comments over last 36 hours, scored on a relative basis
} 1/3: top upvoters of top posts/comments, scored on:
}) - their trust
- how much they tipped
- how early they upvoted it
- how the post/comment scored
*/
// get earners { id, earnings } // get earners { id, earnings }
const earners = await models.$queryRaw(` const earners = await models.$queryRaw(`
SELECT id, FLOOR(${sum} * (trust/${trust}) * 1000) as earnings WITH item_ratios AS (
FROM users SELECT *,
WHERE trust > 0`) "weightedVotes"/(sum("weightedVotes") OVER (PARTITION BY "parentId" IS NULL)) AS ratio
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY "parentId" IS NULL ORDER BY "weightedVotes" desc) AS r
FROM
"Item"
WHERE created_at >= now_utc() - interval '36 hours'
) x
WHERE x.r <= ${TOP_ITEMS}
),
upvoters AS (
SELECT "ItemAct"."userId", item_ratios.id, item_ratios.ratio, item_ratios."parentId",
sum("ItemAct".sats) as tipped, min("ItemAct".created_at) as acted_at
FROM item_ratios
JOIN "ItemAct" on "ItemAct"."itemId" = item_ratios.id
WHERE act IN ('VOTE','TIP')
AND "ItemAct"."userId" <> item_ratios."userId"
GROUP BY "ItemAct"."userId", item_ratios.id, item_ratios.ratio, item_ratios."parentId"
),
upvoter_ratios AS (
SELECT "userId", sum(early_multiplier*tipped_ratio*ratio*users.trust) as upvoting_score,
"parentId" IS NULL as "isPost"
FROM (
SELECT *,
${EARLY_MULTIPLIER_MAX}/(ROW_NUMBER() OVER (partition by id order by acted_at asc)) AS early_multiplier,
tipped::float/(sum(tipped) OVER (partition by id)) tipped_ratio
FROM upvoters
) u
JOIN users on "userId" = users.id
GROUP BY "userId", "parentId" IS NULL
)
SELECT "userId" as id, FLOOR(sum(proportion)*${sum}*1000) as earnings
FROM (
SELECT "userId",
upvoting_score/(sum(upvoting_score) OVER (PARTITION BY "isPost"))/${UPVOTE_EACH_REWARD} as proportion
FROM upvoter_ratios
UNION ALL
SELECT "userId", ratio/${ITEM_EACH_REWARD} as proportion
FROM item_ratios
) a
GROUP BY "userId"
HAVING FLOOR(sum(proportion)*${sum}) >= 1`)
// for each earner, serialize earnings // for each earner, serialize earnings
// we do this for each earner because we don't need to serialize // we do this for each earner because we don't need to serialize
@ -41,47 +91,4 @@ function earn ({ models }) {
} }
} }
// earn historical ... TODO: delete after announcement module.exports = { earn }
function earnHistorical ({ models }) {
return async function ({ name }) {
console.log('running', name)
// compute how much sn earned today
const [{ sum }] = await models.$queryRaw`
SELECT sum("ItemAct".sats)
FROM "ItemAct"
JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE ("ItemAct".act in ('BOOST', 'STREAM')
OR ("ItemAct".act = 'VOTE' AND "Item"."userId" = "ItemAct"."userId"))`
// add in the job sats that weren't recorded from jobs
const fullSum = 200000 + sum
// calculate the total trust
const { sum: { trust } } = await models.user.aggregate({
sum: {
trust: true
}
})
// get earners { id, earnings }
const earners = await models.$queryRaw(`
SELECT id, FLOOR(${fullSum} * (trust/${trust}) * 1000) as earnings
FROM users
WHERE trust > 0`)
// for each earner, serialize earnings
// we do this for each earner because we don't need to serialize
// all earner updates together
earners.forEach(async earner => {
if (earner.earnings > 0) {
await serialize(models,
models.$executeRaw`SELECT earn(${earner.id}, ${earner.earnings})`)
}
})
console.log('done', name)
}
}
module.exports = { earn, earnHistorical }

View File

@ -6,7 +6,7 @@ const { checkInvoice, checkWithdrawal } = require('./wallet')
const { repin } = require('./repin') const { repin } = require('./repin')
const { trust } = require('./trust') const { trust } = require('./trust')
const { auction } = require('./auction') const { auction } = require('./auction')
const { earn, earnHistorical } = require('./earn') const { earn } = require('./earn')
const { ApolloClient, HttpLink, InMemoryCache } = require('@apollo/client') const { ApolloClient, HttpLink, InMemoryCache } = require('@apollo/client')
const { indexItem, indexAllItems } = require('./search') const { indexItem, indexAllItems } = require('./search')
const fetch = require('cross-fetch') const fetch = require('cross-fetch')
@ -45,7 +45,6 @@ async function work () {
await boss.work('indexAllItems', indexAllItems(args)) await boss.work('indexAllItems', indexAllItems(args))
await boss.work('auction', auction(args)) await boss.work('auction', auction(args))
await boss.work('earn', earn(args)) await boss.work('earn', earn(args))
await boss.work('earnHistorical', earnHistorical(args))
console.log('working jobs') console.log('working jobs')
} }