IEVMTransaction
An interface to relay and verify transactions from EVM-compatible blockchains.
Sourced from IEVMTransaction.sol
on GitHub.
Overview
The IEVMTransaction interface enables smart contracts on Flare networks to access and verify transaction data from other EVM-compatible blockchains. This attestation type provides access to transaction details, including associated events (logs), allowing cross-chain verification and integration of data from external EVM chains.
Supported Chains
Network Type | Supported Chains |
---|---|
Mainnet | ETH (Ethereum), FLR (Flare), SGB (Songbird) |
Testnet | testETH (Ethereum Sepolia), testFLR (Flare Testnet Coston2), testSGB (Songbird Testnet Coston) |
Interface Definition
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;
/**
* @custom:name IEVMTransaction
* @custom:id 0x06
* @custom:supported ETH, FLR, SGB
* @author Flare
* @notice A relay of a transaction from an EVM chain.
* This type is only relevant for EVM-compatible chains.
* @custom:verification If a transaction with the `transactionId` is in a block on the main branch with
* at least `requiredConfirmations`, the specified data is relayed.
* If an indicated event does not exist, the request is rejected.
* @custom:lut `timestamp`
* @custom:lutlimit `0x41eb00`, `0x41eb00`, `0x41eb00`
*/
interface IEVMTransaction {
/**
* @notice Toplevel request
* @param attestationType ID of the attestation type.
* @param sourceId ID of the data source.
* @param messageIntegrityCode `MessageIntegrityCode` that is derived from the expected response.
* @param requestBody Data defining the request. Type (struct) and interpretation is
* determined by the `attestationType`.
*/
struct Request {
bytes32 attestationType;
bytes32 sourceId;
bytes32 messageIntegrityCode;
RequestBody requestBody;
}
/**
* @notice Toplevel response
* @param attestationType Extracted from the request.
* @param sourceId Extracted from the request.
* @param votingRound The ID of the State Connector round in which the request was considered.
* @param lowestUsedTimestamp The lowest timestamp used to generate the response.
* @param requestBody Extracted from the request.
* @param responseBody Data defining the response. The verification rules for the construction
* of the response body and the type are defined per specific `attestationType`.
*/
struct Response {
bytes32 attestationType;
bytes32 sourceId;
uint64 votingRound;
uint64 lowestUsedTimestamp;
RequestBody requestBody;
ResponseBody responseBody;
}
/**
* @notice Toplevel proof
* @param merkleProof Merkle proof corresponding to the attestation response.
* @param data Attestation response.
*/
struct Proof {
bytes32[] merkleProof;
Response data;
}
/**
* @notice Request body for EVM transaction attestation type
* @custom:below Note that events (logs) are indexed in block not in each transaction.
* The contract that uses the attestation should specify the order of event logs as needed and the requestor should
* sort `logIndices` with respect to the set specifications.
* If possible, the contact should require one `logIndex`.
* @param transactionHash Hash of the transaction(transactionHash).
* @param requiredConfirmations The height at which a block is considered confirmed by the requestor.
* @param provideInput If true, "input" field is included in the response.
* @param listEvents If true, events indicated by `logIndices` are included in the response.
* Otherwise, no events are included in the response.
* @param logIndices If `listEvents` is `false`, this should be an empty list, otherwise,
* the request is rejected. If `listEvents` is `true`, this is the list of indices (logIndex)
* of the events to be relayed (sorted by the requestor). The array should contain at most 50 indices.
* If empty, it indicates all events in order capped by 50.
*/
struct RequestBody {
bytes32 transactionHash;
uint16 requiredConfirmations;
bool provideInput;
bool listEvents;
uint32[] logIndices;
}
/**
* @notice Response body for EVM transaction attestation type
* @custom:below The fields are in line with transaction provided by EVM node.
* @param blockNumber Number of the block in which the transaction is included.
* @param timestamp Timestamp of the block in which the transaction is included.
* @param sourceAddress The address (from) that signed the transaction.
* @param isDeployment Indicate whether it is a contract creation transaction.
* @param receivingAddress The address (to) of the receiver of the initial transaction.
* Zero address if `isDeployment` is `true`.
* @param value The value transferred by the initial transaction in wei.
* @param input If `provideInput`, this is the data send along with the initial transaction.
* Otherwise it is the default value `0x00`.
* @param status Status of the transaction 1 - success, 0 - failure.
* @param events If `listEvents` is `true`, an array of the requested events.
* Sorted by the logIndex in the same order as `logIndices`. Otherwise, an empty array.
*/
struct ResponseBody {
uint64 blockNumber;
uint64 timestamp;
address sourceAddress;
bool isDeployment;
address receivingAddress;
uint256 value;
bytes input;
uint8 status;
Event[] events;
}
/**
* @notice Event log record
* @custom:above An `Event` is a struct with the following fields:
* @custom:below The fields are in line with EVM event logs.
* @param logIndex The consecutive number of the event in block.
* @param emitterAddress The address of the contract that emitted the event.
* @param topics An array of up to four 32-byte strings of indexed log arguments.
* @param data Concatenated 32-byte strings of non-indexed log arguments. At least 32 bytes long.
* @param removed It is `true` if the log was removed due to a chain reorganization
* and `false` if it is a valid log.
*/
struct Event {
uint32 logIndex;
address emitterAddress;
bytes32[] topics;
bytes data;
bool removed;
}
}
Structs
Request
Toplevel request structure.
Parameters
attestationType
: ID of the attestation type (0x06 for EVMTransaction)sourceId
: ID of the data source (e.g., ETH, FLR, SGB)messageIntegrityCode
: MessageIntegrityCode derived from the expected responserequestBody
: Data defining the request
Response
Toplevel response structure.
Parameters
attestationType
: Extracted from the requestsourceId
: Extracted from the requestvotingRound
: The ID of the State Connector round in which the request was consideredlowestUsedTimestamp
: The lowest timestamp used to generate the responserequestBody
: Extracted from the requestresponseBody
: Data defining the response
Proof
Toplevel proof structure for verification.
Parameters
merkleProof
: Merkle proof corresponding to the attestation responsedata
: Attestation response
RequestBody
Request body specific to EVM transaction verification.
Parameters
transactionHash
: The hash of the transaction to relayrequiredConfirmations
: Number of confirmations required for the block to be considered finalprovideInput
: If true, the transaction input data will be included in the responselistEvents
: If true, events specified by logIndices will be included in the responselogIndices
: Array of event indices to be relayed (max 50), if empty and listEvents is true, includes all events up to 50
ResponseBody
Response body containing transaction details.
Parameters
blockNumber
: Block number containing the transactiontimestamp
: Timestamp of the block containing the transactionsourceAddress
: Address that signed the transaction (from)isDeployment
: True if the transaction created a contractreceivingAddress
: Address receiving the transaction (to), zero address if isDeployment is truevalue
: Value transferred in weiinput
: Transaction input data if provideInput is true, otherwise "0x00"status
: Transaction status (1 = success, 0 = failure)events
: Array of requested events if listEvents is true, otherwise empty
Event
Structure representing a transaction event (log).
Parameters
logIndex
: Index of the event within the blockemitterAddress
: Contract address that emitted the eventtopics
: Array of indexed event parameters (up to 4)data
: Non-indexed event parameters, concatenated as 32-byte stringsremoved
: True if the event was removed due to a chain reorganization
Implementation Notes
- Attestation ID:
0x06
- The
lowestUsedTimestamp
parameter uses the value oftimestamp
- The
lutlimit
(Lowest Used Timestamp limit) is0x41eb00
(4,300,800 seconds = ~50 days) for all supported chains - Events are indexed at the block level, not at the transaction level
- Maximum of 50 events can be included in a single attestation
Event Handling
When working with events, it's important to remember:
- Events (logs) are indexed at the block level, not at the transaction level
- The order of events in
logIndices
should follow the requirements of the consuming contract - If
listEvents
is set to false,logIndices
must be an empty array - If
listEvents
is true butlogIndices
is empty, all events up to a maximum of 50 will be included - Events are returned in the same order as specified in
logIndices
Usage Example
EVMTransactionVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";
import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol";
import {IEVMTransaction} from "@flarenetwork/flare-periphery-contracts/coston2/IEVMTransaction.sol";
contract EVMTransactionVerifier {
// A struct to hold the data from a verified ERC-20 transfer
struct VerifiedTransfer {
address tokenContract;
address from;
address to;
uint256 amount;
bytes32 transactionHash;
}
// An array to store all transfers verified by this contract
VerifiedTransfer[] public verifiedTransfers;
// The signature of the ERC-20 Transfer event
bytes32 private constant EVENT_TRANSFER_SIGNATURE =
keccak256(abi.encodePacked("Transfer(address,address,uint256)"));
event TransferVerified(
bytes32 indexed transactionHash,
address indexed tokenContract,
address from,
address to,
uint256 amount
);
function processTransactionProof(
IEVMTransaction.Proof calldata _proof,
address _tokenContract
) external {
// 1. FDC Logic: Verify the proof's authenticity with the Flare network.
require(isProofValid(_proof), "Invalid EVM transaction proof");
require(
_proof.data.responseBody.status == 1,
"Transaction reverted or not found"
);
// 2. Business Logic: Iterate through events to find and record ERC-20 transfers.
IEVMTransaction.Event[] memory events = _proof.data.responseBody.events;
bytes32 txHash = _proof.data.requestBody.transactionHash;
for (uint i = 0; i < events.length; i++) {
IEVMTransaction.Event memory evt = events[i];
// Filter for the specific token contract if provided
if (
_tokenContract != address(0) &&
evt.emitterAddress != _tokenContract
) {
continue;
}
// Check if the event is an ERC-20 Transfer: Transfer(address,address,uint256)
if (
evt.topics.length == 3 &&
evt.topics[0] == EVENT_TRANSFER_SIGNATURE
) {
// Decode the event data
address from = address(uint160(uint256(evt.topics[1])));
address to = address(uint160(uint256(evt.topics[2])));
uint256 amount = abi.decode(evt.data, (uint256));
// Record the verified transfer
verifiedTransfers.push(
VerifiedTransfer({
tokenContract: evt.emitterAddress,
from: from,
to: to,
amount: amount,
transactionHash: txHash
})
);
emit TransferVerified(
txHash,
evt.emitterAddress,
from,
to,
amount
);
}
}
}
function isProofValid(
IEVMTransaction.Proof memory _proof
) public view returns (bool) {
IFdcVerification fdcVerification = ContractRegistry
.getFdcVerification();
return fdcVerification.verifyEVMTransaction(_proof);
}
}