Skip to content

Commit

Permalink
[PAY-1886] Challenge cooldown: created_at migration + backend updates (
Browse files Browse the repository at this point in the history
  • Loading branch information
dharit-tan authored Oct 13, 2023
1 parent b8cd8db commit 5781951
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 10 deletions.
4 changes: 3 additions & 1 deletion packages/common/src/models/AudioRewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export enum FailureReason {
// An unknown error has occurred
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
// Unknown AAO error
AAO_ATTESTATION_UNKNOWN_RESPONSE = 'AAO_ATTESTATION_UNKNOWN_RESPONSE'
AAO_ATTESTATION_UNKNOWN_RESPONSE = 'AAO_ATTESTATION_UNKNOWN_RESPONSE',
// Need to wait for cooldown period
WAIT_FOR_COOLDOWN = 'WAIT_FOR_COOLDOWN'
}

export type FlowUIOpenEvent = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
begin;

ALTER TABLE
user_challenges
ADD
COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW();

ALTER TABLE
challenges
ADD
COLUMN IF NOT EXISTS cooldown_days INTEGER DEFAULT NULL;

commit;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from datetime import datetime, timezone
from typing import Dict, List, Optional

from sqlalchemy.orm.session import Session
Expand Down Expand Up @@ -26,6 +27,12 @@
AGGREGATE_CHALLENGE_STEP_COUNT = 5


def get_created_at():
return datetime.strptime(
"2023-10-13 11:15:10.627328+00", "%Y-%m-%d %H:%M:%S.%f+00"
).replace(tzinfo=timezone.utc)


def setup_challenges(app):
with app.app_context():
db = get_db()
Expand Down Expand Up @@ -71,6 +78,7 @@ def setup_challenges(app):
is_complete=False,
current_step_count=1,
amount=5,
created_at=get_created_at(),
),
UserChallenge(
challenge_id="test_challenge_1",
Expand All @@ -80,6 +88,7 @@ def setup_challenges(app):
current_step_count=3,
completed_blocknumber=100,
amount=5,
created_at=get_created_at(),
),
UserChallenge(
challenge_id="test_challenge_1",
Expand All @@ -88,13 +97,15 @@ def setup_challenges(app):
current_step_count=2,
is_complete=False,
amount=5,
created_at=get_created_at(),
),
UserChallenge(
challenge_id="test_challenge_2",
user_id=4,
specifier="4",
is_complete=True,
amount=5,
created_at=get_created_at(),
),
UserChallenge(
challenge_id="test_challenge_1",
Expand All @@ -103,6 +114,7 @@ def setup_challenges(app):
is_complete=False,
current_step_count=2,
amount=5,
created_at=get_created_at(),
),
]

Expand Down Expand Up @@ -167,6 +179,7 @@ def test_handle_event(app):
"current_step_count": 1,
"completed_blocknumber": None,
"amount": 5,
"created_at": get_created_at(),
}
assert model_to_dictionary(actual) == expected

Expand Down Expand Up @@ -202,6 +215,7 @@ def test_handle_event(app):
"current_step_count": 2,
"completed_blocknumber": None,
"amount": 5,
"created_at": get_created_at(),
},
# Should be unchanged b/c it was already complete
{
Expand All @@ -212,6 +226,7 @@ def test_handle_event(app):
"current_step_count": 3,
"completed_blocknumber": 100,
"amount": 5,
"created_at": get_created_at(),
},
# Should be newly complete
{
Expand All @@ -222,6 +237,7 @@ def test_handle_event(app):
"current_step_count": 3,
"completed_blocknumber": 100,
"amount": 5,
"created_at": get_created_at(),
},
# Should be untouched bc user 5 wasn't included
{
Expand All @@ -232,6 +248,7 @@ def test_handle_event(app):
"current_step_count": 2,
"completed_blocknumber": None,
"amount": 5,
"created_at": get_created_at(),
},
# Should have created a brand new user 6
{
Expand All @@ -244,6 +261,8 @@ def test_handle_event(app):
"amount": 5,
},
]
# the last challenge was just created so we don't know the created_at time
del res_dicts[-1]["created_at"]
assert expected == res_dicts


Expand Down
3 changes: 3 additions & 0 deletions packages/discovery-provider/src/challenges/challenge.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
from abc import ABC
from collections import defaultdict
from datetime import datetime
from typing import Dict, List, Optional, Set, Tuple, TypedDict, cast

import pytz
from sqlalchemy import func
from sqlalchemy.orm.session import Session

Expand Down Expand Up @@ -359,4 +361,5 @@ def _create_new_user_challenge(self, user_id: int, specifier: str, extra: Dict):
), # Aggregates are made in completed state
current_step_count=0,
amount=extra.get("amount", self._amount),
created_at=datetime.now(pytz.UTC),
)
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"active": true,
"step_count": 2147483647,
"starting_block": 0,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
},
{
"id": "s",
Expand All @@ -91,6 +92,7 @@
"active": true,
"step_count": 2147483647,
"starting_block": 0,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
}
]
6 changes: 4 additions & 2 deletions packages/discovery-provider/src/challenges/challenges.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@
"active": true,
"step_count": 2147483647,
"starting_block": 220157041,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
},
{
"id": "s",
Expand All @@ -113,6 +114,7 @@
"active": true,
"step_count": 2147483647,
"starting_block": 220157041,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"active": true,
"step_count": 2147483647,
"starting_block": 0,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
},
{
"id": "s",
Expand All @@ -91,6 +92,7 @@
"active": true,
"step_count": 2147483647,
"starting_block": 0,
"weekly_pool": 25000
"weekly_pool": 25000,
"cooldown_days": 7
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ChallengeJSON(TypedDict):
step_count: Optional[int]
starting_block: Optional[int]
weekly_pool: Optional[int]
cooldown_days: Optional[int]


class OverrideChallengeJson(TypedDict):
Expand Down Expand Up @@ -60,6 +61,7 @@ def get_challenges_dicts():
"starting_block",
"step_count",
"weekly_pool",
"cooldown_days",
]:
if key in override:
challenge[key] = override[key]
Expand Down Expand Up @@ -98,6 +100,7 @@ def create_new_challenges(session, allowed_challenge_types=None):
starting_block=challenge_dict.get("starting_block"),
step_count=challenge_dict.get("step_count"),
weekly_pool=challenge_dict.get("weekly_pool"),
cooldown_days=challenge_dict.get("cooldown_days"),
)
challenges.append(challenge)
session.add_all(challenges)
Expand All @@ -114,3 +117,4 @@ def create_new_challenges(session, allowed_challenge_types=None):
existing.step_count = challenge_dict.get("step_count")
existing.starting_block = challenge_dict.get("starting_block")
existing.weekly_pool = challenge_dict.get("weekly_pool")
existing.cooldown_days = challenge_dict.get("cooldown_days")
2 changes: 2 additions & 0 deletions packages/discovery-provider/src/models/rewards/challenge.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ class Challenge(Base, RepresentableMixin):
starting_block = Column(Integer)
# Optional field to support challenges with a weekly pool
weekly_pool = Column(Integer)
# Number of days to wait before a user can complete the challenge
cooldown_days = Column(Integer)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, text
from sqlalchemy.orm import relationship

from src.models.base import Base
Expand All @@ -19,5 +19,10 @@ class UserChallenge(Base, RepresentableMixin):
current_step_count = Column(Integer)
completed_blocknumber = Column(Integer)
amount = Column(Integer, nullable=False)
created_at = Column(
DateTime,
nullable=False,
server_default=text("CURRENT_TIMESTAMP"),
)

challenge = relationship("Challenge") # type: ignore
12 changes: 10 additions & 2 deletions packages/discovery-provider/src/queries/get_attestation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime
from typing import Tuple

import pytz
from eth_keys import keys
from eth_utils.conversions import to_bytes
from hexbytes import HexBytes
Expand Down Expand Up @@ -30,6 +31,8 @@
REWARDS_MANAGER_ACCOUNT_PUBLIC_KEY = None
if REWARDS_MANAGER_ACCOUNT:
REWARDS_MANAGER_ACCOUNT_PUBLIC_KEY = Pubkey.from_string(REWARDS_MANAGER_ACCOUNT)
COOLDOWN_CHALLENGE_IDS = ["s", "b"]
DATETIME_FORMAT_STRING = "%Y-%m-%d %H:%M:%S.%f+00"


class Attestation:
Expand Down Expand Up @@ -87,6 +90,7 @@ def get_attestation_bytes(self):
INVALID_INPUT = "INVALID_INPUT"
USER_NOT_FOUND = "USER_NOT_FOUND"
POOL_EXHAUSTED = "POOL_EXHAUSTED"
WAIT_FOR_COOLDOWN = "WAIT_FOR_COOLDOWN"


class AttestationError(Exception):
Expand Down Expand Up @@ -162,10 +166,14 @@ def get_attestation(
raise AttestationError(CHALLENGE_INCOMPLETE)
if disbursement:
raise AttestationError(ALREADY_DISBURSED)

now_utc = datetime.now(pytz.UTC)
if challenge_id in COOLDOWN_CHALLENGE_IDS and challenge.cooldown_days:
time_passed = now_utc - user_challenge.created_at
if time_passed.days < challenge.cooldown_days:
raise AttestationError(WAIT_FOR_COOLDOWN)
if challenge.weekly_pool:
disbursed_amount = get_disbursed_challenges_amount(
session, challenge.id, get_weekly_pool_window_start(datetime.now())
session, challenge.id, get_weekly_pool_window_start(now_utc)
)
if disbursed_amount + user_challenge.amount > challenge.weekly_pool:
raise AttestationError(POOL_EXHAUSTED)
Expand Down
1 change: 1 addition & 0 deletions packages/libs/src/api/Rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const GetAttestationError = Object.freeze({
AAO_ATTESTATION_ERROR: 'AAO_ATTESTATION_ERROR',
AAO_ATTESTATION_REJECTION: 'AAO_ATTESTATION_REJECTION',
AAO_ATTESTATION_UNKNOWN_RESPONSE: 'AAO_ATTESTATION_UNKNOWN_RESPONSE',
WAIT_FOR_COOLDOWN: 'WAIT_FOR_COOLDOWN',
UNKNOWN_ERROR: 'UNKNOWN_ERROR'
})

Expand Down
3 changes: 3 additions & 0 deletions packages/web/src/common/store/pages/audio-rewards/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ function* claimChallengeRewardAsync(
case FailureReason.CHALLENGE_INCOMPLETE:
yield put(claimChallengeRewardFailed())
break
case FailureReason.WAIT_FOR_COOLDOWN:
yield put(claimChallengeRewardFailed())
break
case FailureReason.UNKNOWN_ERROR:
default:
// If there is an AAO error code, then the AAO must have
Expand Down

0 comments on commit 5781951

Please sign in to comment.