Skip to content

Commit c1487d0

Browse files
committed
(feat) Implemented OFAC list address check
1 parent 206383b commit c1487d0

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

pyinjective/composer.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from pyinjective.constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, INJ_DECIMALS, INJ_DENOM
1212
from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket
1313
from pyinjective.core.token import Token
14+
from pyinjective.ofac import OfacChecker
1415
from pyinjective.proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb, tx_pb2 as cosmos_authz_tx_pb
1516
from pyinjective.proto.cosmos.bank.v1beta1 import bank_pb2 as bank_pb, tx_pb2 as cosmos_bank_tx_pb
1617
from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as base_coin_pb
@@ -147,6 +148,7 @@ def __init__(
147148
self.derivative_markets = derivative_markets
148149
self.binary_option_markets = binary_option_markets
149150
self.tokens = tokens
151+
self._ofac_checker = OfacChecker()
150152

151153
def Coin(self, amount: int, denom: str):
152154
"""
@@ -471,6 +473,8 @@ def MsgBid(self, sender: str, bid_amount: float, round: float):
471473

472474
# region Authz module
473475
def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int):
476+
if self._ofac_checker.is_blacklisted(granter):
477+
raise Exception(f"Address {granter} is in the OFAC list")
474478
auth = cosmos_authz_pb.GenericAuthorization(msg=msg_type)
475479
any_auth = any_pb2.Any()
476480
any_auth.Pack(auth, type_url_prefix="")
@@ -2125,6 +2129,9 @@ def MsgGrantTyped(
21252129
subaccount_id: str,
21262130
**kwargs,
21272131
):
2132+
if self._ofac_checker.is_blacklisted(granter):
2133+
raise Exception(f"Address {granter} is in the OFAC list")
2134+
21282135
auth = None
21292136
if msg_type == "CreateSpotLimitOrderAuthz":
21302137
auth = injective_authz_pb.CreateSpotLimitOrderAuthz(

pyinjective/core/broadcaster.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from pyinjective.constant import GAS_PRICE
1313
from pyinjective.core.gas_limit_estimator import GasLimitEstimator
1414
from pyinjective.core.network import Network
15+
from pyinjective.ofac import OfacChecker
1516

1617

1718
class BroadcasterAccountConfig(ABC):
@@ -62,6 +63,10 @@ def __init__(
6263
self._client = client
6364
self._composer = composer
6465
self._fee_calculator = fee_calculator
66+
self._ofac_checker = OfacChecker()
67+
68+
if self._ofac_checker.is_blacklisted(address=self._account_config.trading_injective_address):
69+
raise Exception(f"Address {self._account_config.trading_injective_address} is in the OFAC list")
6570

6671
@classmethod
6772
def new_using_simulation(

pyinjective/ofac.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
[
2+
"0x179f48c78f57a3a78f0608cc9197b8972921d1d2",
3+
"0x1967d8af5bd86a497fb3dd7899a020e47560daaf",
4+
"0x19aa5fe80d33a56d56c78e82ea5e50e5d80b4dff",
5+
"0x19aa5fe80d33a56d56c78e82ea5e50e5d80b4dff",
6+
"0x1da5821544e25c636c1417ba96ade4cf6d2f9b5a",
7+
"0x2f389ce8bd8ff92de3402ffce4691d17fc4f6535",
8+
"0x2f389ce8bd8ff92de3402ffce4691d17fc4f6535",
9+
"0x2f50508a8a3d323b91336fa3ea6ae50e55f32185",
10+
"0x308ed4b7b49797e1a98d3818bff6fe5385410370",
11+
"0x3cbded43efdaf0fc77b9c55f6fc9988fcc9b757d",
12+
"0x3efa30704d2b8bbac821307230376556cf8cc39e",
13+
"0x48549a34ae37b12f6a30566245176994e17c6b4a",
14+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
15+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
16+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
17+
"0x530a64c0ce595026a4a556b703644228179e2d57",
18+
"0x5512d943ed1f7c8a43f3435c85f7ab68b30121b0",
19+
"0x5a7a51bfb49f190e5a6060a5bc6052ac14a3b59f",
20+
"0x5f48c2a71b2cc96e3f0ccae4e39318ff0dc375b2",
21+
"0x6be0ae71e6c41f2f9d0d1a3b8d0f75e6f6a0b46e",
22+
"0x6f1ca141a28907f78ebaa64fb83a9088b02a8352",
23+
"0x746aebc06d2ae31b71ac51429a19d54e797878e9",
24+
"0x77777feddddffc19ff86db637967013e6c6a116c",
25+
"0x797d7ae72ebddcdea2a346c1834e04d1f8df102b",
26+
"0x8576acc5c05d6ce88f4e49bf65bdf0c62f91353c",
27+
"0x901bb9583b24d97e995513c6778dc6888ab6870e",
28+
"0x961c5be54a2ffc17cf4cb021d863c42dacd47fc1",
29+
"0x97b1043abd9e6fc31681635166d430a458d14f9c",
30+
"0x9c2bc757b66f24d60f016b6237f8cdd414a879fa",
31+
"0x9f4cda013e354b8fc285bf4b9a60460cee7f7ea9",
32+
"0xa7e5d5a720f06526557c513402f2e6b5fa20b008",
33+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
34+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
35+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
36+
"0xc455f7fd3e0e12afd51fba5c106909934d8a0e4a",
37+
"0xca0840578f57fe71599d29375e16783424023357",
38+
"0xd0975b32cea532eadddfc9c60481976e39db3472",
39+
"0xd882cfc20f52f2599d84b8e8d58c7fb62cfe344b",
40+
"0xd882cfc20f52f2599d84b8e8d58c7fb62cfe344b",
41+
"0xe1d865c3d669dcc8c57c8d023140cb204e672ee4",
42+
"0xe7aa314c77f4233c18c6cc84384a9247c0cf367b",
43+
"0xed6e0a7e4ac94d976eebfb82ccf777a3c6bad921",
44+
"0xf3701f445b6bdafedbca97d1e477357839e4120d",
45+
"0xfac583c0cf07ea434052c49115a4682172ab6b4f",
46+
"0xfec8a60023265364d066a1212fde3930f6ae8da7",
47+
"0xffbac21a641dcfe4552920138d90f3638b3c9fba"
48+
]

pyinjective/ofac.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import asyncio
2+
import json
3+
import os
4+
5+
import aiohttp
6+
7+
OFAC_LIST_URL = "https://raw.githubusercontent.com/InjectiveLabs/injective-lists/master/wallets/ofac.json"
8+
OFAC_LIST_FILENAME_DEFAULT = "ofac.json"
9+
OFAC_LIST_FILENAME = OFAC_LIST_FILENAME_DEFAULT
10+
11+
12+
class OfacChecker:
13+
def __init__(self):
14+
self._ofac_list_path = self.get_ofac_list_path()
15+
if not os.path.exists(self._ofac_list_path):
16+
raise Exception(
17+
"OFAC list is missing on the disk. Please, download it by running python3 pyinjective/ofac_list.py"
18+
)
19+
20+
with open(self._ofac_list_path, "r") as f:
21+
self._ofac_list = set(json.load(f))
22+
23+
@classmethod
24+
def get_ofac_list_path(cls):
25+
current_directory = os.getcwd()
26+
while os.path.basename(current_directory) != "sdk-python":
27+
current_directory = os.path.dirname(current_directory)
28+
return os.path.join(os.path.join(current_directory, "pyinjective"), OFAC_LIST_FILENAME)
29+
30+
@classmethod
31+
async def download_ofac_list(cls):
32+
async with aiohttp.ClientSession() as session:
33+
try:
34+
async with session.get(OFAC_LIST_URL) as response:
35+
response.raise_for_status()
36+
text_content = await response.text()
37+
ofac_list = json.loads(text_content)
38+
ofac_file_path = cls.get_ofac_list_path()
39+
with open(ofac_file_path, "w") as f:
40+
json.dump(ofac_list, f, indent=2)
41+
f.write("\n")
42+
return
43+
except Exception as e:
44+
raise Exception(f"Error fetching OFAC list: {e}")
45+
46+
def is_blacklisted(self, address: str) -> bool:
47+
return address in self._ofac_list
48+
49+
50+
async def main():
51+
await OfacChecker.download_ofac_list()
52+
53+
54+
if __name__ == "__main__":
55+
asyncio.run(main())

tests/core/test_broadcaster.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import json
2+
import os
3+
import unittest
4+
from unittest.mock import Mock
5+
6+
import pytest
7+
8+
import pyinjective.ofac as ofac
9+
from pyinjective import PrivateKey
10+
from pyinjective.async_client import AsyncClient
11+
from pyinjective.composer import Composer
12+
from pyinjective.core.broadcaster import MsgBroadcasterWithPk, StandardAccountBroadcasterConfig
13+
from pyinjective.core.network import Network
14+
15+
16+
class TestBroadcastAddressInOfacList(unittest.TestCase):
17+
def setUp(self):
18+
ofac.OFAC_LIST_FILENAME = "ofac_test.json"
19+
self.private_key_banned = PrivateKey.from_mnemonic("test mnemonic never use other places")
20+
public_key_banned = self.private_key_banned.to_public_key()
21+
address_banned = public_key_banned.to_address()
22+
23+
ofac_list = [address_banned.to_acc_bech32()]
24+
25+
with open(ofac.OfacChecker.get_ofac_list_path(), "w") as ofac_file:
26+
json.dump(ofac_list, ofac_file)
27+
28+
def tearDown(self):
29+
os.remove(ofac.OfacChecker.get_ofac_list_path())
30+
ofac.OFAC_LIST_FILENAME = ofac.OFAC_LIST_FILENAME_DEFAULT
31+
32+
def test_broadcast_address_in_ofac_list(self):
33+
network = Network.local()
34+
client = AsyncClient(
35+
network=Network.local(),
36+
)
37+
composer = Mock(spec=Composer)
38+
39+
account_config = StandardAccountBroadcasterConfig(private_key=self.private_key_banned.to_hex())
40+
41+
with pytest.raises(Exception):
42+
_ = MsgBroadcasterWithPk(
43+
network=network,
44+
account_config=account_config,
45+
client=client,
46+
composer=composer,
47+
fee_calculator=Mock(),
48+
)

0 commit comments

Comments
 (0)