LogoLogo
  • ☠️Introduction
    • What is Clipper?
    • How Clipper Makes Money for LPs
    • How LPs Earn from Arbitrage
    • Clipper's Benchmark: No Impermanent Loss
      • Clipper vs. CPMMs vs. HODLing
      • Appendix: Math
    • Why Clipper Has Better Trading Prices
    • DAO Protocol Fees
    • DAO Governance
  • ⚔️How to Use Clipper
    • Liquidity Pools
      • Depositing & Withdrawing
      • Farming Pools
    • Trading
    • Community Adventures
    • FAQs
  • 🪙Governance Token
    • Community Governance
    • ⛵SAIL Primer
      • Clipper Fundamentals
      • DEX Market Structure
      • SAIL Supply & Circulation
      • SAIL Farming
      • veSAIL
      • Token Listings
  • 🏴‍☠️Disclaimers & Technical
    • Audits
    • Smart Contracts
      • Subgraph
        • Entities
        • Queries
    • Integrating with Clipper RFQ
      • Introduction
      • Guides
        • How to use clipper RFQ API?
        • Estimate Clipper Prices
        • Interacting with the Clipper Exchange contracts
        • Integration Examples
          • Swap Native token → Shorttail
          • Swap Shorttail → Native token
          • Swap Shorttail → Shorttail
          • Complete Swap Flow
      • API Reference
        • API v2
          • Overview
          • Pool v2
          • Quote v2
        • API v1
          • Overview
          • Pool
          • Quote
          • Sign
      • Troubleshooting & FAQs
    • Terms of Service
    • Privacy Policy
  • ⛵Come Aboard
    • Discord
    • Twitter
    • Github
Powered by GitBook
On this page

Was this helpful?

  1. Disclaimers & Technical
  2. Integrating with Clipper RFQ
  3. Guides
  4. Integration Examples

Swap Shorttail → Native token

PreviousSwap Native token → ShorttailNextSwap Shorttail → Shorttail

Last updated 2 months ago

Was this helpful?

E.g: OP → 0.01 ETH on Optimism (Chain 10)

Since this is a L2 (optimism) example, we use packed form values, as explained . In this case, we need to call the packedTransmitAndSwap method from clipper’s smart contract which has the following interface:

function packedTransmitAndSwap(uint256 packedInput, uint256 packedOutput, uint256 packedGoodUntil, bytes32 auxData, bytes32 r, bytes32 vs)

const fetch = require('node-fetch');
import ethers from "ethers";
import packedExchangeAbi from "./packedExchangeAbi.json";
import { hexZeroPad } from 'ethers/lib/utils';

// Get a quote
async function getQuote() {
  const quotePayload = {
    "output_asset_symbol": "ETH",
    "input_asset_symbol": "OP",
    "chain_id": 10,
    "time_in_seconds": 60,
    "output_amount": "10000000000000000"
  };

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(quotePayload)
  };

  const response = await fetch('https://api.clipper.exchange/rfq/quote', requestOptions);
  const quote = await response.json();
  
  return quote;
}

// Sign the quote
async function signQuote(quoteId) {
  const signPayload = {
    "quote_id": quoteId,
    "destination_address": "0xab83Af831dfb4028EBFd3fFA74A828a4d5DCaAC5"
  };

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(signPayload)
  };

  const response = await fetch('https://api.clipper.exchange/rfq/sign', requestOptions);
  const signResponse = await response.json();
  
  return signResponse;
}

// Execute transaction
async function executeSwap(signResponse) {
  const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
  const clipperPackedContract = new ethers.Contract(
    signResponse.clipper_exchange_address,
    packedExchangeAbi,
    provider
  );

  const auxData = "0x00000000000000000000000000000000000000000000000000";
  const packedInput = packAddressAndAmount(signResponse.input_amount, signResponse.input_asset_address);
  const packedOutput = packAddressAndAmount(signResponse.output_amount, signResponse.output_asset_address);
  const packedGoodUntil = signResponse.good_until;
  const packedData = packAddressAndAmount(auxData, signResponse.destination_address);
  const r = byte32(signResponse.signature.r);
  const vs = byte32(shortenSignature(signResponse.signature.s, signResponse.signature.v));

  const result = await clipperPackedContract.packedTransmitAndSwap(
    packedInput, packedOutput, packedGoodUntil, auxData, r, vs
  );
}

// In order to calculate the packed values, we can use the following methods
function packAddressAndAmount(amount, address) {
  const addressBn = BigInt(address);
  const amountBn = BigInt(amount);

  return (amountBn << 160n) + addressBn;
}

// Converts the value to 32 bytes and fills the rest with leading zeroes.
function byte32(value) {
  return hexZeroPad(value.toString(16), 32);
}

function shortenSignature(s, v) {
  const parity = BigInt(v - 27);
  const shiftedParity = parity << 255n;

  return s + shiftedParity.toString(16);
}

// Main function
async function main() {
  // 1. Get a quotey
  const quote = await getQuote();
  console.log("Quote:", quote);
  
  // 2. Sign a quote
  const signResponse = await signQuote(quote.id);
  console.log("Sign Response:", signResponse);
  
  // 3. Execute transaction
  await executeSwap(signResponse);
  console.log("Swap executed successfully.");
}
🏴‍☠️
21KB
packedExchangeAbi.json
ABI used in the example
here