11import json
2+ import os
23from collections .abc import Iterator
34from datetime import datetime
45from functools import reduce
3233
3334if TYPE_CHECKING :
3435 from ape .api import AccountAPI
36+ from requests import Response
3537
3638APE_SAFE_VERSION = get_package_version (__name__ )
3739APE_SAFE_USER_AGENT = f"Ape-Safe/{ APE_SAFE_VERSION } { USER_AGENT } "
4042assert len (ORIGIN ) <= 200 # NOTE: Must be less than 200 chars
4143
4244# URL for the multichain client gateway
43- SAFE_CLIENT_GATEWAY_URL = "https://safe-client.safe.global"
45+ SAFE_CLIENT_GATEWAY_URL = "https://api.safe.global/tx-service"
46+ GATEWAY_API_KEY = os .environ .get ("APE_SAFE_GATEWAY_API_KEY" )
47+ EIP3770_BLOCKCHAIN_NAMES_BY_CHAIN_ID = {
48+ 1 : "eth" , # Ethereum Mainnet
49+ 11155111 : "sep" , # Ethereum Sepolia
50+ 10 : "oeth" , # Optimism Mainnet
51+ 42161 : "arb1" , # Arbitrum One Mainnet
52+ 56 : "bnb" , # Binance Smart Chain
53+ 146 : "sonic" ,
54+ 5000 : "mantle" ,
55+ 43114 : "avax" ,
56+ 1313161554 : "aurora" ,
57+ 8453 : "base" , # Base Mainnet
58+ 84532 : "basesep" , # Base Sepolia
59+ 42220 : "celo" , # Celo Mainnet
60+ 100 : "gno" , # Gnosis Chain
61+ 59144 : "linea" , # Linea Mainnet
62+ 137 : "pol" , # Polygon
63+ 534352 : "scr" , # Scroll
64+ 130 : "unichain" , # Unichain Mainnet
65+ 480 : "wc" , # Worldchain Mainnet
66+ 324 : "zksync" , # zkSync Mainnet
67+ 57073 : "ink" , # Ink Mainnet
68+ 800094 : "berachain" , # Berachain Mainnet
69+ }
4470
4571
4672class SafeClient (BaseSafeClient ):
@@ -55,15 +81,27 @@ def __init__(
5581
5682 if override_url :
5783 base_url = override_url
58- self .use_client_gateway = False
5984 elif chain_id :
60- base_url = SAFE_CLIENT_GATEWAY_URL
61- self .use_client_gateway = True
85+ if chain_id not in EIP3770_BLOCKCHAIN_NAMES_BY_CHAIN_ID :
86+ raise ValueError (f"Chain ID { chain_id } is not a supported chain." )
87+
88+ elif not GATEWAY_API_KEY :
89+ raise ValueError ("Must provide API key via 'APE_SAFE_GATEWAY_API_KEY='." )
90+
91+ base_url = (
92+ f"{ SAFE_CLIENT_GATEWAY_URL } /{ EIP3770_BLOCKCHAIN_NAMES_BY_CHAIN_ID [chain_id ]} /api"
93+ )
6294 else :
6395 raise ValueError ("Must provide one of chain_id or override_url." )
6496
6597 super ().__init__ (base_url )
6698
99+ def _request (self , method : str , url : str , json : Optional [dict ] = None , ** kwargs ) -> "Response" :
100+ # NOTE: Add authorization header
101+ headers = kwargs .pop ("headers" , {})
102+ headers .update (dict (Authorization = f"Bearer { GATEWAY_API_KEY } " ))
103+ return super ()._request (method , url , json = json , headers = headers , ** kwargs )
104+
67105 @property
68106 def safe_details (self ) -> SafeDetails :
69107 response = self ._get (f"/safes/{ self .address } " )
@@ -77,7 +115,7 @@ def _all_transactions(self) -> Iterator[SafeApiTxData]:
77115 Get all transactions from safe, both confirmed and unconfirmed
78116 """
79117
80- url = f"/safes/{ self .address } /multisig-transactions/raw "
118+ url = f"/safes/{ self .address } /multisig-transactions"
81119 while url :
82120 response = self ._get (url )
83121 data = response .json ()
0 commit comments