> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How-to: Manage delegates for smart contract wallets

When using
[Smart Contract Account (SCA) wallets](/wallets/account-types#smart-contract-accounts-sca)
with Gateway, you need to authorize an Externally Owned Account (EOA) to sign
burn intents on behalf of the SCA. This is necessary because Gateway requires
ECDSA signatures for static verification, which SCAs cannot provide directly.

This guide demonstrates how to add and remove delegates for Gateway transfers
from SCA wallets using Circle
[Developer-controlled wallets](/wallets/dev-controlled).

## Prerequisites

Before you begin, ensure that you've:

* Installed [Node.js v22+](https://nodejs.org/)
* Created a [Circle Developer Console](https://console.circle.com) account
* Obtained an API key and
  [registered your Entity Secret](/wallets/dev-controlled/register-entity-secret)
* Created an SCA wallet and an EOA wallet via Circle Developer-Controlled
  Wallets
  * The SCA wallet holds your Gateway USDC deposits
  * The EOA wallet will sign burn intents on behalf of the SCA
* Deposited USDC into the Gateway Wallet from your SCA wallet
* Created a TypeScript project with the
  [Developer-Controlled Wallets SDK](/sdks/developer-controlled-wallets-nodejs-sdk)
  installed
* Set up a `.env` file with the following variables:

  ```text .env theme={null}
  CIRCLE_API_KEY={YOUR_API_KEY}
  CIRCLE_ENTITY_SECRET={YOUR_ENTITY_SECRET}
  DEPOSITOR_ADDRESS={YOUR_SCA_WALLET_ADDRESS}
  DELEGATE_WALLET_ADDRESS={YOUR_EOA_DELEGATE_ADDRESS}
  ```

## Add a Delegate

Follow these steps to authorize an EOA delegate to sign burn intents on behalf
of your SCA wallet.

### Step 1. Create the add delegate script

Create a new file called `add-delegate.ts` in the root of your project and add
the following code. This calls the
[`addDelegate()`](/gateway/references/contract-interfaces-and-events#adddelegate)
method on the Gateway Wallet contract on Arc Testnet.

```ts add-delegate.ts theme={null}
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";

const GATEWAY_WALLET = "0x0077777d7EBA4688BDeF3E311b846F25870A19B9";
const USDC_ADDRESS = "0x3600000000000000000000000000000000000000"; // Arc Testnet
const BLOCKCHAIN = "ARC-TESTNET";

const client = initiateDeveloperControlledWalletsClient({
  apiKey: process.env.CIRCLE_API_KEY!,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
});

async function waitForTx(txId: string) {
  while (true) {
    const { data } = await client.getTransaction({ id: txId });
    const state = data?.transaction?.state;
    if (["COMPLETE", "CONFIRMED"].includes(state!)) return;
    if (["FAILED", "DENIED", "CANCELLED"].includes(state!))
      throw new Error(`Failed: ${state}`);
    await new Promise((resolve) => setTimeout(resolve, 3000));
  }
}

async function main() {
  console.log(`\n=== Processing ${BLOCKCHAIN} ===`);
  console.log(`Adding delegate: ${process.env.DELEGATE_WALLET_ADDRESS}`);

  const tx = await client.createContractExecutionTransaction({
    walletAddress: process.env.DEPOSITOR_ADDRESS!,
    blockchain: BLOCKCHAIN,
    contractAddress: GATEWAY_WALLET,
    abiFunctionSignature: "addDelegate(address,address)",
    abiParameters: [USDC_ADDRESS, process.env.DELEGATE_WALLET_ADDRESS!],
    fee: { type: "level", config: { feeLevel: "MEDIUM" } },
  });

  await waitForTx(tx.data?.id!);
  console.log(`Done on ${BLOCKCHAIN}`);
}

main().catch((error) => {
  console.error("\nError:", error);
  process.exit(1);
});
```

### Step 2. Run the script

Run the script with the following command:

```shell theme={null}
npx tsx --env-file=.env add-delegate.ts
```

The script output shows "Done on \<SELECTED\_BLOCKCHAIN>" when the delegate is
successfully authorized. You can now use the delegate to sign burn intents on
behalf of your SCA wallet when making Gateway transfers.

### Step 3. Repeat for other chains

To add the delegate on additional chains where the SCA holds Gateway deposits,
repeat Steps 1-2 with different `BLOCKCHAIN` and `USDC_ADDRESS` values for your
target chains. Check the
[USDC contract addresses](/stablecoins/usdc-contract-addresses) for the correct
values.

<Note>
  The delegate authorization remains valid until explicitly removed with the
  [`removeDelegate()`](/gateway/references/contract-interfaces-and-events#removedelegate)
  method.
</Note>

## Remove a Delegate

Follow these steps to revoke a delegate's authorization to sign burn intents on
behalf of your SCA wallet. After removing a delegate, note that:

* The delegate can no longer create new burn intents for the SCA wallet
* Burn intents that were already signed by the delegate remain valid and can
  still be executed on-chain
* This ensures that burns may be executed safely even in the event of a
  revocation
* The Gateway API reflects revocations as soon as they're finalized on-chain

This behavior is by design to prevent race conditions where a valid burn intent
becomes unusable mid-flight.

### Step 1. Create the remove delegate script

Create a new file called `remove-delegate.ts` in the root of your project and
add the following code. This is nearly identical to the add delegate script, but
calls
[`removeDelegate()`](/gateway/references/contract-interfaces-and-events#removedelegate)
instead.

```ts remove-delegate.ts theme={null}
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";

const GATEWAY_WALLET = "0x0077777d7EBA4688BDeF3E311b846F25870A19B9";
const USDC_ADDRESS = "0x3600000000000000000000000000000000000000"; // Arc Testnet
const BLOCKCHAIN = "ARC-TESTNET";

const client = initiateDeveloperControlledWalletsClient({
  apiKey: process.env.CIRCLE_API_KEY!,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
});

async function waitForTx(txId: string) {
  while (true) {
    const { data } = await client.getTransaction({ id: txId });
    const state = data?.transaction?.state;
    if (["COMPLETE", "CONFIRMED"].includes(state!)) return;
    if (["FAILED", "DENIED", "CANCELLED"].includes(state!))
      throw new Error(`Failed: ${state}`);
    await new Promise((resolve) => setTimeout(resolve, 3000));
  }
}

async function main() {
  console.log(`\n=== Processing ${BLOCKCHAIN} ===`);
  console.log(`Removing delegate: ${process.env.DELEGATE_WALLET_ADDRESS}`);

  const tx = await client.createContractExecutionTransaction({
    walletAddress: process.env.DEPOSITOR_ADDRESS!,
    blockchain: BLOCKCHAIN,
    contractAddress: GATEWAY_WALLET,
    abiFunctionSignature: "removeDelegate(address,address)",
    abiParameters: [USDC_ADDRESS, process.env.DELEGATE_WALLET_ADDRESS!],
    fee: { type: "level", config: { feeLevel: "MEDIUM" } },
  });

  await waitForTx(tx.data?.id!);
  console.log(`Done on ${BLOCKCHAIN}`);
}

main().catch((error) => {
  console.error("\nError:", error);
  process.exit(1);
});
```

### Step 2. Run the script

Run the script with the following command:

```shell theme={null}
npx tsx --env-file=.env remove-delegate.ts
```
