Blog

Quotes are contracts: How Turnkey Swaps remain honest in an untrusted world

Developer
·
·
Mohammad Cheikh
Senior Product Engineer

About: Learn how Turnkey makes swap quotes cryptographically binding, so the transaction that gets signed matches the price, fees, destination, and terms the user actually approved.

Audience: Wallet teams, crypto applications, fintech builders, security engineers, and infrastructure teams building swaps or other transaction flows that depend on external providers.

What you’ll learn:
  • Why an untrusted Coordinator creates a quote-substitution risk
  • How Turnkey turns provider quotes into signed, bindable commitments
  • How the Policy Engine, TLS Fetcher, and Signer verify the swap from quote through execution
  • How the same model protects same-chain, cross-chain, and cross-protocol swaps

Reading time: ~9 minutes

As discussed in Yesterday Never Dies, Turnkey treats TEEs as trusted and nearly everything else, including our own Coordinator, as untrusted.

That posture is relatively easy to explain when the task is simply: “evaluate this policy against this Organization.”

Swaps make things more interesting.

To execute a swap, Turnkey needs to communicate with an external swap provider, preserve the price and terms the user actually saw, construct a transaction the user never manually created, and ultimately sign that transaction using keys that live inside an enclave.

The boundary we want is that the quote the user sees is the swap that gets signed. The Coordinator and the swap provider can propose terms, but neither is trusted to decide them: the enclave signs only when the transaction matches that quote, so a compromised Coordinator cannot change the price, the fees, or where the funds go.

First we'll look at the obvious design and how a compromised Coordinator breaks it. Then we'll follow a bindable quote from the price the user sees, through the signature, to settlement.

Understanding the threat model: What is quote substitution?

First, a useful definition:

Quote substitution is an attack in which an untrusted Coordinator replaces the economics or transaction data that a user approved with a different provider response, attempting to obtain a signature on different or worse terms.

For a swap, the state that matters is not just the Organization.

It also includes the provider quote: the input token, output token, amounts, minimum output, fees, destination, and the exact unsigned transaction associated with those terms.

Turnkey's threat model is the same one described in our whitepaper and in Yesterday Never Dies: enclaves are trusted, and everything outside them, including our own Coordinator, is not. Our Policy Engine, TLS Fetcher, Signer, the parsers, and the Notarizer are those enclaves.

The Coordinator retrieves state, communicates with clients, and orchestrates work between those trusted components. A compromised Coordinator is therefore not a scenario we dismiss. It is part of the adversarial model the system is designed to survive.

That distinction becomes especially important for swaps.

If the Coordinator were allowed to independently choose the provider request, interpret the provider response, determine the minimum output or fees, or construct the transaction that eventually reaches Signer, then:

“The user approved a swap” would no longer guarantee that “Signer signed that swap.”

The naive design

The obvious implementation looks something like this: the client sends the desired input token, output token, and input amount. The Coordinator contacts a swap provider, receives a quote and unsigned transaction, asks the Policy Engine whether the swap intent is allowed, and then asks Signer to sign the transaction returned by the provider. When everyone behaves honestly, this works.

Imagine a user wants to swap 1 ETH for USDC. The provider returns an expected output of 3,900 USDC with a minimum output of 3,850 USDC, and the resulting transaction executes those exact terms.

Now consider a malicious Coordinator. It could show the client the correct quote but, during execution, submit something different: a worse minimum output, different fee recipients, or transaction data that sends the funds somewhere the user never intended. 

The Policy Engine might still see a valid ExecuteSwap activity, Signer might still receive an Allow ruling, and the keys could still sign. The user accepted one set of terms, while the enclave signed something else. This is the swap equivalent of the Organization downgrade problem.

One possible defense is to request another quote at execution time and require the provider’s new minimum output to remain above the user’s floor. That improves things, but it still does not bind execution to what the user actually saw. Markets move, quotes change, and, more importantly, the Coordinator still sits between the provider and the trusted components.

What we need instead is a signed quote.

Bindable quotes

A bindable quote is a provider quote that can be cryptographically tied to exact economic and execution commitments.

The user does not sign raw transaction data. Instead, the user requests a quote through CreateSwapQuote. Turnkey freezes the relevant provider response inside trusted infrastructure, and ExecuteSwap can proceed only when the execution request matches those frozen terms.

The public API exposes two stages:

  1. CreateSwapQuote: prices the trade and returns a quote_id along with the economics the UI should display.
  2. ExecuteSwap: consumes that quote_id and executes the previously approved terms.

The client receives only the information it needs: the quote identifier, provider, expected output, minimum output, expiration, optional slippage, and estimated completion time.

A single call that quotes and executes together would be simpler to build. Separating them is what lets an application show the price, the minimum the user will receive, and how long the swap should take before anyone commits. That same pause is where a route preview can live later, once there is more than one path worth showing.

Internally, Turnkey retains the complete signed quote artifact. That signed artifact becomes the source of truth.

Phase 1: Quote generation

CreateSwapQuote follows Turnkey’s normal activity and policy path. This is important because requesting a swap quote is not simply a price lookup.

The request identifies a wallet, trading pair, amount, and other parameters relevant to the swap. Our Policy Engine enclave evaluates the request before the external quote becomes authoritative.

Trusted policy evaluation

The Coordinator first requests a ruling from our Policy Engine enclave which:

  1. Validates the Organization against its trusted snapshot
  2. Confirms that the source wallet is an active account within that Organization
  3. Evaluates the CreateSwapQuote policy
  4. Determines the fee configuration that applies to the swap

The important part is that the Coordinator does not get to independently choose the fees that reach the swap provider.

The trusted ruling commits to the applicable fee configuration before the provider request is made. If an untrusted component attempts to modify or introduce additional fees, the trusted execution path rejects the request.

Those fee decisions are also made at quote time rather than being recalculated during execution.

The quote therefore represents the economics that were actually approved.

Trusted egress

After our Policy Engine enclave produces its ruling, the Coordinator passes it to TLS Fetcher.

Inside TLS Fetcher:

  1. The Policy Engine ruling is verified, including its signature, decision, and freshness.
  2. The provider request is reconstructed from the trusted ruling.
  3. The request is checked to ensure that unapproved parameters have not been introduced.
  4. TLS Fetcher performs the external request.
  5. The response is parsed inside the enclave.
  6. TLS Fetcher signs a canonical representation of the resulting swap quote.

The parsed response includes the expected output, provider-defined minimum output, any required approval transactions, the terminal swap or deposit transaction, and the information needed to track the swap after broadcast.

The resulting quote is signed using the Fetcher quorum key and the public quote_id is deterministically derived from that signed quote. Canonical encoding matters here. Two different encodings should not be able to represent the “same” quote while changing its meaning.

For cross-chain swaps, the quote also respects any provider-defined on-chain expiration. Turnkey quotes have a short lifetime and may expire even sooner when the underlying provider order expires first.

What the quote actually binds

The signed quote commits to the information required to prove that execution corresponds to what was originally approved.

That includes:

Quote commitments
CommitmentWhat it protects
Quote authorizationProves the quote came from an approved Policy Engine decision
Fee configurationPrevents fees from changing after quote creation
Organization stateTies the quote to the correct Organization context
Source walletPrevents execution with a different signing account
Input/output assets and amountDefines the trade being priced
Expected and minimum outputBinds the economics shown to the user
Execution dataBinds the exact transaction or instructions
DestinationProtects the recipient for cross-protocol routes
ExpirationPrevents stale quotes from being executed
Provider tracking informationAllows the resulting swap to be monitored

Gas sponsorship is intentionally not part of the signed quote. Who pays the network fee is chosen at ExecuteSwap, and that choice does not change the quoted price, minimum output, or destination.

The signed quote is retained so it can later be consumed during execution.

Any Coordinator side validation performed at this stage is useful for catching normal implementation bugs, but it is not the security boundary. The real enforcement happens inside the Policy Engine and Signer.

Phase 2: Echo and prove execution

The mechanical implementation of “quotes are contracts” happens during ExecuteSwap.

The client submits the quote_id along with the exact economic terms it was shown, including the input asset and amount, output asset, expected output, minimum output, and sponsorship choice.

The client does not submit a signer or arbitrary transaction data. Instead, the Coordinator retrieves the signed quote and performs basic equality checks as an early failure mechanism. The Policy Engine then performs the trusted verification, ensuring that:

  • The supplied quote_id corresponds to the signed quote
  • The quote has not expired
  • The quote came from the expected swap provider
  • The Organization, wallet, assets, and amounts exactly match the execution request
  • The destination matches for cross-protocol swaps; and
  • The wallet still belongs to the current Organization state.

This binding is exact: the minimum output is not a user-controlled threshold that can be relaxed during execution. It must match the signed quote exactly; otherwise, the binding fails.

Turning the swap Into a transaction

After validating the quote, the Policy Engine transforms the swap execution into the appropriate public transaction activity.

Depending on the chain, that ultimately becomes an EthSendTransaction or SolSendTransaction representation derived from the execution information stored in the signed quote.

That may include approval calls followed by the terminal swap or deposit transaction.

The Coordinator cannot construct a merely “similar” transaction and expect Signer to accept it.

The transaction being signed must be the transaction authorized by the quote.

For EVM execution, required transaction parameters such as gas limits are also incorporated into the trusted transaction representation so that discrepancies cannot silently alter what is broadcast.

Binding the quote to the signature

During execution, the Policy Engine attaches a cryptographic binding to its ruling. That binding commits to four things at once: the activity being executed, the signed quote, the unsigned transaction produced from that quote, and the quote's expiration. The quote is claimed for that activity before execution proceeds, so a retry of the same activity stays idempotent and a second activity cannot spend it. Signer is the final enforcement layer.

Before signing, Signer independently calculates the digest of the exact transaction bytes it is being asked to sign and compares that value against the transaction committed by the Policy Engine.

If the Coordinator modifies the transaction after the ruling was produced, Signer refuses to sign.

That gives us the complete chain:

signed quote ↔ parser output ↔ signature ↔ user activity

Remove any one of those bindings and quote substitution becomes possible again.

Same-chain, cross-chain, and cross-protocol swaps

Swap classification is based on chain identity rather than whether something informally “looks like a bridge.”

Same-chain

The input and output assets live on the same chain.

The swap executes entirely on the origin chain. Post-transaction monitoring can enrich the result with fill information, but there is no separate destination-chain settlement to wait for.

Cross-chain, same protocol

For example, an EVM asset may be swapped into another EVM asset on a different chain.

The origin transaction locks or transfers the funds, while the swap provider completes the destination side.

Turnkey tracks the provider’s settlement after the origin transaction succeeds.

Cross-protocol

For example, an EVM asset may be swapped into an asset on Solana.

These routes use the cross-protocol quote and execution activity versions.

The signed quote additionally binds the destination address, and execution must provide that same destination.

That destination can also be subjected to the appropriate security and compliance checks.

Older execution flows that relied on obtaining a fresh quote during execution are deprecated in favor of this bindable model.

Putting it all together

Turnkey has long treated the Coordinator as an untrusted participant when deciding what should be signed.

Swaps add another external participant, the swap provider, and another important object: the quote.

The same principle still applies:

Don’t trust the last thing the Coordinator fetched. Require cryptographic proof that this is the thing the user saw, that trusted infrastructure attested to it, and that it has not already been consumed.

So why does all of this matter? Bindable quotes extend Turnkey's existing trust model to on-chain financial activity, so a customer can swap at the price they were shown without trusting the Coordinator to keep those terms.

The user approves a set of economic terms. TLS Fetcher proves those terms are what the provider returned, the Policy Engine proves they satisfy policy and match the execution request, and the parser turns them into a transaction. Signer then proves that the bytes under the key are the bytes the Policy Engine authorized. The Coordinator still carries the request from one enclave to the next, and the signature is valid only when every one of those proofs holds.

‍

The binding stack
  1. 01CreateSwapQuote intent
  2. 02Policy Engine rulingPolicy decision, Organization state, wallet, economics, and applicable fees
  3. 03TLS FetcherMakes the trusted request to the swap provider
  4. 04Signed swap quoteCommits to the economics and execution data
  5. 05Temporary quote storageAllows the quote to be retrieved and claimed once
  6. 06ExecuteSwap intentEchoes the terms shown to the user
  7. 07Policy Engine verificationChecks the signed quote and derives the appropriate transaction activity
  8. 08Execution bindingCommits the activity, quote, transaction, and expiration together
  9. 09Signer verificationChecks that the exact transaction being signed matches the trusted binding
  10. 10Broadcast and settlement monitoring

Additional Resources

‍

Mohammad Cheikh
Senior Product Engineer

Related articles

Turnkey’s approach to digital asset security: Secure, verifiable, reproducible

Security starts with private key management. Learn how Turnkey uses secure enclaves, verifiability, and open source infrastructure to protect digital assets.

The developer tooling stack for building secure crypto wallets faster

Build secure digital asset products faster with Turnkey’s developer tooling for wallets and key management.