#77 Add token accounts to AccountMeta

This commit is contained in:
Anton Lisanin 2021-07-15 14:48:35 +03:00
parent 5420cec228
commit 5887e5ca8c
4 changed files with 52 additions and 14 deletions

View File

@ -23,7 +23,7 @@ from sha3 import keccak_256
import base58
import traceback
import threading
from .solana_rest_api_tools import EthereumAddress, create_storage_account, evm_loader_id, getLamports, \
from .solana_rest_api_tools import EthereumAddress, create_storage_account, evm_loader_id, getTokens, \
getAccountInfo, solana_cli, call_signed, solana_url, call_emulated, \
Trx, deploy_contract, EthereumError
from web3 import Web3
@ -94,7 +94,8 @@ class EthereumModel:
"""
eth_acc = EthereumAddress(account)
logger.debug('eth_getBalance: %s %s', account, eth_acc)
balance = getLamports(self.client, evm_loader_id, eth_acc, self.signer.public_key())
balance = getTokens(self.client, evm_loader_id, eth_acc, self.signer.public_key())
return hex(balance*10**9)
def eth_getBlockByNumber(self, tag, full):

View File

@ -1,3 +1,4 @@
from solana.publickey import PublicKey
from solana.transaction import AccountMeta, TransactionInstruction, Transaction
from solana.sysvar import *
from solana.blockhash import Blockhash
@ -17,7 +18,9 @@ from .eth_proto import Trx
from solana.rpc.types import TxOpts
import re
from solana.rpc.commitment import Commitment, Confirmed
from solana.rpc.api import SendTransactionError
from solana.rpc.api import Client, SendTransactionError
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
from spl.token.instructions import get_associated_token_address
from construct import Bytes, Int8ul, Int32ul, Int64ul, Struct as cStruct
from solana._layouts.system_instructions import SYSTEM_INSTRUCTIONS_LAYOUT, InstructionType as SystemInstructionType
@ -40,6 +43,11 @@ keccakprog = "KeccakSecp256k11111111111111111111111111111"
rentid = "SysvarRent111111111111111111111111111111111"
system = "11111111111111111111111111111111"
ETH_TOKEN_MINT_ID: PublicKey = PublicKey(
os.environ.get("ETH_TOKEN_MINT", "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU")
)
ACCOUNT_INFO_LAYOUT = cStruct(
"tag" / Int8ul,
"eth_acc" / Bytes(20),
@ -48,6 +56,7 @@ ACCOUNT_INFO_LAYOUT = cStruct(
"code_acc" / Bytes(32),
"is_blocked" / Int8ul,
"blocked_by" / Bytes(32),
"eth_token" / Bytes(32),
)
CODE_INFO_LAYOUT = cStruct(
@ -96,7 +105,7 @@ def createAccountWithSeed(funding, base, seed, lamports, space, program):
seed_str = str(seed, 'utf8')
data = SYSTEM_INSTRUCTIONS_LAYOUT.build(
dict(
instruction_type = SystemInstructionType.CreateAccountWithSeed,
instruction_type = SystemInstructionType.CREATE_ACCOUNT_WITH_SEED,
args=dict(
base=bytes(base),
seed=dict(length=len(seed_str), chars=seed_str),
@ -513,14 +522,15 @@ def create_account_list_by_emulate(acc, client, ethTrx, storage):
output_json = call_emulated(ethTrx.toAddress.hex(), sender_ether.hex(), ethTrx.callData.hex())
logger.debug("emulator returns: %s", json.dumps(output_json, indent=3))
for acc_desc in output_json["accounts"]:
address = bytes.fromhex(acc_desc["address"][2:])
if address == ethTrx.toAddress:
(contract_sol, code_sol) = (acc_desc["account"], acc_desc["contract"])
(contract_sol, code_sol) = (PublicKey(acc_desc["account"]), PublicKey(acc_desc["contract"]))
elif address == sender_ether:
sender_sol = (acc_desc["account"])
sender_sol = PublicKey(acc_desc["account"])
else:
add_keys_05.append(AccountMeta(pubkey=acc_desc["account"], is_signer=False, is_writable=acc_desc["writable"]))
token_account = get_associated_token_address(PublicKey(acc_desc["account"]), ETH_TOKEN_MINT_ID)
add_keys_05.append(AccountMeta(pubkey=token_account, is_signer=False, is_writable=True))
if acc_desc["contract"]:
add_keys_05.append(AccountMeta(pubkey=acc_desc["contract"], is_signer=False, is_writable=acc_desc["writable"]))
if acc_desc["new"]:
@ -537,11 +547,15 @@ def create_account_list_by_emulate(acc, client, ethTrx, storage):
accounts = [
AccountMeta(pubkey=storage, is_signer=False, is_writable=True),
AccountMeta(pubkey=contract_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=get_associated_token_address(contract_sol, ETH_TOKEN_MINT_ID), is_signer=False, is_writable=True),
AccountMeta(pubkey=code_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=sender_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=get_associated_token_address(sender_sol, ETH_TOKEN_MINT_ID), is_signer=False, is_writable=True),
AccountMeta(pubkey=PublicKey(sysinstruct), is_signer=False, is_writable=False),
AccountMeta(pubkey=evm_loader_id, is_signer=False, is_writable=False),
] + add_keys_05 + [
AccountMeta(pubkey=ETH_TOKEN_MINT_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=PublicKey(sysvarclock), is_signer=False, is_writable=False),
]
return (accounts, sender_ether, sender_sol, trx)
@ -626,8 +640,9 @@ def createEtherAccountTrx(client, ether, evm_loader_id, signer, code_acc=None):
if ether.startswith('0x'): ether = ether[2:]
else: ether = ether.hex()
(sol, nonce) = ether2program(ether, evm_loader_id, signer.public_key())
associated_token = get_associated_token_address(PublicKey(sol), ETH_TOKEN_MINT_ID)
logger.debug('createEtherAccount: {} {} => {}'.format(ether, nonce, sol))
seed = b58encode(bytes.fromhex(ether))
logger.debug('associatedTokenAccount: {}'.format(associated_token))
base = signer.public_key()
data=bytes.fromhex('02000000')+CREATE_ACCOUNT_LAYOUT.build(dict(
lamports=10**9,
@ -642,7 +657,12 @@ def createEtherAccountTrx(client, ether, evm_loader_id, signer, code_acc=None):
keys=[
AccountMeta(pubkey=base, is_signer=True, is_writable=True),
AccountMeta(pubkey=PublicKey(sol), is_signer=False, is_writable=True),
AccountMeta(pubkey=associated_token, is_signer=False, is_writable=True),
AccountMeta(pubkey=system, is_signer=False, is_writable=False),
AccountMeta(pubkey=ETH_TOKEN_MINT_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=ASSOCIATED_TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=rentid, is_signer=False, is_writable=False),
]))
else:
trx.add(TransactionInstruction(
@ -651,8 +671,13 @@ def createEtherAccountTrx(client, ether, evm_loader_id, signer, code_acc=None):
keys=[
AccountMeta(pubkey=base, is_signer=True, is_writable=True),
AccountMeta(pubkey=PublicKey(sol), is_signer=False, is_writable=True),
AccountMeta(pubkey=associated_token, is_signer=False, is_writable=True),
AccountMeta(pubkey=PublicKey(code_acc), is_signer=False, is_writable=True),
AccountMeta(pubkey=system, is_signer=False, is_writable=False),
AccountMeta(pubkey=ETH_TOKEN_MINT_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=ASSOCIATED_TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=rentid, is_signer=False, is_writable=False),
]))
return (trx, sol)
@ -746,9 +771,13 @@ def deploy_contract(acc, client, ethTrx, storage, steps):
accounts = [AccountMeta(pubkey=holder, is_signer=False, is_writable=True),
AccountMeta(pubkey=storage, is_signer=False, is_writable=True),
AccountMeta(pubkey=contract_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=get_associated_token_address(PublicKey(contract_sol), ETH_TOKEN_MINT_ID), is_signer=False, is_writable=True),
AccountMeta(pubkey=code_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=sender_sol, is_signer=False, is_writable=True),
AccountMeta(pubkey=get_associated_token_address(PublicKey(sender_sol), ETH_TOKEN_MINT_ID), is_signer=False, is_writable=True),
AccountMeta(pubkey=evm_loader_id, is_signer=False, is_writable=False),
AccountMeta(pubkey=ETH_TOKEN_MINT_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=PublicKey(sysvarclock), is_signer=False, is_writable=False),
]
@ -783,6 +812,15 @@ def getLamports(client, evm_loader, eth_acc, base_account):
(account, nonce) = ether2program(bytes(eth_acc).hex(), evm_loader, base_account)
return int(client.get_balance(account, commitment=Confirmed)['result']['value'])
def getTokens(client, evm_loader, eth_acc, base_account):
(account, nonce) = ether2program(bytes(eth_acc).hex(), evm_loader, base_account)
token_account = get_associated_token_address(PublicKey(account), ETH_TOKEN_MINT_ID)
balance = client.get_token_account_balance(token_account, commitment=Confirmed)
if 'error' in balance:
return 0
return int(balance['result']['value']['amount'])
def make_instruction_data_from_tx(instruction, private_key=None):
if isinstance(instruction, dict):

View File

@ -11,8 +11,7 @@
@@ -33,6 +33,11 @@
return types.MemcmpOpts(*args, **kwargs)
+class SendTransactionError(Exception):
+ def __init__(self, result):
+ super().__init__(result['message'])
@ -21,7 +20,7 @@
class Client: # pylint: disable=too-many-public-methods
"""Client class."""
@@ -284,7 +289,7 @@
@@ -328,7 +334,7 @@
return self._provider.make_request(types.RPCMethod("getConfirmedSignaturesForAddress2"), account, opts)
@ -30,7 +29,7 @@
"""Returns transaction details for a confirmed transaction.
:param tx_sig: Transaction signature as base-58 encoded string N encoding attempts to use program-specific
@@ -315,7 +320,7 @@
@@ -359,7 +365,7 @@
'signatures': ['3PtGYH77LhhQqTXP4SmDVJ85hmDieWsgXCUbn14v7gYyVYPjZzygUQhTk3bSTYnfA48vCM1rmWY7zWL3j1EVKmEy']}},
'id': 4}
""" # noqa: E501 # pylint: disable=line-too-long
@ -39,7 +38,7 @@
def get_epoch_info(self, commitment: Commitment = Max) -> types.RPCResponse:
"""Returns information about the current epoch.
@@ -1039,6 +1044,7 @@
@@ -1083,6 +1089,7 @@
def __post_send(self, resp: types.RPCResponse, skip_confirm: bool, conf_comm: Commitment) -> types.RPCResponse:
if resp.get("error"):
self._provider.logger.error(resp.get("error"))

View File

@ -4,4 +4,4 @@ pysha3==1.0.2
eth-keys==0.3.3
rlp==2.0.1
web3
solana==0.6.5
solana==0.10.0