reintroduce daily rewards (#1134)
* reintroduce daily rewards * update reward sponsor * daily rewards countdown * update rewards job schedule
This commit is contained in:
parent
54bbb0cc52
commit
fd2008e5d1
|
@ -27,7 +27,7 @@ async function getActiveRewards (models) {
|
|||
return await models.$queryRaw`
|
||||
SELECT
|
||||
(sum(total) / 1000)::INT as total,
|
||||
date_trunc('month', (now() AT TIME ZONE 'America/Chicago') + interval '1 month') AT TIME ZONE 'America/Chicago' as time,
|
||||
date_trunc('day', (now() AT TIME ZONE 'America/Chicago') + interval '1 day') AT TIME ZONE 'America/Chicago' as time,
|
||||
json_build_array(
|
||||
json_build_object('name', 'donations', 'value', (sum(donations) / 1000)::INT),
|
||||
json_build_object('name', 'fees', 'value', (sum(fees) / 1000)::INT),
|
||||
|
@ -36,10 +36,6 @@ async function getActiveRewards (models) {
|
|||
json_build_object('name', 'anon''s stack', 'value', (sum(anons_stack) / 1000)::INT)
|
||||
) AS sources
|
||||
FROM (
|
||||
(SELECT *
|
||||
FROM rewards_days
|
||||
WHERE rewards_days.t >= date_trunc('month', now() AT TIME ZONE 'America/Chicago'))
|
||||
UNION ALL
|
||||
(SELECT * FROM rewards_today)
|
||||
UNION ALL
|
||||
(SELECT * FROM
|
||||
|
@ -79,8 +75,8 @@ async function getRewards (when, models) {
|
|||
throw new GraphQLError('bad date range', { extensions: { code: 'BAD_USER_INPUT' } })
|
||||
}
|
||||
|
||||
if (new Date(when[0]).getTime() > new Date('2024-03-01').getTime()) {
|
||||
// after 3/1/2024, we reward monthly on the 1st
|
||||
if (new Date(when[0]).getTime() > new Date('2024-03-01').getTime() && new Date(when[0]).getTime() < new Date('2024-05-02').getTime()) {
|
||||
// after 3/1/2024 and until 5/1/2024, we reward monthly on the 1st
|
||||
if (new Date(when[0]).getUTCDate() !== 1) {
|
||||
throw new GraphQLError('invalid reward date', { extensions: { code: 'BAD_USER_INPUT' } })
|
||||
}
|
||||
|
@ -159,8 +155,8 @@ export default {
|
|||
leaderboard: async (parent, args, { models, ...context }) => {
|
||||
// get to and from using postgres because it's easier to do there
|
||||
const [{ to, from }] = await models.$queryRaw`
|
||||
SELECT date_trunc('month', (now() AT TIME ZONE 'America/Chicago')) AT TIME ZONE 'America/Chicago' as from,
|
||||
(date_trunc('month', (now() AT TIME ZONE 'America/Chicago')) AT TIME ZONE 'America/Chicago') + interval '1 month - 1 second' as to`
|
||||
SELECT date_trunc('day', (now() AT TIME ZONE 'America/Chicago')) AT TIME ZONE 'America/Chicago' as from,
|
||||
(date_trunc('day', (now() AT TIME ZONE 'America/Chicago')) AT TIME ZONE 'America/Chicago') + interval '1 day - 1 second' as to`
|
||||
return await topUsers(parent, { when: 'custom', to: new Date(to).getTime().toString(), from: new Date(from).getTime().toString(), limit: 100 }, { models, ...context })
|
||||
}
|
||||
},
|
||||
|
|
|
@ -37,7 +37,7 @@ export function CompactLongCountdown (props) {
|
|||
{...props} formatter={props => {
|
||||
return (
|
||||
<>
|
||||
{props.formatted.days
|
||||
{Number(props.formatted.days) > 0
|
||||
? ` ${props.formatted.days}d ${props.formatted.hours}h ${props.formatted.minutes}m ${props.formatted.seconds}s`
|
||||
: ` ${props.formatted.hours}:${props.formatted.minutes}:${props.formatted.seconds}`}
|
||||
</>
|
||||
|
|
119
lib/madness.js
119
lib/madness.js
|
@ -1,101 +1,22 @@
|
|||
export const proportions = [
|
||||
0.08122,
|
||||
0.07,
|
||||
0.06,
|
||||
0.05,
|
||||
0.045,
|
||||
0.04,
|
||||
0.035,
|
||||
0.03,
|
||||
0.029,
|
||||
0.028,
|
||||
0.027,
|
||||
0.026,
|
||||
0.025,
|
||||
0.024,
|
||||
0.023,
|
||||
0.022,
|
||||
0.021,
|
||||
0.02,
|
||||
0.019,
|
||||
0.018,
|
||||
0.017,
|
||||
0.016,
|
||||
0.015,
|
||||
0.014,
|
||||
0.013,
|
||||
0.012,
|
||||
0.011,
|
||||
0.01,
|
||||
0.009,
|
||||
0.0083,
|
||||
0.0077,
|
||||
0.0074,
|
||||
0.0071,
|
||||
0.0068,
|
||||
0.0065,
|
||||
0.0063,
|
||||
0.0061,
|
||||
0.0059,
|
||||
0.0057,
|
||||
0.0055,
|
||||
0.0053,
|
||||
0.0051,
|
||||
0.0049,
|
||||
0.0047,
|
||||
0.0045,
|
||||
0.0043,
|
||||
0.0041,
|
||||
0.0039,
|
||||
0.0037,
|
||||
0.0036,
|
||||
0.0035,
|
||||
0.0034,
|
||||
0.0033,
|
||||
0.0032,
|
||||
0.0031,
|
||||
0.003,
|
||||
0.0029,
|
||||
0.0028,
|
||||
0.0027,
|
||||
0.0026,
|
||||
0.0025,
|
||||
0.0024,
|
||||
0.0023,
|
||||
0.0022,
|
||||
0.0021,
|
||||
0.002,
|
||||
0.0019,
|
||||
0.0018,
|
||||
0.0017,
|
||||
0.0016,
|
||||
0.0015,
|
||||
0.0014,
|
||||
0.0013,
|
||||
0.0012,
|
||||
0.0011,
|
||||
0.001,
|
||||
0.0009,
|
||||
0.0008,
|
||||
0.00078,
|
||||
0.00076,
|
||||
0.00074,
|
||||
0.00072,
|
||||
0.0007,
|
||||
0.00068,
|
||||
0.00066,
|
||||
0.00064,
|
||||
0.00062,
|
||||
0.0006,
|
||||
0.00058,
|
||||
0.00056,
|
||||
0.00054,
|
||||
0.00052,
|
||||
0.0005,
|
||||
0.00048,
|
||||
0.00046,
|
||||
0.00044,
|
||||
0.00042,
|
||||
0.0004,
|
||||
0.00038
|
||||
0.07575508, 0.06619601, 0.05835029, 0.05183037, 0.0463526,
|
||||
0.04170543, 0.0377285, 0.03429843, 0.03131904, 0.02871442,
|
||||
0.02642405, 0.02439916, 0.0226001, 0.0209944, 0.01955519,
|
||||
0.01826016, 0.0170906, 0.01603075, 0.01506725, 0.01418874,
|
||||
0.01338546, 0.01264904, 0.01197222, 0.01134872, 0.01077306,
|
||||
0.01024046, 0.0097467, 0.00928808, 0.00886135, 0.00846359,
|
||||
0.00809223, 0.00774497, 0.00741977, 0.0071148, 0.00682839,
|
||||
0.00655908, 0.00630551, 0.00606648, 0.0058409, 0.00562778,
|
||||
0.0054262, 0.00523534, 0.00505446, 0.00488287, 0.00471994,
|
||||
0.0045651, 0.00441782, 0.0042776, 0.00414401, 0.00401663,
|
||||
0.00389509, 0.00377902, 0.00366811, 0.00356204, 0.00346055,
|
||||
0.00336337, 0.00327026, 0.003181, 0.00309537, 0.00301318,
|
||||
0.00293424, 0.0028584, 0.00278548, 0.00271534, 0.00264783,
|
||||
0.00258284, 0.00252022, 0.00245988, 0.00240169, 0.00234556,
|
||||
0.00229139, 0.0022391, 0.00218858, 0.00213978, 0.00209259,
|
||||
0.00204697, 0.00200283, 0.00196012, 0.00191877, 0.00187873,
|
||||
0.00183994, 0.00180234, 0.0017659, 0.00173056, 0.00169628,
|
||||
0.00166301, 0.00163072, 0.00159937, 0.00156893, 0.00153935,
|
||||
0.00151061, 0.00148267, 0.00145551, 0.00142909, 0.00140339,
|
||||
0.00137839, 0.00135405, 0.00133035, 0.00130728, 0.00128481
|
||||
]
|
||||
|
|
|
@ -108,11 +108,10 @@ export default function Rewards ({ ssrData }) {
|
|||
if (!dat) return <PageLoading />
|
||||
|
||||
function EstimatedReward ({ rank }) {
|
||||
const totalRest = total - 1000000
|
||||
return (
|
||||
<div className='text-muted fst-italic'>
|
||||
<small>
|
||||
<span>estimated reward: {numWithUnits(rank === 1 ? 1000000 : Math.floor(totalRest * proportions[rank - 2]))}</span>
|
||||
<span>estimated reward: {numWithUnits(Math.floor(total * proportions[rank - 1]))}</span>
|
||||
</small>
|
||||
</div>
|
||||
)
|
||||
|
@ -120,10 +119,9 @@ export default function Rewards ({ ssrData }) {
|
|||
|
||||
return (
|
||||
<Layout footerLinks>
|
||||
<Link className='text-reset align-self-center' href='https://btcplusplus.dev/conf/atx24?ref=stackernews' target='_blank' rel='noreferrer'>
|
||||
<Link className='text-reset align-self-center' href='/items/141924'>
|
||||
<h4 className='pt-3 text-start text-reset' style={{ lineHeight: 1.5, textDecoration: 'underline' }}>
|
||||
bitcoin++ is a developer-focused conference series.
|
||||
<div>Join us in Austin May 1-4 for a deep dive into bitcoin script.</div>
|
||||
rewards are sponsored by ... we are hiring
|
||||
</h4>
|
||||
</Link>
|
||||
<Row className='pb-3'>
|
||||
|
|
|
@ -7,7 +7,6 @@ import Snl from '@/components/snl'
|
|||
import { useQuery } from '@apollo/client'
|
||||
import PageLoading from '@/components/page-loading'
|
||||
import TerritoryHeader from '@/components/territory-header'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps({
|
||||
query: SUB_ITEMS,
|
||||
|
@ -30,14 +29,6 @@ export default function Sub ({ ssrData }) {
|
|||
<>
|
||||
<Snl />
|
||||
</>)}
|
||||
<small className='pb-3 px-1 text-muted' style={{ marginTop: '-0.25rem', lineHeight: 1.5 }}>
|
||||
<Link className='text-reset' href='/rewards' style={{ textDecoration: 'underline' }}>
|
||||
Million Sat Madness
|
||||
</Link> is sponsored by{' '}
|
||||
<Link className='text-reset' href='https://btcplusplus.dev/conf/atx24?ref=stackernews' target='_blank' rel='noreferrer' style={{ textDecoration: 'underline' }}>
|
||||
the Bitcoin++ Conference in Austin May 1-4
|
||||
</Link>
|
||||
</small>
|
||||
<Items ssrData={ssrData} variables={variables} />
|
||||
</Layout>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
CREATE OR REPLACE FUNCTION reschedule_earn_job()
|
||||
RETURNS INTEGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
BEGIN
|
||||
UPDATE pgboss.schedule set cron = '0 0 * * *' WHERE name = 'earn';
|
||||
return 0;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
return 0;
|
||||
END;
|
||||
$$;
|
||||
|
||||
SELECT reschedule_earn_job();
|
||||
DROP FUNCTION IF EXISTS reschedule_earn_job;
|
|
@ -4,18 +4,17 @@ import { PrismaClient } from '@prisma/client'
|
|||
import { proportions } from '@/lib/madness.js'
|
||||
import { SN_NO_REWARDS_IDS } from '@/lib/constants.js'
|
||||
|
||||
const TOTAL_UPPER_BOUND_MSATS = 10000000000
|
||||
const TOTAL_UPPER_BOUND_MSATS = 1_000_000_000
|
||||
|
||||
export async function earn ({ name }) {
|
||||
// grab a greedy connection
|
||||
const models = new PrismaClient()
|
||||
|
||||
try {
|
||||
// compute how much sn earned got the month
|
||||
// compute how much sn earned yesterday
|
||||
const [{ sum: sumDecimal }] = await models.$queryRaw`
|
||||
SELECT coalesce(sum(total), 0) as sum
|
||||
FROM rewards_days
|
||||
WHERE date_trunc('month', rewards_days.t) = date_trunc('month', (now() AT TIME ZONE 'America/Chicago' - interval '1 month'))`
|
||||
SELECT total as sum
|
||||
FROM rewards(now() AT TIME ZONE 'America/Chicago' - interval '1 day', now() AT TIME ZONE 'America/Chicago' - interval '1 day', '1 day'::INTERVAL, 'day')`
|
||||
|
||||
// XXX primsa will return a Decimal (https://mikemcl.github.io/decimal.js)
|
||||
// because sum of a BIGINT returns a NUMERIC type (https://www.postgresql.org/docs/13/functions-aggregate.html)
|
||||
|
@ -52,11 +51,9 @@ export async function earn ({ name }) {
|
|||
|
||||
// get earners { userId, id, type, rank, proportion }
|
||||
const earners = await models.$queryRaw`
|
||||
SELECT id AS "userId", sum(proportion) as proportion, ROW_NUMBER() OVER (ORDER BY sum(proportion) DESC) as rank
|
||||
FROM user_values_days
|
||||
WHERE date_trunc('month', user_values_days.t) = date_trunc('month', (now() AT TIME ZONE 'America/Chicago' - interval '1 month'))
|
||||
AND NOT (id = ANY (${SN_NO_REWARDS_IDS}))
|
||||
GROUP BY id
|
||||
SELECT id AS "userId", proportion, ROW_NUMBER() OVER (ORDER BY proportion DESC) as rank
|
||||
FROM user_values_days(now() AT TIME ZONE 'America/Chicago' - interval '1 day', now() AT TIME ZONE 'America/Chicago' - interval '1 day', '1 day'::INTERVAL, 'day')
|
||||
WHERE NOT (id = ANY (${SN_NO_REWARDS_IDS}))
|
||||
ORDER BY proportion DESC
|
||||
LIMIT 100`
|
||||
|
||||
|
@ -69,14 +66,7 @@ export async function earn ({ name }) {
|
|||
|
||||
const notifications = {}
|
||||
for (const [i, earner] of earners.entries()) {
|
||||
let earnings = 0
|
||||
if (i === 0) {
|
||||
// top earner gets 1m sats
|
||||
earnings = 1_000_000_000
|
||||
} else {
|
||||
// everyone else gets a proportion of the total
|
||||
earnings = Math.floor(parseFloat(proportions[i - 1] * (sum - 1_000_000_000)))
|
||||
}
|
||||
const earnings = Math.floor(parseFloat(proportions[i] * sum))
|
||||
total += earnings
|
||||
if (total > sum) {
|
||||
console.log(name, 'total exceeds sum', total, '>', sum)
|
||||
|
|
Loading…
Reference in New Issue