Skip to Content
API ReferenceSubmit Wrap Order

POST /api/v1/mev/wrap/order

Submit signed wrap/unwrap transaction with MEV-protected execution.

This endpoint submits your signed WETH wrap/unwrap transaction through MEV-protected routing to prevent frontrunning.


Endpoint Details

POST https://api.unikron.ch/api/v1/mev/wrap/order

Authentication Required: Yes (API Key via X-API-Key header)


Request Parameters

Request Body (JSON)

ParameterTypeRequiredDescription
quoteIdstringNoQuote ID from quote response (optional, for tracking)
signedTransactionstringYesHex-encoded signed transaction (starting with 0x)
providerMetadataobjectYesProvider metadata from quote (mevProtection.providerMetadata)
operationstringYes"wrap" or "unwrap"
amountstringNoAmount for tracking/logging (optional)

Headers

HeaderRequiredDescriptionExample
X-API-KeyYesYour UNIKRON API keyuk_live_abc123...
Content-TypeYesMust be application/jsonapplication/json

Important Requirements

Provider Metadata Required

The providerMetadata object from the quote response is required for order submission. It contains the MEV Blocker endpoint configuration and routing information. Missing this will cause a 400 error.

Sign Transaction Parameters Exactly The signedTransaction must be signed using exactly the transaction parameters from the quote response (with nonce added). Do not modify any fields.

Set Nonce Before Signing The quote returns nonce: null. You must set the nonce to the user’s current nonce before signing:

const nonce = await provider.getTransactionCount(userAddress); txParams.nonce = nonce; const signedTx = await signer.signTransaction(txParams);

Code Examples

JavaScript / TypeScript

import { ethers } from "ethers"; const API_KEY = process.env.UNIKRON_API_KEY; const API_URL = "https://api.unikron.ch"; async function submitWrapOrder(quote: any, signer: ethers.Signer) { // 1. Get current nonce const nonce = await signer.provider.getTransactionCount( await signer.getAddress() ); // 2. Add nonce to transaction params const txParams = { ...quote.mevProtection.transactionParams, nonce, }; // 3. Sign transaction const signedTx = await signer.signTransaction(txParams); // 4. Submit order const response = await fetch(`${API_URL}/api/v1/mev/wrap/order`, { method: "POST", headers: { "X-API-Key": API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ quoteId: quote.quoteId, signedTransaction: signedTx, providerMetadata: quote.mevProtection.providerMetadata, // Required! operation: quote.operation, amount: quote.amount, }), }); if (!response.ok) { const error = await response.text(); throw new Error(`HTTP ${response.status}: ${error}`); } const { ok, data } = await response.json(); if (!ok) { throw new Error(`API Error: ${data.error}`); } return data.order; } // Example usage - Complete wrap flow async function wrapEth(amountEth: string, signer: ethers.Signer) { const userAddress = await signer.getAddress(); // Step 1: Get quote const quoteResponse = await fetch(`${API_URL}/api/v1/mev/wrap/quote`, { method: "POST", headers: { "X-API-Key": API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ operation: "wrap", amount: amountEth, userAddress, chainId: 1, }), }); const { data } = await quoteResponse.json(); const quote = data.quote; console.log(" Quote received:", quote.quoteId); // Step 2: Submit order const order = await submitWrapOrder(quote, signer); console.log("\n=== Wrap Order Submitted ==="); console.log(`Operation: ${order.operation}`); console.log(`Amount: ${order.amount} ETH`); console.log(`TX Hash: ${order.txHash}`); console.log(`Status: ${order.status}`); console.log(`Provider: ${order.provider}`); console.log(`Tracking URL: ${order.trackingUrl}`); console.log(`Explorer: ${order.explorerUrl}`); console.log(`Submitted: ${order.submittedAt}`); return order; } // Execute wrap const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); wrapEth("1.0", wallet) .then((order) => console.log("\n Wrap completed successfully")) .catch((error) => console.error(" Wrap failed:", error));

Response Format

Success Response (200 OK)

{ "ok": true, "data": { "order": { "operation": "wrap", "txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "amount": "1.0", "status": "submitted", "provider": "MEV Blocker", "trackingUrl": "https://rpc.mevblocker.io/tx/0x1234567890abcdef...", "explorerUrl": "https://etherscan.io/tx/0x1234567890abcdef...", "submittedAt": "2024-01-15T10:30:00.000Z" } } }

Response Fields Reference

Order Object

FieldTypeDescription
operationstring”wrap” or “unwrap”
txHashstringTransaction hash (use for tracking)
fromstringTransaction sender address
amountstringAmount being wrapped/unwrapped (in ETH)
statusstringOrder status (always “submitted” initially)
providerstringMEV protection provider (e.g., “MEV Blocker”)
trackingUrlstringMEV Blocker tracking URL
explorerUrlstringEtherscan transaction URL
submittedAtstringSubmission timestamp (ISO 8601)

Error Responses

400 Bad Request - Missing Parameter

{ "ok": false, "error": "MISSING_PARAMETER", "message": "signedTransaction is required", "details": { "field": "signedTransaction", "required": true } }

400 Bad Request - Invalid Signature

{ "ok": false, "error": "INVALID_SIGNATURE", "message": "Transaction signature is invalid", "details": { "reason": "Failed to recover signer address" } }

400 Bad Request - Nonce Too Low

{ "ok": false, "error": "NONCE_TOO_LOW", "message": "Transaction nonce has already been used", "details": { "provided": 35, "expected": 36 }, "suggestion": "Get fresh quote and use current nonce" }

400 Bad Request - Insufficient Balance

{ "ok": false, "error": "INSUFFICIENT_BALANCE", "message": "Insufficient ETH balance for wrap operation", "details": { "required": "1000000000000000000", "available": "500000000000000000" } }

Common Error Codes

HTTPError CodeReasonSolution
400MISSING_PARAMETERRequired field missingInclude all required fields
400INVALID_SIGNATURETransaction signature invalidRe-sign with correct private key
400NONCE_TOO_LOWTransaction already minedUse current nonce
400INSUFFICIENT_BALANCENot enough ETH/WETHCheck wallet balance
400INVALID_TRANSACTIONTransaction params invalidUse exact params from quote
401UNAUTHORIZEDInvalid/missing API keyCheck X-API-Key header
422VALIDATION_ERRORParams don’t match quoteUse exact params from quote
429RATE_LIMIT_EXCEEDEDToo many requestsWait and retry with backoff
503PROVIDER_UNAVAILABLEMEV Blocker temporarily downRetry after a few seconds

Transaction Monitoring

Track Your Transaction: After submission, monitor transaction status using: 1. MEV Blocker Tracking: order.trackingUrl 2. Etherscan: order.explorerUrl 3. RPC Provider: Poll with order.txHash

// Monitor transaction confirmation async function waitForConfirmation(txHash: string, provider: ethers.Provider) { console.log(`⏳ Waiting for confirmation: ${txHash}`); const receipt = await provider.waitForTransaction(txHash, 1); // 1 confirmation if (receipt.status === 1) { console.log(" Transaction confirmed!"); console.log(`Block: ${receipt.blockNumber}`); console.log(`Gas used: ${receipt.gasUsed.toString()}`); } else { console.log(" Transaction failed"); } return receipt; } // Usage const order = await submitWrapOrder(quote, signer); await waitForConfirmation(order.txHash, provider);

Complete Wrap/Unwrap Flow

Step-by-Step Process:

  1. Get Quote: POST /api/v1/mev/wrap/quote
  2. Get Nonce: Fetch user’s current transaction nonce
  3. Sign Transaction: Add nonce and sign transaction params
  4. Submit Order: POST /api/v1/mev/wrap/order (this endpoint)
  5. Monitor: Track transaction until confirmed
// Complete flow example async function completeWrapFlow(amountEth: string, signer: ethers.Signer) { try { // 1. Get quote const quote = await getWrapQuote( "wrap", amountEth, await signer.getAddress() ); console.log(" Step 1: Quote received"); // 2. Get nonce const nonce = await signer.provider.getTransactionCount( await signer.getAddress() ); console.log(` Step 2: Nonce retrieved (${nonce})`); // 3. Sign transaction const txParams = { ...quote.mevProtection.transactionParams, nonce }; const signedTx = await signer.signTransaction(txParams); console.log(" Step 3: Transaction signed"); // 4. Submit order const order = await submitWrapOrder(quote, signer); console.log(" Step 4: Order submitted"); console.log(` TX Hash: ${order.txHash}`); // 5. Monitor confirmation await waitForConfirmation(order.txHash, signer.provider); console.log(" Step 5: Transaction confirmed"); return order; } catch (error) { console.error(" Wrap flow failed:", error); throw error; } }

Best Practices

Transaction Signing

Never Modify Transaction Parameters Sign the transaction using exactly the parameters from the quote (with nonce added). Any modification will cause the transaction to fail.

// CORRECT - Using transactionParams const txParams = { ...quote.mevProtection.transactionParams }; txParams.nonce = await signer.provider.getTransactionCount(userAddress); const signedTx = await signer.signTransaction(txParams); // Then submit with providerMetadata const orderPayload = { quoteId: quote.quoteId, signedTransaction: signedTx, providerMetadata: quote.mevProtection.providerMetadata, // Required! operation: quote.operation, amount: quote.amount, }; // WRONG - Don't modify const txParams = { ...quote.mevProtection.transactionParams }; txParams.gasLimit = "100000"; // Don't do this! txParams.nonce = await signer.provider.getTransactionCount(userAddress); // WRONG - Missing providerMetadata const orderPayload = { signedTransaction: signedTx, operation: "wrap", // Missing providerMetadata - will fail with 400 error! };

Error Handling

try { const order = await submitWrapOrder(quote, signer); } catch (error) { if (error.message.includes("INSUFFICIENT_BALANCE")) { console.log("Not enough ETH/WETH in wallet"); } else if (error.message.includes("NONCE_TOO_LOW")) { console.log("Nonce already used, get fresh quote"); } else if (error.message.includes("INVALID_SIGNATURE")) { console.log("Check signing configuration"); } else { console.error("Order submission failed:", error); } }

Gas Estimation

Gas Costs:

  • Wrap (ETH → WETH): Approx 46,000 gas (Approx $1-3 at 50 gwei)
  • Unwrap (WETH → ETH): Approx 30,000 gas (Approx $0.5-2 at 50 gwei)

Gas estimates include MEV protection overhead.


Related Operations:


Need Help?

Last updated on