Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5984c19
cherrypick part of changes
Dec 1, 2021
613a469
create indexer.py
Dec 1, 2021
c0d0e6c
remove solana_receipts_update.py
Dec 1, 2021
3f6b5c4
Cherry pick files from old branch
Dec 1, 2021
0790298
add requirement
Dec 1, 2021
340c854
fix refactoring issues
Dec 1, 2021
7449b38
Fix inspection issues
Dec 1, 2021
b3dacfa
fix last issue
Dec 1, 2021
a50cd47
Merge branch '336_indexer_refactoring' into 337_сreate_base_airdroppe…
Dec 1, 2021
2b8f879
Merge remote-tracking branch 'origin/develop' into 337_сreate_base_ai…
Dec 2, 2021
f51f2ed
simplify tests
Dec 2, 2021
6678924
add test
Dec 2, 2021
5d454b7
Merge remote-tracking branch 'origin/develop' into 337_сreate_base_ai…
Dec 3, 2021
add136a
add price provider
Dec 1, 2021
9a4be44
fix PriceProvider, add test
Dec 1, 2021
07aaca8
Add tests. Check worn on all nets
Dec 1, 2021
7a46c12
refactoring
Dec 1, 2021
2fc1424
integrate price_provider into airdropper
Dec 2, 2021
d157d67
integrate price provider
Dec 2, 2021
8a6abfd
use new faucet method
Dec 3, 2021
3d4dec9
add new parameter to airdropper main
Dec 3, 2021
5c29832
Test discriptions for airdropper
Dec 3, 2021
6a4efdc
Comments for price provider tests
Dec 3, 2021
14aeeed
remove unnecessary comment
Dec 3, 2021
bd35791
Merge remote-tracking branch 'origin/develop' into 338_create_sol_pri…
Dec 3, 2021
ff1f557
Merge remote-tracking branch 'origin/develop' into 338_create_sol_pri…
Dec 6, 2021
c28ca8e
fix error
Dec 6, 2021
8c68755
Merge remote-tracking branch 'origin/develop' into 338_create_sol_pri…
Dec 7, 2021
5325895
Merge remote-tracking branch 'origin/develop' into 338_create_sol_pri…
Dec 8, 2021
a1cbad2
fix airdropper run
Dec 10, 2021
4ed6d78
remove duplicated code
Dec 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
use new faucet method
  • Loading branch information
ivanl committed Dec 3, 2021
commit 8a6abfda1e2ad8748b8eeeef739598ffb9802714
18 changes: 12 additions & 6 deletions proxy/indexer/airdropper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def __init__(self,
evm_loader_id,
faucet_url = '',
wrapper_whitelist = [],
log_level = 'INFO'):
log_level = 'INFO',
neon_decimals = 9):
IndexerBase.__init__(self, solana_url, evm_loader_id, log_level)

# collection of eth-address-to-create-accout-trx mappings
Expand All @@ -36,6 +37,7 @@ def __init__(self,
# so using mainnet solana for simplicity
self.price_provider = PriceProvider(mainnet_solana,
mainnet_price_accounts)
self.neon_decimals = neon_decimals


# helper function checking if given contract address is in whitelist
Expand Down Expand Up @@ -81,9 +83,10 @@ def _airdrop_to(self, create_acc):
logger.info(f"NEON price: ${NEON_PRICE_USD}")
airdrop_amount_neon = airdrop_amount_usd / NEON_PRICE_USD
logger.info(f"Airdrop {airdrop_amount_neon} NEONs to address: {eth_address}")
airdrop_galans = int(airdrop_amount_neon * pow(10, self.neon_decimals))

json_data = { 'wallet': eth_address, 'amount': airdrop_amount_neon }
resp = requests.post(self.faucet_url + '/request_eth_token', json = json_data)
json_data = { 'wallet': eth_address, 'amount': airdrop_galans }
resp = requests.post(self.faucet_url + '/request_neon_in_galans', json = json_data)
if not resp.ok:
logger.warning(f'Failed to airdrop: {resp.status_code}')
return
Expand Down Expand Up @@ -157,21 +160,24 @@ def run_airdropper(solana_url,
evm_loader_id,
faucet_url = '',
wrapper_whitelist = [],
log_level = 'INFO'):
log_level = 'INFO',
neon_decimals = 9):
logging.basicConfig(format='%(asctime)s - pid:%(process)d [%(levelname)-.1s] %(funcName)s:%(lineno)d - %(message)s')
logger.setLevel(logging.DEBUG)
logger.info(f"""Running indexer with params:
solana_url: {solana_url},
evm_loader_id: {evm_loader_id},
log_level: {log_level},
faucet_url: {faucet_url},
wrapper_whitelist: {wrapper_whitelist}""")
wrapper_whitelist: {wrapper_whitelist},
NEON decimals: {neon_decimals}""")

airdropper = Airdropper(solana_url,
evm_loader_id,
faucet_url,
wrapper_whitelist,
log_level)
log_level,
neon_decimals)
airdropper.run()


Expand Down
76 changes: 40 additions & 36 deletions proxy/testing/test_airdropper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
class MockFaucet(MockServer):
def __init__(self, port):
super().__init__(port)
self.request_eth_token_mock = MagicMock()
self.request_eth_token_mock.side_effect = itertools.repeat({})
self.add_url_rule("/request_eth_token", callback=self.request_eth_token, methods=['POST'])
self.request_neon_in_galans_mock = MagicMock()
self.request_neon_in_galans_mock.side_effect = itertools.repeat({})
self.add_url_rule("/request_neon_in_galans", callback=self.request_neon_in_galans, methods=['POST'])

def request_eth_token(self):
def request_neon_in_galans(self):
req = request.get_json()
return self.request_eth_token_mock(req)
return self.request_neon_in_galans_mock(req)


def create_signature_for_address(signature: str):
Expand Down Expand Up @@ -49,23 +49,27 @@ def setUpClass(cls) -> None:
cls.address = 'localhost'
cls.faucet_port = 3333

cls.faucet = MockFaucet(cls.faucet_port)
cls.faucet.start()
time.sleep(0.2)


cls.evm_loader_id = evm_loader_addr
cls.wrapper_whitelist = wrapper_whitelist
cls.neon_decimals = 9
cls.airdropper = Airdropper(f'http://{cls.address}:8899',
cls.evm_loader_id,
f'http://{cls.address}:{cls.faucet_port}',
cls.wrapper_whitelist,
'INFO')
'INFO',
cls.neon_decimals)

def setUp(self) -> None:
self.faucet = MockFaucet(self.faucet_port)
self.faucet.start()
time.sleep(0.2)

def tearDown(self) -> None:
self.faucet.shutdown_server()
self.faucet.join()

@classmethod
def tearDownClass(cls) -> None:
cls.faucet.shutdown_server()
cls.faucet.join()

@patch.object(PriceProvider, 'get_price')
@patch.object(SQLDict, '__setitem__')
Expand All @@ -77,19 +81,19 @@ def test_success_process_trx_with_one_airdrop(self,
print("\n\nShould airdrop to new address - one target in transaction")

sol_price = 341
airdrop_amount = (AIRDROP_AMOUNT_SOL * sol_price) / NEON_PRICE_USD
airdrop_amount = int(pow(10, self.neon_decimals) * (AIRDROP_AMOUNT_SOL * sol_price) / NEON_PRICE_USD)
mock_get_price.side_effect = [sol_price]
mock_sql_dict_contains.side_effect = [False] # new eth address
self.faucet.request_eth_token_mock.side_effect = [Response("{}", status=200, mimetype='application/json')]
self.faucet.request_neon_in_galans_mock.side_effect = [Response("{}", status=200, mimetype='application/json')]

self.airdropper.process_trx_airdropper_mode(pre_token_airdrop_trx1)

mock_sql_dict_contains.assert_called_once_with(token_airdrop_address1)
mock_sql_dict_setitem.assert_has_calls([call(token_airdrop_address1, ANY)])
mock_get_price.assert_called_once_with('SOL/USD')
json_req = {'wallet': token_airdrop_address1, 'amount': airdrop_amount}
self.faucet.request_eth_token_mock.assert_called_once_with(json_req)
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_called_once_with(json_req)
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(PriceProvider, 'get_price')
Expand All @@ -103,15 +107,15 @@ def test_failed_process_trx_with_one_airdrop_price_provider_error(self,

mock_get_price.side_effect = [None]
mock_sql_dict_contains.side_effect = [False] # new eth address
self.faucet.request_eth_token_mock.side_effect = [Response("{}", status=200, mimetype='application/json')]
self.faucet.request_neon_in_galans_mock.side_effect = [Response("{}", status=200, mimetype='application/json')]

self.airdropper.process_trx_airdropper_mode(pre_token_airdrop_trx1)

mock_sql_dict_contains.assert_called_once_with(token_airdrop_address1)
mock_sql_dict_setitem.assert_not_called()
mock_get_price.assert_called_once_with('SOL/USD')
self.faucet.request_eth_token_mock.assert_not_called()
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_not_called()
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(Airdropper, '_is_allowed_wrapper_contract')
Expand All @@ -128,8 +132,8 @@ def test_failed_airdrop_contract_not_in_whitelist(self,
mock_is_allowed_contract.assert_called_once()
mock_sql_dict_contains.assert_not_called()
mock_sql_dict_setitem.assert_not_called()
self.faucet.request_eth_token_mock.assert_not_called()
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_not_called()
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(PriceProvider, 'get_price')
Expand All @@ -142,19 +146,19 @@ def test_faucet_failure(self,
print("\n\nShould not add address to processed list due to faucet error")

sol_price = 341
airdrop_amount = (AIRDROP_AMOUNT_SOL * sol_price) / NEON_PRICE_USD
airdrop_amount = int(pow(10, self.neon_decimals) * (AIRDROP_AMOUNT_SOL * sol_price) / NEON_PRICE_USD)
mock_get_price.side_effect = [sol_price]
mock_sql_dict_contains.side_effect = [False] # new eth address
self.faucet.request_eth_token_mock.side_effect = [Response("{}", status=400, mimetype='application/json')]
self.faucet.request_neon_in_galans_mock.side_effect = [Response("{}", status=400, mimetype='application/json')]

self.airdropper.process_trx_airdropper_mode(pre_token_airdrop_trx1)

mock_sql_dict_contains.assert_called_once_with(token_airdrop_address1)
mock_get_price.assert_called_once_with('SOL/USD')
mock_sql_dict_setitem.assert_not_called()
json_req = {'wallet': token_airdrop_address1, 'amount': airdrop_amount}
self.faucet.request_eth_token_mock.assert_called_once_with(json_req)
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_called_once_with(json_req)
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(SQLDict, '__setitem__')
Expand All @@ -169,8 +173,8 @@ def test_process_trx_with_one_airdrop_for_already_processed_address(self,

mock_sql_dict_contains.assert_called_once_with(token_airdrop_address1)
mock_sql_dict_setitem.assert_not_called()
self.faucet.request_eth_token_mock.assert_not_called()
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_not_called()
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(PriceProvider, 'get_price')
Expand All @@ -183,12 +187,12 @@ def test_complex_transation(self,
print("\n\nShould airdrop to several targets in one transaction")
sol_price1 = 341
sol_price2 = 225
airdrop_amount1 = (AIRDROP_AMOUNT_SOL * sol_price1) / NEON_PRICE_USD
airdrop_amount2 = (AIRDROP_AMOUNT_SOL * sol_price2) / NEON_PRICE_USD
airdrop_amount1 = int(pow(10, self.neon_decimals) * (AIRDROP_AMOUNT_SOL * sol_price1) / NEON_PRICE_USD)
airdrop_amount2 = int(pow(10, self.neon_decimals) * (AIRDROP_AMOUNT_SOL * sol_price2) / NEON_PRICE_USD)
mock_get_price.side_effect = [sol_price1, sol_price2]
mock_sql_dict_contains.side_effect = [False, False] # both targets are new
self.faucet.request_eth_token_mock.side_effect = [Response("{}", status=200, mimetype='application/json'),
Response("{}", status=200, mimetype='application/json')]
self.faucet.request_neon_in_galans_mock.side_effect = [Response("{}", status=200, mimetype='application/json'),
Response("{}", status=200, mimetype='application/json')]

self.airdropper.process_trx_airdropper_mode(pre_token_airdrop_trx2)

Expand All @@ -199,8 +203,8 @@ def test_complex_transation(self,
call(token_airdrop_address2, ANY)])
json_req1 = {'wallet': token_airdrop_address2, 'amount': airdrop_amount2}
json_req2 = {'wallet': token_airdrop_address3, 'amount': airdrop_amount1}
self.faucet.request_eth_token_mock.assert_has_calls([call(json_req2), call(json_req1)])
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_has_calls([call(json_req2), call(json_req1)])
self.faucet.request_neon_in_galans_mock.reset_mock()


@patch.object(SQLDict, '__setitem__')
Expand All @@ -213,6 +217,6 @@ def test_no_airdrop_instructions(self,

mock_sql_dict_contains.assert_not_called()
mock_sql_dict_setitem.assert_not_called()
self.faucet.request_eth_token_mock.assert_not_called()
self.faucet.request_eth_token_mock.reset_mock()
self.faucet.request_neon_in_galans_mock.assert_not_called()
self.faucet.request_neon_in_galans_mock.reset_mock()