# Permit

## Specification

{% hint style="info" %}
Refer to [API - EVM Swaps](/developer-guide/aggregator-api/aggregator-api-specification/evm-swaps.md) for details on where `permit`can be used
{% endhint %}

[EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) tokens can be swapped directly without an initial approval transaction. The client needs to provide an abi-encoded `permit` function calldata (without selector) as a parameter to [API - EVM Swaps](/developer-guide/aggregator-api/aggregator-api-specification/evm-swaps.md#chain-api-v1-route-build) API call. Refer to the [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) specification for how to sign and encode this call. `permit` function ABI is provided below for reference:

{% code overflow="wrap" %}

```solidity
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external
```

{% endcode %}

* `owner`: the swap's token sender
* `spender`: the KyberSwap router address as returned by the GET-route API
* `value`: the amount of token to be swapped
* `deadline`: deadline by which the permit is valid
* `v`, `r`, `s`: a valid `secp256k1` signature from the swap's token sender for the following typed message:

{% code overflow="wrap" %}

```javascript
const domain = {
  name,
  version,
  chainId,
  verifyingContract: await token.getAddress(),
};

const types = {
  Permit: [
    { name: "owner", type: "address" },
    { name: "spender", type: "address" },
    { name: "value", type: "uint256" },
    { name: "nonce", type: "uint256" },
    { name: "deadline", type: "uint256" },
  ],
};

const message = {
  owner,
  spender,
  value,
  nonce,
  deadline,
};
```

{% endcode %}

## Example

```javascript
import { ethers } from "ethers";
import fetch from "node-fetch";

const rpcUrl = "https://ethereum.publicnode.com";
const provider = new ethers.JsonRpcProvider(rpcUrl);
const signer = new ethers.Wallet(process.env.PRIV_KEY, provider);

const clientId = "permit-test";

const erc20Abi = [
  "function name() view returns (string)",
  "function nonces(address) view returns (uint256)",
  "function version() view returns (string)",
];

async function signPermit(signer, token, spender, value, chainId) {
  const owner = await signer.getAddress();
  const nonce = await token.nonces(owner);
  const name = await token.name();
  let version = "1";
  try {
    version = await token.version();
  } catch {}

  const deadline = Math.floor(Date.now() / 1000) + 3600;

  const domain = {
    name,
    version,
    chainId,
    verifyingContract: await token.getAddress(),
  };

  const types = {
    Permit: [
      { name: "owner", type: "address" },
      { name: "spender", type: "address" },
      { name: "value", type: "uint256" },
      { name: "nonce", type: "uint256" },
      { name: "deadline", type: "uint256" },
    ],
  };

  const message = {
    owner,
    spender,
    value,
    nonce,
    deadline,
  };

  const sig = await signer.signTypedData(domain, types, message);
  const { v, r, s } = ethers.Signature.from(sig);

  return { v, r, s, deadline };
}

async function getRoute(tokenIn, tokenOut, amountIn) {
  const url =
    `https://aggregator-api.kyberswap.com/ethereum/api/v1/routes` +
    `?tokenIn=${tokenIn}&tokenOut=${tokenOut}&amountIn=${amountIn}`;

  const res = await fetch(url, {
    headers: { "X-Client-Id": clientId },
  });

  const j = await res.json();
  if (!j.data) {
    throw new Error("no route: " + JSON.stringify(j));
  }
  const routeSummary = j.data.routeSummary;
  console.log(
    `Got a route to swap from ${routeSummary.amountIn} ${
      routeSummary.tokenIn
    } to ${routeSummary.amountOut} ${routeSummary.tokenOut}`,
  );
  return j.data;
}

async function buildRoute(route, permit, sender, amountIn) {
  const body = {
    routeSummary: route.routeSummary,
    sender,
    recipient: sender,
    slippageTolerance: 10,
    permit: ethers.AbiCoder.defaultAbiCoder().encode(
      [
        "address",
        "address",
        "uint256",
        "uint256",
        "uint8",
        "bytes32",
        "bytes32",
      ],
      [
        sender,
        route.routerAddress,
        amountIn,
        permit.deadline,
        permit.v,
        permit.r,
        permit.s,
      ],
    ),
    deadline: permit.deadline + 300,
    enableGasEstimation: false,
  };

  const res = await fetch(
    "https://aggregator-api.kyberswap.com/ethereum/api/v1/route/build",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Client-Id": clientId,
      },
      body: JSON.stringify(body),
    },
  );

  const j = await res.json();
  if (!j.data) {
    throw new Error("build failed: " + JSON.stringify(j));
  }
  return j.data;
}

async function executeSwap(routerAddress, calldata, signer) {
  const tx = await signer.sendTransaction({
    to: routerAddress,
    data: calldata,
  });
  return tx.wait();
}

async function main() {
  const signerAddr = await signer.getAddress();

  const tokenIn = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; // USDC
  const tokenOut = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; // ETH pseudo-address
  const amountIn = 100000000n; // USDC 100 * 1e6

  const route = await getRoute(tokenIn, tokenOut, amountIn);
  const router = route.routerAddress;

  const token = new ethers.Contract(tokenIn, erc20Abi, provider);
  const net = await provider.getNetwork();

  const permit = await signPermit(signer, token, router, amountIn, net.chainId);

  const built = await buildRoute(route, permit, signerAddr, amountIn);

  const receipt = await executeSwap(router, built.data, signer);
  console.log(receipt);
}

main().catch(console.error);

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kyberswap.com/developer-guide/aggregator-api/how-to-guides/permit.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
