3

I am running the Frontier-Node-Template and using the library Web3JS to generate EVM transactions following the Moonbeam guide.

const Web3 = require('web3');
const web3 = new Web3('ws://127.0.0.1:9944');

I am generating my Account using:

./target/release/frontier-template-node key generate

The account generated:

  Secret phrase:     worth wrestle meat ecology merry ginger online glad soda usage peasant lava
  Network ID:        substrate
  Secret seed:       0x8e940c2a136dadf87c3b4b408866ff5fb1cbb64893a933493341c5e400a81690
  Public key (hex):  0x381faf1906bf0ea763e7e25f110b26b880680d55bed21f52b76d9d5973fcee6e
  Account ID:        0x381faf1906bf0ea763e7e25f110b26b880680d55bed21f52b76d9d5973fcee6e
  Public key (SS58): 5DLHx6nDCn9EiYHryuyELhvsDKBmZGwLZthSdD3cshjAzusN
  SS58 Address:      5DLHx6nDCn9EiYHryuyELhvsDKBmZGwLZthSdD3cshjAzusN

Following the tutorial from the Substrate Docs I calculated the Ethereum Address for my account, basically truncating the Public key (hex) value above: 0x381faf1906bf0ea763e7e25f110b26b880680d55

With an Account that has funds, I sent some funds into this account. I check the Balance and works fine:

const balanceTo = web3.utils.fromWei(await web3.eth.getBalance("0x381faf1906bf0ea763e7e25f110b26b880680d55"), 'ether');
console.log(`The balance of 0x381faf1906bf0ea763e7e25f110b26b880680d55 is: ${balanceTo} ETH`);

The balance of 0x381faf1906bf0ea763e7e25f110b26b880680d55 is: 2.4999999999999995 ETH

Now I want to send funds from this account, and my question is how I calculate the ETH private key of this account?

I have tried with the Secret seed and to generate an Ethereum wallet from the mnemonic phrase:

const { Wallet } = require('ethers');
const myWalletMnemonic = "worth wrestle meat ecology merry ginger online glad soda usage peasant lava";
const wallet = Wallet.fromMnemonic(myWalletMnemonic);

But when sending the transfer:

const createTransaction = await web3.eth.accounts.signTransaction(
    {
      gas: 21000,
      to: accountFrom.address,
      value: web3.utils.toWei('1', 'ether'),
    },
    wallet.privateKey
  );
 const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction);

I am getting an error:

Error: Returned error: submit transaction to pool failed: Pool(InvalidTransaction(InvalidTransaction::Payment))

4 Answers 4

5

IIUC, these are two different crypto systems.

The public key works. But it doesn't mean anything.

You can even make a transfer to 0x12345.... But you don't know its private key.

You need to generate the private key correctly first. Then uses its public key.

In Rust, it should be https://github.com/hack-ink/eth-key/blob/main/src/main.rs.

In your code, it might be web3.account.generate(). I'm not familiar with that.


The node key generate equals subkey generate.

You should use Ethereum key tool.


You made some mistakes about the frontier framework.

In low level, the account storage is frame_system::AccountInfo.

So, Alice's balances data is in there. You could use Alice's public key to query the data.

And in EVM, there is a mapping address. Which is the truncated Alice's public key. So, there is no private key for that address. You should use the source account to control the mapping account. It just feels like a deriving.

                   substrate address
                 /
pallet storage -      | truncate
                 \
                   evm address

If your account is Substrate account. You can interact with Substrate. And use it to control the mapping account to interact with EVM.

If your account is EVM account. You can only use it to interact with EVM. And if you provide a mapping algorithm from H160 to H256 then you can use it to control the mapping account to interact with Substrate.

In default, frontier only provides H256 to H160.

H160 to H256 is our customization.

Here's how Darwinia did:

https://github.com/darwinia-network/darwinia-common/blob/6a9392cfb9fe2c99b1c2b47d0c36125d61991bb7/frame/support/src/evm.rs#L89

https://github.com/darwinia-network/darwinia-common/blob/6a9392cfb9fe2c99b1c2b47d0c36125d61991bb7/frame/support/src/evm.rs#L62

5
  • I got their are different systems, but in the docs: docs.substrate.io/tutorials/integrate-with-tools/… are not getting the public key from the Alice account generated with subkey??
    – Alex Bean
    Commented Jan 11, 2023 at 10:54
  • Anyway, try what I said. If it works, it means there are some mistakes.
    – AurevoirXavier
    Commented Jan 11, 2023 at 11:35
  • Yes, it works generating the account only with web3.account.generate(), I was wondering if with subkey generate you could do it too. Because in the docs it was getting a public key of Alice to use, which means you can control the account too
    – Alex Bean
    Commented Jan 11, 2023 at 11:51
  • I voted up, because is a workaround. Thanks!
    – Alex Bean
    Commented Jan 11, 2023 at 11:52
  • I found you made a mistake. I updated my answer.
    – AurevoirXavier
    Commented Jan 11, 2023 at 12:43
4

my question is how I calculate the ETH private key of this account?

There is no way to do that =/

The most important thing to note here is that the mnemonic:

worth wrestle meat ecology merry ginger online glad soda usage peasant lava

results in a public_key X on Substrate and in a public_key Y on EVM, due the fact that Substrate uses different crypto system than Ethereum's (like @aurevoirxavier said).

One thing that you can do is to use Frontier node (PolkadotJS) to sign and send Ethereum Transactions (Developer -> Extrinsics -> evm.call(...)) using your created address: 5DLHx6nDCn9EiYHryuyELhvsDKBmZGwLZthSdD3cshjAzusN

That way, the pallet_evm will translate that AccountId (5DLHx6nDCn9EiYHryuyELhvsDKBmZGwLZthSdD3cshjAzusN) into EVM's 0x381faf1906bf0ea763e7e25f110b26b880680d55 and things should work.

3

Thanks to AurevoirXavier and Artur for the responses, as they explained to sign and send Ethereum Transactions using a Substrate Account has to be done via the EVM pallet.

I just want to add here the code I have used to send the transaction using JS,

const signedTransaction = "0x79038400381faf1906bf0ea763e7e25f110b26b880680d55bed21f52b76d9d5973fcee6e01b0778735b494c9665381dd52b7f30c3803c5170e880e0fd9e8d375a2ea267d05800246ca0d812af082c6037f937dc5bda6cdfb2ad1e68c692f31ffd1365b9d86450324000901381faf1906bf0ea763e7e25f110b26b880680d55d43593c715fdd31c61141abd04a99fd6822c85580430000064a7b3b6e00d000000000000000000000000000000000000000000000000ffffffff0000000000e1f50500000000000000000000000000000000000000000000000000000000000000";
const sendExt = await api.rpc.author.submitExtrinsic(signedTransaction);

To generate this signed transaction I have used PolkadotJS UI, preparing the Ethereum transfer. enter image description here

And unselecting the Sign and Send you can see the result of the signature, the signedTransaction value:

enter image description here

2

The best way I found to interact with the EVM in Substrate Frontier is to use the Web3.js lib as explained in this Moonbeam tutorial: https://docs.moonbeam.network/builders/build/eth-api/libraries/web3js/

I use this code to retrieve the EVM account address from my substrate account private key:

const account = web3.eth.accounts.privateKeyToAccount(privateKey);
const address = account.address;

To send and sign a transaction, you just have to follow the "Send Transaction Script" section of the Moonbeam tutorial.

2

Not the answer you're looking for? Browse other questions tagged or ask your own question.