We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`/api/v1/chains` returns unexpected nativeCurrency.logoUri path
**Describe the bug**
I deployed a project locally using the code from `https://github.com/safe-global/safe-infrastructure`. However, after adding a configuration for a chain in cfg, the `/v1/chains` endpoint of cgw started returning a 500 error. After enabling debug logs, I found that cgw returned the following error:
```json
{
    "build_number": "edc276d",
    "level": "error",
    "message": {
        "chain_id": null,
        "client_ip": "172.70.223.68",
        "detail": "[\n  {\n    \"validation\": \"url\",\n    \"code\": \"invalid_string\",\n    \"message\": \"Invalid url\",\n    \"path\": [\n      \"nativeCurrency\",\n      \"logoUri\"\n    ]\n  }\n]",
        "method": "GET",
        "path": "/v1/chains",
        "response_time_ms": 107.19920100085437,
        "route": "/v1/chains",
        "safe_app_user_agent": null,
        "status_code": 500
    },
    "request_id": "1e37d27b-02b6-468a-a290-b6e06f7bc911",
    "timestamp": "2024-03-29T07:54:29.220Z",
    "version": "v1.31.0"
}
````
After investigating further, I found that the `nativeCurrency.logoUri` in the response data from cfg is not an absolute path:

```json
{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
          ...
            "nativeCurrency": {
                "name": "ETH",
                "symbol": "ETH",
                "decimals": 18,
                "logoUri": "/media/chains/100/currency_logo_3fdtfcf.png"
            },
          ...
    ]
}
```

**To Reproduce**
Steps to reproduce the behavior:

 - Clone the code from `https://github.com/safe-global/safe-infrastructure`
 - Modify the MEDIA_URL in cfg.env to `/media/`
**Expected behavior**
The `nativeCurrency.logoUri` in the response data from cfg should be `https://config.xxx.xyz/media/chains/100/currency_logo_3fdtfcf.png` instead of `/media/chains/100/currency_logo_3fdtfcf.png`.

**Environment (please complete the following information):**
 - Version of safe-config-service: latest(possibly [v2.75.0])
 
**Additional context**
I made the following edits to the `src/chains/serializers.py` file
from
```python
    @staticmethod
    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]
    def get_native_currency(obj: Chain) -> ReturnDict:
        return CurrencySerializer(obj).data
```
to
```python
    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]
    def get_native_currency(self, obj: Chain) -> ReturnDict:
        request = self.context.get('request')
        logo_uri = obj.currency_logo_uri
        dict = CurrencySerializer(obj).data
        dict.update({"logo_uri":request.build_absolute_uri(logo_uri)})
        return dict
```
After applying the temporary workaround, cfg is able to return the expected data. However, since I'm not familiar with Python and Django, this was just a temporary solution on my part. I hope that you can find a better way to fix this issue.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/chains/serializers.py`
Content:
```
1 from abc import abstractmethod
2 
3 from drf_yasg.utils import swagger_serializer_method
4 from gnosis.eth.django.serializers import EthereumAddressField
5 from rest_framework import serializers
6 from rest_framework.exceptions import APIException
7 from rest_framework.utils.serializer_helpers import ReturnDict
8 
9 from .models import Chain, Feature, GasPrice, Wallet
10 
11 
12 class GasPriceOracleSerializer(serializers.Serializer[GasPrice]):
13     type = serializers.ReadOnlyField(default="oracle")
14     uri = serializers.URLField(source="oracle_uri")
15     gas_parameter = serializers.CharField(source="oracle_parameter")
16     gwei_factor = serializers.DecimalField(max_digits=19, decimal_places=9)
17 
18 
19 class GasPriceFixedSerializer(serializers.Serializer[GasPrice]):
20     type = serializers.ReadOnlyField(default="fixed")
21     wei_value = serializers.CharField(source="fixed_wei_value")
22 
23 
24 class GasPriceFixed1559Serializer(serializers.Serializer[GasPrice]):
25     type = serializers.ReadOnlyField(default="fixed1559")
26     max_fee_per_gas = serializers.CharField()
27     max_priority_fee_per_gas = serializers.CharField()
28 
29 
30 class GasPriceSerializer(serializers.Serializer[GasPrice]):
31     def to_representation(self, instance: GasPrice) -> ReturnDict:
32         if (
33             instance.oracle_uri
34             and instance.fixed_wei_value is None
35             and instance.max_fee_per_gas is None
36             and instance.max_priority_fee_per_gas is None
37         ):
38             return GasPriceOracleSerializer(instance).data
39         elif (
40             instance.fixed_wei_value
41             and instance.oracle_uri is None
42             and instance.max_fee_per_gas is None
43             and instance.max_priority_fee_per_gas is None
44         ):
45             return GasPriceFixedSerializer(instance).data
46         elif (
47             instance.max_fee_per_gas
48             and instance.max_priority_fee_per_gas
49             and instance.oracle_uri is None
50             and instance.fixed_wei_value is None
51         ):
52             return GasPriceFixed1559Serializer(instance).data
53         else:
54             raise APIException(
55                 f"The gas price oracle or a fixed gas price was not provided for chain {instance.chain}"
56             )
57 
58 
59 class ThemeSerializer(serializers.Serializer[Chain]):
60     text_color = serializers.CharField(source="theme_text_color")
61     background_color = serializers.CharField(source="theme_background_color")
62 
63 
64 class CurrencySerializer(serializers.Serializer[Chain]):
65     name = serializers.CharField(source="currency_name")
66     symbol = serializers.CharField(source="currency_symbol")
67     decimals = serializers.IntegerField(source="currency_decimals")
68     logo_uri = serializers.ImageField(use_url=True, source="currency_logo_uri")
69 
70 
71 class BaseRpcUriSerializer(serializers.Serializer[Chain]):
72     authentication = serializers.SerializerMethodField()
73     value = serializers.SerializerMethodField(method_name="get_rpc_value")
74 
75     @abstractmethod
76     def get_authentication(self, obj: Chain) -> str:  # pragma: no cover
77         pass
78 
79     @abstractmethod
80     def get_rpc_value(self, obj: Chain) -> str:  # pragma: no cover
81         pass
82 
83 
84 class RpcUriSerializer(BaseRpcUriSerializer):
85     def get_authentication(self, obj: Chain) -> str:
86         return obj.rpc_authentication
87 
88     def get_rpc_value(self, obj: Chain) -> str:
89         return obj.rpc_uri
90 
91 
92 class SafeAppsRpcUriSerializer(BaseRpcUriSerializer):
93     def get_authentication(self, obj: Chain) -> str:
94         return obj.safe_apps_rpc_authentication
95 
96     def get_rpc_value(self, obj: Chain) -> str:
97         return obj.safe_apps_rpc_uri
98 
99 
100 class PublicRpcUriSerializer(BaseRpcUriSerializer):
101     def get_authentication(self, obj: Chain) -> str:
102         return obj.public_rpc_authentication
103 
104     def get_rpc_value(self, obj: Chain) -> str:
105         return obj.public_rpc_uri
106 
107 
108 class BlockExplorerUriTemplateSerializer(serializers.Serializer[Chain]):
109     address = serializers.URLField(source="block_explorer_uri_address_template")
110     tx_hash = serializers.URLField(source="block_explorer_uri_tx_hash_template")
111     api = serializers.URLField(source="block_explorer_uri_api_template")
112 
113 
114 class FeatureSerializer(serializers.Serializer[Feature]):
115     class Meta:
116         ref_name = "chains.serializers.FeatureSerializer"
117 
118     @staticmethod
119     def to_representation(instance: Feature) -> str:
120         return instance.key
121 
122 
123 class WalletSerializer(serializers.Serializer[Wallet]):
124     @staticmethod
125     def to_representation(instance: Wallet) -> str:
126         return instance.key
127 
128 
129 class ChainSerializer(serializers.ModelSerializer[Chain]):
130     chain_id = serializers.CharField(source="id")
131     chain_name = serializers.CharField(source="name")
132     short_name = serializers.CharField()
133     chain_logo_uri = serializers.ImageField(use_url=True)
134     rpc_uri = serializers.SerializerMethodField()
135     safe_apps_rpc_uri = serializers.SerializerMethodField()
136     public_rpc_uri = serializers.SerializerMethodField()
137     block_explorer_uri_template = serializers.SerializerMethodField()
138     native_currency = serializers.SerializerMethodField()
139     transaction_service = serializers.URLField(
140         source="transaction_service_uri", default=None
141     )
142     vpc_transaction_service = serializers.URLField(source="vpc_transaction_service_uri")
143     theme = serializers.SerializerMethodField()
144     gas_price = serializers.SerializerMethodField()
145     ens_registry_address = EthereumAddressField()
146     disabled_wallets = serializers.SerializerMethodField()
147     features = serializers.SerializerMethodField()
148 
149     class Meta:
150         model = Chain
151         fields = [
152             "chain_id",
153             "chain_name",
154             "short_name",
155             "description",
156             "chain_logo_uri",
157             "l2",
158             "is_testnet",
159             "rpc_uri",
160             "safe_apps_rpc_uri",
161             "public_rpc_uri",
162             "block_explorer_uri_template",
163             "native_currency",
164             "transaction_service",
165             "vpc_transaction_service",
166             "theme",
167             "gas_price",
168             "ens_registry_address",
169             "recommended_master_copy_version",
170             "disabled_wallets",
171             "features",
172         ]
173 
174     @staticmethod
175     @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]
176     def get_native_currency(obj: Chain) -> ReturnDict:
177         return CurrencySerializer(obj).data
178 
179     @staticmethod
180     @swagger_serializer_method(serializer_or_field=ThemeSerializer)  # type: ignore[misc]
181     def get_theme(obj: Chain) -> ReturnDict:
182         return ThemeSerializer(obj).data
183 
184     @staticmethod
185     @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]
186     def get_safe_apps_rpc_uri(obj: Chain) -> ReturnDict:
187         return SafeAppsRpcUriSerializer(obj).data
188 
189     @staticmethod
190     @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]
191     def get_rpc_uri(obj: Chain) -> ReturnDict:
192         return RpcUriSerializer(obj).data
193 
194     @staticmethod
195     @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]
196     def get_public_rpc_uri(obj: Chain) -> ReturnDict:
197         return PublicRpcUriSerializer(obj).data
198 
199     @staticmethod
200     @swagger_serializer_method(serializer_or_field=BlockExplorerUriTemplateSerializer)  # type: ignore[misc]
201     def get_block_explorer_uri_template(obj: Chain) -> ReturnDict:
202         return BlockExplorerUriTemplateSerializer(obj).data
203 
204     @swagger_serializer_method(serializer_or_field=GasPriceSerializer)  # type: ignore[misc]
205     def get_gas_price(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]
206         ranked_gas_prices = instance.gasprice_set.all().order_by("rank")
207         return GasPriceSerializer(ranked_gas_prices, many=True).data
208 
209     @swagger_serializer_method(serializer_or_field=WalletSerializer)  # type: ignore[misc]
210     def get_disabled_wallets(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]
211         disabled_wallets = instance.get_disabled_wallets().order_by("key")
212         return WalletSerializer(disabled_wallets, many=True).data
213 
214     @swagger_serializer_method(serializer_or_field=FeatureSerializer)  # type: ignore[misc]
215     def get_features(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]
216         enabled_features = instance.feature_set.all().order_by("key")
217         return FeatureSerializer(enabled_features, many=True).data
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/chains/serializers.py b/src/chains/serializers.py
--- a/src/chains/serializers.py
+++ b/src/chains/serializers.py
@@ -171,10 +171,11 @@
             "features",
         ]
 
-    @staticmethod
     @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]
-    def get_native_currency(obj: Chain) -> ReturnDict:
-        return CurrencySerializer(obj).data
+    def get_native_currency(self, obj: Chain) -> ReturnDict:
+        return CurrencySerializer(
+            obj, context={"request": self.context["request"]}
+        ).data
 
     @staticmethod
     @swagger_serializer_method(serializer_or_field=ThemeSerializer)  # type: ignore[misc]

{"golden_diff": "diff --git a/src/chains/serializers.py b/src/chains/serializers.py\n--- a/src/chains/serializers.py\n+++ b/src/chains/serializers.py\n@@ -171,10 +171,11 @@\n             \"features\",\n         ]\n \n-    @staticmethod\n     @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]\n-    def get_native_currency(obj: Chain) -> ReturnDict:\n-        return CurrencySerializer(obj).data\n+    def get_native_currency(self, obj: Chain) -> ReturnDict:\n+        return CurrencySerializer(\n+            obj, context={\"request\": self.context[\"request\"]}\n+        ).data\n \n     @staticmethod\n     @swagger_serializer_method(serializer_or_field=ThemeSerializer)  # type: ignore[misc]\n", "issue": "`/api/v1/chains` returns unexpected nativeCurrency.logoUri path\n**Describe the bug**\r\nI deployed a project locally using the code from `https://github.com/safe-global/safe-infrastructure`. However, after adding a configuration for a chain in cfg, the `/v1/chains` endpoint of cgw started returning a 500 error. After enabling debug logs, I found that cgw returned the following error:\r\n```json\r\n{\r\n    \"build_number\": \"edc276d\",\r\n    \"level\": \"error\",\r\n    \"message\": {\r\n        \"chain_id\": null,\r\n        \"client_ip\": \"172.70.223.68\",\r\n        \"detail\": \"[\\n  {\\n    \\\"validation\\\": \\\"url\\\",\\n    \\\"code\\\": \\\"invalid_string\\\",\\n    \\\"message\\\": \\\"Invalid url\\\",\\n    \\\"path\\\": [\\n      \\\"nativeCurrency\\\",\\n      \\\"logoUri\\\"\\n    ]\\n  }\\n]\",\r\n        \"method\": \"GET\",\r\n        \"path\": \"/v1/chains\",\r\n        \"response_time_ms\": 107.19920100085437,\r\n        \"route\": \"/v1/chains\",\r\n        \"safe_app_user_agent\": null,\r\n        \"status_code\": 500\r\n    },\r\n    \"request_id\": \"1e37d27b-02b6-468a-a290-b6e06f7bc911\",\r\n    \"timestamp\": \"2024-03-29T07:54:29.220Z\",\r\n    \"version\": \"v1.31.0\"\r\n}\r\n````\r\nAfter investigating further, I found that the `nativeCurrency.logoUri` in the response data from cfg is not an absolute path:\r\n\r\n```json\r\n{\r\n    \"count\": 1,\r\n    \"next\": null,\r\n    \"previous\": null,\r\n    \"results\": [\r\n        {\r\n          ...\r\n            \"nativeCurrency\": {\r\n                \"name\": \"ETH\",\r\n                \"symbol\": \"ETH\",\r\n                \"decimals\": 18,\r\n                \"logoUri\": \"/media/chains/100/currency_logo_3fdtfcf.png\"\r\n            },\r\n          ...\r\n    ]\r\n}\r\n```\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n - Clone the code from `https://github.com/safe-global/safe-infrastructure`\r\n - Modify the MEDIA_URL in cfg.env to `/media/`\r\n**Expected behavior**\r\nThe `nativeCurrency.logoUri` in the response data from cfg should be `https://config.xxx.xyz/media/chains/100/currency_logo_3fdtfcf.png` instead of `/media/chains/100/currency_logo_3fdtfcf.png`.\r\n\r\n**Environment (please complete the following information):**\r\n - Version of safe-config-service: latest(possibly [v2.75.0])\r\n \r\n**Additional context**\r\nI made the following edits to the `src/chains/serializers.py` file\r\nfrom\r\n```python\r\n    @staticmethod\r\n    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]\r\n    def get_native_currency(obj: Chain) -> ReturnDict:\r\n        return CurrencySerializer(obj).data\r\n```\r\nto\r\n```python\r\n    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]\r\n    def get_native_currency(self, obj: Chain) -> ReturnDict:\r\n        request = self.context.get('request')\r\n        logo_uri = obj.currency_logo_uri\r\n        dict = CurrencySerializer(obj).data\r\n        dict.update({\"logo_uri\":request.build_absolute_uri(logo_uri)})\r\n        return dict\r\n```\r\nAfter applying the temporary workaround, cfg is able to return the expected data. However, since I'm not familiar with Python and Django, this was just a temporary solution on my part. I hope that you can find a better way to fix this issue.\n", "before_files": [{"content": "from abc import abstractmethod\n\nfrom drf_yasg.utils import swagger_serializer_method\nfrom gnosis.eth.django.serializers import EthereumAddressField\nfrom rest_framework import serializers\nfrom rest_framework.exceptions import APIException\nfrom rest_framework.utils.serializer_helpers import ReturnDict\n\nfrom .models import Chain, Feature, GasPrice, Wallet\n\n\nclass GasPriceOracleSerializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"oracle\")\n    uri = serializers.URLField(source=\"oracle_uri\")\n    gas_parameter = serializers.CharField(source=\"oracle_parameter\")\n    gwei_factor = serializers.DecimalField(max_digits=19, decimal_places=9)\n\n\nclass GasPriceFixedSerializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"fixed\")\n    wei_value = serializers.CharField(source=\"fixed_wei_value\")\n\n\nclass GasPriceFixed1559Serializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"fixed1559\")\n    max_fee_per_gas = serializers.CharField()\n    max_priority_fee_per_gas = serializers.CharField()\n\n\nclass GasPriceSerializer(serializers.Serializer[GasPrice]):\n    def to_representation(self, instance: GasPrice) -> ReturnDict:\n        if (\n            instance.oracle_uri\n            and instance.fixed_wei_value is None\n            and instance.max_fee_per_gas is None\n            and instance.max_priority_fee_per_gas is None\n        ):\n            return GasPriceOracleSerializer(instance).data\n        elif (\n            instance.fixed_wei_value\n            and instance.oracle_uri is None\n            and instance.max_fee_per_gas is None\n            and instance.max_priority_fee_per_gas is None\n        ):\n            return GasPriceFixedSerializer(instance).data\n        elif (\n            instance.max_fee_per_gas\n            and instance.max_priority_fee_per_gas\n            and instance.oracle_uri is None\n            and instance.fixed_wei_value is None\n        ):\n            return GasPriceFixed1559Serializer(instance).data\n        else:\n            raise APIException(\n                f\"The gas price oracle or a fixed gas price was not provided for chain {instance.chain}\"\n            )\n\n\nclass ThemeSerializer(serializers.Serializer[Chain]):\n    text_color = serializers.CharField(source=\"theme_text_color\")\n    background_color = serializers.CharField(source=\"theme_background_color\")\n\n\nclass CurrencySerializer(serializers.Serializer[Chain]):\n    name = serializers.CharField(source=\"currency_name\")\n    symbol = serializers.CharField(source=\"currency_symbol\")\n    decimals = serializers.IntegerField(source=\"currency_decimals\")\n    logo_uri = serializers.ImageField(use_url=True, source=\"currency_logo_uri\")\n\n\nclass BaseRpcUriSerializer(serializers.Serializer[Chain]):\n    authentication = serializers.SerializerMethodField()\n    value = serializers.SerializerMethodField(method_name=\"get_rpc_value\")\n\n    @abstractmethod\n    def get_authentication(self, obj: Chain) -> str:  # pragma: no cover\n        pass\n\n    @abstractmethod\n    def get_rpc_value(self, obj: Chain) -> str:  # pragma: no cover\n        pass\n\n\nclass RpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.rpc_uri\n\n\nclass SafeAppsRpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.safe_apps_rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.safe_apps_rpc_uri\n\n\nclass PublicRpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.public_rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.public_rpc_uri\n\n\nclass BlockExplorerUriTemplateSerializer(serializers.Serializer[Chain]):\n    address = serializers.URLField(source=\"block_explorer_uri_address_template\")\n    tx_hash = serializers.URLField(source=\"block_explorer_uri_tx_hash_template\")\n    api = serializers.URLField(source=\"block_explorer_uri_api_template\")\n\n\nclass FeatureSerializer(serializers.Serializer[Feature]):\n    class Meta:\n        ref_name = \"chains.serializers.FeatureSerializer\"\n\n    @staticmethod\n    def to_representation(instance: Feature) -> str:\n        return instance.key\n\n\nclass WalletSerializer(serializers.Serializer[Wallet]):\n    @staticmethod\n    def to_representation(instance: Wallet) -> str:\n        return instance.key\n\n\nclass ChainSerializer(serializers.ModelSerializer[Chain]):\n    chain_id = serializers.CharField(source=\"id\")\n    chain_name = serializers.CharField(source=\"name\")\n    short_name = serializers.CharField()\n    chain_logo_uri = serializers.ImageField(use_url=True)\n    rpc_uri = serializers.SerializerMethodField()\n    safe_apps_rpc_uri = serializers.SerializerMethodField()\n    public_rpc_uri = serializers.SerializerMethodField()\n    block_explorer_uri_template = serializers.SerializerMethodField()\n    native_currency = serializers.SerializerMethodField()\n    transaction_service = serializers.URLField(\n        source=\"transaction_service_uri\", default=None\n    )\n    vpc_transaction_service = serializers.URLField(source=\"vpc_transaction_service_uri\")\n    theme = serializers.SerializerMethodField()\n    gas_price = serializers.SerializerMethodField()\n    ens_registry_address = EthereumAddressField()\n    disabled_wallets = serializers.SerializerMethodField()\n    features = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Chain\n        fields = [\n            \"chain_id\",\n            \"chain_name\",\n            \"short_name\",\n            \"description\",\n            \"chain_logo_uri\",\n            \"l2\",\n            \"is_testnet\",\n            \"rpc_uri\",\n            \"safe_apps_rpc_uri\",\n            \"public_rpc_uri\",\n            \"block_explorer_uri_template\",\n            \"native_currency\",\n            \"transaction_service\",\n            \"vpc_transaction_service\",\n            \"theme\",\n            \"gas_price\",\n            \"ens_registry_address\",\n            \"recommended_master_copy_version\",\n            \"disabled_wallets\",\n            \"features\",\n        ]\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]\n    def get_native_currency(obj: Chain) -> ReturnDict:\n        return CurrencySerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=ThemeSerializer)  # type: ignore[misc]\n    def get_theme(obj: Chain) -> ReturnDict:\n        return ThemeSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_safe_apps_rpc_uri(obj: Chain) -> ReturnDict:\n        return SafeAppsRpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_rpc_uri(obj: Chain) -> ReturnDict:\n        return RpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_public_rpc_uri(obj: Chain) -> ReturnDict:\n        return PublicRpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BlockExplorerUriTemplateSerializer)  # type: ignore[misc]\n    def get_block_explorer_uri_template(obj: Chain) -> ReturnDict:\n        return BlockExplorerUriTemplateSerializer(obj).data\n\n    @swagger_serializer_method(serializer_or_field=GasPriceSerializer)  # type: ignore[misc]\n    def get_gas_price(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        ranked_gas_prices = instance.gasprice_set.all().order_by(\"rank\")\n        return GasPriceSerializer(ranked_gas_prices, many=True).data\n\n    @swagger_serializer_method(serializer_or_field=WalletSerializer)  # type: ignore[misc]\n    def get_disabled_wallets(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        disabled_wallets = instance.get_disabled_wallets().order_by(\"key\")\n        return WalletSerializer(disabled_wallets, many=True).data\n\n    @swagger_serializer_method(serializer_or_field=FeatureSerializer)  # type: ignore[misc]\n    def get_features(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        enabled_features = instance.feature_set.all().order_by(\"key\")\n        return FeatureSerializer(enabled_features, many=True).data\n", "path": "src/chains/serializers.py"}], "after_files": [{"content": "from abc import abstractmethod\n\nfrom drf_yasg.utils import swagger_serializer_method\nfrom gnosis.eth.django.serializers import EthereumAddressField\nfrom rest_framework import serializers\nfrom rest_framework.exceptions import APIException\nfrom rest_framework.utils.serializer_helpers import ReturnDict\n\nfrom .models import Chain, Feature, GasPrice, Wallet\n\n\nclass GasPriceOracleSerializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"oracle\")\n    uri = serializers.URLField(source=\"oracle_uri\")\n    gas_parameter = serializers.CharField(source=\"oracle_parameter\")\n    gwei_factor = serializers.DecimalField(max_digits=19, decimal_places=9)\n\n\nclass GasPriceFixedSerializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"fixed\")\n    wei_value = serializers.CharField(source=\"fixed_wei_value\")\n\n\nclass GasPriceFixed1559Serializer(serializers.Serializer[GasPrice]):\n    type = serializers.ReadOnlyField(default=\"fixed1559\")\n    max_fee_per_gas = serializers.CharField()\n    max_priority_fee_per_gas = serializers.CharField()\n\n\nclass GasPriceSerializer(serializers.Serializer[GasPrice]):\n    def to_representation(self, instance: GasPrice) -> ReturnDict:\n        if (\n            instance.oracle_uri\n            and instance.fixed_wei_value is None\n            and instance.max_fee_per_gas is None\n            and instance.max_priority_fee_per_gas is None\n        ):\n            return GasPriceOracleSerializer(instance).data\n        elif (\n            instance.fixed_wei_value\n            and instance.oracle_uri is None\n            and instance.max_fee_per_gas is None\n            and instance.max_priority_fee_per_gas is None\n        ):\n            return GasPriceFixedSerializer(instance).data\n        elif (\n            instance.max_fee_per_gas\n            and instance.max_priority_fee_per_gas\n            and instance.oracle_uri is None\n            and instance.fixed_wei_value is None\n        ):\n            return GasPriceFixed1559Serializer(instance).data\n        else:\n            raise APIException(\n                f\"The gas price oracle or a fixed gas price was not provided for chain {instance.chain}\"\n            )\n\n\nclass ThemeSerializer(serializers.Serializer[Chain]):\n    text_color = serializers.CharField(source=\"theme_text_color\")\n    background_color = serializers.CharField(source=\"theme_background_color\")\n\n\nclass CurrencySerializer(serializers.Serializer[Chain]):\n    name = serializers.CharField(source=\"currency_name\")\n    symbol = serializers.CharField(source=\"currency_symbol\")\n    decimals = serializers.IntegerField(source=\"currency_decimals\")\n    logo_uri = serializers.ImageField(use_url=True, source=\"currency_logo_uri\")\n\n\nclass BaseRpcUriSerializer(serializers.Serializer[Chain]):\n    authentication = serializers.SerializerMethodField()\n    value = serializers.SerializerMethodField(method_name=\"get_rpc_value\")\n\n    @abstractmethod\n    def get_authentication(self, obj: Chain) -> str:  # pragma: no cover\n        pass\n\n    @abstractmethod\n    def get_rpc_value(self, obj: Chain) -> str:  # pragma: no cover\n        pass\n\n\nclass RpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.rpc_uri\n\n\nclass SafeAppsRpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.safe_apps_rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.safe_apps_rpc_uri\n\n\nclass PublicRpcUriSerializer(BaseRpcUriSerializer):\n    def get_authentication(self, obj: Chain) -> str:\n        return obj.public_rpc_authentication\n\n    def get_rpc_value(self, obj: Chain) -> str:\n        return obj.public_rpc_uri\n\n\nclass BlockExplorerUriTemplateSerializer(serializers.Serializer[Chain]):\n    address = serializers.URLField(source=\"block_explorer_uri_address_template\")\n    tx_hash = serializers.URLField(source=\"block_explorer_uri_tx_hash_template\")\n    api = serializers.URLField(source=\"block_explorer_uri_api_template\")\n\n\nclass FeatureSerializer(serializers.Serializer[Feature]):\n    class Meta:\n        ref_name = \"chains.serializers.FeatureSerializer\"\n\n    @staticmethod\n    def to_representation(instance: Feature) -> str:\n        return instance.key\n\n\nclass WalletSerializer(serializers.Serializer[Wallet]):\n    @staticmethod\n    def to_representation(instance: Wallet) -> str:\n        return instance.key\n\n\nclass ChainSerializer(serializers.ModelSerializer[Chain]):\n    chain_id = serializers.CharField(source=\"id\")\n    chain_name = serializers.CharField(source=\"name\")\n    short_name = serializers.CharField()\n    chain_logo_uri = serializers.ImageField(use_url=True)\n    rpc_uri = serializers.SerializerMethodField()\n    safe_apps_rpc_uri = serializers.SerializerMethodField()\n    public_rpc_uri = serializers.SerializerMethodField()\n    block_explorer_uri_template = serializers.SerializerMethodField()\n    native_currency = serializers.SerializerMethodField()\n    transaction_service = serializers.URLField(\n        source=\"transaction_service_uri\", default=None\n    )\n    vpc_transaction_service = serializers.URLField(source=\"vpc_transaction_service_uri\")\n    theme = serializers.SerializerMethodField()\n    gas_price = serializers.SerializerMethodField()\n    ens_registry_address = EthereumAddressField()\n    disabled_wallets = serializers.SerializerMethodField()\n    features = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Chain\n        fields = [\n            \"chain_id\",\n            \"chain_name\",\n            \"short_name\",\n            \"description\",\n            \"chain_logo_uri\",\n            \"l2\",\n            \"is_testnet\",\n            \"rpc_uri\",\n            \"safe_apps_rpc_uri\",\n            \"public_rpc_uri\",\n            \"block_explorer_uri_template\",\n            \"native_currency\",\n            \"transaction_service\",\n            \"vpc_transaction_service\",\n            \"theme\",\n            \"gas_price\",\n            \"ens_registry_address\",\n            \"recommended_master_copy_version\",\n            \"disabled_wallets\",\n            \"features\",\n        ]\n\n    @swagger_serializer_method(serializer_or_field=CurrencySerializer)  # type: ignore[misc]\n    def get_native_currency(self, obj: Chain) -> ReturnDict:\n        return CurrencySerializer(\n            obj, context={\"request\": self.context[\"request\"]}\n        ).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=ThemeSerializer)  # type: ignore[misc]\n    def get_theme(obj: Chain) -> ReturnDict:\n        return ThemeSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_safe_apps_rpc_uri(obj: Chain) -> ReturnDict:\n        return SafeAppsRpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_rpc_uri(obj: Chain) -> ReturnDict:\n        return RpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BaseRpcUriSerializer)  # type: ignore[misc]\n    def get_public_rpc_uri(obj: Chain) -> ReturnDict:\n        return PublicRpcUriSerializer(obj).data\n\n    @staticmethod\n    @swagger_serializer_method(serializer_or_field=BlockExplorerUriTemplateSerializer)  # type: ignore[misc]\n    def get_block_explorer_uri_template(obj: Chain) -> ReturnDict:\n        return BlockExplorerUriTemplateSerializer(obj).data\n\n    @swagger_serializer_method(serializer_or_field=GasPriceSerializer)  # type: ignore[misc]\n    def get_gas_price(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        ranked_gas_prices = instance.gasprice_set.all().order_by(\"rank\")\n        return GasPriceSerializer(ranked_gas_prices, many=True).data\n\n    @swagger_serializer_method(serializer_or_field=WalletSerializer)  # type: ignore[misc]\n    def get_disabled_wallets(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        disabled_wallets = instance.get_disabled_wallets().order_by(\"key\")\n        return WalletSerializer(disabled_wallets, many=True).data\n\n    @swagger_serializer_method(serializer_or_field=FeatureSerializer)  # type: ignore[misc]\n    def get_features(self, instance) -> ReturnDict:  # type: ignore[no-untyped-def]\n        enabled_features = instance.feature_set.all().order_by(\"key\")\n        return FeatureSerializer(enabled_features, many=True).data\n", "path": "src/chains/serializers.py"}]}