Get Started

Welcome to Mercury's documentation for developers. This rust book is meant to give you a complete understanding of Mercury's features and what you need in getting started using Mercury's preview releases as the indexer for your services, apps, and protocols; so if some points need clarification don't hesitate to let us know by opening an issue on Github.


Mercury: a Managed Indexing Service

Let's start off by saying that Mercury is a managed indexing service, which means that we control on our servers everything ranging from ingestion to the GraphQL API.

This design choice is likely what will impact more your decision in choosing an indexer, here are some of the pros and cons of using a managed indexer service.

Note: these charateristics aren't about Mercury specifically, they are about the advantages and disadvantages of relying on a managed indexing service.

Pros of a managed service.

  • No need for a setup and development of any kind.

    • this also includes not needing to worry about DB structure and its efficiency
  • No need of performing maintenance. There is no workload that is streamlined to the user, so also no workload in having to stay up to date with the code, dependencies, etc.

  • Cheaper. In most circumnstances, using a managed indexer is cheaper than running and maintaining your own instance. Also, you might want to account for development costs, which are non-existing when relying on a managed service.

  • Security. While it's true that you don't have control over the security of the product you're relying to, our team does. We are committed to building a secure product and also have a solid background in security research.

  • Smoother experience. Generally, managed services can offer a smoother experience due to the nature of their design, including also more specific support.

Pros of a self-hosted service.

  • Vendor lock-in. When you're running your own indexer you don't have much constraints around which server you use and you don't have to worry about lack of availability on the service's end. For example, if you want to migrate to another service, self-hosted services offer a much smoother experience, and in some managed service that is not even an option.

  • Customization. As you're actually building the service yourself, you can give it the shape you want. In some situations where very high customization degrees are needed, relying on a self-hosted service reduces a lot of workload for the client.


You can understand that the choicce depends on you use case and needs. If you'd like to get help in understanding if Mercury fits your requirements you can ask on our team's public discord server.

Anyways, for Mercury we are committed to lowering the gaps between a self-hosted solution's pros and a managed's cons. In fact:

  • we tackle customizability by developing and integrating in Mercury the Zephyr VM, xyclooLab's WebAssembly VM for communication between the Stellar Network's data and the guest environemnt. Users that wish to have full customizability (and also additional perks) can write their logic in any WASM-compatible language and deploy it to Mercury's cloud execution environment. Read more about Zephyr in our blog here - introduction and here - an experimental Zephyr program.

    • also, we generally don't envision Mercury itself not to cover most use cases, even those who need some customizability. Our extensive knowledge of Stellar + Soroban structures, dynamics, and logics are helping us to craft an implementation that will fit most use cases for developers. This is also why we have developed the Zephyr Virtual Machine with also other features in mind.
  • there isn't really a way of tackling vendor lock and ensuring availability over time, but:

    • we're committed with working with users that wish to migrate in order to provide the cleanest migration experience as possible. In our mind we have DB write channels, but this is not going to be prioritized and included in the first releases.
    • while it is not possible for us to, at least currently, guarantee consistent availability over time, our team is committed to do so. We have been working on Stellar for more than two years and have strong ties with the community, of which we are also a part.

Pricing

While we don't have yet any hard numbers on pricing, we have defined a very solid model that involves down-payments and reimbursements. The main advantages of our cost model are:

  • very cost efficient: you only pay for the data you request to store, and for the amount of data you're actually occupying in our database.
  • efficiency in managing payments: you know exactly how much you'll spend at most.
  • payments are performed through stellar payments.

If you're interested in learning more, we suggest checking out our SCF presentation document.

Request Access

Mercury is a complex product and is still in development, so access is not open. However, we grant preview access to anyone who is interested. Just let us know in the discord server, or by reaching out on discord to heytdep or itsfederico.

Current endpoints

BACKENDhttp://ec2-16-170-242-7.eu-north-1.compute.amazonaws.com:3030/
GraphQlhttp://ec2-16-170-242-7.eu-north-1.compute.amazonaws.com:5000/graphiql
GraphiQlhttp://ec2-16-170-242-7.eu-north-1.compute.amazonaws.com:5000/graphql

Mercury is still under development so the above endpoints (besides being still http) might change.

Subscriptions: What and Why

As you've read in the introduction, Mercury only stores the data you request. This translates to us adopting our so-called "subscriptions-based" model.

The "subscriptions-based" model consists in users having to create subscriptions through our subscriptions backend.

Note: When Mercury will release its first stable release, payments to Mercury will begin when creating the subscription.

A user subscription defines the charateristics that the Network data ingested by Mercury's ingestor must have in order to be stored on our database (thus subsequently queried).

Example

Imagine having a factory contract. You'd want to be able to keep track of the contracts deployed by your factory, and your factory contract emits a contract event (Symbol("deploy"), created_by, deployed_id) whenever it deployed a new contract.

If you go for an event-based approach, you can set up a subscription to all contract events for all your factory's "deploy" events:

Subscription:

{
	"contract_id" : "contract id (as strkey)",
	"max_single_size": 144,
	"topic1": "'deploy' as base64 xdr"
}

max_single_size is the maximum amount of bytes a single event can reach.

About subscription customizability

Subscruptions offer a good level of customizability in the data you want to be able to query. Say for example in the example above you only want to store deploy events where created_by is a specific address, you can easily achive this by making the subscription look like:

{
	"contract_id" : "contract id (as strkey)",
	"max_single_size": 144,
	"topic1": "'deploy' as base64 xdr",
	"topic2": "specific address as base64 xdr",
}

You could also subscribe to all the contract's event with

{
	"contract_id" : "contract id (as strkey)",
	"max_single_size": 144,
}

In the next sections of the documentation, we'll guide you through how to create subscriptions to the currently indexed data structures.

Creating contract event subscriptions

To create a new subscription to a contract event, refer to the following API:

endpoint: INSTANCE:3030/event method: POST content-type: application/json auth: "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" body:

{"contract_id": "CONTRACT_ID", "topic1": "XDR", "topic2": "XDR", "topic3": "XDR", "topic4": "XDR", "max_single_size": "MAX_EVENT_BYTE_SIZE as integer"}

As you can see, you can choose to be as specific as you want with the events you subscribe to. You can leave fields (contract_id, topic1, topic2, topic3, topic4) null to have the field match with any value, for example, setting the contract id to null and the first topic to transfer matches with all transfer events from all contracts.

We also set the max single size parameter which indicates how much will one event cost us at most (for now that we don't have the metering running, you can also set to the network's max so like 2000 bytes).

Example

This example subscribes to all events of xycLoans' XLM pool:

 curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"contract_id":"CCVP5K2R2X4RWSJB7WZDDYVWHWDUUZWBWHLFPSZBIDOAWXH3LX6GG5PU", "max_single_size": 200}' -H "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" \
  BACKEND/event

Ledger entries

Mercury also allows to easily record state changes. This is especially useful in scenarios where events alone don't give you enough context. When you subscribe to a ledger entry update for a contract you are subscribing to the contract instance, to a presistent, or to temporary entry.

To create a new subscription to a ledger entry, refer to the following API:

endpoint: INSTANCE:3030/entry method: POST content-type: application/json auth: "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" body:

{"contract_id": "CONTRACT_ID", "key_xdr": "entry key as base64 xdr", "max_single_size": "MAX_ENTRY_BYTE_SIZE as integer"}

Example

To subscribe to a contract's instance updates:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"contract_id":"contract id", "key_xdr": "AAAAFA==", "max_single_size": 64000}' -H "Authorization: Bearer $JWT_TOKEN" \
  BACKEND/entry

Ledger etries expiration

Soroban introduces the novel concept of state expiration, and it's essential that developers and users are able to efficiently know the expiration state of their entries.

To create a new subscription to a ledger entry expiration, refer to the following API:

endpoint: INSTANCE:3030/expiration method: POST content-type: application/json auth: "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" body:

{"hash_xdr": "base64 xdr of your entry's hash"}

Full account subscriptions - Stellar Classic

Mercury aims to also enable efficient indexing of all stellar classic operations. Currently, we do so through full account subscriptions. These are stellar account-centered subscriptions, and a subscription for an account will tell mercury to index all the currently supported operations that encompass the specified stellar account.

Currently-supported stellar classic operations are:

  • payments
  • createaccount

To create a full account subscription, refer to the following API:

endpoint: INSTANCE:3030/account method: POST content-type: application/json auth: "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" body:

{"publickey": "public key of the account (strkey)"}

Example

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"publickey":"GDEFZKAH3SDHKR6OJYNORMTQY7QB44EJX5BL6WHVZBDQKOYO7BHEBC5C"}' -H "Authorization: Bearer $JWT_TOKEN" \                         
  BACKEND/account

Before querying

Before you start querying, remember that you need to have subscriptions in place.

Mercury will not store nor grant you access to data that isn't covered by a subscription.

For example, if you want to index all leder entries for two contracts, you need to perform two ledger entry subscriptions.

Make sure you checked out the subscriptions chapter.

Contract Events

Assuming that you have a subscription targeted to the events you are indexing, below are some instructions to get started making some more specific queries.

Events by contract id

In this example, we're querying events (within the constraints of our subscription) for Testnet's native token contract.

query MyQuery {
  eventByContractId(
    searchedContractId: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"
  ) {
    edges {
      node {
        contractId
        data
        ledger
        ledgerTimestamp
        topic2
        topic1
        topic4
        topic3
      }
    }
  }
}

Example response:

{
  "data": {
    "eventByContractId": {
      "edges": [
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAAX14QA=",
            "ledger": 1976715,
            "ledgerTimestamp": 1697125133,
            "topic2": "AAAAEgAAAAAAAAAAlgxjlS3RNgkTERctfeiCrlUtOyt9BCzR4tRDDY9zmIE=",
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA==",
            "topic3": "AAAAEgAAAAFkp3At7J1OWk8PiDhUMY2lWuneIYknC4OsmpJHxEYR7Q=="
          }
        },
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAAABgnY=",
            "ledger": 1977257,
            "ledgerTimestamp": 1697127978,
            "topic2": "AAAAEgAAAAAAAAAAtXs1DVecP4w3jdgAVoD8DDcUkSryRVL3pjWQIbk1EZY=",
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA==",
            "topic3": "AAAAEgAAAAAAAAAAPTdgJsV5ZyTSlS3RBk3s+JcreccjoCp3Vj7Z8jmU26k="
          }
        },
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAAAAA+g=",
            "ledger": 1977723,
            "ledgerTimestamp": 1697130446,
            "topic2": "AAAAEgAAAAAAAAAAJYf9NMqmC02G4br+I6LKzbfLvGV8QeiHblDN8VQtkyI=",
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA==",
            "topic3": "AAAAEgAAAAAAAAAAf1sKj1rp5aRGdzj/pa4Yh0Jg83YJhhCmvWdqZoi4zks="
          }
        },
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAlQL5AA=",
            "ledger": 1977738,
            "ledgerTimestamp": 1697130525,
            "topic2": "AAAAEgAAAAAAAAAAJYf9NMqmC02G4br+I6LKzbfLvGV8QeiHblDN8VQtkyI=",
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA==",
            "topic3": "AAAAEgAAAAAAAAAAf1sKj1rp5aRGdzj/pa4Yh0Jg83YJhhCmvWdqZoi4zks="
          }
        },
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAAX14QA=",
            "ledger": 1978025,
            "ledgerTimestamp": 1697132038,
            "topic2": "AAAAEgAAAAAAAAAAlgxjlS3RNgkTERctfeiCrlUtOyt9BCzR4tRDDY9zmIE=",
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA==",
            "topic3": "AAAAEgAAAAAAAAAADrWdipCyvgYDlv6kRpdNchs5UGHB3Dsol3VHKAS2tYE="
          }
        }
      ]
    }
  }
}

Note that the data for events is stored as base64-encoded XDR.

Events by topics

Mercury also allows you to query events given certain topics. For instance, let's index all transfer events in our subscription to the address GAHLLHMKSCZL4BQDS37KIRUXJVZBWOKQMHA5YOZIS52UOKAEW22YDSXX:

query MyQuery {
  eventByTopic(
    t1: "AAAADwAAAAh0cmFuc2Zlcg=="
    t3: "AAAAEgAAAAAAAAAADrWdipCyvgYDlv6kRpdNchs5UGHB3Dsol3VHKAS2tYE="
  ) {
    edges {
      node {
        contractId
        data
        ledger
        ledgerTimestamp
        topic1
        topic2
        topic3
        topic4
      }
    }
  }
}

sample response:

{
  "data": {
    "eventByTopic": {
      "edges": [
        {
          "node": {
            "contractId": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "data": "AAAACgAAAAAAAAAAAAAAAAX14QA=",
            "ledger": 1978025,
            "ledgerTimestamp": 1697132038,
            "topic1": "AAAADwAAAAh0cmFuc2Zlcg==",
            "topic2": "AAAAEgAAAAAAAAAAlgxjlS3RNgkTERctfeiCrlUtOyt9BCzR4tRDDY9zmIE=",
            "topic3": "AAAAEgAAAAAAAAAADrWdipCyvgYDlv6kRpdNchs5UGHB3Dsol3VHKAS2tYE=",
            "topic4": "AAAADgAAAAZuYXRpdmUAAA=="
          }
        }
      ]
    }
  }
}

Note: this assumes that you already know the exact structure of the events you're querying. In this example we know that topic1 (t1) holds the event kind (Symbol("transfer") in our case) and that topic3 (t3) holds an Address object for the public key GAHLLHMKSCZL4BQDS37KIRUXJVZBWOKQMHA5YOZIS52UOKAEW22YDSXX. Building these xdrs must be done by the client and can be easily done with the existing stellar xdr tooling.

Querying ledger entries

Entries by contract id

query EntriesByContractId {
  entryUpdateByContractId(
    contract: "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75"
  ) {
    nodes {
      contractId
      entryDurability
      keyXdr
      ledger
      ledgerTimestamp
      valueXdr
    }
  }
}

Example response

{
  "data": {
    "entryUpdateByContractId": {
      "nodes": [
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAFA==",
          "ledger": 2043931,
          "ledgerTimestamp": 1697478387,
          "valueXdr": "AAAAEwAAAABSupsyUp3yF//KIautJd9SeXc+dBHo/b5Q7dAU1R1gggAAAAEAAAACAAAAEAAAAAEAAAABAAAADwAAAAdUb2tlbklkAAAAABIAAAAB15KLcsJwPM/q9+uf9O9NUEpVqLl5/JtFDqLIQrTRzmEAAAAQAAAAAQAAAAEAAAAPAAAACVRvdFN1cHBseQAAAAAAAAoAAAAAAAAAAAAAAAAL68IA"
        },
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAEAAAAAEAAAACAAAADwAAABVGZWVQZXJTaGFyZVBhcnRpY3VsYXIAAAAAAAASAAAAAAAAAACWDGOVLdE2CRMRFy196IKuVS07K30ELNHi1EMNj3OYgQ==",
          "ledger": 2043931,
          "ledgerTimestamp": 1697478387,
          "valueXdr": "AAAACgAAAAAAAAAAAAAAAAAAAAA="
        },
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAJYMY5Ut0TYJExEXLX3ogq5VLTsrfQQs0eLUQw2Pc5iB",
          "ledger": 2043931,
          "ledgerTimestamp": 1697478387,
          "valueXdr": "AAAACgAAAAAAAAAAAAAAAAvrwgA="
        },
		....
	]
    }
  }
}

Entries by contract id and data

query EntriesByContractId {
  entryUpdateByContractIdAndKey(
    contract: "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75"
    ledgerKey: "AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAJYMY5Ut0TYJExEXLX3ogq5VLTsrfQQs0eLUQw2Pc5iB"
  ) {
    nodes {
      contractId
      entryDurability
      keyXdr
      ledger
      ledgerTimestamp
      valueXdr
    }
  }
}

Example response

{
  "data": {
    "entryUpdateByContractIdAndKey": {
      "nodes": [
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAJYMY5Ut0TYJExEXLX3ogq5VLTsrfQQs0eLUQw2Pc5iB",
          "ledger": 2043931,
          "ledgerTimestamp": 1697478387,
          "valueXdr": "AAAACgAAAAAAAAAAAAAAAAvrwgA="
        },
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAJYMY5Ut0TYJExEXLX3ogq5VLTsrfQQs0eLUQw2Pc5iB",
          "ledger": 2061071,
          "ledgerTimestamp": 1697568458,
          "valueXdr": "AAAACgAAAAAAAAAAAAAAABHhowA="
        },
        {
          "contractId": "CDSFM6YQ5PBC3QZT5CSJNMROM355RE2OFIWBMQZHEXBJGCQYJW6JFO75",
          "entryDurability": "PERSISTENT",
          "keyXdr": "AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAJYMY5Ut0TYJExEXLX3ogq5VLTsrfQQs0eLUQw2Pc5iB",
          "ledger": 2061140,
          "ledgerTimestamp": 1697568815,
          "valueXdr": "AAAACgAAAAAAAAAAAAAAABfXhAA="
        },
		...
	  ]
	  }
	}
}

Stellar classic

Mercury allows indexing stellar classic operations throught full account subscriptions. Any operation that encompasses an account you're subscribed to will be indexed on Mercury, for instance, whether it's your account that's making the payment or receiving it, Mercury will index the payment.

This is especially useful for wallets looking to integrate Mercury as their source for all Soroban + Stellar data.

Indexing Payments

Assuming that you already have a full account subscription for the account you wish to index payments for, with Mercury you can query both payments from and to this account.

From account

query MyQuery {
  paymentsByPublicKey(
    publicKeyText: "GAQX75URIUYBKEUWDWPRTFBMTW6ZWMAGDMC7IBBA6XWTIDYOSE5LRXLE"
  ) {
    edges {
      node {
        amount
        assetByAsset {
          code
          issuer
        }
        accountByDestination {
          publickey
        }
        accountBySource {
          publickey
        }
        muxedaccountByDestinationMuxed {
          publickey
          muxedaccountid
        }
        muxedaccountBySourceMuxed {
          publickey
          muxedaccountid
        }
        ledgerByLedger {
          closeTime
          sequence
        }
        assetNative
      }
    }
  }
}

Sample response:

{
  "data": {
    "paymentsToPublicKey": {
      "edges": [
        {
          "node": {
            "amount": "100000000",
            "assetByAsset": null,
            "accountByDestination": {
              "publickey": "GAHLLHMKSCZL4BQDS37KIRUXJVZBWOKQMHA5YOZIS52UOKAEW22YDSXX"
            },
            "accountBySource": {
              "publickey": "GAQX75URIUYBKEUWDWPRTFBMTW6ZWMAGDMC7IBBA6XWTIDYOSE5LRXLE"
            },
            "muxedaccountByDestinationMuxed": null,
            "muxedaccountBySourceMuxed": null,
            "ledgerByLedger": {
              "closeTime": 1697129852,
              "sequence": 1977611
            },
            "assetNative": true
          }
        }
      ]
    }
  }
}

As you can see, there are some null fields in our response, and it's perfectly normal. This is because:

  • in Mercury, when an asset is queried the response can include either:
    • assetNative: when true it means the asset sent is XLM
    • assetByAsset: the asset object for non-native assets. When the asset being sent is not xlm this field holds an object with the code and the issuer of the asset.
  • The query is asking Mercury to look for payments that have been made:
    1. from an account to another
    2. from a muxed account to another muxed account
    3. from an account to a muxed account
    4. from a muxed account to an account. For this payment we indexed, it's situation 1, so muxedaccountByDestinationMuxed and muxedaccountBySourceMuxed are both null, but you can see the accountBySource and accountByDestination populated with the receiver and destination public keys.

This data structure design makes queries very efficient on our end, and allows the client to easily understand whether the asset sent is native or not, whether the source is muxed, etc.

Create Account OPs

Account created

query MyQuery {
  createAccountToPublicKey(
    publicKeyText: "GAQX75URIUYBKEUWDWPRTFBMTW6ZWMAGDMC7IBBA6XWTIDYOSE5LRXLE"
  ) {
    edges {
      node {
        accountByDestination {
          publickey
        }
        accountBySource {
          publickey
        }
        muxedaccountBySourceMuxed {
          publickey
          muxedaccountid
        }
        ledgerByLedger {
          closeTime
          sequence
        }
        startingBalance
      }
    }
  }
}

{
  "data": {
    "createAccountToPublicKey": {
      "edges": [
        {
          "node": {
            "accountByDestination": {
              "publickey": "GAQX75URIUYBKEUWDWPRTFBMTW6ZWMAGDMC7IBBA6XWTIDYOSE5LRXLE"
            },
            "accountBySource": {
              "publickey": "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR"
            },
            "muxedaccountBySourceMuxed": null,
            "ledgerByLedger": {
              "closeTime": 1697129852,
              "sequence": 1977611
            },
            "startingBalance": "100000000000"
          }
        }
      ]
    }
  }
}

Account created from

query MyQuery {
  createAccountByPublicKey(
    publicKeyText: "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR"
  ) {
    edges {
      node {
        accountByDestination {
          publickey
        }
        accountBySource {
          publickey
        }
        muxedaccountBySourceMuxed {
          publickey
          muxedaccountid
        }
        ledgerByLedger {
          closeTime
          sequence
        }
        startingBalance
      }
    }
  }
}
{
  "data": {
    "createAccountByPublicKey": {
      "edges": [
        {
          "node": {
            "accountByDestination": {
              "publickey": "GAGTO2P23XRSRUGH7NIRH4GIZX55X77DWNHI6UMHN3JVMJJ2FRZKW2TS"
            },
            "accountBySource": {
              "publickey": "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR"
            },
            "muxedaccountBySourceMuxed": null,
            "ledgerByLedger": {
              "closeTime": 1697129852,
              "sequence": 1977611
            },
            "startingBalance": "100000000000"
          }
        },
        {
          "node": {
            "accountByDestination": {
              "publickey": "GAQX75URIUYBKEUWDWPRTFBMTW6ZWMAGDMC7IBBA6XWTIDYOSE5LRXLE"
            },
            "accountBySource": {
              "publickey": "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR"
            },
            "muxedaccountBySourceMuxed": null,
            "ledgerByLedger": {
              "closeTime": 1697129852,
              "sequence": 1977611
            },
            "startingBalance": "100000000000"
          }
        }
      ]
    }
  }
}

Path payments (strict receive)

From Account

query FullQuery {
  pathPaymentsStrictSendByPublicKey(publicKeyText: "$PUBLIC_KEY") {
    nodes {
      ledgerByLedger {
        closeTime
        sequence
      }
      accountBySource {
        publickey
      }
      accountByDestination {
        publickey
      }
      assetByDestAsset {
        code
        issuer
      }
      assetByPath1 {
        code
        issuer
      }
      assetByPath2 {
        code
        issuer
      }
      assetByPath3 {
        issuer
        code
      }
      assetByPath4 {
        issuer
        code
      }
      assetByPath5 {
        issuer
        code
      }
      assetBySendAsset {
        code
        issuer
      }
      destAssetNative
      destMin
      path1Native
      path2Native
      path3Native
      path4Native
      path5Native
      sendAmount
      sendAssetNative
    }
  }
}

To Account

query FullQuery {
  pathPaymentsStrictSendToPublicKey(publicKeyText: "$PUBLIC_KEY") {
    nodes {
      ledgerByLedger {
        closeTime
        sequence
      }
      accountBySource {
        publickey
      }
      accountByDestination {
        publickey
      }
      assetByDestAsset {
        code
        issuer
      }
      assetByPath1 {
        code
        issuer
      }
      assetByPath2 {
        code
        issuer
      }
      assetByPath3 {
        issuer
        code
      }
      assetByPath4 {
        issuer
        code
      }
      assetByPath5 {
        issuer
        code
      }
      assetBySendAsset {
        code
        issuer
      }
      destAssetNative
      destMin
      path1Native
      path2Native
      path3Native
      path4Native
      path5Native
      sendAmount
      sendAssetNative
    }
  }
}

Path payments (strict send)

By account

query FullQuery {
  pathPaymentsStrictReceiveByPublicKey(publicKeyText: "") {
    nodes {
      ledgerByLedger {
        closeTime
        sequence
      }
      accountBySource {
        publickey
      }
      accountByDestination {
        publickey
      }
      assetByDestAsset {
        code
        issuer
      }
      assetByPath1 {
        code
        issuer
      }
      assetByPath2 {
        code
        issuer
      }
      assetByPath3 {
        issuer
        code
      }
      assetByPath4 {
        issuer
        code
      }
      assetByPath5 {
        issuer
        code
      }
      assetBySendAsset {
        code
        issuer
      }
      destAssetNative
      path1Native
      path2Native
      path3Native
      path4Native
      path5Native
      sendAssetNative
      destAmount
      sendMax
    }
  }
}

To account

query FullQuery {
  pathPaymentsStrictReceiveToPublicKey(publicKeyText: "") {
    nodes {
      ledgerByLedger {
        closeTime
        sequence
      }
      accountBySource {
        publickey
      }
      accountByDestination {
        publickey
      }
      assetByDestAsset {
        code
        issuer
      }
      assetByPath1 {
        code
        issuer
      }
      assetByPath2 {
        code
        issuer
      }
      assetByPath3 {
        issuer
        code
      }
      assetByPath4 {
        issuer
        code
      }
      assetByPath5 {
        issuer
        code
      }
      assetBySendAsset {
        code
        issuer
      }
      destAssetNative
      path1Native
      path2Native
      path3Native
      path4Native
      path5Native
      sendAssetNative
      destAmount
      sendMax
    }
  }
}

Manage sell offer

query FullQuery {
  manageSellOfferByPublicKey(
    publicKeyText: "$PUBLIC_KEY"
  ) {
    edges {
      node {
        buyingNative
        accountBySource {
          publickey
        }
        assetByBuying {
          issuer
          code
        }
        assetBySelling {
          code
          issuer
        }
        ledgerByLedger {
          closeTime
          sequence
        }
        muxedaccountBySourceMuxed {
          id
          publickey
        }
        offerId
        priceD
        priceN
        sellingNative
      }
    }
  }
}

Manage buy offer

query FullQuery {
  manageBuyOfferByPublicKey(
    publicKeyText: "$PUBLIC_KEY"
  ) {
    edges {
      node {
        buyingNative
        accountBySource {
          publickey
        }
        assetByBuying {
          issuer
          code
        }
        assetBySelling {
          code
          issuer
        }
        ledgerByLedger {
          closeTime
          sequence
        }
        muxedaccountBySourceMuxed {
          id
          publickey
        }
        offerId
        priceD
        priceN
        sellingNative
      }
    }
  }
}

Create passive sell offer

query FullQuery {
  createPassiveSellOfferByPublicKey(publicKeyText: "$PUBLIC_KEY") {
    nodes {
      accountBySource {
        publickey
      }
      amount
      assetByBuying {
        code
        issuer
      }
      assetBySelling {
        code
        issuer
      }
      buyingNative
      ledgerByLedger {
        closeTime
        sequence
      }
      muxedaccountBySourceMuxed {
        id
        publickey
      }
      priceD
      priceN
      sellingNative
    }
  }
}

n

Change trust

query FullQuery {
  changeTrustByPublicKey(publicKeyText: "$PUBLIC_KEY") {
    nodes {
      accountBySource {
        publickey
      }
      assetByLineAsset {
        issuer
        code
      }
      ledgerByLedger {
        closeTime
        sequence
      }
      limit
      lineNative
      poolshareByLinePoolShare {
        assetA
        assetB
        fee
      }
    }
  }
}

Allow trust

Mercury supports indexing this operation, but it was deprecated as of protocol 17.