From c1cb0fe30b3a34022d9f8387a311c59575b144c3 Mon Sep 17 00:00:00 2001 From: adamvizly Date: Tue, 2 Jul 2024 11:39:12 +0330 Subject: [PATCH 1/4] add arbitrum bridge function --- core/constraints/abstract.py | 1 + core/constraints/arbitrum.py | 44 ++++++++++++++ core/thirdpartyapp/__init__.py | 1 + core/thirdpartyapp/arbitrum.py | 102 +++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 core/constraints/arbitrum.py create mode 100644 core/thirdpartyapp/arbitrum.py diff --git a/core/constraints/abstract.py b/core/constraints/abstract.py index a406908f..f2c7a832 100644 --- a/core/constraints/abstract.py +++ b/core/constraints/abstract.py @@ -11,6 +11,7 @@ class ConstraintApp(Enum): ENS = "ENS" EAS = "EAS" GITCOIN_PASSPORT = "gitcoin_passport" + ARBITRUM = "arbitrum" @classmethod def choices(cls): diff --git a/core/constraints/arbitrum.py b/core/constraints/arbitrum.py new file mode 100644 index 00000000..f80ee2bd --- /dev/null +++ b/core/constraints/arbitrum.py @@ -0,0 +1,44 @@ +from core.constraints.abstract import ( + ConstraintApp, + ConstraintParam, + ConstraintVerification, +) +from core.thirdpartyapp.arbitrum import ArbitrumUtils + + +class HasBridgedToken(ConstraintVerification): + _param_keys = [ + ConstraintParam.ADDRESS, + ConstraintParam.MINIMUM, + ConstraintParam.CHAIN, + ] + app_name = ConstraintApp.ARBITRUM.value + + def __init__(self, user_profile) -> None: + super().__init__(user_profile) + + def is_observed(self, *args, **kwargs) -> bool: + minimum_amount = float(self.param_values[ConstraintParam.MINIMUM.name]) + chain = self.param_values[ConstraintParam.CHAIN.name] + token_address = self.param_values[ConstraintParam.ADDRESS.name] + + arb_utils = ArbitrumUtils() + user_wallets = self.user_addresses + + for wallet in user_wallets: + bridging_results = arb_utils.check_bridge_transactions( + wallet, token_address, minimum_amount + ) + + if chain == "ethereum_to_arbitrum": + return bridging_results["Ethereum to Arbitrum"] + elif chain == "arbitrum_to_ethereum": + return bridging_results["Arbitrum to Ethereum"] + elif chain == "arbitrum_to_nova": + return bridging_results["Arbitrum to Nova"] + elif chain == "nova_to_arbitrum": + return bridging_results["Nova to Arbitrum"] + elif chain == "any": + return any(bridging_results.values()) + else: + raise ValueError(f"Invalid chain parameter: {chain}") diff --git a/core/thirdpartyapp/__init__.py b/core/thirdpartyapp/__init__.py index 6d5d9724..25caa35e 100644 --- a/core/thirdpartyapp/__init__.py +++ b/core/thirdpartyapp/__init__.py @@ -1,3 +1,4 @@ +from .arbitrum import ArbitrumUtils from .EAS import EASUtils from .ens import ENSUtil # noqa: F401 from .farcaster import FarcasterUtil # noqa: F401 diff --git a/core/thirdpartyapp/arbitrum.py b/core/thirdpartyapp/arbitrum.py new file mode 100644 index 00000000..08d610b8 --- /dev/null +++ b/core/thirdpartyapp/arbitrum.py @@ -0,0 +1,102 @@ +from web3 import Web3 + + +class ArbitrumUtils: + def __init__(self): + # Initialize Web3 instances + self.eth_w3 = Web3( + Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID") + ) + self.arb_w3 = Web3(Web3.HTTPProvider("https://arb1.arbitrum.io/rpc")) + self.nova_w3 = Web3(Web3.HTTPProvider("https://nova.arbitrum.io/rpc")) + + # Bridge contract addresses + self.eth_arb_bridge = "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a" + self.arb_eth_bridge = "0x0000000000000000000000000000000000000064" + self.arb_nova_bridge = "0x0000000000000000000000000000000000000064" + self.nova_arb_bridge = "0x0000000000000000000000000000000000000064" + + # ABI for the bridge contracts + self.bridge_abi = [ + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "l1Token", "type": "address"}, + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "ERC20DepositInitiated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "l1Token", "type": "address"}, + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "WithdrawalInitiated", + "type": "event", + }, + ] + + def check_bridge_transactions(self, wallet_address, token_address, amount): + # Create contract instances + eth_arb_contract = self.eth_w3.eth.contract( + address=self.eth_arb_bridge, abi=self.bridge_abi + ) + arb_eth_contract = self.arb_w3.eth.contract( + address=self.arb_eth_bridge, abi=self.bridge_abi + ) + arb_nova_contract = self.arb_w3.eth.contract( + address=self.arb_nova_bridge, abi=self.bridge_abi + ) + nova_arb_contract = self.nova_w3.eth.contract( + address=self.nova_arb_bridge, abi=self.bridge_abi + ) + + results = {} + + # Check Ethereum to Arbitrum + eth_arb_filter = eth_arb_contract.events.ERC20DepositInitiated.createFilter( + fromBlock=0, + argument_filters={"from": wallet_address, "l1Token": token_address}, + ) + eth_arb_events = eth_arb_filter.get_all_entries() + results["Ethereum to Arbitrum"] = any( + event["args"]["amount"] >= amount for event in eth_arb_events + ) + + # Check Arbitrum to Ethereum + arb_eth_filter = arb_eth_contract.events.WithdrawalInitiated.createFilter( + fromBlock=0, + argument_filters={"from": wallet_address, "l1Token": token_address}, + ) + arb_eth_events = arb_eth_filter.get_all_entries() + results["Arbitrum to Ethereum"] = any( + event["args"]["amount"] >= amount for event in arb_eth_events + ) + + # Check Arbitrum to Nova + arb_nova_filter = arb_nova_contract.events.WithdrawalInitiated.createFilter( + fromBlock=0, + argument_filters={"from": wallet_address, "l1Token": token_address}, + ) + arb_nova_events = arb_nova_filter.get_all_entries() + results["Arbitrum to Nova"] = any( + event["args"]["amount"] >= amount for event in arb_nova_events + ) + + # Check Nova to Arbitrum + nova_arb_filter = nova_arb_contract.events.WithdrawalInitiated.createFilter( + fromBlock=0, + argument_filters={"from": wallet_address, "l1Token": token_address}, + ) + nova_arb_events = nova_arb_filter.get_all_entries() + results["Nova to Arbitrum"] = any( + event["args"]["amount"] >= amount for event in nova_arb_events + ) + + return results From 49c839702bece21a39d5e4706c7594cbc07aa89d Mon Sep 17 00:00:00 2001 From: adamvizly Date: Tue, 2 Jul 2024 11:41:43 +0330 Subject: [PATCH 2/4] fix web3 initialization --- core/thirdpartyapp/arbitrum.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/thirdpartyapp/arbitrum.py b/core/thirdpartyapp/arbitrum.py index 08d610b8..a4535525 100644 --- a/core/thirdpartyapp/arbitrum.py +++ b/core/thirdpartyapp/arbitrum.py @@ -4,11 +4,11 @@ class ArbitrumUtils: def __init__(self): # Initialize Web3 instances - self.eth_w3 = Web3( - Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID") + self.eth_w3 = Web3.HTTPProvider( + "https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID" ) - self.arb_w3 = Web3(Web3.HTTPProvider("https://arb1.arbitrum.io/rpc")) - self.nova_w3 = Web3(Web3.HTTPProvider("https://nova.arbitrum.io/rpc")) + self.arb_w3 = Web3.HTTPProvider("https://arb1.arbitrum.io/rpc") + self.nova_w3 = Web3.HTTPProvider("https://nova.arbitrum.io/rpc") # Bridge contract addresses self.eth_arb_bridge = "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a" From 31fa3e9beb0d0990cccb17d58576d95fe4e226b6 Mon Sep 17 00:00:00 2001 From: adamvizly Date: Tue, 2 Jul 2024 13:54:25 +0330 Subject: [PATCH 3/4] change arbitrum utils and added tests --- core/constraints/arbitrum.py | 44 +++++--- core/tests.py | 107 ++++++++++++++++++ core/thirdpartyapp/arbitrum.py | 201 ++++++++++++++++++--------------- 3 files changed, 248 insertions(+), 104 deletions(-) diff --git a/core/constraints/arbitrum.py b/core/constraints/arbitrum.py index f80ee2bd..8de47551 100644 --- a/core/constraints/arbitrum.py +++ b/core/constraints/arbitrum.py @@ -23,22 +23,34 @@ def is_observed(self, *args, **kwargs) -> bool: token_address = self.param_values[ConstraintParam.ADDRESS.name] arb_utils = ArbitrumUtils() - user_wallets = self.user_addresses + if token_address.lower() in ["eth", ""]: + token_address = None + + user_wallets = self.user_addresses for wallet in user_wallets: - bridging_results = arb_utils.check_bridge_transactions( - wallet, token_address, minimum_amount - ) - - if chain == "ethereum_to_arbitrum": - return bridging_results["Ethereum to Arbitrum"] - elif chain == "arbitrum_to_ethereum": - return bridging_results["Arbitrum to Ethereum"] - elif chain == "arbitrum_to_nova": - return bridging_results["Arbitrum to Nova"] - elif chain == "nova_to_arbitrum": - return bridging_results["Nova to Arbitrum"] - elif chain == "any": - return any(bridging_results.values()) - else: + if chain == "any": + bridging_results = arb_utils.check_all_bridge_transactions( + wallet, token_address, minimum_amount + ) + if any(bridging_results.values()): + return True + else: + source_chain, target_chain = self._parse_chain(chain) + if arb_utils.check_bridge_transactions( + wallet, token_address, minimum_amount, source_chain, target_chain + ): + return True + + return False + + def _parse_chain(self, chain): + chain_mapping = { + "ethereum_to_arbitrum": ("ethereum", "arbitrum"), + "arbitrum_to_ethereum": ("arbitrum", "ethereum"), + "arbitrum_to_nova": ("arbitrum", "nova"), + "nova_to_arbitrum": ("nova", "arbitrum"), + } + if chain not in chain_mapping: raise ValueError(f"Invalid chain parameter: {chain}") + return chain_mapping[chain] diff --git a/core/tests.py b/core/tests.py index 8f9433ae..ae263af3 100644 --- a/core/tests.py +++ b/core/tests.py @@ -4,7 +4,9 @@ from rest_framework.test import APITestCase from authentication.models import GitcoinPassportConnection, UserProfile, Wallet +from core.constraints.arbitrum import HasBridgedToken from core.models import Chain, NetworkTypes, WalletAccount +from core.thirdpartyapp.arbitrum import ArbitrumUtils from .constraints import ( Attest, @@ -363,3 +365,108 @@ def test_gitcoin_passport_connection_constraint_fail(self): constraint = HasGitcoinPassportProfile(self.not_connected_user_profile) self.assertEqual(constraint.is_observed(), False) + + +class TestArbitrumBridgeConstraint(BaseTestCase): + def setUp(self): + super().setUp() + self.user = User.objects.create_user(username="testuser", password="12345") + self.user_profile = UserProfile.objects.create( + user=self.user, initial_context_id="testuser", username="testuser" + ) + self.address1 = "0x0cE49AF5d8c5A70Edacd7115084B2b3041fE4fF6" + self.address2 = "0x319B32d11e29dB4a6dB9E4E3da91Fc7FA2D2ff92" + Wallet.objects.create( + user_profile=self.user_profile, address=self.address1, wallet_type="EVM" + ) + Wallet.objects.create( + user_profile=self.user_profile, address=self.address2, wallet_type="EVM" + ) + self.token_address = "0x1234567890123456789012345678901234567890" + self.minimum_amount = 1.0 + + @patch.object(ArbitrumUtils, "check_all_bridge_transactions") + def test_has_bridged_token_any_chain_success(self, mock_check_all): + mock_check_all.return_value = { + "Ethereum to Arbitrum": True, + "Arbitrum to Ethereum": False, + } + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "any", + "ADDRESS": self.token_address, + } + self.assertTrue(constraint.is_observed()) + + @patch.object(ArbitrumUtils, "check_all_bridge_transactions") + def test_has_bridged_token_any_chain_fail(self, mock_check_all): + mock_check_all.return_value = { + "Ethereum to Arbitrum": False, + "Arbitrum to Ethereum": False, + } + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "any", + "ADDRESS": self.token_address, + } + self.assertFalse(constraint.is_observed()) + + @patch.object(ArbitrumUtils, "check_bridge_transactions") + def test_has_bridged_token_specific_chain_success(self, mock_check): + mock_check.return_value = True + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "ethereum_to_arbitrum", + "ADDRESS": self.token_address, + } + self.assertTrue(constraint.is_observed()) + + @patch.object(ArbitrumUtils, "check_bridge_transactions") + def test_has_bridged_token_specific_chain_fail(self, mock_check): + mock_check.return_value = False + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "ethereum_to_arbitrum", + "ADDRESS": self.token_address, + } + self.assertFalse(constraint.is_observed()) + + @patch.object(ArbitrumUtils, "check_bridge_transactions") + def test_has_bridged_eth_success(self, mock_check): + mock_check.return_value = True + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "ethereum_to_arbitrum", + "ADDRESS": "eth", + } + self.assertTrue(constraint.is_observed()) + mock_check.assert_called_with( + self.address1, None, self.minimum_amount, "ethereum", "arbitrum" + ) + + @patch.object(ArbitrumUtils, "check_bridge_transactions") + def test_has_bridged_token_multiple_wallets(self, mock_check): + mock_check.side_effect = [False, True] + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "ethereum_to_arbitrum", + "ADDRESS": self.token_address, + } + self.assertTrue(constraint.is_observed()) + self.assertEqual(mock_check.call_count, 2) + + def test_has_bridged_token_invalid_chain(self): + constraint = HasBridgedToken(self.user_profile) + constraint.param_values = { + "MINIMUM": self.minimum_amount, + "CHAIN": "invalid_chain", + "ADDRESS": self.token_address, + } + with self.assertRaises(ValueError): + constraint.is_observed() diff --git a/core/thirdpartyapp/arbitrum.py b/core/thirdpartyapp/arbitrum.py index a4535525..74c0618f 100644 --- a/core/thirdpartyapp/arbitrum.py +++ b/core/thirdpartyapp/arbitrum.py @@ -1,102 +1,127 @@ -from web3 import Web3 +from typing import Optional + +from core.utils import Web3Utils class ArbitrumUtils: + ETH_W3 = Web3Utils("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID") + ARB_W3 = Web3Utils("https://arb1.arbitrum.io/rpc") + NOVA_W3 = Web3Utils("https://nova.arbitrum.io/rpc") + + BRIDGE_ADDRESSES = { + "ethereum": "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a", + "arbitrum": "0x0000000000000000000000000000000000000064", + "nova": "0x0000000000000000000000000000000000000064", + } + + BRIDGE_ABI = [ + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "l1Token", "type": "address"}, + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "ERC20DepositInitiated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "DepositInitiated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "l1Token", "type": "address"}, + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "WithdrawalInitiated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "name": "from", "type": "address"}, + {"indexed": True, "name": "to", "type": "address"}, + {"indexed": False, "name": "amount", "type": "uint256"}, + ], + "name": "ETHWithdrawalInitiated", + "type": "event", + }, + ] + def __init__(self): - # Initialize Web3 instances - self.eth_w3 = Web3.HTTPProvider( - "https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID" - ) - self.arb_w3 = Web3.HTTPProvider("https://arb1.arbitrum.io/rpc") - self.nova_w3 = Web3.HTTPProvider("https://nova.arbitrum.io/rpc") + self.contracts = { + "ethereum": self.ETH_W3.set_contract( + self.BRIDGE_ADDRESSES["ethereum"], self.BRIDGE_ABI + ), + "arbitrum": self.ARB_W3.set_contract( + self.BRIDGE_ADDRESSES["arbitrum"], self.BRIDGE_ABI + ), + "nova": self.NOVA_W3.set_contract( + self.BRIDGE_ADDRESSES["nova"], self.BRIDGE_ABI + ), + } - # Bridge contract addresses - self.eth_arb_bridge = "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a" - self.arb_eth_bridge = "0x0000000000000000000000000000000000000064" - self.arb_nova_bridge = "0x0000000000000000000000000000000000000064" - self.nova_arb_bridge = "0x0000000000000000000000000000000000000064" + def check_bridge_transactions( + self, + wallet_address: str, + token_address: Optional[str], + amount: float, + source_chain: str, + target_chain: str, + ) -> bool: + if source_chain not in self.contracts or target_chain not in self.contracts: + raise ValueError(f"Invalid chain: {source_chain} or {target_chain}") - # ABI for the bridge contracts - self.bridge_abi = [ - { - "anonymous": False, - "inputs": [ - {"indexed": True, "name": "l1Token", "type": "address"}, - {"indexed": True, "name": "from", "type": "address"}, - {"indexed": True, "name": "to", "type": "address"}, - {"indexed": False, "name": "amount", "type": "uint256"}, - ], - "name": "ERC20DepositInitiated", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "name": "l1Token", "type": "address"}, - {"indexed": True, "name": "from", "type": "address"}, - {"indexed": True, "name": "to", "type": "address"}, - {"indexed": False, "name": "amount", "type": "uint256"}, - ], - "name": "WithdrawalInitiated", - "type": "event", - }, - ] + contract = self.contracts[source_chain] - def check_bridge_transactions(self, wallet_address, token_address, amount): - # Create contract instances - eth_arb_contract = self.eth_w3.eth.contract( - address=self.eth_arb_bridge, abi=self.bridge_abi - ) - arb_eth_contract = self.arb_w3.eth.contract( - address=self.arb_eth_bridge, abi=self.bridge_abi - ) - arb_nova_contract = self.arb_w3.eth.contract( - address=self.arb_nova_bridge, abi=self.bridge_abi - ) - nova_arb_contract = self.nova_w3.eth.contract( - address=self.nova_arb_bridge, abi=self.bridge_abi - ) + if token_address is None: # ETH transaction + if source_chain == "ethereum": + event_name = "DepositInitiated" + else: + event_name = "ETHWithdrawalInitiated" - results = {} + event = getattr(contract.events, event_name) + event_filter = event.createFilter( + fromBlock=0, argument_filters={"from": wallet_address} + ) + else: # ERC-20 transaction + if source_chain == "ethereum": + event_name = "ERC20DepositInitiated" + else: + event_name = "WithdrawalInitiated" - # Check Ethereum to Arbitrum - eth_arb_filter = eth_arb_contract.events.ERC20DepositInitiated.createFilter( - fromBlock=0, - argument_filters={"from": wallet_address, "l1Token": token_address}, - ) - eth_arb_events = eth_arb_filter.get_all_entries() - results["Ethereum to Arbitrum"] = any( - event["args"]["amount"] >= amount for event in eth_arb_events - ) + event = getattr(contract.events, event_name) + event_filter = event.createFilter( + fromBlock=0, + argument_filters={"from": wallet_address, "l1Token": token_address}, + ) - # Check Arbitrum to Ethereum - arb_eth_filter = arb_eth_contract.events.WithdrawalInitiated.createFilter( - fromBlock=0, - argument_filters={"from": wallet_address, "l1Token": token_address}, - ) - arb_eth_events = arb_eth_filter.get_all_entries() - results["Arbitrum to Ethereum"] = any( - event["args"]["amount"] >= amount for event in arb_eth_events - ) + events = event_filter.get_all_entries() + return any(event["args"]["amount"] >= amount for event in events) - # Check Arbitrum to Nova - arb_nova_filter = arb_nova_contract.events.WithdrawalInitiated.createFilter( - fromBlock=0, - argument_filters={"from": wallet_address, "l1Token": token_address}, - ) - arb_nova_events = arb_nova_filter.get_all_entries() - results["Arbitrum to Nova"] = any( - event["args"]["amount"] >= amount for event in arb_nova_events - ) + def check_all_bridge_transactions( + self, wallet_address: str, token_address: Optional[str], amount: float + ) -> dict[str, bool]: + results = {} + chains = ["ethereum", "arbitrum", "nova"] - # Check Nova to Arbitrum - nova_arb_filter = nova_arb_contract.events.WithdrawalInitiated.createFilter( - fromBlock=0, - argument_filters={"from": wallet_address, "l1Token": token_address}, - ) - nova_arb_events = nova_arb_filter.get_all_entries() - results["Nova to Arbitrum"] = any( - event["args"]["amount"] >= amount for event in nova_arb_events - ) + for source in chains: + for target in chains: + if source != target: + key = f"{source.capitalize()} to {target.capitalize()}" + results[key] = self.check_bridge_transactions( + wallet_address, token_address, amount, source, target + ) return results From ebb440123d67dcfe338fdabdb4782609e7e62fba Mon Sep 17 00:00:00 2001 From: Pooya Fekri Date: Wed, 10 Jul 2024 17:30:17 +0330 Subject: [PATCH 4/4] arbitrume bridge --- core/constraints/abstract.py | 2 ++ core/constraints/arbitrum.py | 16 +++++++++------- core/tests.py | 2 +- core/thirdpartyapp/__init__.py | 2 +- .../{arbitrum.py => arbitrum_bridge.py} | 19 ++++++------------- core/thirdpartyapp/config.py | 6 ++++++ 6 files changed, 25 insertions(+), 22 deletions(-) rename core/thirdpartyapp/{arbitrum.py => arbitrum_bridge.py} (89%) diff --git a/core/constraints/abstract.py b/core/constraints/abstract.py index f2c7a832..1998f45c 100644 --- a/core/constraints/abstract.py +++ b/core/constraints/abstract.py @@ -35,6 +35,8 @@ class ConstraintParam(Enum): VALUE = "value" EAS_SCHEMA_ID = "eas_schema_id" FARCASTER_CHANNEL_ID = "FARCASTER_CHANNEL_ID" + SOURCE_CHAIN = "source_chain" + DESTINATION_CHAIN = "destination_chain" @classmethod def choices(cls): diff --git a/core/constraints/arbitrum.py b/core/constraints/arbitrum.py index 8de47551..dc8edc87 100644 --- a/core/constraints/arbitrum.py +++ b/core/constraints/arbitrum.py @@ -3,14 +3,15 @@ ConstraintParam, ConstraintVerification, ) -from core.thirdpartyapp.arbitrum import ArbitrumUtils +from core.thirdpartyapp.arbitrum_bridge import ArbitrumBridgeUtils class HasBridgedToken(ConstraintVerification): _param_keys = [ ConstraintParam.ADDRESS, ConstraintParam.MINIMUM, - ConstraintParam.CHAIN, + ConstraintParam.SOURCE_CHAIN, + ConstraintParam.DESTINATION_CHAIN, ] app_name = ConstraintApp.ARBITRUM.value @@ -18,25 +19,26 @@ def __init__(self, user_profile) -> None: super().__init__(user_profile) def is_observed(self, *args, **kwargs) -> bool: - minimum_amount = float(self.param_values[ConstraintParam.MINIMUM.name]) - chain = self.param_values[ConstraintParam.CHAIN.name] + minimum_amount = int(self.param_values[ConstraintParam.MINIMUM.name]) + sourec_chain = self.param_values[ConstraintParam.SOURCE_CHAIN.name] + # dest_chain = self.param_values[ConstraintParam.DESTINATION_CHAIN.name] token_address = self.param_values[ConstraintParam.ADDRESS.name] - arb_utils = ArbitrumUtils() + arb_utils = ArbitrumBridgeUtils() if token_address.lower() in ["eth", ""]: token_address = None user_wallets = self.user_addresses for wallet in user_wallets: - if chain == "any": + if sourec_chain == "any": bridging_results = arb_utils.check_all_bridge_transactions( wallet, token_address, minimum_amount ) if any(bridging_results.values()): return True else: - source_chain, target_chain = self._parse_chain(chain) + source_chain, target_chain = self._parse_chain(sourec_chain) if arb_utils.check_bridge_transactions( wallet, token_address, minimum_amount, source_chain, target_chain ): diff --git a/core/tests.py b/core/tests.py index ae263af3..a3b2a155 100644 --- a/core/tests.py +++ b/core/tests.py @@ -6,7 +6,7 @@ from authentication.models import GitcoinPassportConnection, UserProfile, Wallet from core.constraints.arbitrum import HasBridgedToken from core.models import Chain, NetworkTypes, WalletAccount -from core.thirdpartyapp.arbitrum import ArbitrumUtils +from core.thirdpartyapp.arbitrum_bridge import ArbitrumUtils from .constraints import ( Attest, diff --git a/core/thirdpartyapp/__init__.py b/core/thirdpartyapp/__init__.py index 25caa35e..7f28f86e 100644 --- a/core/thirdpartyapp/__init__.py +++ b/core/thirdpartyapp/__init__.py @@ -1,4 +1,4 @@ -from .arbitrum import ArbitrumUtils +from .arbitrum_bridge import ArbitrumBridgeUtils from .EAS import EASUtils from .ens import ENSUtil # noqa: F401 from .farcaster import FarcasterUtil # noqa: F401 diff --git a/core/thirdpartyapp/arbitrum.py b/core/thirdpartyapp/arbitrum_bridge.py similarity index 89% rename from core/thirdpartyapp/arbitrum.py rename to core/thirdpartyapp/arbitrum_bridge.py index 74c0618f..fea80e49 100644 --- a/core/thirdpartyapp/arbitrum.py +++ b/core/thirdpartyapp/arbitrum_bridge.py @@ -1,20 +1,11 @@ from typing import Optional +from core.thirdpartyapp.config import ARB_BRIDGE_ADDRESSES from core.utils import Web3Utils -class ArbitrumUtils: - ETH_W3 = Web3Utils("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID") - ARB_W3 = Web3Utils("https://arb1.arbitrum.io/rpc") - NOVA_W3 = Web3Utils("https://nova.arbitrum.io/rpc") - - BRIDGE_ADDRESSES = { - "ethereum": "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a", - "arbitrum": "0x0000000000000000000000000000000000000064", - "nova": "0x0000000000000000000000000000000000000064", - } - - BRIDGE_ABI = [ +class ArbitrumBridgeUtils: + ARB_BRIDGE_ABI = [ { "anonymous": False, "inputs": [ @@ -59,7 +50,9 @@ class ArbitrumUtils: }, ] - def __init__(self): + def __init__(self, chain_name: str, rpc_url_private: str, poa: bool = False): + self.w3 = Web3Utils(rpc_url_private=rpc_url_private, poa=poa) + self.w3.set_contract(ARB_BRIDGE_ADDRESSES.get(chain_name), self.BRIDGE_ABI) self.contracts = { "ethereum": self.ETH_W3.set_contract( self.BRIDGE_ADDRESSES["ethereum"], self.BRIDGE_ABI diff --git a/core/thirdpartyapp/config.py b/core/thirdpartyapp/config.py index b3be82c6..d50c3249 100644 --- a/core/thirdpartyapp/config.py +++ b/core/thirdpartyapp/config.py @@ -22,3 +22,9 @@ ), } SUBGRAPH_BASE_URL = os.getenv("SUBGRAPH_BASE_URL", "https://api.studio.thegraph.com") + +ARB_BRIDGE_ADDRESSES = { + "ethereum": "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a", + "arbitrum": "0x0000000000000000000000000000000000000064", + "nova": "0x0000000000000000000000000000000000000064", +}