> For the complete documentation index, see [llms.txt](https://docs.kyberswap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kyberswap.com/developer-guide/aggregator-api/how-to-guides/permit.md).

# Permit

For swaps from supported EIP-2612 tokens, the \`permit\` parameter allows swapping without an approval transaction beforehand.

## 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
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
