Skip to main content
To get started with Warp, let’s get a quote for a cross-chain intent. You can do that using the /intents/route endpoint. To get a quote, you’ll need the destination chain, the token and amount on that chain, and the account address:
Get Quote
const baseUrl = "https://v1.orchestrator.rhinestone.dev";
const endpoint = `${baseUrl}/intents/route`;
const apiKey = "YOUR_RHINESTONE_API_KEY";

const payload = {
  account: {
    address: EOA_ADDRESS,
    accountType: "EOA",
  },
  destinationChainId: 8453,
  tokenRequests: [
    {
      tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      amount: "5000000",
    },
  ],
};

const res = await fetch(endpoint, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": apiKey,
    Accept: "application/json",
  },
  body: JSON.stringify(payload),
});

if (!res.ok) {
  const errorBody = await res.text().catch(() => "");
  throw new Error(
    `Request failed: ${res.status} ${res.statusText}${errorBody ? ` - ${errorBody}` : ""}`
  );
}

const data = await res.json();
console.log("Quote:", data);
The API response includes three top-level fields:
  • intentOp: the full intent operation the user must sign (see below)
  • intentCost: the cost breakdown including tokens spent, tokens received, and fees
  • tokenRequirements: the list of token requirements to fulfill before signing

Understanding the response

intentOp

The intentOp object contains everything needed to build signatures and submit the intent. Key fields:
FieldDescription
elementsOne entry per source chain involved. Each element describes what tokens are pulled from that chain and what the user receives on the destination.
nonceA unique nonce for Permit2 signing.
expiresUnix timestamp when the quote expires. Fetch a fresh quote if this has passed.
signedMetadataOrchestrator-signed metadata including token prices. Do not modify this.

Element fields

Each element in intentOp.elements describes one source chain:
FieldDescription
chainIdThe source chain ID (e.g. "8453" for Base).
arbiterThe arbiter contract that validates the fill.
idsAndAmountsArray of [tokenId, amount] pairs: tokens pulled from the user on this chain.
mandate.recipientAddress that receives tokens on the destination.
mandate.tokenOutArray of [tokenId, amount] pairs: tokens delivered to the recipient.
mandate.destinationChainIdThe destination chain ID.
mandate.fillDeadlineUnix timestamp by which the solver must fill.
mandate.destinationOpsCalls to execute on the destination chain after fill.
Token amounts in elements use a packed uint256 encoding called a token ID. The token ID encodes the ERC-20 address in its lower 160 bits. To extract the address:
function toToken(id: bigint): `0x${string}` {
  return `0x${(id & ((1n << 160n) - 1n)).toString(16).padStart(40, "0")}`;
}

// Example: extract the token address from an element
const element = intentOp.elements[0];
const [tokenId, amount] = element.idsAndAmounts[0];
const tokenAddress = toToken(BigInt(tokenId));
// tokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" (USDC on Base)
The same encoding applies to:
  • element.idsAndAmounts: tokens pulled from the source chain (what the user spends)
  • element.spendTokens: tokens the solver must lock
  • element.mandate.tokenOut: tokens delivered on the destination chain

intentCost

The intentCost object breaks down what the user pays:
FieldDescription
tokensSpentMap of chainId -> tokenAddress -> { locked, unlocked, version }. Shows exactly what leaves the user’s wallet per chain.
tokensReceivedArray of objects showing what arrives on the destination, including amountSpent, destinationAmount, and fee.
feeBreakdownUSDUSD breakdown of swap, bridge, gas, and settlement fees (when available).

Executions (calls)

You can make executions on behalf of the EOA on the destination chain. Note: the executions run in the context of the multicall contract. If you’re sending any tokens, make sure to add a call to transfer any output back to the EOA.
const payload = {
  // …
  destinationExecutions: [
    // Deposit USDC to a vault
    {
      to: VAULT_CONTRACT,
      value: 0n,
      data: encodeFunctionData({
        abi: vaultAbi,
        functionName: 'deposit',
        args: [usdcAmount],
      }),
    },
    // Send vault receipt token back to the EOA
    {
      to: USDC_VAULT_CONTRACT,
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: 'transfer',
        args: [tokenAmount, EOA_ADDRESS],
      }),
    }
  ],
}

Sponsorship

You can mark the intent as sponsored (covering the gas and bridging costs for the user) by setting the sponsorSettings field:
Sponsor the Intent
const payload = {
  destinationChainId: 8453,
  tokenRequests: [
    {
      tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      amount: "5000000",
    },
  ],
  account: {
    address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    accountType: "EOA",
  },
  options: {
    sponsorSettings: {
      gasSponsored: true,
      bridgeFeesSponsored: true,
      swapFeesSponsored: false
    }
  }
};

Source Chain / Token

You can select which tokens and/or chains to use as the source of funds. To limit the source of funds to specific chains:
Select Input Chains
const payload = {
  // …
  accountAccessList: {
    chainIds: [10, 8453]
  }
};
To limit the source of funds to specific tokens:
Select Input Tokens
const payload = {
  // …
  accountAccessList: {
    tokens: ["USDC", "0x4200000000000000000000000000000000000006"]
  }
};
To limit the source of funds to specific chains and tokens:
Select Input Chains and Tokens
const payload = {
  // …
  accountAccessList: {
    chainIds: [10, 8453],
    tokens: ["USDC"]
  }
};
or:
Select Input Chains and Tokens
const payload = {
  // …
  accountAccessList: {
    chainTokens: {
      "10": ["USDC"],
      "8453": ["WETH"]
    }
  }
};

Swaps

If the destination token differs from the user’s source token, Warp handles the bridge and swap automatically. No additional parameters are needed — just specify the token you want on the destination chain. In a swap quote, tokensSpent and tokensReceived will show different tokens:
{
  "intentCost": {
    "tokensReceived": [
      {
        "tokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
        "hasFulfilled": true,
        "amountSpent": "81032981",
        "destinationAmount": "81029468",
        "fee": "3513"
      }
    ],
    "tokensSpent": {
      "8453": {
        "0x4200000000000000000000000000000000000006": {
          "locked": "0",
          "unlocked": "22291303013436002",
          "version": 0
        }
      }
    }
  }
}
Here the user is spending WETH on Base (chain 8453) to receive USDC on Optimism. The fee is deducted from the received amount (amountSpent minus destinationAmount).

Next Steps

Token Requirements

What the intent requirements are and how to fulfill them