Receipts
Every transaction in the Fuel network contains a list of receipts with information about that transaction, including what contract function was called, logged data, data returned from a function, etc.
There are several types of receipts that can be attached to a transaction and indexed. You can learn more about each of these in the sections below.
Burn
Call
Log
LogData
MessageOut
Mint
Panic
Return
ReturnData
Revert
ScriptResult
Transfer
TransferOut
Burn
A Burn
receipt is generated whenever an asset is burned in a Sway contract. Read more about Burn
in the Fuel protocol ABI spec.
use fuel_types::{AssetId, ContractId};
pub struct Burn {
pub sub_id: AssetId,
pub contract_id: ContractId,
pub val: u64,
pub pc: u64,
pub is: u64,
}
mod indexer_mod {
fn handle_burn_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Burn { contract_id, .. } => {
info!("Found burn receipt from contract {contract_id:?}");
}
}
}
}
}
}
Call
A Call
receipt is generated whenever a function is called in a Sway contract. The fn_name
field contains the name of the called function from the aforementioned contract. Read more about Call
in the Fuel protocol ABI spec.
use fuel_types::{AssetId, ContractId};
pub struct Call {
pub contract_id: ContractId,
pub to: ContractId,
pub amount: u64,
pub asset_id: AssetId,
pub gas: u64,
pub fn_name: String,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_call_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Call { contract_id, .. } => {
info!("Found call receipt from contract {contract_id:?}");
}
}
}
}
}
}
Log
A Log
receipt is generated when calling log()
on a non-reference types in a Sway contracts - specifically bool
, u8
, u16
, u32
, and u64
. The ra
field includes the value being logged while rb
may include a non-zero value representing a unique ID for the log
instance. Read more about Log
in the Fuel protocol ABI spec.
use fuel_types::ContractId;
pub struct Log {
pub contract_id: ContractId,
pub ra: u64,
pub rb: u64,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_log_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Log { contract_id, .. } => {
info!("Found log receipt from contract {contract_id:?}");
}
}
}
}
}
}
LogData
A LogData
receipt is generated when calling log()
in a Sway contract on a reference type; this includes all types except non-reference types. The data
field will include the logged value as a hexadecimal. The rb
field will contain a unique ID that can be used to look up the logged data type. Read more about LogData
in the Fuel protocol ABI spec.
>
use fuel_types::ContractId;
pub struct LogData {
pub contract_id: ContractId,
pub data: Vec<u8>,
pub rb: u64,
pub len: u64,
pub ptr: u64,
}
Note: the example below will run both when the type
MyEvent
is logged as well as whenMyEvent
is returned from a function.
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_log_data(event: MyEvent) {
info!("Event {event:?} was logged in the contract");
}
}
MessageOut
A MessageOut
receipt is generated as a result of the send_typed_message()
Sway method in which a message is sent to a recipient address along with a certain amount of coins. The data
field supports data of an arbitrary type T
and will be decoded by the indexer upon receipt. Read more about MessageOut
in the Fuel protocol ABI spec.
use fuel_types::{MessageId, Bytes32, Address};
pub struct MessageOut {
pub message_id: MessageId,
pub sender: Address,
pub recipient: Address,
pub amount: u64,
pub nonce: Bytes32,
pub len: u64,
pub digest: Bytes32,
pub data: Vec<u8>,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_message_out(event: MyEvent) {
info!("Event {event:?} was logged in the contract");
}
}
Mint
A Mint
receipt is generated whenever an asset is burned in a Sway contract. Read more about Mint
in the Fuel protocol ABI spec.
use fuel_types::{AssetId, ContractId};
pub struct Mint {
pub sub_id: AssetId,
pub contract_id: ContractId,
pub val: u64,
pub pc: u64,
pub is: u64,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_mint_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Mint { contract_id, .. } => {
info!("Found mint receipt from contract {contract_id:?}");
}
}
}
}
}
}
Panic
A Panic
receipt is produced when a Sway smart contract call fails for a reason that doesn't produce a revert. The reason field records the reason for the panic, which is represented by a number between 0 and 255. You can find the mapping between the values and their meanings here in the FuelVM source code. Read more about Panic
in the Fuel protocol spec.
use fuel_types::ContractId;
pub struct Panic {
pub contract_id: ContractId,
pub reason: u32,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_panic_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Panic { contract_id, .. } => {
info!("Found panic receipt from contract {contract_id:?}");
}
}
}
}
}
}
Return
A Return
receipt is generated when returning a non-reference type in a Sway contract, specifically bool
, u8
, u16
, u32
, and u64
. The val
field includes the value being returned. Read more about Return
in the Fuel protocol spec.
use fuel_types::ContractId;
pub struct Return {
pub contract_id: ContractId,
pub val: u64,
pub pc: u64,
pub is: u64,
}
You can handle functions that produce a Return
receipt type by adding a parameter with the type Return
.
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_return_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Return { contract_id, .. } => {
info!("Found return receipt from contract {contract_id:?}");
}
}
}
}
}
}
ReturnData
A ReturnData
receipt is generated when returning a reference type in a Sway contract; this includes all types except non-reference types. The data
field will include the returned value as a hexadecimal. Read more about ReturnData
in the Fuel protocol ABI spec.
use fuel_types::ContractId;
pub struct ReturnData {
id: ContractId,
data: Vec<u8>,
}
Note: the example below will run both when the type
MyStruct
is logged as well as whenMyStruct
is returned from a function.
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_return_data(event: MyStruct) {
info!("MyStruct is: {event:#}");
}
}
Revert
A Revert
receipt is produced when a Sway smart contract function call fails. The table below lists possible reasons for the failure and their values. The error_val
field records these values, enabling your indexer to identify the specific cause of the reversion. Read more about Revert
in the Fuel protocol spec.
use fuel_types::ContractId;
pub struct Revert {
pub contract_id: ContractId,
pub error_val: u64,
}
Reason | Value |
---|---|
FailedRequire | 0 |
FailedTransferToAddress | 1 |
FailedSendMessage | 2 |
FailedAssertEq | 3 |
FailedAssert | 4 |
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_revert_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Revert { contract_id, .. } => {
info!("Found return receipt from contract {contract_id:?}");
}
}
}
}
}
}
ScriptResult
A ScriptResult
receipt is generated when a contract call resolves; that is, it's generated as a result of the RET
, RETD
, and RVRT
instructions. The result
field will contain a 0
for success, and a non-zero value otherwise. Read more about ScriptResult
in the Fuel protocol spec.
pub struct ScriptResult {
pub result: u64,
pub gas_used: u64,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_script_result_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::ScriptResult { result, .. } => {
info!("Result from script: {result:?}");
}
}
}
}
}
}
Transfer
A Transfer
receipt is generated when coins are transferred to a contract as part of a Sway contract. The asset_id
field contains the asset ID of the transferred coins, as the FuelVM has built-in support for working with multiple assets. The pc
and is
fields aren't currently used for anything, but are included for completeness. Read more about Transfer
in the Fuel protocol spec.
use fuel_types::{ContractId, AssetId};
pub struct Transfer {
pub contract_id: ContractId,
pub to: ContractId,
pub amount: u64,
pub asset_id: AssetId,
pub pc: u64,
pub is: u64,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_transfer_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::Transfer { contract_id, .. } => {
info!("Found transfer receipt from contract {contract_id:?}");
}
}
}
}
}
}
TransferOut
A TransferOut
receipt is generated when coins are transferred to an address rather than a contract. Every other field of the receipt works the same way as it does in the Transfer
receipt. Read more about TransferOut
in the Fuel protocol spec.
use fuel_types::{ContractId, AssetId, Address};
pub struct TransferOut {
pub contract_id: ContractId,
pub to: Address,
pub amount: u64,
pub asset_id: AssetId,
pub pc: u64,
pub is: u64,
}
extern crate alloc;
use fuel_indexer_utils::prelude::*;
#[indexer(manifest = "indexer.manifest.yaml")]
mod indexer_mod {
fn handle_transfer_out_receipt(block_data: BlockData) {
let height = block_data.header.height;
if !block_data.transactions.is_empty() {
let transaction = block_data.transactions[0];
for receipt in transaction.receipts {
match receipt {
fuel::Receipt::TransferOut { contract_id, .. } => {
info!("Found transfer_out receipt from contract {contract_id:?}");
}
}
}
}
}
}