Skip to content

Commit

Permalink
Add executed filter to SafeOperation
Browse files Browse the repository at this point in the history
- Add also more filters
- Closes #2314
  • Loading branch information
Uxio0 committed Nov 8, 2024
1 parent 7444f23 commit 3635d19
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 12 deletions.
47 changes: 47 additions & 0 deletions safe_transaction_service/account_abstraction/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import django_filters
from django_filters import rest_framework as filters
from safe_eth.eth.django.filters import Keccak256Filter

from safe_transaction_service.utils.filters import filter_overrides

from .models import SafeOperation


class SafeOperationFilter(filters.FilterSet):
executed = django_filters.BooleanFilter(method="filter_executed")
has_confirmations = django_filters.BooleanFilter(method="filter_confirmations")
execution_date__gte = django_filters.IsoDateTimeFilter(
field_name="user_operation__ethereum_tx__block__timestamp", lookup_expr="gte"
)
execution_date__lte = django_filters.IsoDateTimeFilter(
field_name="user_operation__ethereum_tx__block__timestamp", lookup_expr="lte"
)
submission_date__gte = django_filters.IsoDateTimeFilter(
field_name="created", lookup_expr="gte"
)
submission_date__lte = django_filters.IsoDateTimeFilter(
field_name="created", lookup_expr="lte"
)
transaction_hash = Keccak256Filter(field_name="user_operation__ethereum_tx_id")

def filter_confirmations(self, queryset, _name: str, value: bool):
if value:
return queryset.with_confirmations()
else:
return queryset.without_confirmations()

def filter_executed(self, queryset, _name: str, value: bool):
if value:
return queryset.executed()
else:
return queryset.not_executed()

class Meta:
model = SafeOperation
fields = {
"modified": ["lt", "gt", "lte", "gte"],
"valid_after": ["lt", "gt", "lte", "gte"],
"valid_until": ["lt", "gt", "lte", "gte"],
"module_address": ["exact"],
}
filter_overrides = filter_overrides
15 changes: 15 additions & 0 deletions safe_transaction_service/account_abstraction/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,22 @@ def __str__(self) -> str:
return f"{HexBytes(self.user_operation_id).hex()} UserOperationReceipt"


class SafeOperationQuerySet(models.QuerySet):
def executed(self):
return self.exclude(user_operation__ethereum_tx=None)

def not_executed(self):
return self.filter(user_operation__ethereum_tx=None)

def with_confirmations(self):
return self.exclude(confirmations__isnull=True)

def without_confirmations(self):
return self.filter(confirmations__isnull=True)


class SafeOperation(TimeStampedModel):
objects = SafeOperationQuerySet.as_manager()
hash = Keccak256Field(primary_key=True) # safeOperationHash
user_operation = models.OneToOneField(
UserOperation, on_delete=models.CASCADE, related_name="safe_operation"
Expand Down
51 changes: 51 additions & 0 deletions safe_transaction_service/account_abstraction/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@ def test_safe_operations_view(self):
{"count": 1, "next": None, "previous": None, "results": [expected]},
)

# Check confirmations flag
response = self.client.get(
reverse("v1:account_abstraction:safe-operations", args=(safe_address,))
+ "?has_confirmations=True"
)
self.assertDictEqual(
response.json(),
{"count": 0, "next": None, "previous": None, "results": []},
)

# Add a confirmation
safe_operation_confirmation = factories.SafeOperationConfirmationFactory(
safe_operation=safe_operation
Expand Down Expand Up @@ -204,6 +214,47 @@ def test_safe_operations_view(self):
{"count": 1, "next": None, "previous": None, "results": [expected]},
)

# Check executed flag
response = self.client.get(
reverse("v1:account_abstraction:safe-operations", args=(safe_address,))
+ "?executed=False"
)
self.assertDictEqual(
response.json(),
{"count": 0, "next": None, "previous": None, "results": []},
)

response = self.client.get(
reverse("v1:account_abstraction:safe-operations", args=(safe_address,))
+ "?executed=True"
)
self.assertDictEqual(
response.json(),
{"count": 1, "next": None, "previous": None, "results": [expected]},
)

# Set transaction as not executed and check again
safe_operation.user_operation.ethereum_tx = None
safe_operation.user_operation.save(update_fields=["ethereum_tx"])
response = self.client.get(
reverse("v1:account_abstraction:safe-operations", args=(safe_address,))
+ "?executed=True"
)
self.assertDictEqual(
response.json(),
{"count": 0, "next": None, "previous": None, "results": []},
)

response = self.client.get(
reverse("v1:account_abstraction:safe-operations", args=(safe_address,))
+ "?executed=False"
)
expected["userOperation"]["ethereumTxHash"] = None
self.assertDictEqual(
response.json(),
{"count": 1, "next": None, "previous": None, "results": [expected]},
)

@mock.patch.object(
SafeOperationSerializer,
"_get_owners",
Expand Down
3 changes: 2 additions & 1 deletion safe_transaction_service/account_abstraction/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from rest_framework.response import Response
from safe_eth.eth.utils import fast_is_checksum_address

from . import pagination, serializers
from . import filters, pagination, serializers
from .models import SafeOperation, SafeOperationConfirmation, UserOperation


Expand All @@ -29,6 +29,7 @@ class SafeOperationsView(ListCreateAPIView):
django_filters.rest_framework.DjangoFilterBackend,
OrderingFilter,
]
filterset_class = filters.SafeOperationFilter
ordering = ["-user_operation__nonce", "-created"]
ordering_fields = ["user_operation__nonce", "created"]
pagination_class = pagination.DefaultPagination
Expand Down
13 changes: 2 additions & 11 deletions safe_transaction_service/history/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,10 @@
from django_filters import rest_framework as filters
from rest_framework.exceptions import ValidationError
from safe_eth.eth.django.filters import EthereumAddressFilter, Keccak256Filter
from safe_eth.eth.django.models import (
EthereumAddressBinaryField,
Keccak256Field,
Uint256Field,
)

from .models import ModuleTransaction, MultisigTransaction
from safe_transaction_service.utils.filters import filter_overrides

filter_overrides = {
Uint256Field: {"filter_class": django_filters.NumberFilter},
Keccak256Field: {"filter_class": Keccak256Filter},
EthereumAddressBinaryField: {"filter_class": EthereumAddressFilter},
}
from .models import ModuleTransaction, MultisigTransaction


class DelegateListFilter(filters.FilterSet):
Expand Down
13 changes: 13 additions & 0 deletions safe_transaction_service/utils/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import django_filters
from safe_eth.eth.django.filters import EthereumAddressFilter, Keccak256Filter
from safe_eth.eth.django.models import (
EthereumAddressBinaryField,
Keccak256Field,
Uint256Field,
)

filter_overrides = {
Uint256Field: {"filter_class": django_filters.NumberFilter},
Keccak256Field: {"filter_class": Keccak256Filter},
EthereumAddressBinaryField: {"filter_class": EthereumAddressFilter},
}

0 comments on commit 3635d19

Please sign in to comment.