---
eip: 9999
title: Minimal Orchestrator RPC
description: A minimal data model that an Orchestrator can understand to help fulfil a request for a solution from a wallet or any other system.
author: Kieran Goodary (@IAmKio), Pillar Wallet (@pillarwallet), Luke Wickens (@lbw33), Rana Khoury (@RanaBug)
discussions-to: https://ethereum-magicians.org/t/erc-7845-minimal-orchestrator-rpc/21885
status: Draft
type: Standards Track
category: ERC
created: 2024-11-07
---
## Abstract
> "Hey Google, swap my SHIB for Pillar"
> "Alexa, how much USDC can I buy with what's in my wallet?"
> "Siri, send 10 OP to Vitalik and 5 PEPE to Deimantas"
The Minimal Orchestrator RPC aims to standardise the **minimum shape and requirements** of a **request for a solution** **_from_** an arbitrary system managing an Ethereum wallet **_to_**, ultimately, an Orchestrator.
An arbitrary system could be a website, device, app, server program etc - anything that manages an Ethereum wallet, **speaks Ethereum JSON-RPC** and is looking to request solutions from an Orchestrator.
All solutions from an Orchestrator are ChA¹ (Chain Abstraction-first) by default.

## Motivation
Data model standards can be written in any shape. A system will often expose their external interface but require that the request to the aforementioned interface is modelled in a way that the service understands. This creates a huge level of inconsistency and in turn makes Orchestrator interoperability more difficult.
Orchestrators will become more widespread and numerous over time. This is especially true with the advent of Artificial Intelligence (AI) driven systems, the continued advancement of Human Computer Interaction (HCI) devices (especially those that are voice controlled) and the emergence of Extended Reality (XR) platforms.
Standardising the request object that an Orchestrator can understand from a wallet will drive adoption and make decentralised app development easier for developers that don't know how to make on-chain transactions or have the required technical understanding of block building systems.
## Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The Orchestrator's external interface(s) that expose functionality to an end-user application or another system `MUST` use JavaScript Object Notation (JSON).
The following data definitions are available and `MUST` **prefer chain abstraction (ChA¹)**, unless stated.
The following sequence diagram shows the flow that this ERC aims to standardise:

This specification follows the top level data shape of Ethereum JSON-RPC requests, as shown below:
### Request
The request definition is what a wallet sends to an Orchestrator for solutions to one or more problems. The request follows the specification from Ethereum JSON-RPC.
#### RPC
```typescript
interface Rpc: {
id: number; // REQUIRED
jsonrpc: string; // REQUIRED
method: string; // REQUIRED
params: Problem[]; // REQUIRED
}
```
The top level definition is an Ethereum RPC object.
- The `id` property is a random number that you can assign for your own purposes.
- The `jsonrpc` property takes a `string` that represents the version of JSON-RPC being used. Usually `"2.0"`.
- The `method` property is the method call intended for the Orchestrator, and by default CAN be `orchestrator_findSolutions`.
- The `params` property contains an array of `Problem` objects, and is `REQUIRED`. The Problem object is defined below.
#### Problem
```typescript
interface Problem: {
actions: Action[] // REQUIRED
chainId: number; // OPTIONAL
}
```
The `Problem` definition has just one `REQUIRED` property, `actions`. The `Problem` interface leaves space for additional properties in future network upgrades and existing or emerging standards.
- The `actions` property takes an `array` of `Action` objects, defined below, and is `REQUIRED`.
- The `chainId` takes a `number`, representing the chain ID, and is `OPTIONAL`.
- If no `chainId` is provided:
- `chainId` property `MUST` assume `1`
#### Action
```typescript
interface Action: {
from: string; // REQUIRED
towards: (Asset|Destination)[]; // REQUIRED
with: Offering[]; // OPTIONAL
type: string; // OPTIONAL
functionCallName: string; // OPTIONAL
functionCallData: string; // OPTIONAL
deadline: number; // OPTIONAL
}
```
The `Action` definition has several properties that indicate the desired action. The set properties determine the action that needs to be solved.
- The `from` property is `REQUIRED`, takes a `string` and represents the wallet that this `Action` is for.
- The `towards` property is `REQUIRED`, takes an `array` of either an `Asset` or a `Destination` type and represents where this `Action` is targeted towards.
- The `with` property is `OPTIONAL`, takes an `array` of `Offering` type and represents what assets the wallet is prepared to offer to facilitate this `Action`
- If the `with` property contains no `Offering` entries, then the Orchestrator `MUST` consider all assets available in the address space for an `Offering`.
- The `type` property is `OPTIONAL`, takes a `string` and is intended to help classify this action. Examples might include, but are not limited to - `transfer`, `swap`, `call` etc and is intended to assist the Orchestrator with the action.
- If no `type` is provided, then 'transfer' `MUST` be assumed
- The `functionCallName` property is `OPTIONAL`, takes a `string` and represents the function name to call against the `towards` property. If this is defined, the Orchestrator can be assumed that this Action desires to call a smart contract as part of the action.
- The `functionCallData` property is `OPTIONAL`, takes a `string` and represents the data payload for `functionCallName`. If this is defined but `functionCallName` is not, this property `SHOULD` be ignored.
- The `deadline` property is `OPTIONAL`, takes a `number` and represents a wallet-defined unix timestamp for when an action should have a solution by. Useful for high throughput systems, or time sensitive actions.
#### Asset
```typescript
interface Asset: {
symbol: string; // OPTIONAL
address: string; // OPTIONAL
chainId: number; // OPTIONAL
}
```
The Asset definition defines an asset in question. This definition prefers chain abstraction.
- The `symbol` property is `OPTIONAL`, takes a `string` and represents the symbol of the Asset in question.
- if no `symbol` is provided, `address` must be used
- The `address` property is `OPTIONAL`, takes a `string` and represents the `address` of the smart contract for this `Asset`.
- if no `address` is provided, the native gas token `MUST` be used
- The `chainId` property is `OPTIONAL`, takes a `number` and represents the chain that this asset resides on. Useful for direct targeting of an `Asset` on a particular chain.
- If no `chainId` is provided: - The Orchestrator is free to use any corresponding asset on any chain to facilitate the action
#### Destination
```typescript
interface Destination: {
address: string; // REQUIRED
chainId: number; // REQUIRED
}
```
The Destination definition defines a direct target and is used in scenarios where the Orchestrator interpretation `MUST NOT` be used.
- The `address` property is `REQUIRED` and takes a `string` that represents the address space for this `Destination`.
- The `chainId` property is `REQUIRED` and takes a `number` and represents the chain the above `address` property resides on.
#### Offering
```typescript
interface Offering: {
symbol: string; // SHOULD
address: string; // SHOULD
amount: (number|string); // OPTIONAL
chainId: number; // OPTIONAL
}
```
The `Offering` definition defines what the requester is willing to spend from their wallet in order to facilitate the action being solved.
- The `symbol` property `SHOULD` be specified and represents the symbol of the `Offering` in question
- If no `symbol` is provided, the address `MUST` be used
- The `address` property `SHOULD` be specified and takes a `string` that represents the address space for this `Offering`.
- If no `address` is provided, the native gas token `MUST` be used
- The `amount` property is `OPTIONAL` and represents the amount to be offered as part of the `Action`. Accepts either a `number`, which represents an ether unit, or a `string` which can be used for BigNumbers.
- If no amount is provided, the maximum value of the address, symbol or native gas unit must be assumed
- The `chainId` property is `OPTIONAL` and takes a `number` that represents the chain the above `address` property resides on.
- If no `chainId` is provided:
- `address` `MUST NOT` be used
- `symbol` `MUST` be used (ChA¹)
- If no higher level `chainId` property exists in the `Problem` property
- The Orchestrator is free to use any corresponding asset on any chain to facilitate the action (ChA¹)
### Response
The response definition is what an Orchestrator sends back as a response to the request for solutions from a wallet. The response, like the request, follows the specification from Ethereum JSON-RPC.
#### RPC
```typescript
interface Rpc: {
id: string; // REQUIRED
jsonrpc: string; // REQUIRED
result: Solution[]; // REQUIRED
}
```
The top level object is an Ethereum RPC object.
- The `id` property is `REQUIRED`, takes a `string` and `MUST` correlate to the same `number` that was received as part of the request object to the Orchestrator.
- The `jsonrpc` property is `REQUIRED`, takes a `string` and represents the version of JSON-RPC being used. Usually `"2.0"`.
- The `result` property is `REQUIRED` and takes an array of `Solution` objects. The `Solution` object is defined below.
#### Solution
```typescript
interface Solution: {
name: string; // REQUIRED
description: string; // OPTIONAL
transactions: Transaction[]; // REQUIRED
deadline: number; // OPTIONAL
}
```
The above `Solution` interface is the _solution_ to a _problem_ requested above. The `Solution` `MUST` be in the same order to a `Problem` that was requested.
- The `name` property is `REQUIRED`, takes a `string` and represents a short, non-technical and user-friendly, name of the solution.
- The `description` property is `OPTIONAL`, takes a `string` and represents a longer, non-technical and user-friendly, description of the solution.
- The `transactions` property is `REQUIRED`, takes an `array` of `Transaction` objects and represents one or more transactions needed for the user to execute the solution.
- The `deadline` property is `OPTIONAL`, takes a `number` and represents a unix timestamp by which this `Solution` should be executed. This is defined by the Orchestrator.
#### Transaction
```typescript
interface Transaction: {
to: Destination; // REQUIRED
chainId: number; // REQUIRED
amount: (number|string); // REQUIRED
calldata: string; // OPTIONAL
}
```
The above `Transaction` interface is a transaction definition that allows a wallet to perform their solution to a problem. There may be 1 or more transactions for a `Solution`.
- The `to` property is `REQUIRED`, takes a `Destination` type and represents the target for this Solution.
- The `chainId` property is `REQUIRED`, takes a number and represents the chain that this `Transaction` is targeted at. The `chainId` is `REQUIRED` here because the wallet `MUST` know where to send assets from as an origin due to the existence of multichain assets.
- The `amount` property is `REQUIRED` and represents the amount to be sent as part of the `Transaction`. Accepts either a `number`, which represents an ether unit, or a `string` which can be used for BigNumbers.
## Rationale
- Uses the Ethereum JSON-RPC JSON wrapper for greater compatibility.
- The interface definitions use only generic primitive types to ensure wide compatibility for any programming language.
- The interface definitions defined in this ERC attempts to cover as many scenarios as possible, from an Orchestrator perspective that a wallet may ask for, but focuses on core blockchain functionality.
- Certain high-level definitions, such as the `Problem` object definition, are sparse by design to allow space for future features introduced by other ERC's or network upgrades.
- Terminology is targeted towards a non-technical lexicon to aid in wider adoption and understanding.
- Nearly all options are `REQUIRED`, `SHOULD` and `OPTIONAL` to allow for both wallet and Orchestrator flexibility in providing solutions for the wallet request.
- It's understood that the Orchestrator interpretations and implementations will vary, so where possible the specification enforces `REQUIRED` and `MUST` to provide a minimal level of service to an end-user or another service.
- The specification is **NOT** intended to standardise or modify the internal data structure or communication layer of an Orchestrator.
- Other parameters that could be considered, such as gas limits and estimations, are delegated back to the wallet as ultimately it is the wallet that will execute the solution(s).
## Backwards Compatibility
No backward compatibility issues found.
## Reference Implementation
### Example requests and responses for solutions
The following examples show a few common scenarios with their requests to, and from, an Orchestrator. All examples are chain abstracted (ChA¹) by default, unless specified.
#### Sending an [ERC-20](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-20.md) token to another address
The following request performs an action:
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards address 0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629
- with symbol USDC, amount 5
:::info
Notes: All requests for solutions should be chain abstracted (ChA¹) by default. The Orchestrator can check for 5 USDC on any chain for the above "from" address, and send a solution that receives the 5 USDC on any other chain.
:::
##### Request to Orchestrator
```json
{
"id": 1234,
"jsonrpc": "2.0",
"method": "orchestrator_findSolutions",
"params": {
"problems": [
{
"actions": [
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"address": "0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629"
},
"with": [
{
"symbol": "USDC",
"amount": 5
}
]
}
]
}
]
}
}
```
##### Response from Orchestrator
```json
{
"id": 1234,
"jsonrpc": "2.0",
"result": [
{
"name": "Send 5 USDC",
"description": "Send 5 USDC from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165 to 0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629",
"transactions": [
{
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"chainId": 1,
"calldata": "0x0...",
"value": 0
}
]
}
]
}
```
#### Swapping native token to USDC
The following request performs an action:
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards symbol USDC
- with: 0.1
:::info
Notes: All requests for solutions should be chain abstracted (ChA¹) by default. The Orchestrator can take 0.1 native asset from any chain in return for USDC on any chain.
:::
##### Request to Orchestrator
```json
{
"id": 1337,
"jsonrpc": "2.0",
"method": "orchestrator_findSolutions",
"params": {
"problems": [
{
"actions": [
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"symbol": "USDC"
},
"with": [
{
"amount": 0.1
}
]
}
]
}
]
}
}
```
##### Response from Orchestrator
```json
{
"id": 1337,
"jsonrpc": "2.0",
"result": [
{
"name": "Swap 0.1 ETH for 371.498 USDC",
"description": "Swapping 0.1 ETH from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165 to 371.498 USDC via Uniswap",
"transactions": [
{
"to": "0x...",
"chainId": 1,
"calldata": "0x0...",
"value": 0
},
{
"to": "0x...",
"chainId": 1,
"calldata": "0x...",
"value": 0.1
}
]
}
]
}
```
#### Swapping multiple tokens to USDC
The following request performs an action:
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards symbol USDC
- with SHIB and / or Pillar
:::info
Notes: All requests for solutions should be chain abstracted (ChA¹) by default. The Orchestrator can take any amount of SHIB and / or Pillar from any chain in return for an exchanged amount of USDC on any chain.
:::
##### Request to Orchestrator
```json
{
"id": 1234,
"jsonrpc": "2.0",
"method": "orchestrator_findSolutions",
"params": {
"problems": [
{
"actions": [
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"symbol": "USDC"
},
"with": [
{
"symbol": "SHIB"
},
{
"symbol": "Pillar"
}
]
}
]
}
]
}
}
```
##### Response from Orchestrator
```json
{
"id": 1337,
"jsonrpc": "2.0",
"result": [
{
"name": "Swap 171,246 SHIB and 1004.72 Pillar for 10 USDC",
"description": "Swapping 171,246 SHIB and 1004.72 Pillar from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165 to 10 USDC via Uniswap",
"transactions": [
{
"to": "0x...",
"chainId": 1,
"calldata": "0x0...",
"value": 0
},
{
"to": "0x...",
"chainId": 1,
"calldata": "0x0...",
"value": 0
},
{
"to": "0x...",
"chainId": 1,
"calldata": "0x...",
"value": 0.1
}
]
}
]
}
```
#### Sending an ERC-20 token to multiple addresses
The following request performs the following actions:
- Action 1
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards address 0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629
- with 5 USDC
- Action 2
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards address 0xFCd239451346238B5560511Ae47A0b82b1bbE9f0
- with 100 PLR
:::info
Notes: All requests for solutions should be chain abstracted (ChA¹) by default. The Orchestrator can move the specified asset amounts on any chain where the asset exists in the "from" address.
:::
##### Request to Orchestrator
```json
{
"id": 1000,
"jsonrpc": "2.0",
"method": "orchestrator_findSolutions",
"params": {
"problems": [
{
"actions": [
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"address": "0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629"
},
"with": [
{
"symbol": "USDC",
"amount": 5
}
]
},
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"address": "0xFCd239451346238B5560511Ae47A0b82b1bbE9f0"
},
"with": [
{
"symbol": "PLR",
"amount": 100
}
]
}
]
}
]
}
}
```
##### Response from Orchestrator
```json
{
"id": 1000,
"jsonrpc": "2.0",
"result": [
{
"name": "Send 5 USDC to 0x...629 and 100 PLR to 0x...9f0",
"description": "Send 5 USDC to 0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629 and 100 PLR to 0xFCd239451346238B5560511Ae47A0b82b1bbE9f0",
"transactions": [
{
"to": "0x...",
"chainId": 1,
"calldata": "0x0...",
"value": 0
},
{
"to": "0x...",
"chainId": 1,
"calldata": "0x...",
"value": 0
}
]
}
]
}
```
#### Calling a Smart Contract function on Polygon: Inscribing a message which costs 1 USDC
The following request performs an action:
- from 0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165
- towards address 0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629 on chain 137
- with 1 USDC
- calling "inscribe" with "0x..."
:::info
Notes: All requests for solutions should be chain abstracted (ChA¹) by default - HOWEVER in this example, the `chainId` property on the `Destination` interface has been specified. The operation should now be locked to the specified chain. Because `functionCallName` and `functionCallData` exist, the Orchestrator can infer that this is a smart contract call and act accordingly.
:::
##### Request to Orchestrator
```json
{
"id": 420,
"jsonrpc": "2.0",
"method": "orchestrator_findSolutions",
"params": {
"problems": [
{
"actions": [
{
"from": "0xbafB4E1EFA94B359e2E175CF6156AedA2cACa165",
"towards": {
"address": "0x50840CE036eEf2005d3c4d6f6Eb65f8116a01629",
"chainId": 137
},
"with": [
{
"symbol": "USDC",
"amount": 1
}
],
"functionCallName": "inscribe",
"functionCallData": "0x..."
}
]
}
]
}
}
```
##### Response from Orchestrator
```json
{
"id": 420,
"jsonrpc": "2.0",
"result": [
{
"name": "Inscribe with 1 USDC",
"description": "Call the Inscribe function with 1 USDC on Polygon",
"transactions": [
{
"to": "0x...",
"chainId": 137,
"calldata": "0x0...",
"value": 0
},
{
"to": "0x...",
"chainId": 137,
"calldata": "0x...",
"value": 0
}
]
}
]
}
```
## Security Considerations
### Orchestrator reputation
The ability for anyone to build an Orchestrator inherently brings the opportunity for code errors and therefore a degraded service. Orchestrators may also be abandoned over time. A reputation score should be leveraged by the Orchestrator to determine if the Orchestrator is fit for purpose. This should be up to the requesting system or wallet to determine.
### Orchestrator producing dishonest solutions
An Orchestrator may return transactions as part of a solution that are wrong or attempt to take more than what was asked of it. Where possible, the Orchestrator should validate returned transaction address destinations and any other data.
### Orchestrator personality variations
Whilst not a security consideration per-se, some Orchestrators may gravitate towards their own business targets which may skew the outcome of Orchestrator solutions. The systems or wallets requesting solutions from Orchestrators should be mindful of this unless it is intended.
## Copyright
Copyright and related rights waived via [CC0](../LICENSE.md).