Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
5056536
constants and utils
Nov 2, 2021
95cfd3a
solana rest api tools imports
Nov 2, 2021
c108013
comments and tabs
Nov 2, 2021
505a58a
rename calling getTokens function
Nov 2, 2021
1626d5b
Meet SolanaErrors
Nov 2, 2021
0226e97
Implement creating account on getting balance
Nov 2, 2021
6b95b80
Merge branch 'develop' into 191-create-and-airdrop-eth-account
Nov 2, 2021
6451aa6
Move tests and add get_from_dict test
Nov 2, 2021
a9a9c25
Add test "Metamask creates an account"
Nov 4, 2021
644f28d
Just not ot loose changes
Nov 7, 2021
3bc25ef
implemented
Nov 7, 2021
db81aa3
Fix tests on CI
Nov 7, 2021
3c63dab
set NEW_USER_AIRDROP_AMOUNT on CI
Nov 7, 2021
771ca64
improve logging
Nov 8, 2021
a90d8ad
improve logging of SendTransactionError
Nov 9, 2021
aa2f329
spit and polish
Nov 9, 2021
e14a6b1
extend airdrop tests
Nov 10, 2021
0b0046e
spit and polish
Nov 10, 2021
3faddaa
Merge branch 'develop' into 191-create-and-airdrop-eth-account
Nov 10, 2021
d9c677b
spit and polish
Nov 10, 2021
9d411c8
move tests
Nov 10, 2021
e9a18b7
move tests
Nov 10, 2021
343cedb
Get rid off extra data.py
Nov 10, 2021
f1b8efb
Improve logging
Nov 11, 2021
df19a62
spit and polish
Nov 11, 2021
4a390d1
spit and polish
Nov 11, 2021
5481615
Merge branch 'develop' into 191-create-and-airdrop-eth-account
Nov 11, 2021
31c7ddb
spit and polish
Nov 11, 2021
b6927e9
spit and polish
Nov 11, 2021
c394edb
Pass MINIMAL_GAS_PRICE int airdrop tests
Nov 11, 2021
0b97d84
spit and polish
Nov 11, 2021
e1bf416
move test_operator_spending.py
Nov 11, 2021
c1321fc
move test_operator_spending.py
Nov 11, 2021
517c133
spit and polish
Nov 11, 2021
644a64f
spit and polish
Nov 11, 2021
7c5ac61
Fix message printing
Nov 11, 2021
85e89fe
spit and polish
Nov 11, 2021
790e6a5
spit and polish
Nov 11, 2021
26d58f7
spit and polish
Nov 11, 2021
39ed586
spit and polish
Nov 11, 2021
955d0aa
use error instead of debug
Nov 12, 2021
a22639b
Revert "constants and utils"
Nov 15, 2021
4995d3f
Emphasize meaning of trx extending functions
Nov 15, 2021
b61f5a8
Resolve @otselik remarks
Nov 15, 2021
0c047e7
rollback common/utils.py
Nov 15, 2021
4ba69a6
Merge branch 'develop' into 191-create-and-airdrop-eth-account
Nov 15, 2021
e1fd299
Rollback some changes
Nov 15, 2021
1c9862c
Resolve remarks
Nov 15, 2021
0bbc7d9
Use exception to check result of get_token_balance_gwei
Nov 16, 2021
f1dc4f7
just not to loose changes
Nov 16, 2021
781e986
spit and polish
Nov 16, 2021
2f9216c
Provide estimate_gas with airdropping
Nov 16, 2021
65bfb8d
just not to loose changes
Nov 17, 2021
92f26c8
Update tests
Nov 17, 2021
a62f413
Simplify airdrop processing
Nov 17, 2021
026a4a6
Spit and polish
Nov 17, 2021
db47b80
Spit and polish
Nov 17, 2021
a102251
Spit and polish
Nov 17, 2021
d1a9019
Merge branch '191-create-and-airdrop-eth-account' into 342-just-airdr…
Nov 17, 2021
cc42eea
Freeze changes up
Nov 17, 2021
458878e
Isolate errors
Nov 18, 2021
8190225
spit and polish
Nov 18, 2021
f761ab6
spit and polish
Nov 18, 2021
f9af195
Merge branch 'develop' into 191-create-and-airdrop-eth-account
Nov 18, 2021
e51445a
Merge branch '191-create-and-airdrop-eth-account' into 299-emulate-so…
Nov 18, 2021
dfea371
fix estimate gas
Nov 18, 2021
dba8068
Merge branch '342-just-airdrop-on-gas-estimation' into 299-emulate-so…
Nov 18, 2021
eb0bb46
not to loose changes
Nov 18, 2021
73a0423
Remove extra args from ether2program
Nov 19, 2021
9e6b7dc
Spit and polish
Nov 19, 2021
5be978c
Spit and polish
Nov 19, 2021
884ec0f
spit and polish
Nov 19, 2021
a0e3ebb
Spit and polish
Nov 19, 2021
210d052
Rollback changes
Nov 19, 2021
51a3430
Merge branch '304-remove-extra-args-from-ether2program' into 299-emul…
Nov 19, 2021
72ef3d0
Implement test
Nov 25, 2021
addb0dd
Merge branch 'develop' into 299-emulate-solidity-raise-an-exception
Nov 25, 2021
e740883
Spit and polish
Nov 25, 2021
8a6595c
Just not to loose changes
Nov 25, 2021
a5cf3ad
Implement revert processing
Dec 8, 2021
9a9757e
Merge branch 'develop' into 299-emulate-solidity-raise-an-exception
Dec 8, 2021
b5720a6
rename tests airdrop on ci
Dec 8, 2021
685c2a9
rename airdrop on ci tests
Dec 8, 2021
4531d2d
Spit and polish
Dec 8, 2021
e15a7bb
Merge branch 'develop' into 299-emulate-solidity-raise-an-exception
Dec 8, 2021
6e2a308
Check check
Dec 9, 2021
3cbbee0
Check check
Dec 9, 2021
f993964
Merge branch 'develop' into 299-emulate-solidity-raise-an-exception
Dec 15, 2021
b768240
Spit and polish
Dec 15, 2021
3a07c1b
Rollback some
Dec 15, 2021
99ce2b7
Fix tests
Dec 16, 2021
d9b9dcb
Spit and polish
Dec 20, 2021
29b361a
Spit and polish
Dec 20, 2021
967d79f
new test
Dec 20, 2021
174ec47
Fix tests
Dec 20, 2021
5edb830
Merge remote-tracking branch 'origin/develop' into 299-emulate-solidi…
Dec 20, 2021
98c6aae
Spit and polish
Dec 20, 2021
1aca196
Add an extra checks on decode revert message
Dec 21, 2021
97645c3
Get rid of hex on str typed revert data
Dec 21, 2021
c9e34da
Process empty revert data other way
Dec 21, 2021
7e31816
spit and polish
Dec 21, 2021
4e9472c
spit and polish
Dec 21, 2021
c4bd1c3
spit and polish
Dec 22, 2021
631e122
spit and polish
Dec 22, 2021
00104ba
spit and polish
Dec 22, 2021
b6ef371
spit and polish
Dec 22, 2021
05a4af2
spit and polish
Dec 22, 2021
5309fc9
spit and polish
Dec 22, 2021
7d9f01b
spit and polish
Dec 22, 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
extend airdrop tests
  • Loading branch information
rozhkovdmitrii committed Nov 10, 2021
commit e14a6b1c5c36afb32be87e498b90cf860a00655d
45 changes: 25 additions & 20 deletions proxy/plugin/solana_rest_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:copyright: (c) 2013-present by Abhinav Singh and contributors.
:license: BSD, see LICENSE for more details.
"""
from typing import List, Tuple
from typing import List, Tuple, Optional
import json
import unittest
import rlp
Expand All @@ -25,7 +25,7 @@
import base58
import traceback
import threading
from .solana_rest_api_tools import EthereumAddress, create_account_with_seed, evm_loader_id, get_token_balance, \
from .solana_rest_api_tools import EthereumAddress, create_account_with_seed, evm_loader_id, get_token_balance_or_airdrop, \
getAccountInfo, solana_cli, call_signed, solana_url, call_emulated, \
Trx, EthereumError, create_collateral_pool_address, getTokenAddr, STORAGE_SIZE, neon_config_load
from solana.rpc.commitment import Commitment, Confirmed
Expand Down Expand Up @@ -69,22 +69,8 @@ def __init__(self, client, signer, proxy_id):
class EthereumModel:
def __init__(self):
# Initialize user account
res = solana_cli().call('config', 'get')
substr = "Keypair Path: "
path = ""
for line in res.splitlines():
if line.startswith(substr):
path = line[len(substr):].strip()
if path == "":
raise Exception("cannot get keypair path")

with open(path.strip(), mode='r') as file:
pk = (file.read())
nums = list(map(int, pk.strip("[] \n").split(',')))
nums = nums[0:32]
values = bytes(nums)
self.signer = sol_Account(values)

self.signer = self.get_solana_account()
self.client = SolanaClient(solana_url)

self.logs_db = LogDB(filename="local.db")
Expand All @@ -102,6 +88,26 @@ def __init__(self):
neon_config_load(self)
pass

@staticmethod
def get_solana_account() -> Optional[sol_Account]:
solana_account = None
res = solana_cli().call('config', 'get')
substr = "Keypair Path: "
path = ""
for line in res.splitlines():
if line.startswith(substr):
path = line[len(substr):].strip()
if path == "":
raise Exception("cannot get keypair path")

with open(path.strip(), mode='r') as file:
pk = (file.read())
nums = list(map(int, pk.strip("[] \n").split(',')))
nums = nums[0:32]
values = bytes(nums)
solana_account = sol_Account(values)
return solana_account

def web3_clientVersion(self):
neon_config_load(self)
return self.neon_config_dict['web3_clientVersion']
Expand Down Expand Up @@ -150,7 +156,7 @@ def eth_getBalance(self, account, tag):
"""
eth_acc = EthereumAddress(account)
logger.debug('eth_getBalance: %s %s', account, eth_acc)
balance = get_token_balance(self.client, self.signer, evm_loader_id, eth_acc, self.signer.public_key())
balance = get_token_balance_or_airdrop(self.client, self.signer, evm_loader_id, eth_acc)

return hex(balance*10**9)

Expand Down Expand Up @@ -478,12 +484,11 @@ def default(self, obj):


class SolanaContractTests(unittest.TestCase):

def setUp(self):
self.model = EthereumModel()
self.owner = '0xc1566af4699928fdf9be097ca3dc47ece39f8f8e'
self.token1 = '0x49a449cd7fd8fbcf34d103d98f2c05245020e35b'
# self.assertEqual(self.getBalance(self.owner), 1000*10**18)
# self.assertEqual(self.getBalance(self.token1), 0)

def getBalance(self, account):
return int(self.model.eth_getBalance(account, 'latest'), 16)
Expand Down
15 changes: 8 additions & 7 deletions proxy/plugin/solana_rest_api_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1238,32 +1238,33 @@ def create_and_mint_tkn_acc(client: SolanaClient, signer: SolanaAccount, eth_acc
raise Exception("Create account error")


def get_token_balance_impl(client: SolanaClient, account: str, eth_acc: EthereumAddress) -> [Optional[int], Optional[Union[Dict, str]]]:
token_account = get_associated_token_address(PublicKey(account), ETH_TOKEN_MINT_ID)
def get_token_balance_gwei(client: SolanaClient, token_owner_acc: str, eth_acc: EthereumAddress) \
-> [Optional[int], Optional[Union[Dict, str]]]:
token_account = get_associated_token_address(PublicKey(token_owner_acc), ETH_TOKEN_MINT_ID)
rpc_response = client.get_token_account_balance(token_account, commitment=Confirmed)
error = rpc_response.get('error')
if error is None:
balance = get_from_dict(rpc_response, "result", "value", "amount")
if balance is None:
return None, f"Failed to get token balance from: {rpc_response}, by eth account:" \
f" {eth_acc} aka: {token_account} at token: {ETH_TOKEN_MINT_ID}"
return balance, None
return int(balance), None
return None, error


def get_token_balance(client: SolanaClient, signer: SolanaAccount, evm_loader: str, eth_acc: EthereumAddress, base_account: PublicKey) -> int:
def get_token_balance_or_airdrop(client: SolanaClient, signer: SolanaAccount, evm_loader: str, eth_acc: EthereumAddress) -> int:

account, nonce = ether2program(bytes(eth_acc).hex(), evm_loader, base_account)
account, nonce = ether2program(bytes(eth_acc).hex(), evm_loader, signer.public_key())
logger.debug(f"Get balance for eth account: {eth_acc} aka: {account} at token: {ETH_TOKEN_MINT_ID}")

balance, error = get_token_balance_impl(client, account, eth_acc)
balance, error = get_token_balance_gwei(client, account, eth_acc)
if error is None:
return int(balance)

if error.get("message") == SolanaErrors.AccountNotFound.value and NEW_USER_AIRDROP_AMOUNT > 0:
logger.debug(f"Account not found: {eth_acc} aka: {account} at token: {ETH_TOKEN_MINT_ID}")
create_and_mint_tkn_acc(client, signer, eth_acc)
balance, error = get_token_balance_impl(client, account, eth_acc)
balance, error = get_token_balance_gwei(client, account, eth_acc)
if error is None:
return int(balance)

Expand Down
98 changes: 70 additions & 28 deletions proxy/testing/test_airdropping_eth_accounts.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,80 @@
import unittest
import os
import solcx

import eth_account
import eth_typing
import eth_utils
import os
from web3 import Web3
import solcx
import logging
from eth_account.account import LocalAccount

from web3 import Web3, eth as web3_eth
from solana.rpc.api import Client as SolanaClient

NEW_USER_AIRDROP_AMOUNT = int(os.environ.get("NEW_USER_AIRDROP_AMOUNT", "0"))
from ..plugin.solana_rest_api import EthereumModel
from ..plugin.solana_rest_api_tools import get_token_balance_gwei, EthereumAddress, ether2program


class TestAirdroppingEthAccounts(unittest.TestCase):

@classmethod
def setUpClass(cls) -> None:
cls._EVM_LOADER_ID = os.environ.get("EVM_LOADER")
new_user_airdrop_amount = int(os.environ.get("NEW_USER_AIRDROP_AMOUNT", "0"))
cls._EXPECTED_BALANCE_WEI = eth_utils.to_wei(new_user_airdrop_amount, 'ether')

proxy_url = os.environ.get('PROXY_URL', 'http://localhost:9090/solana')
cls.proxy = Web3(Web3.HTTPProvider(proxy_url))
cls._web3 = Web3(Web3.HTTPProvider(proxy_url))
solana_url = os.environ.get("SOLANA_URL", "http://localhost:8899")
cls._solana_client = SolanaClient(solana_url)
cls._host_solana_account = EthereumModel.get_solana_account()

def test_airdrop_on_get_balance(self):
account: eth_account.account.LocalAccount = eth_account.account.Account.create()
block_number: eth_typing.BlockNumber = self.proxy.eth.get_block_number()
actual_balance_wei = self.proxy.eth.get_balance(account.address, block_identifier=block_number)
expected_balance_wei = eth_utils.to_wei(NEW_USER_AIRDROP_AMOUNT, 'ether')
self.assertEqual(expected_balance_wei, actual_balance_wei)
account: LocalAccount = eth_account.account.Account.create()
block_number: eth_typing.BlockNumber = self._web3.eth.get_block_number()
actual_balance_wei = self._web3.eth.get_balance(account.address, block_identifier=block_number)
self.assertEqual(self._EXPECTED_BALANCE_WEI, actual_balance_wei)

def test_airdrop_on_deploy(self):
contract_owner: eth_account.account.LocalAccount = self.proxy.eth.account.create()
compiled_sol = solcx.compile_source(self._CONTRACT_STORAGE_SOURCE)
contract_owner: LocalAccount = self._web3.eth.account.create()
contract = self._compile_and_deploy_contract(contract_owner, self._CONTRACT_STORAGE_SOURCE)
actual_balance_wei = self._get_balance_wei(contract.address)
self.assertEqual(self._EXPECTED_BALANCE_WEI, actual_balance_wei)

def test_airdrop_onto_wrapped_new_address(self):
contract_owner: LocalAccount = self._web3.eth.account.create()
contract = self._compile_and_deploy_contract(contract_owner, self._WRAPPER_CONTRACT_STORAGE_SOURCE)
nested_contract_address = contract.functions.getNested().call()
nested_actual_balance = self._get_balance_wei(nested_contract_address)
wrapper_actual_balance = self._get_balance_wei(contract.address)
self.assertEqual(self._EXPECTED_BALANCE_WEI, wrapper_actual_balance)
self.assertEqual(self._EXPECTED_BALANCE_WEI, nested_actual_balance)

def _compile_and_deploy_contract(self, contract_owner: LocalAccount, source: str) -> web3_eth.Contract:
compiled_sol = solcx.compile_source(source)
contract_id, contract_interface = compiled_sol.popitem()
storage = self.proxy.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
nonce = self.proxy.eth.get_transaction_count(contract_owner.address)
chain_id = self.proxy.eth.chain_id
trx_signed = self.proxy.eth.account.sign_transaction(
dict(nonce=nonce, chainId=chain_id, gas=987654321, gasPrice=0, to='', value=0, data=storage.bytecode),
contract = self._web3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
nonce = self._web3.eth.get_transaction_count(contract_owner.address)
chain_id = self._web3.eth.chain_id
trx_signed = self._web3.eth.account.sign_transaction(
dict(nonce=nonce, chainId=chain_id, gas=987654321, gasPrice=0, to='', value=0, data=contract.bytecode),
contract_owner.key
)
trx_hash = self.proxy.eth.send_raw_transaction(trx_signed.rawTransaction)
trx_receipt = self.proxy.eth.wait_for_transaction_receipt(trx_hash)
storage_contract = self.proxy.eth.contract(
trx_hash = self._web3.eth.send_raw_transaction(trx_signed.rawTransaction)
trx_receipt = self._web3.eth.wait_for_transaction_receipt(trx_hash)
contract = self._web3.eth.contract(
address=trx_receipt.contractAddress,
abi=storage.abi
abi=contract.abi
)
actual_balance_wei = self.proxy.eth.get_balance(storage_contract.address, block_identifier="latest")
expected_balance_wei = eth_utils.to_wei(NEW_USER_AIRDROP_AMOUNT, 'ether')
return contract

owner_balance = self.proxy.eth.get_balance(contract_owner.address, block_identifier="latest")

self.assertEqual(expected_balance_wei, owner_balance)
self.assertEqual(expected_balance_wei, actual_balance_wei)
def _get_balance_wei(self, eth_acc: str) -> int:
pub_key = self._host_solana_account.public_key()
token_owner_account, nonce = ether2program(eth_acc, self._EVM_LOADER_ID, pub_key)
balance, error = get_token_balance_gwei(self._solana_client, token_owner_account, EthereumAddress(eth_acc))
self.assertIsNone(error)
self.assertIsNotNone(balance)
self.assertIsInstance(balance, int)
return balance * eth_utils.denoms.gwei

_CONTRACT_STORAGE_SOURCE = '''pragma solidity >=0.7.0 <0.9.0;
contract Storage {
Expand All @@ -61,3 +88,18 @@ def test_airdrop_on_deploy(self):
}
'''

_WRAPPER_CONTRACT_STORAGE_SOURCE = '''
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Wrapper {
address private nested_address;
constructor() {
Nested nested = new Nested();
nested_address = address(nested);
}
function getNested() public view returns (address) {
return nested_address;
}
}
contract Nested {}
'''