Skip to content

Commit

Permalink
Introduce sign transfer assets automation
Browse files Browse the repository at this point in the history
  • Loading branch information
ipdae committed Sep 20, 2024
1 parent 5187177 commit 79d7a9a
Show file tree
Hide file tree
Showing 10 changed files with 379 additions and 116 deletions.
158 changes: 48 additions & 110 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ strawberry-graphql = {extras = ["fastapi"], version = "^0.215.1"}
gql = {extras = ["aiohttp", "requests"], version = "^3.4.1"}
pyjwt = "^2.8.0"
types-requests = "^2.31.0.20240125"
apscheduler = "^3.10.4"


[tool.poetry.group.dev.dependencies]
Expand Down
45 changes: 44 additions & 1 deletion tests/raid_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from datetime import datetime, timezone
import typing
from datetime import date, datetime, timezone
from typing import List
from unittest.mock import patch

import bencodex
import pytest
from sqlalchemy.orm import Session

from world_boss.app.cache import cache_exists
from world_boss.app.enums import NetworkType
Expand All @@ -11,7 +14,10 @@
from world_boss.app.raid import (
create_unsigned_tx,
get_assets,
get_latest_raid_id,
get_next_month_last_day,
get_next_tx_nonce,
get_reward_count,
get_transfer_assets_plain_value,
get_tx_delay_factor,
list_tx_nonce,
Expand Down Expand Up @@ -344,3 +350,40 @@ def test_create_unsigned_tx(
b"u": [],
}
assert bencodex.dumps(expected) == actual


@pytest.mark.parametrize("season, expected", [(None, 1), (1, 1), (2, 2)])
def test_get_latest_season(
fx_session: Session, season: typing.Optional[int], expected: int
):
if season:
reward = WorldBossReward()
reward.raid_id = season
avatar_address = "avatar_address"
agent_address = "agent_address"
reward.avatar_address = avatar_address
reward.agent_address = agent_address
reward.ranking = 1
fx_session.add(reward)
fx_session.commit()
assert get_latest_raid_id(fx_session) == expected


def test_get_reward_count(fx_session: Session):
reward = WorldBossReward()
reward.raid_id = 1
avatar_address = "avatar_address"
agent_address = "agent_address"
reward.avatar_address = avatar_address
reward.agent_address = agent_address
reward.ranking = 1
fx_session.add(reward)
fx_session.commit()
assert get_reward_count(fx_session, 1) == 1
assert get_reward_count(fx_session, 2) == 0


def test_get_next_month_last_day():
with patch("datetime.date") as m:
m.today.return_value = date(2024, 9, 19)
assert get_next_month_last_day() == datetime(2024, 10, 31, tzinfo=timezone.utc)
70 changes: 70 additions & 0 deletions tests/tasks_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
RankingRewardWithAgentDictionary,
)
from world_boss.app.tasks import (
check_season,
check_signer_balance,
count_users,
get_ranking_rewards,
insert_world_boss_rewards,
query_tx_result,
save_ranking_rewards,
send_slack_message,
sign_transfer_assets,
stage_transaction,
Expand Down Expand Up @@ -367,3 +369,71 @@ def test_stage_transactions_with_countdown(
channel=config.slack_channel_id,
text=f"stage {len(fx_transactions)} transactions",
)


def test_check_season(redisdb, celery_session_worker, fx_session, httpx_mock):
raid_id = 1
network_type = NetworkType.MAIN
offset = 0
check_season.delay().get(timeout=10)
httpx_mock.add_response(
method="POST",
url=config.data_provider_url,
json={"data": {"worldBossTotalUsers": 20000}},
)


@pytest.mark.parametrize("exist", [True, False])
def test_save_ranking_rewards(
redisdb,
celery_session_worker,
httpx_mock: HTTPXMock,
fx_ranking_rewards,
fx_session,
exist: bool,
):
raid_id = 1
network_type = NetworkType.MAIN

# get from service query
requested_rewards: List[RankingRewardDictionary] = [
{
"raider": {
"address": "01A0b412721b00bFb5D619378F8ab4E4a97646Ca",
"ranking": 2,
},
"rewards": fx_ranking_rewards,
},
]
httpx_mock.add_response(
method="POST",
url=config.data_provider_url,
json={"data": {"worldBossRankingRewards": requested_rewards}},
)
httpx_mock.add_response(
method="POST",
url=config.headless_url,
json={
"data": {
"stateQuery": {
"arg01A0b412721b00bFb5D619378F8ab4E4a97646Ca": {
"agentAddress": "0x9EBD1b4F9DbB851BccEa0CFF32926d81eDf6De52",
},
}
}
},
)
if exist:
wb = WorldBossReward()
wb.ranking = 2
wb.avatar_address = "01A0b412721b00bFb5D619378F8ab4E4a97646Ca"
wb.agent_address = "0x9EBD1b4F9DbB851BccEa0CFF32926d81eDf6De52"
wb.raid_id = raid_id
fx_session.add(wb)
fx_session.commit()
save_ranking_rewards(raid_id, 500, 1, signer.address)
assert redisdb.exists(f"world_boss_{raid_id}_{network_type}_1_500")
assert redisdb.exists(f"world_boss_agents_{raid_id}_{network_type}_1_500")
assert fx_session.query(Transaction).filter_by(signer=signer.address).count() == 1
assert fx_session.query(WorldBossReward).filter_by(raid_id=raid_id).count() == 1
assert fx_session.query(WorldBossRewardAmount).count() == len(fx_ranking_rewards)
6 changes: 5 additions & 1 deletion world_boss/app/data_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ def get_ranking_rewards(
{"raidId": raid_id, "offset": offset, "limit": limit},
)
if result.get("errors"):
raise Exception(result["errors"][0]["message"])
raise RankingRewardsException(result["errors"][0]["message"])
rewards = result["data"]["worldBossRankingRewards"]
set_to_cache(cache_key, json.dumps(rewards))
return rewards


class RankingRewardsException(Exception):
pass


data_provider_client = DataProviderClient()
9 changes: 5 additions & 4 deletions world_boss/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
String,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, backref, mapped_column, relationship
from sqlalchemy.orm import Mapped, mapped_column, relationship

from world_boss.app.orm import Base
from world_boss.app.schemas import WorldBossRewardAmountSchema, WorldBossRewardSchema
Expand All @@ -25,9 +25,9 @@ class WorldBossRewardAmount(Base):
tx_id: Mapped[str] = mapped_column(
String, ForeignKey("transaction.tx_id"), nullable=False
)
transaction = relationship("Transaction", backref=backref("amounts", lazy=True))
transaction = relationship("Transaction", back_populates="amounts")
reward_id = Column(Integer, ForeignKey("world_boss_reward.id"), nullable=False)
reward = relationship("WorldBossReward", backref=backref("amounts", lazy=True))
reward = relationship("WorldBossReward", back_populates="amounts")
created_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=datetime.utcnow
)
Expand Down Expand Up @@ -56,7 +56,7 @@ class WorldBossReward(Base):
created_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=datetime.utcnow
)
# amounts = relationship('WorldBossRewardAmount', back_populates='reward')
amounts = relationship("WorldBossRewardAmount", back_populates="reward")

__table_args__ = (
UniqueConstraint(raid_id, avatar_address, agent_address),
Expand Down Expand Up @@ -87,5 +87,6 @@ class Transaction(Base):
created_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=datetime.utcnow
)
amounts = relationship("WorldBossRewardAmount", back_populates="transaction")

__table_args__ = (UniqueConstraint(signer, nonce),)
32 changes: 32 additions & 0 deletions world_boss/app/raid.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import calendar
import csv
import datetime
import json
Expand Down Expand Up @@ -357,3 +358,34 @@ def get_genesis_block_hash(planet_id: str) -> bytes:
raise ValueError("Invalid planet id")

return switcher[planet_id]


def get_latest_raid_id(db: Session) -> int:
season = db.query(func.max(WorldBossReward.raid_id)).scalar()
if season is None:
return 1
return season


def get_reward_count(db: Session, raid_id: int) -> int:
return (
db.query(func.count(WorldBossReward.ranking))
.filter_by(raid_id=raid_id)
.scalar()
)


def get_next_month_last_day() -> datetime.datetime:
# Today's date
today = datetime.date.today()

# Calculating the year and month of the next month
next_month_year = today.year + (today.month // 12)
next_month = (today.month % 12) + 1

# Getting the last day of the next month
last_day = calendar.monthrange(next_month_year, next_month)[1]
last_date = datetime.datetime(
next_month_year, next_month, last_day, tzinfo=datetime.timezone.utc
)
return last_date
12 changes: 12 additions & 0 deletions world_boss/app/scheduler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from apscheduler.schedulers.background import BackgroundScheduler

from world_boss.app.tasks import check_season

scheduler = BackgroundScheduler()


def check():
check_season.delay()


scheduler.add_job(check, "interval", seconds=60 * 30)
Loading

0 comments on commit 79d7a9a

Please sign in to comment.