Docs
Authentication

Authentication

Some endpoints may require authentication. We use EIP-712 signTypedData_v4 to sign and validate the API request and identify the requester ("Referrer").

As this logic utilizes Referrer's private key, it is highly encouraged for the Referrer to have their service in between the actual end user and our API so that the private key does not get exposed to the public.

💡

A compromised private key may allow an unwanted party to send and sign requests as you, consuming your rate limit points.

Suggested Request Flow

Following two figures demonstrate how the request goes through. While there are mainly two options, we generally recommend the first one (Figure 1). This is because the latter one (Figure 2) will effectively expose the Referrer’s signing address to the end user, along with the signature and other stuff.

Although those params including signatures are cryptographically safe to be exposed to the end user, the end user does not need to know about their existence in the end.

Example

import express from 'express';
import { quote } from #signing-request;

const app = express();

app.get('/quote', async (req, res) => {
  // this way the signing related params are not exposed to the end user.
  res.send(await quote(req.query));
});

app.listen();

Figure 1. (Recommended) While the Referrer proxies the end user's request, the end user does not know if there is any authentication layer exists.


Figure 2. The Referrer only signs the quoting request and the end user directly makes the request.

Signing Request

Following example demonstrates how to sign and make a Quote v0 API.

💡

Signing address does not need to be equal with the address that you will be sending the transaction from (req.query.from).

import crypto from 'node:crypto';
import { URL } from 'node:url';
import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util';

// while the account here does not need to have any balance, it needs to be a valid address.
const REFERRER = {
  account: '0x5f08...[REDACTED]...baBA',
  privateKey: Buffer.from('5746...[REDACTED]...ff4f', 'hex'),
};

// TODO: use your own fetcher.
const fetch = (url) => console.log(url.toString());

// NOTE: ensure every hex digits are in lowercase
const quote = (message) => {
  // `salt` needs to be cryptographically randomly generated for every other request. Reusing the
  // same `salt` more than one time (within a certain time interval) is forbidden.
  const salt = '0x' + crypto.randomBytes(32).toString('hex');

  // sign the data (signTypedData_v4).
  const signature = signTypedData({
    privateKey: REFERRER.privateKey,
    data: {
      message,
      // all the entries in the domain field are fixed constants for now, except for the salt.
      domain: {
        name: 'Swapscanner Navigator',
        version: 'v0',
        chainId: '8217',
        verifyingContract: '0x8888888888888888888888888888888888888888',
        salt,
      },
      // all the remaining fields are fixed constants.
      primaryType: 'QuoteRequestV0',
      types: {
        EIP712Domain: [
          { name: 'name', type: 'string' },
          { name: 'version', type: 'string' },
          { name: 'chainId', type: 'uint256' },
          { name: 'verifyingContract', type: 'address' },
          { name: 'salt', type: 'bytes32' },
        ],
        QuoteRequestV0: [
          { name: 'issuedAt', type: 'uint256' },
          { name: 'from', type: 'address' },
          { name: 'tokenInAddress', type: 'address' },
          { name: 'tokenOutAddress', type: 'address' },
          { name: 'amount', type: 'uint256' },
          { name: 'slippageNumerator', type: 'uint256' },
          { name: 'slippageDenominator', type: 'uint256' },
          { name: 'mode', type: 'string' },
        ],
      },
    },
    version: SignTypedDataVersion.V4,
  });

  const url = new URL('https://api.swapscanner.io/api/v0/quote');
  url.searchParams.set('salt', salt);
  url.searchParams.set('referrer', REFERRER.account.toLowerCase());
  url.searchParams.set('signature', signature);
  Object.entries(message).forEach(([key, value]) => url.searchParams.set(key, value));

  return fetch(url);
};

quote({
  issuedAt: Math.floor(Date.now() / 1000),
  from: '0x4236...[REDACTED]...57a9'.toLowerCase(),
  tokenInAddress: '0x754288077d0ff82af7a5317c7cb8c444d421d103'.toLowerCase(),
  tokenOutAddress: '0x0000000000000000000000000000000000000000'.toLowerCase(),
  amount: '1000000',
  slippageNumerator: '1',
  slippageDenominator: '100',
  mode: 'gasEfficient',
});

Whitelisting Signing Address

That being said, to access endpoints that requires authentication, your signing account address needs to be whitelisted on our end.

To get your address whitelisted, please contact us at contact@swapscanner.io.

💡

Please never share your private key.