Skip to content

Commit

Permalink
Merge branch 'kacper/feat/oct-2263-community-onboarding-through-sabli…
Browse files Browse the repository at this point in the history
…er' of github.com:golemfoundation/octant into kacper/feat/oct-2263-community-onboarding-through-sablier
  • Loading branch information
kgarbacinski committed Jan 27, 2025
2 parents 00ffdd9 + bc7d67f commit fb61b28
Show file tree
Hide file tree
Showing 70 changed files with 2,658 additions and 750 deletions.
498 changes: 245 additions & 253 deletions backend/app/constants.py

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions backend/app/infrastructure/sablier/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ def fetch_streams(query: str, variables: Dict) -> List[SablierStream]:
for stream in streams:
actions = stream.get("actions", [])
final_intact_amount = stream.get("intactAmount", 0)
is_cancelled = stream["canceled"]
end_time = stream["endTime"]
deposit_amount = stream["depositAmount"]
is_cancelled = stream.get("canceled")
end_time = stream.get("endTime")
deposit_amount = stream.get("depositAmount")

all_streams.append(
SablierStream(
Expand Down
40 changes: 26 additions & 14 deletions backend/app/modules/facades/confirm_multisig.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import json

from flask import current_app as app

from app.modules.multisig_signatures.controller import (
apply_pending_tos_signature,
apply_pending_allocation_signature,
Expand All @@ -19,19 +21,29 @@ def confirm_multisig():
approvals = approve_pending_signatures()

for tos_signature in approvals.tos_signatures:
tos_controller.post_user_terms_of_service_consent(
tos_signature.user_address,
tos_signature.signature,
tos_signature.ip_address,
)
apply_pending_tos_signature(tos_signature.id)
# We don't want to fail the whole process if one TOS fails
try:
tos_controller.post_user_terms_of_service_consent(
tos_signature.user_address,
tos_signature.signature,
tos_signature.ip_address,
)
apply_pending_tos_signature(tos_signature.id)

except Exception as e:
app.logger.error(f"Error confirming TOS signature: {e}")

for allocation_signature in approvals.allocation_signatures:
message = json.loads(allocation_signature.message)
message["signature"] = allocation_signature.signature
allocations_controller.allocate(
allocation_signature.user_address,
message,
is_manually_edited=message.get("isManuallyEdited"),
)
apply_pending_allocation_signature(allocation_signature.id)
# We don't want to fail the whole process if one allocation fails
try:
message = json.loads(allocation_signature.message)
message["signature"] = allocation_signature.signature
allocations_controller.allocate(
allocation_signature.user_address,
message,
is_manually_edited=message.get("isManuallyEdited"),
)
apply_pending_allocation_signature(allocation_signature.id)

except Exception as e:
app.logger.error(f"Error confirming allocation signature: {e}")
35 changes: 26 additions & 9 deletions backend/app/modules/user/antisybil/core.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import datetime, timezone
import json
from typing import Optional

Expand All @@ -22,14 +23,15 @@ def determine_antisybil_score(
if score is None:
return None

potential_score = _apply_gtc_staking_stamp_nullification(score.score, score)
now = datetime.now(timezone.utc)
potential_score = _apply_gtc_staking_stamp_nullification(score.score, score, now)

if user_address.lower() in timeout_list:
return AntisybilStatusDTO(
score=0.0, expires_at=score.expires_at, is_on_timeout_list=True
)
elif user_address.lower() in GUEST_LIST and not _has_guest_stamp_applied_by_gp(
score
score, now
):
return AntisybilStatusDTO(
score=potential_score + 21.0,
Expand All @@ -46,23 +48,38 @@ def _get_provider(stamp) -> str:
return stamp["credential"]["credentialSubject"]["provider"]


def _has_guest_stamp_applied_by_gp(score: GPStamps) -> bool:
def _is_not_expired(stamp, now: datetime) -> bool:
expiration_date = datetime.fromisoformat(stamp["credential"]["expirationDate"])
return expiration_date > now


def _has_guest_stamp_applied_by_gp(score: GPStamps, now: datetime) -> bool:
all_stamps = json.loads(score.stamps)
stamps = [
stamp
for stamp in all_stamps
if _get_provider(stamp) in GUEST_LIST_STAMP_PROVIDERS
and _is_not_expired(stamp, now)
]
return len(stamps) > 0


def _apply_gtc_staking_stamp_nullification(score: int, stamps: GPStamps) -> int:
def _apply_gtc_staking_stamp_nullification(
score: int, stamps: GPStamps, now: datetime
) -> int:
"""Take score and stamps as returned by Passport and remove score associated with GTC staking"""

delta = 0
all_stamps = json.loads(stamps.stamps)
providers = [_get_provider(stamp) for stamp in all_stamps]
for provider in providers:
if provider in GTC_STAKING_STAMP_PROVIDERS_AND_SCORES.keys():
delta = delta + GTC_STAKING_STAMP_PROVIDERS_AND_SCORES[provider]
delta = 0

# Consider only stamps that are not expired
for stamp in all_stamps:
expiration_date = datetime.fromisoformat(stamp["credential"]["expirationDate"])

if expiration_date < now:
continue

provider = stamp["credential"]["credentialSubject"]["provider"]
delta += GTC_STAKING_STAMP_PROVIDERS_AND_SCORES.get(provider, 0)

return score - delta
121 changes: 63 additions & 58 deletions backend/app/modules/user/events_generator/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,59 @@
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 @@ -19,67 +65,26 @@ def unify_deposit_balances(
acc_balance_sablier = 0
acc_balance_octant = events[0].deposit_before # balance from previous epoch

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
for event in modified_events[1:]:
combined_balance = acc_balance_sablier + acc_balance_octant
current_event.deposit_before = combined_balance
event.deposit_before = combined_balance

if current_event.type == EventType.LOCK:
if current_event.source == DepositSource.SABLIER:
acc_balance_sablier += current_event.amount
if event.type == EventType.LOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier += event.amount
else:
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 -= current_event.amount

current_event.deposit_after = (
current_event.deposit_before - current_event.amount
)
acc_balance_octant += event.amount

i += 1
event.deposit_after = event.deposit_before + event.amount
elif event.type == EventType.UNLOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier -= event.amount
else:
acc_balance_octant -= 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
event.deposit_after = event.deposit_before - event.amount

return modified_events
modified_events_with_grace_period = _remove_redundant_events_within_grace_period(
modified_events, sablier_unlock_grace_period
)
return modified_events_with_grace_period
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Remove addresses from timeout list (epoch6)
Revision ID: 1361f75e59a7
Revises: 976c7c2adb0f
Create Date: 2025-01-20 14:29:35.248940
"""
from alembic import op
import sqlalchemy as sa
from eth_utils import to_checksum_address


# revision identifiers, used by Alembic.
revision = "1361f75e59a7"
down_revision = "976c7c2adb0f"
branch_labels = None
depends_on = None


def upgrade():
epoch = 6
addresses = [
"0x826976d7c600d45fb8287ca1d7c76fc8eb732030",
"0x981e7512e87d2f7228d3f03b65950eb6a1b21bac",
"0x1d921dff757610fbdb0073479e12c0a07d382677",
"0xb6989f472bef8931e6ca882b1f875539b7d5da19",
"0x774c3ccfde30a5e7263e8d8ec80b3d419c13ddd3",
"0x5a1f55459c07432165a93eac188076d2ecbf6814",
"0x87f64272eb089a14dc5764b848e3488710b829ea",
"0x2f0642874d5651ba794f8e20774cf9452edc96e2",
]
# INFO: remember to checksum addresses :)
checksum_addresses = [to_checksum_address(address) for address in addresses]

soft_delete_allocations_query = """\
UPDATE allocations
SET deleted_at = CURRENT_TIMESTAMP
WHERE epoch = :epoch
AND user_id IN (SELECT id FROM users WHERE address IN :addresses)
AND deleted_at IS NULL;
"""

delete_uniqueness_quotients_query = """\
DELETE FROM uniqueness_quotients
WHERE epoch = :epoch
AND user_id IN (SELECT id FROM users WHERE address IN :addresses);
"""

session = op.get_context().bind

session.execute(
sa.text(soft_delete_allocations_query),
{"epoch": epoch, "addresses": tuple(checksum_addresses)},
)
session.execute(
sa.text(delete_uniqueness_quotients_query),
{"epoch": epoch, "addresses": tuple(checksum_addresses)},
)

session.commit()


def downgrade():
# We don't downgrade this migration
pass
Loading

0 comments on commit fb61b28

Please sign in to comment.