# Building a Meta Transaction Relayer with NextJS
This guide will walk you through the steps required to construct a meta transaction relayer using NextJS 13. We will divide this process into three major parts:
1. Environment setup
2. API Route creation
3. Client code execution
## Environment Setup
Before we begin, it's crucial to configure our environment correctly. We need to set some environment variables. This is done in the `.env` file at the root of your project.
```
NEXT_PUBLIC_RELAYER_ACCOUNT_ID=xyz.testnet
RELAYER_ACCOUNT_PRIVATE_KEY=xyz
```
The `NEXT_PUBLIC_RELAYER_ACCOUNT_ID` is your public relayer account identifier and the `RELAYER_ACCOUNT_PRIVATE_KEY` is your relayer account's private key.
## API Route Creation
The next step is creating the API route. For this, we need to take the following actions:
1. Navigate to the `./src/app/api/` directory
2. Inside the `api` directory, create a new folder called `relayer`
3. Inside the `relayer` folder, create a new file named `route.ts`
Now, let's fill `route.ts` with the following code:
```ts
import { submitTransaction } from "@/utils/near/meta-transactions";
import { SCHEMA } from "@/utils/near/types/schema";
import { SignedDelegate } from "@near-js/transactions";
import { deserialize } from "borsh";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const body = await req.json();
const { delegated, network } = body;
const deserializeDelegate = deserialize(
SCHEMA,
SignedDelegate,
Buffer.from(new Uint8Array(delegated))
);
const result = await submitTransaction({
delegate: deserializeDelegate,
network,
});
return NextResponse.json(
{ result },
{
status: 200,
headers: {
"content-type": "application/json",
},
}
);
}
```
This script is responsible for receiving a delegated transaction, deserializing it, and submitting the transaction using the `submitTransaction` utility.
## Client Code Execution
The client code is divided into two parts. The first part signs a delegated transaction, and the second part submits the transaction through the relayer.
### Signing a Delegated Transaction
We use the following code snippet to sign a delegated transaction:
```ts
import { getKeys } from "@near-js/biometric-ed25519";
import { InMemoryKeyStore } from "@near-js/keystores";
import { actionCreators } from "@near-js/transactions";
import BN from "bn.js";
import { connect } from "./meta-transactions";
export const signDelegatedTransaction = async ({
network,
signer,
privateKey,
transaction,
contractAddress,
}: {
network: string;
signer: string;
privateKey: string;
transaction: {
methodName: string;
args: any;
gas: string | number;
deposit: string | number;
};
contractAddress: string;
}) => {
const keyStore = new InMemoryKeyStore();
// TODO: Connect the user
const signerAccount = await connect(signer, keyStore, network);
const action = actionCreators.functionCall(
transaction.methodName,
JSON.parse(transaction.args),
new BN(transaction.gas),
new BN(transaction.deposit)
);
const delegate = await signerAccount.signedDelegate({
actions: [action],
blockHeightTtl: 600,
receiverId: contractAddress,
});
return delegate;
};
```
This function receives several parameters, including `network`, `signer`, `privateKey`, `transaction`, and `contractAddress`. It generates a delegate using the `signedDelegate` method, which is later used to submit the transaction.
### Submitting the Transaction via the Relayer
After signing the delegated transaction, we use the following code snippet to submit the transaction through the relayer:
```ts
await fetch("/api/relayer", {
body: JSON.stringify({
delegated: Array.from(encodeSignedDelegate(delegated)),
network: "testnet",
}),
headers: {},
method: "POST",
});
```
The `fetch` function sends a POST request to the API route we created earlier. The body of this request includes the delegated transaction and the network.