Skip to content

Commit

Permalink
OCT-2103: Integrate with Sablier (#515)
Browse files Browse the repository at this point in the history
…e and for user

## Description

## Definition of Done

1. [ ] If required, the desciption of your change is added to the [QA
changelog](https://www.notion.so/octantapp/Changelog-for-the-QA-d96fa3b411cf488bb1d8d9a598d88281)
2. [ ] Acceptance criteria are met.
3. [ ] PR is manually tested before the merge by developer(s).
    - [ ] Happy path is manually checked.
4. [ ] PR is manually tested by QA when their assistance is required
(1).
- [ ] Octant Areas & Test Cases are checked for impact and updated if
required (2).
5. [ ] Unit tests are added unless there is a reason to omit them.
6. [ ] Automated tests are added when required.
7. [ ] The code is merged.
8. [ ] Tech documentation is added / updated, reviewed and approved
(including mandatory approval by a code owner, should such exist for
changed files).
    - [ ] BE: Swagger documentation is updated.
9. [ ] When required by QA:
    - [ ] Deployed to the relevant environment.
    - [ ] Passed system tests.

---

(1) Developer(s) in coordination with QA decide whether it's required.
For small tickets introducing small changes QA assistance is most
probably not required.

(2) [Octant Areas & Test
Cases](https://docs.google.com/spreadsheets/d/1cRe6dxuKJV3a4ZskAwWEPvrFkQm6rEfyUCYwLTYw_Cc).
  • Loading branch information
kgarbacinski authored Oct 28, 2024
1 parent 0743172 commit 76943bb
Show file tree
Hide file tree
Showing 26 changed files with 715 additions and 62 deletions.
2 changes: 2 additions & 0 deletions backend/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ GLM_SENDER_ADDRESS=
GLM_SENDER_PRIVATE_KEY=
GLM_SENDER_NONCE=
MAINNET_PROPOSAL_CIDS=

SABLIER_MAINNET_SUBGRAPH_URL=
24 changes: 24 additions & 0 deletions backend/app/engine/user/effective_deposit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ class EventType(StrEnum):
UNLOCK = "Unlocked"


class SablierEventType(StrEnum):
CREATE = "Create"
WITHDRAW = "Withdraw"
CANCEL = "Cancel"


class DepositSource(StrEnum):
OCTANT = "Octant"
SABLIER = "Sablier"


def _calculate_deposit_after_event(
event_type: EventType, before: int, amount: int
) -> int:
Expand All @@ -32,6 +43,8 @@ class DepositEvent:
amount: int
deposit_before: int
deposit_after: int
source: DepositSource
mapped_event: Optional[SablierEventType]

def __init__(
self,
Expand All @@ -40,6 +53,8 @@ def __init__(
timestamp: int,
amount: int,
deposit_before: int,
source: DepositSource = DepositSource.OCTANT,
mapped_event: Optional[SablierEventType] = None,
):
self.user = user
self.type = type
Expand All @@ -49,10 +64,17 @@ def __init__(
self.deposit_after = _calculate_deposit_after_event(
type, deposit_before, amount
)
self.source = source
self.mapped_event = mapped_event

@staticmethod
def from_dict(event: Dict):
event_type = EventType(event["__typename"])
source = DepositSource.OCTANT
mapped_event = None
if event.get("__source") == DepositSource.SABLIER:
mapped_event = event["type"]
source = DepositSource.SABLIER
user = to_checksum_address(event["user"])
timestamp = int(event["timestamp"])
amount = int(event["amount"])
Expand All @@ -64,6 +86,8 @@ def from_dict(event: Dict):
timestamp=timestamp,
amount=amount,
deposit_before=deposit_before,
source=source,
mapped_event=mapped_event,
)


Expand Down
8 changes: 5 additions & 3 deletions backend/app/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from app.infrastructure.contracts.erc20 import ERC20
from app.infrastructure.contracts.projects import Projects
from app.infrastructure.contracts.vault import Vault
from app.infrastructure import GQLConnectionFactory
from app.infrastructure import GQLConnectionFactory, SubgraphEndpoints

# Flask extensions
api = Api(
Expand All @@ -39,7 +39,8 @@
vault = Vault(abi=abi.VAULT)

# GQL extensions
gql_factory = GQLConnectionFactory()
gql_octant_factory = GQLConnectionFactory()
gql_sablier_factory = GQLConnectionFactory()


def init_web3(app):
Expand All @@ -55,7 +56,8 @@ def init_web3(app):


def init_subgraph(app):
gql_factory.set_url(app.config)
gql_octant_factory.set_url(app.config, SubgraphEndpoints.OCTANT_SUBGRAPH)
gql_sablier_factory.set_url(app.config, SubgraphEndpoints.SABLIER_SUBGRAPH)


def init_scheduler(app):
Expand Down
9 changes: 7 additions & 2 deletions backend/app/infrastructure/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
}


class SubgraphEndpoints:
OCTANT_SUBGRAPH = "SUBGRAPH_ENDPOINT"
SABLIER_SUBGRAPH = "SABLIER_MAINNET_SUBGRAPH_URL"


class OctantResource(Resource):
def __init__(self, *args, **kwargs):
Resource.__init__(self, *args, *kwargs)
Expand Down Expand Up @@ -108,8 +113,8 @@ class GQLConnectionFactory:
def __init__(self):
self._url = None

def set_url(self, config: Config):
self._url = config["SUBGRAPH_ENDPOINT"]
def set_url(self, config: Config, key: SubgraphEndpoints):
self._url = config[key]

def build(self):
if not self._url:
Expand Down
28 changes: 15 additions & 13 deletions backend/app/infrastructure/graphql/epochs.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
from flask import current_app as app
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory

from app import exceptions


def get_epoch_by_number(epoch_number):
query = gql(
"""
query GetEpoch($epochNo: Int!) {
epoches(where: {epoch: $epochNo}) {
epoch
fromTs
toTs
duration
decisionWindow
}
}
"""
query GetEpoch($epochNo: Int!) {
epoches(where: {epoch: $epochNo}) {
epoch
fromTs
toTs
duration
decisionWindow
}
}
"""
)

variables = {"epochNo": epoch_number}
app.logger.debug(
f"[Subgraph] Getting epoch properties for epoch number: {epoch_number}"
)
data = gql_factory.build().execute(query, variable_values=variables)["epoches"]
data = gql_octant_factory.build().execute(query, variable_values=variables)[
"epoches"
]

if data:
app.logger.debug(f"[Subgraph] Received epoch properties: {data[0]}")
Expand Down Expand Up @@ -56,5 +58,5 @@ def get_epochs():
)

app.logger.debug("[Subgraph] Getting list of all epochs")
data = gql_factory.build().execute(query)
data = gql_octant_factory.build().execute(query)
return data
4 changes: 2 additions & 2 deletions backend/app/infrastructure/graphql/info.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory


def get_indexed_block_num() -> int:
Expand All @@ -15,7 +15,7 @@ def get_indexed_block_num() -> int:
}
"""
)
data = gql_factory.build().execute(query)
data = gql_octant_factory.build().execute(query)
if data:
return data["_meta"]["block"]["number"]
else:
Expand Down
20 changes: 13 additions & 7 deletions backend/app/infrastructure/graphql/locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from flask import current_app as app
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory


class LockEvent(TypedDict):
Expand Down Expand Up @@ -43,9 +43,9 @@ def get_user_locks_history(
}
app.logger.debug(f"[Subgraph] Getting user {user_address} locks")

partial_result = gql_factory.build().execute(query, variable_values=variables)[
"lockeds"
]
partial_result = gql_octant_factory.build().execute(
query, variable_values=variables
)["lockeds"]

result = []

Expand Down Expand Up @@ -90,7 +90,9 @@ def get_locks_by_timestamp_range(from_ts: int, to_ts: int) -> list[LockEvent]:
"toTimestamp": to_ts,
}
app.logger.debug(f"[Subgraph] Getting locks in timestamp range {from_ts} - {to_ts}")
result = gql_factory.build().execute(query, variable_values=variables)["lockeds"]
result = gql_octant_factory.build().execute(query, variable_values=variables)[
"lockeds"
]
app.logger.debug(f"[Subgraph] Received locks: {result}")

return result
Expand Down Expand Up @@ -124,7 +126,9 @@ def get_last_lock_before(user_address: str, before: int) -> LockEvent | None:
app.logger.debug(
f"[Subgraph] Getting user {user_address} last lock before {before}"
)
locks = gql_factory.build().execute(query, variable_values=variables)["lockeds"]
locks = gql_octant_factory.build().execute(query, variable_values=variables)[
"lockeds"
]
app.logger.debug(f"[Subgraph] Received locks: {locks}")

return locks[0] if locks else None
Expand Down Expand Up @@ -160,7 +164,9 @@ def get_locks_by_address_and_timestamp_range(
app.logger.debug(
f"[Subgraph] Getting user {user_address} locks in timestamp range {from_ts} - {to_ts}"
)
result = gql_factory.build().execute(query, variable_values=variables)["lockeds"]
result = gql_octant_factory.build().execute(query, variable_values=variables)[
"lockeds"
]
app.logger.debug(f"[Subgraph] Received locks: {result}")

return result
4 changes: 2 additions & 2 deletions backend/app/infrastructure/graphql/merkle_roots.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import current_app as app
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory


def get_all_vault_merkle_roots():
Expand All @@ -18,7 +18,7 @@ def get_all_vault_merkle_roots():
)

app.logger.debug("[Subgraph] Getting all vault merkle roots")
result = gql_factory.build().execute(query)["vaultMerkleRoots"]
result = gql_octant_factory.build().execute(query)["vaultMerkleRoots"]
app.logger.debug(f"[Subgraph] Received merkle roots: {result}")

return result
24 changes: 15 additions & 9 deletions backend/app/infrastructure/graphql/unlocks.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Literal, TypedDict
from typing import Literal, TypedDict, List
from flask import current_app as app
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory


class UnlockEvent(TypedDict):
Expand All @@ -16,7 +16,7 @@ class UnlockEvent(TypedDict):

def get_user_unlocks_history(
user_address: str, from_timestamp: int, limit: int
) -> list[UnlockEvent]:
) -> List[UnlockEvent]:
query = gql(
"""
query GetUnlocks($userAddress: Bytes!, $fromTimestamp: Int!, $limit: Int!) {
Expand Down Expand Up @@ -44,9 +44,9 @@ def get_user_unlocks_history(
}

app.logger.debug(f"[Subgraph] Getting user {user_address} unlocks")
partial_result = gql_factory.build().execute(query, variable_values=variables)[
"unlockeds"
]
partial_result = gql_octant_factory.build().execute(
query, variable_values=variables
)["unlockeds"]

result = []

Expand Down Expand Up @@ -94,7 +94,9 @@ def get_unlocks_by_timestamp_range(from_ts, to_ts) -> list[UnlockEvent]:
app.logger.debug(
f"[Subgraph] Getting unlocks in timestamp range {from_ts} - {to_ts}"
)
result = gql_factory.build().execute(query, variable_values=variables)["unlockeds"]
result = gql_octant_factory.build().execute(query, variable_values=variables)[
"unlockeds"
]
app.logger.debug(f"[Subgraph] Received unlocks: {result}")

return result
Expand Down Expand Up @@ -130,7 +132,9 @@ def get_unlocks_by_address_and_timestamp_range(
app.logger.debug(
f"[Subgraph] Getting user {user_address} unlocks in timestamp range {from_ts} - {to_ts}"
)
result = gql_factory.build().execute(query, variable_values=variables)["unlockeds"]
result = gql_octant_factory.build().execute(query, variable_values=variables)[
"unlockeds"
]
app.logger.debug(f"[Subgraph] Received unlocks: {result}")

return result
Expand Down Expand Up @@ -164,7 +168,9 @@ def get_last_unlock_before(user_address: str, before: int) -> UnlockEvent | None
app.logger.debug(
f"[Subgraph] Getting user {user_address} last unlock before {before}"
)
unlocks = gql_factory.build().execute(query, variable_values=variables)["unlockeds"]
unlocks = gql_octant_factory.build().execute(query, variable_values=variables)[
"unlockeds"
]
app.logger.debug(f"[Subgraph] Received unlocks: {unlocks}")

return unlocks[0] if unlocks else None
10 changes: 5 additions & 5 deletions backend/app/infrastructure/graphql/withdrawals.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import current_app as app
from gql import gql

from app.extensions import gql_factory
from app.extensions import gql_octant_factory


def get_user_withdrawals_history(user_address: str, from_timestamp: int, limit: int):
Expand Down Expand Up @@ -32,9 +32,9 @@ def get_user_withdrawals_history(user_address: str, from_timestamp: int, limit:
app.logger.debug(
f"[Subgraph] Getting user {user_address} withdrawals before ts {from_timestamp}"
)
partial_result = gql_factory.build().execute(query, variable_values=variables)[
"withdrawals"
]
partial_result = gql_octant_factory.build().execute(
query, variable_values=variables
)["withdrawals"]

result = []

Expand Down Expand Up @@ -81,7 +81,7 @@ def get_withdrawals_by_address_and_timestamp_range(
f"[Subgraph] Getting user {user_address} withdrawals in timestamp range {from_timestamp} - {to_timestamp}"
)

result = gql_factory.build().execute(query, variable_values=variables)[
result = gql_octant_factory.build().execute(query, variable_values=variables)[
"withdrawals"
]

Expand Down
5 changes: 4 additions & 1 deletion backend/app/infrastructure/routes/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ class History(OctantResource):
@ns.param("cursor", description="History page cursor", _in="query")
@ns.param("limit", description="History page size", _in="query")
@ns.marshal_with(user_history_model)
@ns.response(200, "User history successfully retrieved")
@ns.response(
200,
"User history from the Octant's and Sablier's Subgraphes successfully retrieved",
)
def get(self, user_address):
page_cursor = request.args.get("cursor", type=str)
page_limit = request.args.get("limit", type=int)
Expand Down
Empty file.
Loading

0 comments on commit 76943bb

Please sign in to comment.