Skip to content

Commit

Permalink
Add FuelChampion api
Browse files Browse the repository at this point in the history
  • Loading branch information
PooyaFekri committed Jan 3, 2024
1 parent d97996e commit 338a363
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 18 deletions.
59 changes: 43 additions & 16 deletions faucet/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,22 @@ class Meta:
"is_one_time_claim",
]

# def get_claimed(self, chain) -> int:
# user = self.context["request"].user

# if not user.is_authenticated:
# return "N/A"
# user_profile = user.profile
# return CreditStrategyFactory(chain, user_profile).get_strategy().get_claimed()
# def get_claimed(self, chain) -> int:
# user = self.context["request"].user

# def get_unclaimed(self, chain) -> int:
# user = self.context["request"].user
# if not user.is_authenticated:
# return "N/A"
# user_profile = user.profile
# return CreditStrategyFactory(chain, user_profile).get_strategy().get_claimed()

# if not user.is_authenticated:
# return "N/A"
# user_profile = user.profile
# return CreditStrategyFactory(chain, user_profile).get_strategy().get_unclaimed()
# def get_unclaimed(self, chain) -> int:
# user = self.context["request"].user

# if not user.is_authenticated:
# return "N/A"
# user_profile = user.profile
# return CreditStrategyFactory(chain, user_profile).get_strategy().get_unclaimed()


class ReceiptSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -180,19 +181,45 @@ def _validate_chain(self, pk: str):
try:
chain: Chain = Chain.objects.get(pk=pk, chain_type="EVM")
except Chain.DoesNotExist:
raise serializers.ValidationError({"chain": "chain is not EVM or does not exist."})
raise serializers.ValidationError(
{"chain": "chain is not EVM or does not exist."}
)
return chain

class Meta:
model = DonationReceipt
depth = 1
fields = ["tx_hash", "chain", "datetime", "total_price", "value", "chain_pk", "status", "user_profile"]
read_only_fields = ["value", "datetime", "total_price", "chain", "status", "user_profile"]
fields = [
"tx_hash",
"chain",
"datetime",
"total_price",
"value",
"chain_pk",
"status",
"user_profile",
]
read_only_fields = [
"value",
"datetime",
"total_price",
"chain",
"status",
"user_profile",
]


class LeaderboardSerializer(serializers.Serializer):
username = serializers.CharField(max_length=150, read_only=True)
sum_total_price = serializers.CharField(max_length=150, read_only=True)
interacted_chains = serializers.ListField(child=serializers.IntegerField(), read_only=True)
interacted_chains = serializers.ListField(
child=serializers.IntegerField(), read_only=True
)
wallet = serializers.CharField(max_length=512, read_only=True)
rank = serializers.IntegerField(read_only=True, required=False)


class FuelChampionSerializer(serializers.Serializer):
chain_pk = serializers.CharField(max_length=20, read_only=True)
username = serializers.CharField(max_length=150, read_only=True)
donation_amount = serializers.FloatField(read_only=True, required=False)
91 changes: 91 additions & 0 deletions faucet/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from unittest import skipIf
from unittest.mock import patch

from django.core.cache import cache
from django.urls import reverse
from django.utils import timezone
from rest_framework.test import APITestCase
Expand Down Expand Up @@ -710,3 +711,93 @@ def test_optimism_donation_contraint(self):
# self.wallet.address = "0xB9e291b68E584be657477289389B3a6DEED3E34C"
# self.wallet.save()
# self.assertFalse(constraint.is_observed())


class TestFuelChampion(APITestCase):
def setUp(self) -> None:
self.wallet = WalletAccount.objects.create(
name="Test Wallet", private_key=test_wallet_key
)

self.test_chain = create_test_chain(self.wallet)

self.optimism = Chain.objects.create(
chain_name="Optimism",
native_currency_name="ETH",
symbol="ETH",
rpc_url_private="https://optimism.llamarpc.com",
wallet=self.wallet,
fund_manager_address="0xb3A97684Eb67182BAa7994b226e6315196D8b364",
chain_id=10,
max_claim_amount=t_chain_max,
explorer_url="https://optimistic.etherscan.io/",
explorer_api_url="https://api-optimistic.etherscan.io",
explorer_api_key="6PGF5HBTT7DG9CQCQZK3MWR9146JAWQKAC",
)

self.user_profile = create_new_user(
"0x5A73E32a77E04Fb3285608B0AdEaa000B8e248F4"
)
self.wallet = Wallet.objects.create(
user_profile=self.user_profile,
wallet_type=NetworkTypes.EVM,
address="0x5A73E32a77E04Fb3285608B0AdEaa000B8e248F2",
)
self.client.force_authenticate(user=self.user_profile.user)

def test_get_unverified_fuel_champion(self):
cache.delete("FuelChampionQuerySet")
endpoint = reverse("FAUCET:gas-tap-fuel-champion")
DonationReceipt.objects.create(
user_profile=self.user_profile,
tx_hash="0x0",
chain=self.test_chain,
value=10,
)
res = self.client.get(endpoint)
self.assertEqual(res.status_code, 200)
self.assertEqual(len(res.data), 0)

def test_get_verified_fuel_champion(self):
cache.delete("FuelChampionQuerySet")
endpoint = reverse("FAUCET:gas-tap-fuel-champion")
DonationReceipt.objects.create(
user_profile=self.user_profile,
tx_hash="0x0",
chain=self.test_chain,
value=10,
status=ClaimReceipt.VERIFIED,
)
res = self.client.get(endpoint)
self.assertEqual(res.status_code, 200)
self.assertEqual(len(res.data), 1)

def test_get_fuel_champion_when_two_person_had_donation(self):
cache.delete("FuelChampionQuerySet")
endpoint = reverse("FAUCET:gas-tap-fuel-champion")
DonationReceipt.objects.create(
user_profile=self.user_profile,
tx_hash="0x0",
chain=self.test_chain,
value=10,
status=ClaimReceipt.VERIFIED,
)
DonationReceipt.objects.create(
user_profile=self.user_profile,
tx_hash="0x1",
chain=self.test_chain,
value=100,
status=ClaimReceipt.VERIFIED,
)
test_user = create_new_user("0x5A73E32a77E04Fb3285608B0AdEaa000B8e248F3")
DonationReceipt.objects.create(
user_profile=test_user,
tx_hash="0x2",
chain=self.test_chain,
value=10,
status=ClaimReceipt.VERIFIED,
)
res = self.client.get(endpoint)
self.assertEqual(res.status_code, 200)
self.assertEqual(len(res.data), 1)
self.assertEqual(res.data[-1].get("donation_amount", 0), 110)
12 changes: 11 additions & 1 deletion faucet/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ClaimCountView,
ClaimMaxView,
DonationReceiptView,
FuelChampionView,
GetTotalRoundClaimsRemainingView,
GlobalSettingsView,
LastClaimView,
Expand Down Expand Up @@ -66,5 +67,14 @@
),
path("user/donation/", DonationReceiptView.as_view(), name="donation-receipt"),
path("gas-tap/leaderboard/", LeaderboardView.as_view(), name="gas-tap-leaderboard"),
path("user/gas-tap/leaderboard/", UserLeaderboardView.as_view(), name="user-gas-tap-leaderboard"),
path(
"gas-tap/fuel-champion/",
FuelChampionView.as_view(),
name="gas-tap-fuel-champion",
),
path(
"user/gas-tap/leaderboard/",
UserLeaderboardView.as_view(),
name="user-gas-tap-leaderboard",
),
]
52 changes: 51 additions & 1 deletion faucet/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import rest_framework.exceptions
from django.conf import settings
from django.contrib.postgres.expressions import ArraySubquery
from django.db.models import FloatField, OuterRef, Subquery, Sum
from django.core.cache import cache
from django.db.models import F, FloatField, OuterRef, Subquery, Sum
from django.db.models.functions import Cast
from django.http import FileResponse, Http404, HttpResponse
from django.urls import reverse
Expand All @@ -34,6 +35,7 @@
ChainBalanceSerializer,
ChainSerializer,
DonationReceiptSerializer,
FuelChampionSerializer,
GlobalSettingsSerializer,
LeaderboardSerializer,
ReceiptSerializer,
Expand Down Expand Up @@ -341,6 +343,54 @@ def list(self, request, *args, **kwargs):
return Response(serializer.data)


class FuelChampionView(ListAPIView):
serializer_class = FuelChampionSerializer

def get_queryset(self):
queryset = cache.get("FuelChampionQuerySet")
if queryset is not None:
return queryset
round_datetime = RoundCreditStrategy.get_start_of_the_round()
subquery_user_profile = (
DonationReceipt.objects.filter(status=ClaimReceipt.VERIFIED)
.filter(datetime__gt=round_datetime)
.filter(chain=OuterRef("chain"))
.annotate(float_value=Cast("value", FloatField()))
.values("user_profile", "chain")
.annotate(value=Sum("float_value"))
.order_by("-value")
.values("user_profile")[:1]
)
subquery_donation_amount = (
DonationReceipt.objects.filter(status=ClaimReceipt.VERIFIED)
.filter(datetime__gt=round_datetime)
.filter(chain=OuterRef("chain"))
.filter(user_profile=OuterRef("user_profile"))
.annotate(float_value=Cast("value", FloatField()))
.values("user_profile", "chain")
.annotate(value=Sum("float_value"))
.order_by("-value")
.values("value")
)
username_subquery = UserProfile.objects.filter(
pk=OuterRef("user_profile")
).values("username")
queryset = (
DonationReceipt.objects.values("chain", "user_profile")
.annotate(max_user_profile=Subquery(subquery_user_profile))
.filter(max_user_profile__isnull=False)
.filter(user_profile=F("max_user_profile"))
.annotate(donation_amount=subquery_donation_amount)
.annotate(chain_pk=F("chain"))
.annotate(username=username_subquery)
.values("donation_amount", "chain_pk", "username")
.distinct()
)

cache.set("FuelChampionQuerySet", queryset, timeout=120)
return queryset


def artwork_video(request):
video_file = os.path.join(settings.BASE_DIR, "faucet/artwork.mp4")
return FileResponse(open(video_file, "rb"), content_type="video/mp4")
Expand Down

0 comments on commit 338a363

Please sign in to comment.