Skip to Content
SDK & CLISDKImpersonation

Impersonation

Send transactions from any address on your Stagenet — without needing its private key.

Use it to:

  • Call gated functions as an owner, admin, or multisig.
  • Move tokens from whale addresses into target accounts.
  • Reproduce flows that depend on specific production wallets.

How it works

When you impersonate an address, that address is added to an allowlist on your Stagenet.

Your Stagenet will then accept eth_sendTransaction requests where the from field matches the impersonated address.

No private key or signature is required. The EVM sees the impersonated address as the transaction’s msg.sender.

Impersonation only works with eth_sendTransaction, where the transaction is submitted to the Stagenet RPC as an unsigned transaction request.

It does not work with eth_sendRawTransaction. Raw transactions are already signed locally, so the sender is fixed by the signature before the transaction reaches your Stagenet.

Use a JSON-RPC signer — one that sends transaction requests through the Stagenet RPC, rather than signing locally with a private key:

  • ethers: provider.getSigner(address)
  • viem: createWalletClient({ account: address, transport: http(stagenetUrl) })

Methods

stagenet.impersonateAccount(address)

Adds an address to the impersonation allowlist.

await stagenet.impersonateAccount("0x28C6c06298d514Db089934071355E5743bf21d60");

Returns true on success.

stagenet.stopImpersonatingAccount(address)

Removes an address from the impersonation allowlist. After this, unsigned transactions from that address are rejected unless it is impersonated again.

await stagenet.stopImpersonatingAccount(whale);

Returns true on success.

stagenet.getImpersonatedAccounts()

Lists every address currently on the allowlist (lowercased).

const accounts = await stagenet.getImpersonatedAccounts();

Returns string[].

Usage

ethers

import { ethers } from "ethers"; import { createStagenet } from "contract.dev"; const stagenetUrl = "<YOUR_STAGENET_RPC_URL>"; const stagenet = createStagenet(stagenetUrl); const provider = new ethers.JsonRpcProvider(stagenetUrl); const whale = "0x28C6c06298d514Db089934071355E5743bf21d60"; const recipient = "0x1111111111111111111111111111111111111111"; const usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; // 1. Start impersonating await stagenet.impersonateAccount(whale); // 2. Get a JSON-RPC signer for the address const signer = await provider.getSigner(whale); // 3. Send a transaction as the impersonated address const erc20 = new ethers.Contract( usdc, ["function transfer(address to, uint256 amount) returns (bool)"], signer, ); await erc20.transfer(recipient, 1_000_000n); // 4. Stop impersonating when finished await stagenet.stopImpersonatingAccount(whale);

viem

import { createWalletClient, http } from "viem"; import { createStagenet } from "contract.dev"; const stagenetUrl = "<YOUR_STAGENET_RPC_URL>"; const stagenet = createStagenet(stagenetUrl); const whale = "0x28C6c06298d514Db089934071355E5743bf21d60"; // 1. Start impersonating await stagenet.impersonateAccount(whale); // 2. Create a wallet client using only the address const wallet = createWalletClient({ account: whale, transport: http(stagenetUrl), }); // 3. Send a transaction as the impersonated address await wallet.writeContract({ address: usdcAddress, abi: erc20Abi, functionName: "transfer", args: [recipient, 1_000_000n], }); // 4. Stop impersonating when finished await stagenet.stopImpersonatingAccount(whale);

Multiple accounts

You can impersonate multiple addresses at the same time. The JSON-RPC signer you use determines which impersonated address is used as msg.sender.

await stagenet.impersonateAccount(alice); await stagenet.impersonateAccount(bob); const aliceSigner = await provider.getSigner(alice); const bobSigner = await provider.getSigner(bob); await myContract.connect(aliceSigner).vote(1); await myContract.connect(bobSigner).vote(2);

Topping up gas

Impersonated accounts still need native tokens to pay for gas. If the address is empty, fund it with addBalance first:

await stagenet.impersonateAccount(whale); await stagenet.addBalance(whale, 10n ** 18n); // 1 ETH for gas
Last updated on