Mercury Documentation
  • Get Started with Mercury
    • Pricing
    • Endpoints
    • Authentication
  • The Definitive Guide to Understanding The Mercury's Stack Vision
  • Retroshades
    • Introduction to Retroshades
    • Get Started
      • Importing the Retroshades SDK
      • Writing and Emitting Retroshades
      • Deploying to Mercury Retroshades
      • Querying Retroshades
  • Zephyr: Full Customization
    • Introduction
    • General concepts
      • Zephyr Programs
      • Accessing the Ledger: Contract Entries
      • Accessing the Ledger Meta: Contract Events
      • Database Interactions
      • Create Custom Callable APIs: Serverless Functions
      • Catchups
      • Using Soroban inside Zephyr
    • Quickstart
    • Learn
      • Introduction to Mercury's Cloud and the Zephyr Stack
      • Get Started: Set Up and Manage the Project
        • Create the Project
        • Writing the Program
        • Local Testing
        • Deploy
        • Data catchups/backfill
        • Monitor Execution
        • Querying
      • Database Interactions
        • Zephyr.toml: Define the Tables Structure
        • Understanding Database Interactions
        • Database Operations
      • Accessing the Ledger
      • Accessing Ledger Transition: Soroban Events
      • Working with Contract Custom Types
      • Working with Soroban SDK Types
      • Web Requests, Automation and Alerts.
      • Zephyr.toml Extensions: Indexes And Dashboard
      • Reading From Indexes/External Tables
      • Custom APIs - Serverless Functions
        • General Concepts
        • Custom RPC-alike Endpoints
        • Querying APIs for Composable Data
      • Data Catchups/Backfill
      • Custom Dashboards
        • Creating the Dashboard
        • Plotting: Simple
        • Complex Plotting
    • Support
  • Mercury "Classic"
    • Subscriptions
      • API Definition
    • Queries
      • Contract Events
      • Contract Data Entry Updates
      • Stellar Operations, Balances, and Account Objects
  • TUTORIALS
    • Zephyr
      • Self-hosting Zephyr
      • No-RPC Dapp
      • Indexing a DeFi liquidity pool (Blend)
      • Building a Secure DeFi Real-Time Bot Through Smart Accounts
      • Monitoring Large Deposits with Zephyr and Sending Web Alerts
    • Mercury Classic
      • Index and query contract events
Powered by GitBook
On this page
  • Contract Call Simulation
  • Contract Calls
  • Advantages of Simulating with Zephyr
  • On-Demand getLedger API
  • Resources
  1. Zephyr: Full Customization
  2. Learn
  3. Custom APIs - Serverless Functions

Custom RPC-alike Endpoints

Learn how you can set from your program a RPC-alike endpoint for ledger entries retrieval and contract call simulation.

Through serverless functions, it is possible to set endpoints that have the same functionality you could find in a RPC provider. Those are contract call simulation and on-demand getLedger APIs.

No need to pay for an external RPC provider to simulate transactions in your project when already using Mercury for the indexing!

Contract Call Simulation

Simulating a contract call with Zephyr is quite straightforward: you just have to set up a serverless function, as seen before and as you can see in the example, and call the env.simulate_contract_call_to_tx() function. The function takes the following arguments:

  • the account that makes the contract call

  • the ledger sequence

  • the contract address

  • the function to call

  • the arguments to call the function with

To return the response we use env.conclude.

#[no_mangle]
pub extern "C" fn simulate() {
    let env = EnvClient::empty();
    let request: SimulationRequest = env.read_request_body();

    let response = match request {
        SimulationRequest::Send(SimulateSend { from, sequence, message }) => {
            let address = Address::from_string(&SString::from_str(&env.soroban(), &from));
            let message = Bytes::from_slice(&env.soroban(), message.as_bytes());
            env.simulate_contract_call_to_tx(
                from,
                sequence,
                CONTRACT_ADDRESS,
                Symbol::new(&env.soroban(), "send"),
                vec![
                    &env.soroban(),
                    address.into_val(env.soroban()),
                    message.into_val(env.soroban()),
                ],
            )
            
        },
        // other match arms...
    }
    env.conclude(response)
}

Contract Calls

Once the transaction is simulated, you can even perform the contract call by making a web request to Horizon.

Advantages of Simulating with Zephyr

It was already said that if already using Zephyr, the user doesn't need to pay for an external RPC provider to simulate its contract calls, having everything in one place and saving some costs.

Moreover, by setting your custom simulation endpoint in a Zephyr program, you can leverage the Soroban/Rust type system, which is more straightforward and user-friendly. You have the flexibility to configure your endpoint as desired, allowing you to define the argument types for function parameters and handle the conversion within the program.

On-Demand getLedger API

A simple example of how to do that may look like this:

#[contracttype]
pub enum DataKey {
    Balance(Address)
}
#[derive(Serialize, Deserialize)]
pub struct Balance {
    addr: String,
    balance: i128
}
#[derive(Serialize, Deserialize)]
pub struct Request {
    addesses: Vec<String>
}

#[no_mangle]
pub extern "C" fn get_all_balances() {
    let env = EnvClient::empty();
    let req: Request = env.read_request_body();
    let mut balances = Vec::new();
    for addr in req.addesses {
        let source_addr = Address::from_string(&SorString::from_str(&env.soroban(), &addr));
        let res: i128 = env.read_contract_entry_by_key([0;32], DataKey::Balance(source_addr)).unwrap().unwrap();
        balances.push(Balance { addr, balance: res })
    }

    env.conclude(balances)
}

Here we are creating an endpoint that accesses a specific custom entry (Balance(Address)for a contract ([0;32]), using the env.read_contract_entry_by_key() function. The Balance objects holding the balance value for the different addresses are stored in a vector. You can see here how the possibility of using contract custom types reduces the amount of work on the user side.

This is only one of the many things you can do: instead of using read_contract_entry_by_key() you could use any of the functions that access the ledger state and customize the endpoint as you wish.


Resources

Here are additional automation resources:

PreviousGeneral ConceptsNextQuerying APIs for Composable Data

Last updated 8 months ago

In this example, taken from the , we use match to simulate different functions based on the request. We suggest to have a look at the full example to better understand the code. Here we are simulating the "send" function of the contract, which takes as arguments an address and a message in bytes. To learn more about the data types conversion, head to the working with data section, but just note here that the args you pass to the contract function need to be ScVals.

Another important feature generally offered by RPC providers is that of providing access to the current ledger state by retrieving ledger entries on demand. As already seen in , this can be easily done also from within a Zephyr program. The only difference now is that we also can retrieve the entries from within a serverless function and, after having set up the endpoint, call it on-demand.

on-chain stellar complaints indexer
Accessing the Ledger
https://blog.xycloo.com/blog/on-chain-compaints-dapp