Remote EVM Calls Through XCM¶
Introduction¶
The XCM Transactor Pallet provides a simple interface to perform remote cross-chain calls through XCM. However, this does not consider the possibility of doing remote calls to Moonbeam's EVM, only to Substrate specific pallets (functionalities).
Moonbeam's EVM is only accessible through the Ethereum Pallet. Among many other things, this pallet handles certain validations of transactions before getting them into the transaction pool. Then, it performs other validation step before inserting a transaction from the pool in a block. Lastly, it provides the interface through a transact
function to execute a validated transaction. All these steps follow the same behavior as an Ethereum transaction in terms of structure and signature scheme.
However, calling the Ethereum Pallet directly through an XCM Transact
is not feasible. Mainly because the dispatcher account for the remote EVM call (referred to as msg.sender
in Ethereum) does not sign the XCM transaction on the Moonbeam side. The XCM extrinsic is signed in the origin chain, and the XCM executor dispatches the call, through the Transact
instruction, from a known caller linked to the sender in the origin chain. In this context, the Ethereum Pallet will not be able to verify the signature and, ultimately, validate the transaction.
To this end, the Ethereum XCM Pallet was introduced. It acts as a middleware between the XCM Transact
instruction and the Ethereum Pallet, as special considerations need to be made when performing EVM calls remotely through XCM. The pallet performs the necessary checks and validates the transaction. Next, the pallet calls the Ethereum Pallet to dispatch the transaction to the EVM. Due to how the EVM is accessed, there are some differences between regular and remote EVM calls.
The happy path for both regular and remote EVM calls through XCM is portrayed in the following diagram:
This guide will go through the differences between regular and remote EVM calls. In addition, it will show you how to perform remote EVM calls through the extrinsic exposed by the Ethereum XCM pallet.
Note
Remote EVM calls are done through the XCM Transactor Pallet. Therefore, it is recommended to get familiar with XCM Transactor concepts before trying to perform remote EVM calls through XCM.
Note that remote calls to Moonbeam's EVM through XCM are still being actively developed. In addition, developers must understand that sending incorrect XCM messages can result in the loss of funds. Consequently, it is essential to test XCM features on a TestNet before moving to a production environment.
Relevant XCM Definitions¶
- Sovereign account — an account each chain in the ecosystem has, one for the relay chain and the other for other parachains. It is calculated as the
blake2
hash of a specific word and parachain ID concatenated (blake2(para+ParachainID)
for the Sovereign account in the relay chain, andblake2(sibl+ParachainID)
for the Sovereign account in other parachains), truncating the hash to the correct length. The account is owned by root and can only be used through SUDO (if available) or governance (referenda). The Sovereign account typically signs XCM messages in other chains in the ecosystem -
Multilocation — a way to specify a point in the entire relay chain/parachain ecosystem relative to a given origin. For example, it can be used to specify a specific parachain, asset, account, or even a pallet inside a parachain. In general terms, a multilocation is defined with a
parents
and aninterior
:parents
- refers to how many "hops" into a parent blockchain you need to take from a given origininterior
- refers to how many fields you need to define the target point.
For example, to target a parachain with ID
1000
from another parachain, the multilocation would be{ "parents": 1, "interior": { "X1": [{ "Parachain": 1000 }]}}
-
Multilocation-derivative account — an account derivated from the new origin set by the Descend Origin XCM instruction and the provided multilocation, which is typically the sovereign account from which the XCM originated. Derivative accounts are keyless (the private key is unknown). Consequently, derivative accounts related to XCM-specific use cases can only be accessed through XCM extrinsics. For Moonbeam-based networks, the derivation method is calculating the
blake2
hash of the multilocation, which includes the origin parachain ID, and truncating the hash to the correct length (20 bytes for an Ethereum-styled account). The XCM call origin conversion happens when theTransact
instruction gets executed. Consequently, each parachain can convert the origin with its own desired procedure, so the user who initiated the transaction might have a different derivative account per parachain. This derivative account pays for transaction fees, and it is set as the dispatcher of the call - Transact information — relates to extra weight and fee information for the XCM remote execution part of the XCM Transactor extrinsic. This is needed because the sovereign account pays the XCM transaction fee. Therefore, XCM Transactor calculates what the fee is and charges the sender of the XCM Transactor extrinsic the estimated amount in the corresponding XC-20 token to repay the sovereign account
Differences Between Regular and Remote EVM Calls Through XCM¶
As explained in the Introduction, the paths that regular and remote EVM calls take to get to the EVM are quite different. The main reason behind this difference is the dispatcher of the transaction.
A regular EVM call has an apparent sender who signs the Ethereum transaction with its private key. The signature, of ECDSA type, can be verified with the signed message and the r-s
values that are produced from the signing algorithm. Ethereum signatures use an additional variable, called v
, which is the recovery identifier.
With remote EVM calls, the signer signed an XCM transaction in another chain. Moonbeam receives that XCM message which must be constructed with the following instructions:
The first instruction, DescendOrigin
, will mutate the origin of the XCM call on the Moonbeam side to a keyless account through the multilocation-derivative account mechanism described in the Relevant XCM Definitions section. The remote EVM call is dispatched from that keyless account (or a related proxy). Therefore, because the transaction is not signed, it does not have the real v-r-s
values of the signature, but 0x1
instead.
Because a remote EVM call does not have the actual v-r-s
values of the signature, there could be collision problems of the EVM transaction hash, as it is calculated as the keccak256 hash of the signed transaction blob. In consequence, if two accounts with the same nonce submit the same transaction object, they will end up with the same EVM transaction hash. Therefore, all remote EVM transactions use a global nonce that is attached to the Ethereum XCM pallet.
Another significant difference is in terms of the gas price. The fee for remote EVM calls is charged at an XCM execution level. Consequently, the gas price at an EVM level is zero, and the EVM will not charge for the execution itself. This can also be seen in the receipt of a remote EVM call transaction. Accordingly, the XCM message must be configured so that the BuyExecution
buys enough weight to cover the gas cost.
The last difference is in terms of gas limit. Ethereum uses a gas-metered system to moderate the amount of execution that can be done in a block. On the contrary, Moonbeam uses a weight-based system, in which each call is characterized by the time it takes to execute in a block. Each unit of weight corresponds to one picosecond of execution time.
The configuration of the XCM queue suggests that XCM messages should be executable within 20,000,000,000
weight units (that is, 0.02
seconds of block execution time). Suppose the XCM message can't be executed due to the lack of execution time in a given block, and the weight requirement is over 20,000,000,000
. In that case, the XCM message will be marked as overweight
and would only be executable through democracy.
The 20,000,000,000
weight limit per XCM message constrains the gas limit available for remote EVM calls through XCM. For all Moonbeam-based networks, there is a ratio of 25,000
units of gas per unit of weight (WEIGHT_REF_TIME_PER_SECOND
/ GAS_PER_SECOND
). Considering that you need some of the XCM message weight to execute the XCM instructions themselves. Therefore, a remote EVM call might have around 18,000,000,000
weight left, which is 720,000
gas units. Consequently, the maximum gas limit you can provide for a remote EVM call is around 720,000
gas units. Note that this might change in the future.
In summary, these are the main differences between regular and remote EVM calls:
- Remote EVM calls use a global nonce (owned by the Ethereum-XCM pallet) instead of a nonce per account
- The
v-r-s
values of the signature for remote EVM calls are0x1
. The sender can't be retrieved from the signature through standard methods (for example, through ECRECOVER). Nevertheless, thefrom
is included in both the transaction receipt and when getting the transaction by hash (using the Ethereum JSON RPC) - The gas price for all remote EVM calls is zero. The EVM execution is charged at an XCM execution level and not at an EVM level
- The current maximum gas limit you can set for a remote EVM call is
720,000
gas units
Ethereum XCM Pallet Interface¶
Extrinsics¶
The Ethereum XCM pallet provides the following extrinsics (functions) that can be called by the Transact
instruction to access Moonbeam's EVM through XCM:
- transact(xcmTransaction) — function to remotely call the EVM through XCM. Only callable through the execution of an XCM message
- transactThroughProxy(transactAs, xcmTransaction) — similar to the
transact
extrinsic, but withtransactAs
as an additional field. This function allows the remote EVM call to be dispatched from a given account with known keys (themsg.sender
). This account needs to have set the multilocation-derivative account as a proxy of typeany
on Moonbeam. On the contrary, the dispatch of the remote EVM call will fail. Transaction fees are still paid by the multilocation-derivative account
Where the inputs that need to be provided can be defined as:
- xcmTransaction — contains the Ethereum transaction details of the call that will be dispatched. This includes the call data,
msg.value
and gas limit - transactAs — account from which the remote EVM call will be dispatched (the
msg.sender
). The account set in this field needs to have set the multilocation-derivative account as a proxy of typeany
on Moonbeam. Transaction fees are still paid by the multilocation-derivative account
Building a Remote EVM call through XCM¶
This guide covers building an XCM message for remote EVM calls using the XCM Pallet from the relay chain to Moonbase Alpha. More specifically, it will use the transact
function. The steps to use the transactThroughProxy
function are identical. However, you'll need to provide the transactAs
account and ensure that this account has set the multilocation-derivative account as a proxy of type any
on Moonbase Alpha.
Note
When using transactThroughProxy
, the EVM call is dispatched by the transactAs account you provide, acting as the msg.sender
, as long as this account has set the the multilocation-derivative account as a proxy of type any
in the Moonbeam-based network you are using. However, transaction fees are still paid by the multilocation-derivative account, so you need to ensure it has enough funds to cover them.
Checking Prerequisites¶
To be able to send the call from the relay chain, you need to have the following:
-
An account on the relay chain with funds (UNIT) to pay for the transaction fees. You can acquire some xcUNIT by swapping for DEV tokens (Moonbase Alpha's native token) on Moonbeam-Swap, a demo Uniswap-V2 clone on Moonbase Alpha, and then send them to the relay chain. Additionally, you can contact us to get some UNIT tokens directly
-
Fund the multilocation-derivative account, which you can obtain by following the steps in the next section. The account must have enough DEV tokens (or GLMR/MOVR for Moonbeam/Moonriver) to cover the cost of the XCM execution of the remote EVM call. Note that this is the account from which the remote EVM call will be dispatched (the
msg.sender
). Consequently, the account must satisfy whatever conditions are required for the EVM call to be executed correctly. For example, hold any relevant ERC-20 token if you are doing an ERC-20 transfer
Note
Suppose you are using the transactThroughProxy
function. In that case, the transactAs
account must satisfy whatever conditions are required for the EVM call to be executed correctly, as it acts as the msg.sender
. However, the multilocation-derivative account is the one that needs to hold the DEV tokens (or GLMR/MOVR for Moonbeam/Moonriver) to cover the cost of the XCM execution of the remote EVM call.
Calculating the Multilocation-Derivative Account¶
As mentioned before, a remote EVM call is dispatched from an account called the multilocation-derivative account. This is calculated using the information provided by the Descend Origin
instruction. Consequently, the computed account depends directly on how the instruction is constructed.
For example, from the relay chain, the DescendOrigin
instruction is natively injected by the XCM Pallet. In the case of Moonbase Alpha's relay chain (based on Westend), is with the following format (a multilocation junction):
{
DescendOrigin: {
X1: {
AccountId32: {
network: 'Westend',
id: decodedAddress,
},
},
},
}
Where the decodedAddress
corresponds to the address of the account who signed the transaction on the relay chain (in a decoded 32 bytes format). You can make sure that your address is properly decoded by using the following snippet, which will decode an address if needed and ignore it if not:
import { decodeAddress } from '@polkadot/util-crypto';
const decodedAddress = decodeAddress('INSERT_ADDRESS');
When the XCM instruction gets executed in Moonbeam (Moonbase Alpha in this example), the origin will have mutated to the following multilocation:
{
DescendOrigin: {
parents: 1,
interior: {
X1: {
AccountId32: {
network: 'Westend',
id: decodedAddress,
},
},
},
},
}
This is the multilocation used to calculate the multilocation-derivative account. You can use the calculate multilocation-derivative account script to help you obtain its value. To do so, you can use the following command:
yarn calculate-multilocation-derivative-account \
--w wss://wss.api.moonbase.moonbeam.network \
--a INSERT_MOONBASE_RELAY_ACCOUNT \
--p PARACHAIN_ID_IF_APPLIES \
--n westend
The parameters that you need to pass along with this command are:
- The
-w
flag corresponds to the endpoint you’re using to fetch this information - The
-a
flag corresponds to your Moonbase relay chain address - The
-p
flag corresponds to the parachain ID of the origin chain (if applies), if you are sending the XCM from the relay chain you don't need to provide this parameter - The
-n
flag corresponds to the name of the relay chain that Moonbase relay is based on
For example, for Alice's relay chain account is 5EnnmEp2R92wZ7T8J2fKMxpc1nPW5uP8r5K3YUQGiFrw8uG6
, you can calculate her Moonbase Alpha multilocation-derivative account by running:
yarn calculate-multilocation-derivative-account \
--w wss://wss.api.moonbase.moonbeam.network \
--a 5EnnmEp2R92wZ7T8J2fKMxpc1nPW5uP8r5K3YUQGiFrw8uG6 \
--n westend
The relevant values for this calculation are summarized in the following table:
Name | Value |
---|---|
Origin Chain Encoded Address | 5EnnmEp2R92wZ7T8J2fKMxpc1nPW5uP8r5K3YUQGiFrw8uG6 |
Origin Chain Decoded Address | 0x78914a4d7a946a0e4ed641f336b498736336e05096e342c799cc33c0f868d62f |
Origin Chain Account Name | Westend |
Multilocation Received in Destination Chain | {"parents":1,"interior":{"x1":{"accountId32":{"network": {"westend":null},"id":"0x78914a4d7a946a0e4ed641f336b498736336e05096e342c799cc33c0f868d62f"}}}} |
Multilocation-Derivative Account (32 bytes) | 0xda51eac6eb3502b0a113effcb3950c52e873a24c6ef54cab13abdd56a55ddd7e |
Multilocation-Derivative Account (20 bytes) | 0xda51eac6eb3502b0a113effcb3950c52e873a24c |
Consequently, for this example, the multilocation-derivative account for Moonbase Alpha is 0xda51eac6eb3502b0a113effcb3950c52e873a24c
. Note that Alice is the only person who can access this account through a remote transact from the relay chain, as she is the owner of its private keys and the multilocation-derivative account is keyless.
Ethereum XCM Transact Call Data¶
Before you send the XCM message from the relay chain to Moonbase Alpha, you need to get the encoded call data that will be dispatched through the execution of the Transact
XCM instruction.
In this example, you'll be interacting with the transact
function of the Ethereum XCM Pallet, which accepts an xcmTransaction
as a parameter.
The xcmTransaction
parameter requires you to define:
- A gas limit
- The action to be executed, which provides two options:
Call
andCreate
. The current implementation of the Ethereum XCM pallet does not support theCREATE
operation. Therefore, you can't deploy a smart contract through remote EVM calls. ForCall
, you'll need to specify the contract address you're interacting with - The value of native tokens to send
- The input, which is the encoded call data of the contract interaction
For the action to be executed, you'll be performing a contract interaction with a simple incrementer contract, which is located at 0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8
. You'll be calling the increment
function, which has no input argument and will increase the value of the number
by one. Also, it will store the block's timestamp in which the function is executed to the timestamp
variable.
The encoded call data of the interaction with the increment
function is 0xd09de08a
, which is the first eight hexadecimal characters (or 4 bytes) of the keccak256 hash of increment()
. If you choose to interact with a function that has input parameters, they also need to be encoded. The easiest way to get the encoded call data is to emulate a transaction either in Remix or Moonscan. Next, in Metamask, check the HEX DATA: 4 BYTES selector under the HEX tab before signing it. You don't need to sign the transaction.
Now that you have the encoded contract interaction data, you can determine the gas limit for this call using the eth_estimateGas
JSON RPC method. For this example, you can set the gas limit to 71000
.
For the value, you can set it to 0
since this particular interaction does not need DEV (or GLMR/MOVR for Moonbeam/Moonriver). For an interaction that requires DEV, you'll need to modify this value accordingly.
Now that you have all of the components required for the xcmTransaction
parameter, you can build it:
const xcmTransaction = {
V2: {
gasLimit: 71000,
action: { Call: '0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8' }, // Call the incrementer contract
value: 0,
input: '0xd09de08a', // Call the increment function
},
};
Next, you can write the script to get the encoded call data for the transaction. You'll take the following steps:
- Provide the input data for the call. This includes:
- The Moonbase Alpha endpoint URL to create the provider
- The value for the
xcmTransaction
parameter of thetransact
function
- Create the Polkadot.js API provider
- Craft the
ethereumXcm.transact
extrinsic with thexcmTransaction
value - Get the encoded call data for the extrinsic. You don't need to sign and send the transaction
import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 9.13.6
// 1. Input data
const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network';
const xcmTransaction = {
V2: {
gasLimit: 71000,
action: { Call: '0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8' },
value: 0,
input: '0xd09de08a',
},
};
const getEncodedCallData = async () => {
// 2. Create Substrate API Provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 3. Create the extrinsic
const tx = api.tx.ethereumXcm.transact(xcmTransaction);
// 4. Get the encoded call data
const encodedCall = tx.method.toHex();
console.log(`Encoded Calldata: ${encodedCall}`);
api.disconnect();
};
getEncodedCallData();
Note
You can view an example of the output of the above script on Polkadot.js Apps using the following encoded call data: 0x260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00
.
You'll use the encoded call data in the Transact
instruction in the following section.
Building the XCM for Remote XCM Execution¶
In this example, you'll build an XCM message to execute a remote EVM call in Moonbase Alpha from its relay chain through the Transact
XCM instruction and the transact
function of the Ethereum XCM pallet.
Now that you've generated the Ethereum XCM pallet encoded call data, you're going to use the XCM Pallet on the relay chain to perform a remote execution. To do so, you'll use the send
function, which accepts two parameters: dest
and message
. You can start assembling these parameters by taking the following steps:
-
Build the multilocation of the destination, which is Moonbase Alpha:
const dest = { V3: { parents: 0, interior: { X1: { Parachain: 1000 } } } };
-
Build the
WithdrawAsset
instruction, which will require you to define:- The multilocation of the DEV token on Moonbase Alpha
- The amount of DEV tokens to withdraw
const instr1 = { WithdrawAsset: [ { id: { Concrete: { parents: 0, interior: { X1: { PalletInstance: 3 } } } }, fun: { Fungible: 100000000000000000n }, // 1 DEV }, ], };
-
Build the
BuyExecution
instruction, which will require you to define:- The multilocation of the DEV token on Moonbase Alpha
- The amount of DEV tokens to buy for execution
- The weight limit
const instr2 = { BuyExecution: [ { id: { Concrete: { parents: 0, interior: { X1: { PalletInstance: 3 } } } }, fun: { Fungible: 100000000000000000n }, // 1 DEV }, { Unlimited: null }, ], };
-
Build the
Transact
instruction, which will require you to define:- The origin kind
- The required weight for the transaction. You'll need to define a value for
refTime
, which is the amount of computational time that can be used for execution, and theproofSize
, which is the amount of storage in bytes that can be used. It is recommended that the weight given to this instruction needs to be around 10% more of25000
times the gas limit for the EVM call you want to execute via XCM - The encoded call data, which you generated in the Ethereum XCM Transact Call Data section
const instr3 = { Transact: { originKind: 'SovereignAccount', requireWeightAtMost: { refTime: 4000000000n, proofSize: 0 }, call: { encoded: '0x260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00', }, }, };
-
Combine the XCM instructions into a versioned XCM message:
const message = { V3: [instr1, instr2, instr3] };
Now that you have the values for each of the parameters, you can write the script for the execution. You'll take the following steps:
- Provide the input data for the call. This includes:
- The relay chain endpoint URL to create the provider
- The values for each of the parameters of the
send
function
- Create a Keyring instance that will be used to send the transaction
- Create the Polkadot.js API provider
- Craft the
xcmPallet.send
extrinsic with thedest
andmessage
values - Send the transaction using the
signAndSend
extrinsic and the Keyring instance you created in the second step
Remember
This is for demo purposes only. Never store your private key in a JavaScript file.
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 9.13.6
// 1. Input data
const providerWsURL =
'wss://frag-moonbase-relay-rpc-ws.g.moonbase.moonbeam.network';
const privateKey = 'INSERT_PRIVATE_KEY';
const dest = { V3: { parents: 0, interior: { X1: { Parachain: 1000 } } } };
const instr1 = {
WithdrawAsset: [
{
id: { Concrete: { parents: 0, interior: { X1: { PalletInstance: 3 } } } },
fun: { Fungible: 100000000000000000n }, // 1 DEV
},
],
};
const instr2 = {
BuyExecution: [
{
id: { Concrete: { parents: 0, interior: { X1: { PalletInstance: 3 } } } },
fun: { Fungible: 100000000000000000n }, // 1 DEV
},
{ Unlimited: null },
],
};
const instr3 = {
Transact: {
originKind: 'SovereignAccount',
requireWeightAtMost: { refTime: 4000000000n, proofSize: 0 },
call: {
encoded:
'0x260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00',
},
},
};
const message = { V3: [instr1, instr2, instr3] };
// 2. Create Keyring instance
const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri(privateKey);
const sendXcmMessage = async () => {
// 3. Create Substrate API Provider
const substrateProvider = new WsProvider(providerWsURL);
const api = await ApiPromise.create({ provider: substrateProvider });
// 4. Create the extrinsic
const tx = api.tx.xcmPallet.send(dest, message);
// 5. Send the transaction
const txHash = await tx.signAndSend(alice);
console.log(`Submitted with hash ${txHash}`);
api.disconnect();
};
sendXcmMessage();
Note
You can view an example of the output of the above script on Polkadot.js Apps using the following encoded call data: 0x630003000100a10f030c00040000010403001300008a5d78456301130000010403001300008a5d784563010006010300286bee007901260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00
.
Once the transaction is processed, you can check the relevant extrinsics and events in the relay chain and Moonbase Alpha.
In the relay chain, the extrinsic is xcmPallet.send
, and the associated event is xcmPallet.Sent
(among others related to the fee). In Moonbase Alpha, the XCM execution happens within the parachainSystem.setValidationData
extrinsic, and there are multiple associated events that can be highlighted:
- parachainSystem.DownwardMessagesReceived — event that signals that a message from the relay chain was received. With the current XCM implementation, messages from other parachains will show the same event
- balances.Withdraw — event related to the withdrawing of tokens to pay for the execution of the call. Note that the
who
address is the multilocation-derivative account calculated before - ethereum.Executed — event associated with the execution of the remote EVM call. It provides the
from
,to
,transactionHash
(calculated with the non-standard signature and global pallet nonce), and theexitReason
. Currently, some common EVM errors, like out of gas, will showReverted
in the exit reason - polkadotXcm.AssetsTrapped — event that is emitted when part of the tokens withdrawn from the account (for fees) are not used. Generally, when there are leftover tokens in the registry that are not allocated to an account. These tokens are temporarily burned and can be retrieved through a democracy proposal. A combination of both
RefundSurplus
andDepositAsset
XCM instructions can prevent assets from getting trapped
To verify that the remote EVM call through XCM was successful, you can head to the contract's page in Moonscan and verify the new value for the number and its timestamp.
Remote EVM Call Transaction by Hash¶
As mentioned before, there are some differences between regular and remote XCM EVM calls. Some main differences can be seen when retrieving the transaction by its hash using the Ethereum JSON RPC.
To do so, you first need to retrieve the transaction hash you want to query. For this example, you can use the transaction hash from the previous section, which is 0x85735a6be6aa0b3ad5f6ce877d8b9048137876517d9ca5b309bcd93ae997bf7a. Open the terminal, and execute the following command:
curl --location --request POST 'https://rpc.api.moonbase.moonbeam.network' \
--header 'Content-Type: application/json' \
--data-raw '{
"jsonrpc":"2.0",
"id":1,
"method":"eth_getTransactionByHash",
"params": ["0x85735a6be6aa0b3ad5f6ce877d8b9048137876517d9ca5b309bcd93ae997bf7a"]
}
'
If the JSON RPC request is sent correctly, the response should look like this:
{
"jsonrpc": "2.0",
"result": {
"hash": "0x85735a6be6aa0b3ad5f6ce877d8b9048137876517d9ca5b309bcd93ae997bf7a",
"nonce": "0x1",
"blockHash": "0xc4b573da6943cc94e55c2fb429160c5b24d91a9da6798102a28dd611c3b76cc0",
"blockNumber": "0x2e7cf1",
"transactionIndex": "0x0",
"from": "0x4e21340c3465ec0aa91542de3d4c5f4fc1def526",
"to": "0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8",
"value": "0x0",
"gasPrice": "0x0",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"gas": "0x11558",
"input": "0xd09de08a",
"creates": null,
"raw": "0xa902e7800180808301155894a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d88084d09de08ac0010101",
"publicKey": "0x3a9b57bdedea5ddd864355487de6285e032eb8798316da6848587c7f67d71a7a7592a1094ba2123f95659827f40a7096ab4fc278fdde688e3a90ee16eed5f720",
"chainId": "0x507",
"standardV": "0x1",
"v": "0x1",
"r": "0x1",
"s": "0x1",
"accessList": [],
"type": "0x2"
},
"id": 1
}
Note that the v-r-s
values are set to 0x1
, and the gas price-related fields are set to 0x0
. In addition, the nonce
field corresponds to a global nonce of the Ethereum XCM pallet, and not the transaction count of the dispatcher account.
Note
You might be able to find some transaction hash collisions in the Moonbase Alpha TestNet, as early versions of remote EVM calls through XCM did not use a global nonce of the Ethereum XCM pallet.
| Created: May 25, 2022