Since this is a L2 (optimism) example, we use packed form values, as explained here. In this case, we need to call the packedTransmitAndSwap method from clipper’s smart contract which has the following interface:
constfetch=require('node-fetch');import ethers from"ethers";import packedExchangeAbi from"./packedExchangeAbi.json";import { hexZeroPad } from'ethers/lib/utils';// Get a quoteasyncfunctiongetQuote() {constquotePayload= {"output_asset_symbol":"ETH","input_asset_symbol":"OP","chain_id":10,"time_in_seconds":60,"output_amount":"10000000000000000" };constrequestOptions= { method:'POST', headers: {'Content-Type':'application/json' }, body:JSON.stringify(quotePayload) };constresponse=awaitfetch('https://api.clipper.exchange/rfq/quote', requestOptions);constquote=awaitresponse.json();return quote;}// Sign the quoteasyncfunctionsignQuote(quoteId) {constsignPayload= {"quote_id": quoteId,"destination_address":"0xab83Af831dfb4028EBFd3fFA74A828a4d5DCaAC5" };constrequestOptions= { method:'POST', headers: {'Content-Type':'application/json' }, body:JSON.stringify(signPayload) };constresponse=awaitfetch('https://api.clipper.exchange/rfq/sign', requestOptions);constsignResponse=awaitresponse.json();return signResponse;}// Execute transactionasyncfunctionexecuteSwap(signResponse) {constprovider=newethers.providers.JsonRpcProvider(process.env.RPC_URL);constclipperPackedContract=newethers.Contract(signResponse.clipper_exchange_address, packedExchangeAbi, provider );constauxData="0x00000000000000000000000000000000000000000000000000";constpackedInput=packAddressAndAmount(signResponse.input_amount,signResponse.input_asset_address);constpackedOutput=packAddressAndAmount(signResponse.output_amount,signResponse.output_asset_address);constpackedGoodUntil=signResponse.good_until;constpackedData=packAddressAndAmount(auxData,signResponse.destination_address);constr=byte32(signResponse.signature.r);constvs=byte32(shortenSignature(signResponse.signature.s,signResponse.signature.v));constresult=awaitclipperPackedContract.packedTransmitAndSwap( packedInput, packedOutput, packedGoodUntil, auxData, r, vs );}// In order to calculate the packed values, we can use the following methodsfunctionpackAddressAndAmount(amount, address) {constaddressBn=BigInt(address);constamountBn=BigInt(amount);return (amountBn <<160n) + addressBn;}// Converts the value to 32 bytes and fills the rest with leading zeroes.functionbyte32(value) {returnhexZeroPad(value.toString(16),32);}functionshortenSignature(s, v) {constparity=BigInt(v -27);constshiftedParity= parity <<255n;return s +shiftedParity.toString(16);}// Main functionasyncfunctionmain() {// 1. Get a quoteyconstquote=awaitgetQuote();console.log("Quote:", quote);// 2. Sign a quoteconstsignResponse=awaitsignQuote(quote.id);console.log("Sign Response:", signResponse);// 3. Execute transactionawaitexecuteSwap(signResponse);console.log("Swap executed successfully.");}