Skip to content

Commit

Permalink
rebase: to master
Browse files Browse the repository at this point in the history
  • Loading branch information
aziolek committed Feb 5, 2025
1 parent 7a4dbda commit 2da8117
Show file tree
Hide file tree
Showing 69 changed files with 249 additions and 3,504 deletions.
1 change: 0 additions & 1 deletion backend/app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
SAFE_API_SEPOLIA = "https://safe-transaction-sepolia.safe.global/api/v1"

DEFAULT_MAINNET_PROJECT_CIDS = "QmSQEFD35gKxdPEmngNt1CWe3kSwiiGqBn1Z3FZvWb8mvK,Qmds9N5y2vkMuPTD6M4EBxNXnf3bjTDmzWBGnCkQGsMMGe,QmSXcT18anMXKACTueom8GXw8zrxTBbHGB71atitf6gZ9V,QmXomSdCCwt4FtBp3pidqSz3PtaiV2EyQikU6zRGWeCAsf,QmdtFLK3sB7EwQTNaqtmBnZqnN2pYZcu6GmUSTrpvb9wcq"
DEFAULT_PROJECTS_CONTRACT_ADDRESS = "0xB259fe6EC190cffF893b247AE688eFBF4261D2fc"

EPOCH0_SYBILS = [
"0xde19a6ce83cc934e5d4c4573f0f026c02c984fb2",
Expand Down
4 changes: 2 additions & 2 deletions backend/app/infrastructure/contracts/erc20.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def glm_fund(self, to_address, nonce):
return self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)

def transfer(self, sender, receiver: str, amount: int):
nonce = self.w3.eth.get_transaction_count(sender.address, "pending")
nonce = self.w3.eth.get_transaction_count(sender.address)
transaction = self.contract.functions.transfer(
receiver, amount
).build_transaction({"from": sender.address, "nonce": nonce})
Expand All @@ -26,7 +26,7 @@ def approve(self, owner, benefactor, wad: int):
print("owner address: ", owner.address)
print("owner key: ", owner.key)
print("benefactor of lock: ", benefactor)
nonce = self.w3.eth.get_transaction_count(owner.address, "pending")
nonce = self.w3.eth.get_transaction_count(owner.address)
transaction = self.contract.functions.approve(
benefactor, wad
).build_transaction({"from": owner.address, "nonce": nonce})
Expand Down
5 changes: 1 addition & 4 deletions backend/app/modules/common/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ def timestamp_s(self) -> float:
return self.timestamp_us() / 10**6

def datetime(self) -> DateTime:
# Make sure the timestamp is in UTC and not local
utc_timestamp = DateTime.fromtimestamp(self.timestamp_s(), timezone.utc)
# Remove timezone info
return utc_timestamp.replace(tzinfo=None)
return DateTime.fromtimestamp(self.timestamp_s())

def to_isoformat(self):
return self.datetime().isoformat()
Expand Down
6 changes: 3 additions & 3 deletions backend/app/modules/projects/details/controller.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Dict

from app.context.manager import epoch_context
from app.modules.registry import get_services
Expand All @@ -7,7 +7,7 @@

def get_projects_details_for_multiple_params(
epochs: List[int], search_phrases: List[str]
) -> list[dict[str, str]]:
) -> List[Dict[str, str]]:
searched_projects = []
for epoch in epochs:
for search_phrase in search_phrases:
Expand All @@ -16,7 +16,7 @@ def get_projects_details_for_multiple_params(
return searched_projects


def get_projects_details(epoch: int, search_phrase: str) -> list[dict[str, str]]:
def get_projects_details(epoch: int, search_phrase: str) -> List[Dict[str, str]]:
context = epoch_context(epoch)

service = get_services(context.epoch_state).projects_details_service
Expand Down
121 changes: 58 additions & 63 deletions backend/app/modules/user/events_generator/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,13 @@
from app.engine.user.effective_deposit import DepositEvent, EventType, DepositSource


def _remove_redundant_events_within_grace_period(
modified_events: List[DepositEvent], sablier_unlock_grace_period: int
) -> List[DepositEvent]:
i = 0
while i < len(modified_events) - 1:
current_event = modified_events[i]
next_event = modified_events[i + 1]

is_unlock_lock_pair = (
current_event.type == EventType.UNLOCK
and next_event.type == EventType.LOCK
and current_event.source == DepositSource.SABLIER
and next_event.source == DepositSource.OCTANT
and next_event.timestamp - current_event.timestamp
< sablier_unlock_grace_period
)

if is_unlock_lock_pair:
if current_event.amount == next_event.amount:
del modified_events[i : i + 2]
continue
elif current_event.amount < next_event.amount:
excessive_amount = next_event.amount - current_event.amount
next_event.amount = excessive_amount
next_event.deposit_before = current_event.deposit_before
next_event.deposit_after = next_event.deposit_before + excessive_amount
del modified_events[i]
continue

i += 1

return modified_events


def unify_deposit_balances(
events: List[DepositEvent], sablier_unlock_grace_period: int
) -> List[DepositEvent]:
"""
Unify deposit balance for each event in the list of events. Events are expected to be sorted by timestamp.
The first event is taken from deposits, but it already includes deposit from Sablier from the past.
Scenario 1:
The user unlocks amount X from Sablier, then locks the same amount X in the Octant contract within the grace period.
==> Such an unlock and lock have no effect and are considered transparent.
Scenario 2:
The user unlocks amount X from Sablier, then locks the amount X - 100 in the Octant contract within the grace period.
==> We treat such events as they occur, meaning a normal unlock of X and a normal lock of X - 100.
Scenario 3:
The user unlocks amount X from Sablier, then locks the amount X + 100 (in a directly subsequent lock) in the Octant contract within the grace period.
==> This unlock should be treated as transparent and only recording the lock for the amount of X + 100 - X = 100, with the timestamp of when the lock occurred.
Returns:
List[DepositEvent]: A list of events with adjusted `deposit_before` and `deposit_after`.
"""
Expand All @@ -65,26 +19,67 @@ def unify_deposit_balances(
acc_balance_sablier = 0
acc_balance_octant = events[0].deposit_before # balance from previous epoch

for event in modified_events[1:]:
i = 0
while i < len(modified_events) - 1:
current_event = modified_events[i]
next_event = modified_events[i + 1]

if current_event.type == EventType.UNLOCK and next_event.type == EventType.LOCK:
if (
current_event.source == DepositSource.SABLIER
and next_event.source == DepositSource.OCTANT
and next_event.timestamp - current_event.timestamp
< sablier_unlock_grace_period
):
unlocked_amount = current_event.amount
locked_amount = next_event.amount

if locked_amount == unlocked_amount:
# Scenario 1: Transparent unlock and lock
del modified_events[i : i + 2]
continue
elif locked_amount > unlocked_amount:
# Scenario 3: Transparent unlock, only record the excess lock
excess_amount = locked_amount - unlocked_amount
next_event.amount = excess_amount
next_event.deposit_before = acc_balance_sablier + acc_balance_octant
next_event.deposit_after = next_event.deposit_before + excess_amount
del modified_events[i] # Remove the unlock event
continue

# Update balances for normal event processing
combined_balance = acc_balance_sablier + acc_balance_octant
event.deposit_before = combined_balance
current_event.deposit_before = combined_balance

if event.type == EventType.LOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier += event.amount
if current_event.type == EventType.LOCK:
if current_event.source == DepositSource.SABLIER:
acc_balance_sablier += current_event.amount
else:
acc_balance_octant += event.amount

event.deposit_after = event.deposit_before + event.amount
elif event.type == EventType.UNLOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier -= event.amount
acc_balance_octant += current_event.amount

current_event.deposit_after = (
current_event.deposit_before + current_event.amount
)
elif current_event.type == EventType.UNLOCK:
if current_event.source == DepositSource.SABLIER:
acc_balance_sablier -= current_event.amount
else:
acc_balance_octant -= event.amount
acc_balance_octant -= current_event.amount

current_event.deposit_after = (
current_event.deposit_before - current_event.amount
)

i += 1

event.deposit_after = event.deposit_before - event.amount
# Process the last event
if modified_events:
last_event = modified_events[-1]
combined_balance = acc_balance_sablier + acc_balance_octant
last_event.deposit_before = combined_balance
if last_event.type == EventType.LOCK:
last_event.deposit_after = last_event.deposit_before + last_event.amount
elif last_event.type == EventType.UNLOCK:
last_event.deposit_after = last_event.deposit_before - last_event.amount

modified_events_with_grace_period = _remove_redundant_events_within_grace_period(
modified_events, sablier_unlock_grace_period
)
return modified_events_with_grace_period
return modified_events
7 changes: 2 additions & 5 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,11 +614,8 @@ def snapshot_status(self, epoch):
return json.loads(rv.text), rv.status_code

def pending_snapshot(self):
rv = self._flask_client.post("/snapshots/pending")
current_app.logger.debug(
f"Request to /snapshots/pending [{rv.status_code}] returned text {rv.text}"
)
return json.loads(rv.text)
rv = self._flask_client.post("/snapshots/pending").text
return json.loads(rv)

def pending_snapshot_simulate(self):
rv = self._flask_client.get("/snapshots/pending/simulate")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from app.engine.user.effective_deposit import DepositEvent, EventType, DepositSource
from app.modules.user.events_generator.core import unify_deposit_balances
from tests.helpers.constants import TWENTY_FOUR_HOURS_PERIOD, FIFTEEN_MINUTES_PERIOD
from tests.helpers.constants import TWENTY_FOUR_HOURS_PERIOD


@pytest.mark.parametrize(
Expand Down Expand Up @@ -234,7 +234,23 @@ def test_unify_deposit_balances(
Test the unify_deposit_balances function with various event orders and types.
"""
result = unify_deposit_balances(events, TWENTY_FOUR_HOURS_PERIOD)
_validate(result, expected)
assert len(result) == len(
expected
), "Number of events in result does not match expected."
for r, e in zip(result, expected):
assert (
r.deposit_before == e.deposit_before
), f"deposit_before mismatch: {r.deposit_before} != {e.deposit_before}"
assert (
r.deposit_after == e.deposit_after
), f"deposit_after mismatch: {r.deposit_after} != {e.deposit_after}"
assert r.amount == e.amount, f"amount mismatch: {r.amount} != {e.amount}"
assert r.type == e.type, f"type mismatch: {r.type} != {e.type}"
assert r.source == e.source, f"source mismatch: {r.source} != {e.source}"
assert r.user == e.user, f"user mismatch: {r.user} != {e.user}"
assert (
r.timestamp == e.timestamp
), f"timestamp mismatch: {r.timestamp} != {e.timestamp}"


@pytest.mark.parametrize(
Expand Down Expand Up @@ -417,7 +433,23 @@ def test_unify_deposit_balances(
)
def test_unify_deposit_balances_with_grace_periods_scenarios(events, expected):
result = unify_deposit_balances(events, TWENTY_FOUR_HOURS_PERIOD)
_validate(result, expected)
assert len(result) == len(
expected
), "Number of events in result does not match expected."
for r, e in zip(result, expected):
assert (
r.deposit_before == e.deposit_before
), f"deposit_before mismatch: {r.deposit_before} != {e.deposit_before}"
assert (
r.deposit_after == e.deposit_after
), f"deposit_after mismatch: {r.deposit_after} != {e.deposit_after}"
assert r.amount == e.amount, f"amount mismatch: {r.amount} != {e.amount}"
assert r.type == e.type, f"type mismatch: {r.type} != {e.type}"
assert r.source == e.source, f"source mismatch: {r.source} != {e.source}"
assert r.user == e.user, f"user mismatch: {r.user} != {e.user}"
assert (
r.timestamp == e.timestamp
), f"timestamp mismatch: {r.timestamp} != {e.timestamp}"


@pytest.mark.parametrize(
Expand Down Expand Up @@ -461,101 +493,7 @@ def test_unify_deposit_balances_with_grace_periods_scenarios(events, expected):
)
def test_unify_deposit_does_not_remove_when_out_of_the_grace_period(expected):
result = unify_deposit_balances(expected, TWENTY_FOUR_HOURS_PERIOD)
_validate(result, expected)


@pytest.mark.parametrize(
"events, expected",
[
(
[
DepositEvent(
user="0x123",
type=EventType.LOCK,
timestamp=1737366360,
amount=0,
deposit_before=10000000000000000000000,
source=DepositSource.OCTANT,
),
DepositEvent(
user="0x123",
type=EventType.UNLOCK,
timestamp=1737382716,
amount=3000000000000000000000,
deposit_before=10000000000000000000000,
source=DepositSource.SABLIER,
),
DepositEvent(
user="0x123",
type=EventType.UNLOCK,
timestamp=1737382764,
amount=3000000000000000000000,
deposit_before=7000000000000000000000,
source=DepositSource.SABLIER,
),
DepositEvent(
user="0x123",
type=EventType.LOCK,
timestamp=1737382884,
amount=6000000000000000000000,
deposit_before=0,
source=DepositSource.OCTANT,
),
DepositEvent(
user="0x123",
type=EventType.UNLOCK,
timestamp=1737382968,
amount=4000000000000000000000,
deposit_before=4000000000000000000000,
source=DepositSource.SABLIER,
),
DepositEvent(
user="0x123",
type=EventType.LOCK,
timestamp=1737383712,
amount=4000000000000000000000,
deposit_before=6000000000000000000000,
source=DepositSource.OCTANT,
),
],
[
DepositEvent(
user="0x123",
type=EventType.LOCK,
timestamp=1737366360,
amount=0,
deposit_before=10000000000000000000000,
source=DepositSource.OCTANT,
),
DepositEvent(
user="0x123",
type=EventType.UNLOCK,
timestamp=1737382716,
amount=3000000000000000000000,
deposit_before=10000000000000000000000,
source=DepositSource.SABLIER,
),
DepositEvent(
user="0x123",
type=EventType.LOCK,
timestamp=1737382884,
amount=3000000000000000000000,
deposit_before=7000000000000000000000,
),
],
),
],
)
def test_unify_deposit_for_a_corner_case1(events, expected):
result = unify_deposit_balances(events, FIFTEEN_MINUTES_PERIOD)

_validate(result, expected)


def _validate(result, expected):
assert len(result) == len(
expected
), "Number of events in result does not match expected."
assert len(result) == len(expected)

for r, e in zip(result, expected):
assert (
Expand Down
Loading

0 comments on commit 2da8117

Please sign in to comment.