Skip to content

RequestNetwork/payments-substream

Repository files navigation

Request Network Payments Substream

Substreams module for indexing Request Network ERC20FeeProxy payment events across multiple blockchain networks. Currently supports TRON with a multi-chain architecture ready for additional networks.

Prerequisites

Install Rust WASM target

rustup target add wasm32-unknown-unknown

Install Substreams CLI

# macOS
brew install streamingfast/tap/substreams

# Linux
curl -sSL https://github.com/streamingfast/substreams/releases/latest/download/substreams_linux_x86_64.tar.gz | tar xz
sudo mv substreams /usr/local/bin/

Install Buf CLI

brew install bufbuild/buf/buf

Project Structure

payments-substream/
├── tron/                          # TRON substream module
│   ├── src/
│   │   ├── lib.rs                 # Main substream logic
│   │   └── pb/                    # Generated protobuf code
│   ├── proto/
│   │   └── request/tron/v1/
│   │       └── payments.proto     # Payment message definitions
│   ├── schema.sql                 # PostgreSQL schema for SQL sink
│   ├── schema.graphql             # GraphQL schema (for future use)
│   ├── substreams.yaml            # Substream manifest
│   ├── Cargo.toml                 # Rust dependencies
│   └── Makefile                   # Build commands
├── docker-compose.yml             # Local development setup
├── docker-compose.prod.yml        # Production deployment (Easypanel)
├── Dockerfile.sink                # SQL sink Docker image
└── .env.example                   # Environment variables template

Development

1. Make Changes to the Substream

Modify the Rust Code

Edit tron/src/lib.rs to change payment parsing logic:

// Example: Add new field extraction
fn parse_transfer_with_reference_and_fee(...) -> Option<Payment> {
    // Your parsing logic here
}

Update Protobuf Messages

Edit tron/proto/request/tron/v1/payments.proto:

message Payment {
  string token_address = 1;
  // Add new fields here
  string new_field = 13;
}

After changing .proto files, regenerate the Rust code:

cd tron
make protogen

Update SQL Schema

Edit tron/schema.sql to add new columns:

ALTER TABLE payments ADD COLUMN new_field TEXT;

2. Build the Substream

cd tron

# Build WASM module
make build

# Run unit tests
make test

# Package into .spkg file
make package

3. Run the Stream Locally

Test the substream against live blockchain data without a database:

cd tron

# Set your API token
export SUBSTREAMS_API_TOKEN="your-token-here"

# Run against TRON mainnet (100 blocks from deployment)
substreams run ./request-network-tron-v0.1.0.spkg \
  map_erc20_fee_proxy_payments \
  -e mainnet.tron.streamingfast.io:443 \
  --start-block 79216121 \
  --stop-block +100

Output Options

# JSON output (for debugging)
substreams run ... -o json

# Protobuf output (default)
substreams run ... -o proto

4. Run the Sink Locally (with PostgreSQL)

Test the full pipeline with a local PostgreSQL database:

Start Local Services

# Create .env file
cp .env.example .env

# Edit .env with your values
# SUBSTREAMS_API_TOKEN=your-token
# POSTGRES_PASSWORD=your-password

# Start PostgreSQL and sink
docker compose up -d

# View logs
docker compose logs -f sink

Query Local Database

# Connect to PostgreSQL
docker exec -it tron-payments-db psql -U postgres -d tron_payments

# Query payments
SELECT * FROM payments LIMIT 10;
SELECT chain, COUNT(*) FROM payments GROUP BY chain;

Stop Local Services

docker compose down

# Remove data volumes (fresh start)
docker compose down -v

Configuration

Substream Parameters

Parameters are configured in tron/substreams.yaml:

params:
  map_erc20_fee_proxy_payments: |
    mainnet_proxy_address=TCUDPYnS9dH3WvFEaE7wN7vnDa51J4R4fd
    chain=tron
Parameter Description Example
mainnet_proxy_address ERC20FeeProxy contract address TCUDPYnS9dH3WvFEaE7wN7vnDa51J4R4fd
chain Chain identifier for multi-chain support tron, ethereum, polygon

Environment Variables

Variable Description
SUBSTREAMS_API_TOKEN Streamingfast API authentication token
DSN PostgreSQL connection string
POSTGRES_PASSWORD PostgreSQL password (local dev)

Deployment

Deploy to Easypanel (Production)

1. Create PostgreSQL Database

In Easypanel:

  1. Create a new PostgreSQL service
  2. Note the internal hostname (e.g., shared_payments-substream-postgres)

2. Deploy the Sink

  1. Create a new Docker Compose app pointing to this repository
  2. Set compose file path: docker-compose.prod.yml
  3. Configure environment variables:
DSN=postgres://postgres:PASSWORD@shared_payments-substream-postgres:5432/shared?sslmode=disable
SUBSTREAMS_API_TOKEN=your-streamingfast-token
  1. Enable "Create .env file" checkbox
  2. Deploy

3. Monitor the Sink

Check logs in Easypanel to verify:

  • Connection to Streamingfast endpoint
  • Database writes (db_flush_rate)
  • Block processing (progress_total_processed_blocks)

Manual Deployment

# Build the Docker image
docker build -f Dockerfile.sink -t payments-sink .

# Run with environment variables
docker run -d \
  -e DSN="postgres://user:pass@host:5432/db?sslmode=disable" \
  -e SUBSTREAMS_API_TOKEN="your-token" \
  payments-sink

GraphQL API (Hasura)

The PostgreSQL database is exposed via Hasura, providing a GraphQL API for the Request Network SDK to query payments.

Architecture

┌─────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│    TRON     │────▶│  Substream   │────▶│  PostgreSQL  │────▶│    Hasura    │
│  Blockchain │     │    Sink      │     │  (payments)  │     │   GraphQL    │
└─────────────┘     └──────────────┘     └──────────────┘     └──────┬───────┘
                                                                     │
                                                                     ▼
                                                             ┌──────────────┐
                                                             │ Request SDK  │
                                                             │  (payment    │
                                                             │  detection)  │
                                                             └──────────────┘

GraphQL Endpoint

  • Staging: https://graphql.stage.request.network/v1/graphql
  • Production: https://graphql.request.network/v1/graphql

Example Query

query GetPayments($reference: String!, $chain: String) {
  payments(
    where: {
      payment_reference: { _eq: $reference }
      chain: { _eq: $chain }
    }
    order_by: { block_number: asc }
  ) {
    id
    chain
    tx_hash
    block_number
    timestamp
    token_address
    from_address
    to_address
    amount
    fee_amount
    fee_address
    payment_reference
    contract_address
  }
}

Query by Payment Reference

curl -X POST https://graphql.stage.request.network/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { payments(where: { payment_reference: { _eq: \"0xabc123...\" } }) { tx_hash amount chain } }"
  }'

SDK Integration

The Request Network SDK uses a custom info retriever to query the Hasura endpoint for TRON payments. See the @requestnetwork/payment-detection package for implementation details.

Multi-Chain Support

The payments table includes a chain field to support multiple networks:

SELECT chain, COUNT(*) as payments FROM payments GROUP BY chain;

Adding a New Network

  1. Create a new substream module (e.g., ethereum/)
  2. Configure the appropriate Streamingfast endpoint
  3. Set the chain parameter in substreams.yaml
  4. Deploy an additional sink pointing to the same database

Example for Ethereum:

params:
  map_erc20_fee_proxy_payments: |
    mainnet_proxy_address=0x...
    chain=ethereum

Troubleshooting

Module Hash Mismatch

If you see cursor module hash mismatch:

-- Connect to PostgreSQL and reset
DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS cursors;

Then redeploy the sink.

Column Does Not Exist

Schema changes require dropping and recreating tables:

DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS cursors;

DNS Resolution Issues

Ensure services are on the same Docker network. In docker-compose.prod.yml:

networks:
  easypanel:
    external: true

Streamingfast Endpoints

Network Endpoint
TRON Mainnet mainnet.tron.streamingfast.io:443
TRON Shasta (Testnet) shasta.tron.streamingfast.io:443
Ethereum Mainnet mainnet.eth.streamingfast.io:443

License

MIT

About

Substream for indexing Request Network payments

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •