ERC721

Source: examples/erc721/ Status: Live on The Graph Studio (Arbitrum One)

Indexes ERC721 NFT Transfer and Approval events. Demonstrates multiple handlers and multiple entity types updating the same Token entity from different events.

Schema

type Token @entity {
  id: ID!
  owner: Bytes!
  approved: Bytes!
}

type Transfer @entity {
  id: ID!
  from: Bytes!
  to: Bytes!
  tokenId: BigInt!
  blockNumber: BigInt!
  timestamp: BigInt!
  transactionHash: Bytes!
}

type Approval @entity {
  id: ID!
  owner: Bytes!
  approved: Bytes!
  tokenId: BigInt!
}

Handlers

Transfer: Creates a Transfer record and upserts the Token owner.

#![allow(unused)]
fn main() {
pub fn handle_transfer_impl(raw: &RawEthereumEvent) {
    let event = ERC721TransferEvent::from_raw_event(raw)?;
    let id = format!("{}-{}", hex_bytes(&event.tx_hash), hex_bytes(&event.log_index));

    Transfer::new(&id)
        .set_from(event.from.to_vec())
        .set_to(event.to.to_vec())
        .set_token_id(event.token_id.clone())
        .set_block_number(event.block_number.clone())
        .set_timestamp(event.block_timestamp.clone())
        .set_transaction_hash(event.tx_hash.to_vec())
        .save();

    // Update the token's current owner
    let token_id_str = hex_bytes(&event.token_id);
    Token::new(&token_id_str)
        .set_owner(event.to.to_vec())
        .set_approved(alloc::vec![0u8; 20])  // clear approval on transfer
        .save();
}
}

Approval: Updates the token's approved address.

#![allow(unused)]
fn main() {
pub fn handle_approval_impl(raw: &RawEthereumEvent) {
    let event = ERC721ApprovalEvent::from_raw_event(raw)?;
    let token_id_str = hex_bytes(&event.token_id);

    Approval::new(&format!("{}-{}", hex_bytes(&event.tx_hash), hex_bytes(&event.log_index)))
        .set_owner(event.owner.to_vec())
        .set_approved(event.approved.to_vec())
        .set_token_id(event.token_id.clone())
        .save();

    if let Some(token) = Token::load(&token_id_str) {
        token.set_approved(event.approved.to_vec()).save();
    }
}
}

Key Points

  • The Token entity is upserted by both handlers — the Transfer handler sets the owner, the Approval handler sets the approved address.
  • Token::load returns Option<Token> — the Approval handler only updates if the token already exists.
  • Approval is cleared on transfer by writing [0u8; 20] as the approved address.
cd examples/erc721
cargo test