Skip to content

Conversation

@0xtiti
Copy link
Collaborator

@0xtiti 0xtiti commented Jul 17, 2025

Universal Intent Interface

Purpose: A standardized API specification that enables cross-chain intent systems to interoperate, creating a unified ecosystem for multi-chain value transfer and execution.

Enabled Flows:

  • Multi-input origins: Aggregate multiple assets/chains in a single intent
  • Multi-output destinations: Split execution across multiple chains and recipients
  • Flexible locking: Support for different escrow mechanisms
  • Priority-based execution: Price optimization, speed prioritization, input sequencing, or trust minimization

Standards Compliance: ERC-7683 Cross Chain Intents and ERC-7930 Interoperable Addresses.

// priority: which token the user prefeer to spend (e.g., 0 = Max Priority)
userBalances: Map<chainId, {balance, tokenAddress, priority}>

// Desired amount to receive on target chain (as integer string in wei)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider the target outputs to be a mapping as well, accepting multiple desired outputs

targetTokenAddress: string

// Optional: specify which routing algorithm to use
algorithm?: 'greedy' | 'dynamic-programming' | 'dijkstra' | 'multi-objective' | 'genetic' | 'simulated-annealing' | 'ant-colony' | 'a-star'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the server does not support this configuration, should it return an error or simply ignore it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could return a NotValidAttribute error, and if the algorithm attribute is valid but the algorithm is not there, we could return a NotFoundAlgorithm error, mentioning the implemented algorithms

}>

// Sum of all fees across all steps (in wei of respective native tokens)
totalFee: string

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this work if there are multiple native tokens involved? We should consider this to be an array of objects (network, fee)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right let's change this for usdTotalFee and then they have each fee inside each step


### **Disadvantages:**

- **Limited Transparency**: Users cannot see alternative options or understand trade-offs

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can potentially change the response format to be an array of options, each option being the currently proposed schema, but allowing solvers to return different options that the client then can decide to show to the users

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good idea.


- **Limited Transparency**: Users cannot see alternative options or understand trade-offs
- **Reduced Control**: Wallets cannot implement custom routing preferences
- **Trust Dependency**: Users must trust the server's optimization choices

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not the definition of an intent? Users do not need to worry about middle steps, and rather select the better output.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. But anyway, I think it's worth mentioning it as a disadvantage to see the trade-offs between approaches.

Like, Approach 2: Client-Side Route Calculation plus a Route endpoint would still have Users do not need to worry about middle steps but also give flexibility for those who want to see what's happening.

@frangio
Copy link
Collaborator

frangio commented Jul 24, 2025

I think the API should be a bit simpler than proposed here. This is closer to what I was imagining:

interface AssetAmount {
    asset: string; // interoperable address
    amount: bigint;
}

interface GetQuoteRequest {
    availableInputs: {
        input: AssetAmount;
        priority?: number;
    }[];
    requestedMinOutputs: AssetAmount[];
    preference?: 'price' | 'speed' | 'input-priority';
}

interface GetQuoteResponse {
    quotes: {
        orders: {
          settler: string; // interoperable address
          data: object; // to be signed and submitted back
        };
        requiredAllowances: AssetAmount[];
        validUntil: number;
        eta: number;
        totalFeeUsd: number;
    }[];
}

Notes on the proposal in this PR:

  • Request:
    • algorithm is too low level. We can specify a high level preference, this will just be a hint though, not a requirement.
    • I find userPreferences too low level as well, in particular specifying costWeight as a number, I'm not sure how a user would pick that or that a solver would be able to input that value into their algorithms.
    • I haven't included maxSlippage in my suggestion but I'm not strongly opposed to it.
  • Response:
    • route.steps is too low level. In an intent protocol, in my view, the end user should be abstracted from the exact route, as it will be executed by the solver. IMO the user should care about cost and risk (trust assumptions) only.
    • The response should give the client exactly what it needs to sign and submit back or post on chain. This will probably be an EIP-712 typed object.

@reednaa
Copy link

reednaa commented Jul 24, 2025

I can't seem to notice that there is no obvious return for the tokens?

I generally support @frangio's feedback with the following comments:

ServerSideQuoteRequest

  • Instead of targetAmount, targetChain, and targetTokenAddress the target should be provided as a dict targetBalances: Map<chainId, {balance, tokenAddress}>
    The goal should be to support multiple target tokens. The trivial example is some tokens and some gas.
  • algorithm? could potentially be an array for possible algorithms.
  • userPreferences should not contain prioritizeSpeed as a boolean parameter, I would argue it should be captured through costWeight or a similar weighted parameter.
  • QuoteRequest should contains an expiry.

I am not sure what consideration has been given to async quoting endpoints, however, the current spec does not seem to include features to accommodate that. In an ideal world this would be part of the spec as you can imagine that a common use case would be for aggregators to aggregate quote calls. Those calls may have to be asynchronously called. Is there also an argument to be made for aggregators of aggregators? In that case, should there be an option in the quote to not do tree style quoting but return immediate quotes instead?

ServerSideQuoteResponse

  • If steps are to be used, they should contain execution instructions for those steps. The current steps increases confusion and it is unclear what it represents and what is needed to implement it.
  • Multiple routes should be returned.
  • Routes should be named.

I have attached 2 modified drafts.

interface ServerSideQuoteRequest {
  userBalances: {chainId, balance, tokenAddress, priority}[]
  targetBalances: {chainId, balance, tokenAddress}[]
  algorithm?: 'greedy' | 'dynamic-programming' | 'dijkstra' | 'multi-objective' | 'genetic' | 'simulated-annealing' | 'ant-colony' | 'a-star'
  userPreferences?: {
    exactOut: boolean // Whether the output is allowed to deviate slightly to optimise the route.
    maxSlippage: number
    costWeight: number
  }
}

Notable differences:

  • Merge balance array into a single [{}]. This is because I believe it is cleaner if tokens on different chains are just treated as different tokens. [chainId, tokenAddress].
  • exactOut option. This parameter serves multiple purposes:
    • It allows for lossy algorithms that optimise without a strict constraint on the output but a looser one in an attempt to optimise for the user.
    • It allows determining whether dutch auctions may be used.
interface ServerSideQuoteResponse Map<name: string, {
  usedUserBalances: {chainId, balance, tokenAddress, priority}[]
  estimatedProvided: {chainId, balance, tokenAddress}[]
  minimumProvided: {chainId, balance, tokenAddress}[]
  route: {
    steps: {
      chain: chainId
      assets: {amount, tokenAddress}
      fee: string
      bridgeAddress: hex
      bridgeCall: hex
      gas: string // Amount of gas used
      gasCost: string //  estimated cost of gas used (in wei)
      usdGasEstimate: string
      timeEstimate: number
      bridgeProvider: string
    }[]
    totalFee: string
    totalGasEstimate: string
    usdTotalGasEstimate: string
    estimatedCompletionTime: number
    maxCompletionTime?: number // Not provided if there is a user activity.
  }
  algorithmUsed: string
  quoteId: string
  validUntil: timestamp
}

Notable differences:

  • The return now sits inside a named map. This allows aggregators of intent protocols to return named routes based on queries.
  • The spent inputs are returned in an easily parsable format.
  • Estimated outputs & minimum outputs are differentiated in case of auctions.
  • Completion time can now be estimated and guaranteed.

On steps

I generally agree with @frangio however I can see that if we wanted this to be compatible with non-intent systems and ordinary bridges, it may be needed. As a result, I don't have anything against it. Instead, I would argue that it should contain execution instructions so that the API becomes more self-serve and these steps don't become arbitrary.

@reednaa
Copy link

reednaa commented Sep 17, 2025

How would this interface be used if you had a fixed number of desired inputs and wanted the maximum outputs?

@frangio
Copy link
Collaborator

frangio commented Sep 17, 2025

The latest spec is found in openintentsframework/oif-specs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants