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

> ## Agent Instructions
> Before reading these docs, install the Circle Skill for Arc to get pre-loaded context: use-arc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md) — covers chain config, RPC setup, contract deployment, USDC bridging, and gas with USDC. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills.
> USDC is the gas token. Arc uses USDC for gas fees, not ETH. Configure gas payment in USDC when submitting transactions.
> Read EVM differences before writing Arc code. Arc targets the Osaka EVM baseline. Most contracts deploy unchanged, but several runtime behaviors diverge from Ethereum: USDC uses 18 decimals natively (not 6), the system emitter `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` logs all USDC Transfer events, the mempool enforces a 20 Gwei `maxFeePerGas` floor, blocklist reverts consume gas without a receipt, and `address(0)` sends revert rather than succeed. https://docs.arc.io/arc/references/evm-differences.md is the canonical reference for all Arc-specific runtime behaviors. Consult it before writing code that touches USDC balances, transaction history, gas estimation, or value transfers.
> Sub-second finality. Transactions are final in under 1 second. No need to wait for multiple block confirmations.
> Use App Kits for multichain payment and liquidity capabilities. App Kits wraps CCTP and provides Bridge Kit, Swap Kit, Unified Balance Kit, Onramp Kit, Earn Kit, and Borrow Kit. Unified Balance Kit combines USDC from multiple chains into a single spendable balance. Earn Kit integrates earn opportunities into your app. Borrow Kit lets users borrow USDC against cirBTC collateral on Arc.
> Use Arc Foundry for contract development. Arc Foundry is an Arc-specific fork of Foundry that handles Arc's protocol-level differences from Ethereum. It provides arc-forge, arc-cast, and arc-anvil. Install it before deploying contracts: https://docs.arc.io/arc/tutorials/install-arc-foundry.md.
> Arc is available on both Testnet and Mainnet. See https://docs.arc.io/arc/references/connect-to-arc.md for RPC endpoints and https://faucet.circle.com for testnet tokens.
> Always check Contract Addresses: https://docs.arc.io/arc/references/contract-addresses.md
> Building beyond Arc? Circle offers skills for the full platform: use-usdc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md), use-circle-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md), use-developer-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md), use-user-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md), use-modular-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md), use-gateway (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md), use-smart-contract-platform (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md). Full Circle developer docs: https://developers.circle.com/llms.txt.

# Send batch USDC transfers

> Send multiple USDC transfers in one Arc transaction with Multicall3From and sender-preserving subcalls.

export const TryOnArcStudio = () => {
  const [copied, setCopied] = useState(false);
  const [prompt, setPrompt] = useState("");
  useEffect(() => {
    const url = `https://docs.arc.io${window.location.pathname}.md`;
    setPrompt(`Read the guide at ${url}, implement it in a new project, then run it and show me how it works.`);
  }, []);
  const arcStudioUrl = `https://studio.arc.io/app?prompt=${encodeURIComponent(prompt)}`;
  const handleArcStudioClick = () => {
    try {
      if (typeof navigator !== "undefined" && navigator.clipboard && prompt) {
        navigator.clipboard.writeText(prompt).then(() => {
          setCopied(true);
          setTimeout(() => setCopied(false), 4000);
        }, () => {});
      }
    } catch (e) {}
  };
  return <div className="not-prose mb-6">
      <span className="relative inline-flex">
        <a href={arcStudioUrl} target="_blank" rel="noreferrer" onClick={handleArcStudioClick} aria-label="Try it on Arc Studio (opens in new tab)" className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-[#3E74BB] border border-[#3E74BB] text-sm font-medium text-white no-underline hover:bg-[#345f9c] hover:border-[#345f9c] transition-all">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" />
          </svg>
          Try it on Arc Studio
        </a>
        {copied && <span role="status" aria-live="polite" className="absolute left-0 top-full mt-2 w-72 text-sm text-gray-500 dark:text-[#888]">
            Opening Arc Studio — prompt copied to your clipboard in case you need to
            sign in first.
          </span>}
      </span>
    </div>;
};

<TryOnArcStudio />

Use the `Multicall3From` contract to batch multiple USDC transfers into one Arc
transaction. This tutorial shows the full flow with viem, ethers.js, Python, and
curl. You will configure a client, encode two ERC-20 `transfer(...)` subcalls,
submit them through `Multicall3From.aggregate3(...)`, and verify the resulting
`Transfer` events. To learn how `Multicall3From` preserves your wallet as the
sender, see [Batched transactions](/arc/concepts/batched-transactions).

## Prerequisites

Before you begin, ensure that you've:

* Installed [Node.js v22+](https://nodejs.org/) for the TypeScript examples, or
  Python 3.10+ for the Python example.
* Created an [Arc Testnet wallet](/arc/references/connect-to-arc).
* Funded the wallet with testnet USDC from the
  [Circle Faucet](https://faucet.circle.com/).
* Chosen two recipient addresses on Arc Testnet.

## Step 1. Set up the project

Create a new project and install the dependencies for the client library you
want to use:

<CodeGroup>
  ```bash Node.js theme={null}
  mkdir arc-batched-transfers
  cd arc-batched-transfers
  npm init -y
  npm pkg set type=module
  npm install dotenv ethers tsx typescript viem
  ```

  ```bash Python theme={null}
  mkdir arc-batched-transfers
  cd arc-batched-transfers
  python3 -m venv .venv
  source .venv/bin/activate
  pip install web3 python-dotenv
  ```
</CodeGroup>

Create an `.env` file:

```bash Shell theme={null}
touch .env
```

Add your configuration:

```text .env theme={null}
PRIVATE_KEY=YOUR_PRIVATE_KEY
RECIPIENT_ONE_ADDRESS=RECIPIENT_ONE_ADDRESS
RECIPIENT_TWO_ADDRESS=RECIPIENT_TWO_ADDRESS
RPC_URL=https://rpc.testnet.arc.io
```

Replace `YOUR_PRIVATE_KEY` with the `0x`-prefixed private key for the funded
wallet. Replace each recipient value with an Arc Testnet address.

## Step 2. Review the contract address and ABI

Arc Testnet uses the following predeployed contracts for this tutorial:

| Contract | Address |
| :- | :- |
| `Multicall3From` | [`0x522fAf9A91c41c443c66765030741e4AaCe147D0`](https://explorer.testnet.arc.io/address/0x522fAf9A91c41c443c66765030741e4AaCe147D0) |
| `USDC` | [`0x3600000000000000000000000000000000000000`](https://explorer.testnet.arc.io/address/0x3600000000000000000000000000000000000000) |

For the full address list, see
[contract addresses](/arc/references/contract-addresses#transaction-extensions).

Create `multicall3from-abi.json` in your project:

```json multicall3from-abi.json theme={null}
[
  {
    "type": "function",
    "name": "aggregate3",
    "stateMutability": "nonpayable",
    "inputs": [
      {
        "name": "calls",
        "type": "tuple[]",
        "components": [
          { "name": "target", "type": "address" },
          { "name": "allowFailure", "type": "bool" },
          { "name": "callData", "type": "bytes" }
        ]
      }
    ],
    "outputs": [
      {
        "name": "returnData",
        "type": "tuple[]",
        "components": [
          { "name": "success", "type": "bool" },
          { "name": "returnData", "type": "bytes" }
        ]
      }
    ]
  }
]
```

The script you build in the next steps loads this ABI file from the project
root.

## Step 3. Configure the client connection

Create the script file for your client library. The first chunk reads the wallet
and recipient configuration from `.env`, sets the contract addresses, loads the
`Multicall3From` ABI, and creates the clients that read chain state and submit
transactions.

<Tabs>
  <Tab title="Viem">
    Create `viem-batch.ts`:

    ```typescript TypeScript theme={null}
    import "dotenv/config";
    import { readFileSync } from "node:fs";
    import {
      type Address,
      createPublicClient,
      createWalletClient,
      defineChain,
      encodeFunctionData,
      erc20Abi,
      getAddress,
      http,
      parseEventLogs,
      parseUnits,
    } from "viem";
    import { privateKeyToAccount } from "viem/accounts";

    const rpcUrl = process.env.RPC_URL ?? "https://rpc.testnet.arc.io";
    const privateKey = process.env.PRIVATE_KEY as `0x${string}`;
    const recipients = [
      getAddress(process.env.RECIPIENT_ONE_ADDRESS as Address),
      getAddress(process.env.RECIPIENT_TWO_ADDRESS as Address),
    ];

    const arcTestnet = defineChain({
      id: 5042002,
      name: "Arc Testnet",
      nativeCurrency: { name: "USDC", symbol: "USDC", decimals: 18 },
      rpcUrls: { default: { http: [rpcUrl] } },
      blockExplorers: {
        default: { name: "Block Explorer", url: "https://explorer.testnet.arc.io" },
      },
      testnet: true,
    });

    const multicall3FromAddress = "0x522fAf9A91c41c443c66765030741e4AaCe147D0";
    const usdcAddress = "0x3600000000000000000000000000000000000000";
    const multicall3FromAbi = JSON.parse(
      readFileSync("multicall3from-abi.json", "utf8"),
    );

    const account = privateKeyToAccount(privateKey);
    const publicClient = createPublicClient({
      chain: arcTestnet,
      transport: http(rpcUrl),
    });
    const walletClient = createWalletClient({
      account,
      chain: arcTestnet,
      transport: http(rpcUrl),
    });
    ```
  </Tab>

  <Tab title="ethers.js">
    Create `ethers-batch.ts`:

    ```typescript TypeScript theme={null}
    import "dotenv/config";
    import { readFileSync } from "node:fs";
    import { ethers } from "ethers";

    const rpcUrl = process.env.RPC_URL ?? "https://rpc.testnet.arc.io";
    const privateKey = process.env.PRIVATE_KEY as string;
    const recipients = [
      ethers.getAddress(process.env.RECIPIENT_ONE_ADDRESS as string),
      ethers.getAddress(process.env.RECIPIENT_TWO_ADDRESS as string),
    ];

    const multicall3FromAddress = "0x522fAf9A91c41c443c66765030741e4AaCe147D0";
    const usdcAddress = "0x3600000000000000000000000000000000000000";
    const explorerUrl = "https://explorer.testnet.arc.io";

    const multicall3FromAbi = JSON.parse(
      readFileSync("multicall3from-abi.json", "utf8"),
    );
    const erc20Abi = [
      "function transfer(address to, uint256 amount) returns (bool)",
      "event Transfer(address indexed from, address indexed to, uint256 value)",
    ];

    const provider = new ethers.JsonRpcProvider(rpcUrl, {
      chainId: 5042002,
      name: "arc-testnet",
    });
    const wallet = new ethers.Wallet(privateKey, provider);
    const multicall3FromInterface = new ethers.Interface(multicall3FromAbi);
    const erc20Interface = new ethers.Interface(erc20Abi);
    ```
  </Tab>

  <Tab title="Python">
    Create `python-batch.py`:

    ```python Python theme={null}
    import json
    import os

    from dotenv import load_dotenv
    from web3 import Web3
    from web3.logs import DISCARD

    load_dotenv()

    rpc_url = os.getenv("RPC_URL", "https://rpc.testnet.arc.io")
    private_key = os.environ["PRIVATE_KEY"]
    recipients = [
        Web3.to_checksum_address(os.environ["RECIPIENT_ONE_ADDRESS"]),
        Web3.to_checksum_address(os.environ["RECIPIENT_TWO_ADDRESS"]),
    ]

    multicall3_from_address = Web3.to_checksum_address(
        "0x522fAf9A91c41c443c66765030741e4AaCe147D0"
    )
    usdc_address = Web3.to_checksum_address("0x3600000000000000000000000000000000000000")
    explorer_url = "https://explorer.testnet.arc.io"

    with open("multicall3from-abi.json", encoding="utf-8") as abi_file:
        multicall3_from_abi = json.load(abi_file)
    erc20_abi = [
        {
            "type": "function",
            "name": "transfer",
            "stateMutability": "nonpayable",
            "inputs": [
                {"name": "to", "type": "address"},
                {"name": "amount", "type": "uint256"},
            ],
            "outputs": [{"name": "", "type": "bool"}],
        },
        {
            "type": "event",
            "name": "Transfer",
            "anonymous": False,
            "inputs": [
                {"name": "from", "type": "address", "indexed": True},
                {"name": "to", "type": "address", "indexed": True},
                {"name": "value", "type": "uint256", "indexed": False},
            ],
        },
    ]

    w3 = Web3(Web3.HTTPProvider(rpc_url))
    account = w3.eth.account.from_key(private_key)
    multicall3_from = w3.eth.contract(
        address=multicall3_from_address,
        abi=multicall3_from_abi,
    )
    usdc = w3.eth.contract(address=usdc_address, abi=erc20_abi)
    ```
  </Tab>
</Tabs>

The public clients read chain state, the wallet or account objects sign
transactions, and the contract interfaces encode the `Multicall3From` and ERC-20
calls.

## Step 4. Encode the transfer calls

Add a chunk that sets the USDC amount and builds one ERC-20 `transfer(...)`
subcall for each recipient. Each subcall targets the USDC contract, sets
`allowFailure` to `false`, and includes the encoded transfer calldata.

<Tabs>
  <Tab title="Viem">
    ```typescript TypeScript theme={null}
    const amount = parseUnits("1", 6);

    const calls = recipients.map((recipient) => ({
      target: usdcAddress,
      allowFailure: false,
      callData: encodeFunctionData({
        abi: erc20Abi,
        functionName: "transfer",
        args: [recipient, amount],
      }),
    }));
    ```
  </Tab>

  <Tab title="ethers.js">
    ```typescript TypeScript theme={null}
    const amount = ethers.parseUnits("1", 6);

    const calls = recipients.map((recipient) => ({
      target: usdcAddress,
      allowFailure: false,
      callData: erc20Interface.encodeFunctionData("transfer", [recipient, amount]),
    }));
    const aggregateData = multicall3FromInterface.encodeFunctionData("aggregate3", [
      calls,
    ]);
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    amount = 1_000_000

    calls = []
    for recipient in recipients:
        transfer_data = usdc.functions.transfer(
            recipient,
            amount,
        )._encode_transaction_data()
        calls.append(
            (
                usdc_address,
                False,
                bytes.fromhex(transfer_data[2:]),
            )
        )
    ```
  </Tab>
</Tabs>

`1000000` is `1` USDC in base units because the USDC ERC-20 interface uses 6
decimals.

## Step 5. Confirm `Multicall3From` is deployed

Before sending a transaction, check that the configured `Multicall3From` address
has deployed bytecode.

<Tabs>
  <Tab title="Viem">
    ```typescript TypeScript theme={null}
    const multicall3FromCode = await publicClient.getCode({
      address: multicall3FromAddress,
    });
    if (!multicall3FromCode || multicall3FromCode === "0x") {
      throw new Error(`Multicall3From is not deployed at ${multicall3FromAddress}`);
    }
    ```
  </Tab>

  <Tab title="ethers.js">
    ```typescript TypeScript theme={null}
    const multicall3FromCode = await provider.getCode(multicall3FromAddress);
    if (multicall3FromCode === "0x") {
      throw new Error(`Multicall3From is not deployed at ${multicall3FromAddress}`);
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    multicall3_from_code = w3.eth.get_code(multicall3_from_address)
    if multicall3_from_code == b"":
        raise RuntimeError(
            f"Multicall3From is not deployed at {multicall3_from_address}"
        )
    ```
  </Tab>
</Tabs>

If the bytecode check returns empty code, confirm that your `RPC_URL` points to
Arc Testnet and that the address matches the table in Step 2.

## Step 6. Simulate and send the batch

Simulate the `aggregate3(...)` call before sending the transaction. The
simulation confirms that each encoded subcall can succeed from your wallet.

<Tabs>
  <Tab title="Viem">
    ```typescript TypeScript theme={null}
    const simulation = await publicClient.simulateContract({
      account,
      address: multicall3FromAddress,
      abi: multicall3FromAbi,
      functionName: "aggregate3",
      args: [calls],
    });

    const simulatedResults = simulation.result as {
      success: boolean;
      returnData: `0x${string}`;
    }[];
    if (!simulatedResults.every((result) => result.success)) {
      throw new Error(
        `Expected all simulated subcalls to succeed: ${JSON.stringify(
          simulatedResults,
        )}`,
      );
    }

    const hash = await walletClient.writeContract(simulation.request);
    const receipt = await publicClient.waitForTransactionReceipt({ hash });
    if (receipt.status !== "success") {
      throw new Error(`Batched transaction reverted: ${hash}`);
    }
    ```
  </Tab>

  <Tab title="ethers.js">
    ```typescript TypeScript theme={null}
    const [simulatedResults] = multicall3FromInterface.decodeFunctionResult(
      "aggregate3",
      await provider.call({
        from: wallet.address,
        to: multicall3FromAddress,
        data: aggregateData,
      }),
    ) as unknown as [{ success: boolean; returnData: string }[]];
    if (!simulatedResults.every((result) => result.success)) {
      throw new Error(
        `Expected all simulated subcalls to succeed: ${JSON.stringify(
          simulatedResults,
        )}`,
      );
    }

    const tx = await wallet.sendTransaction({
      to: multicall3FromAddress,
      data: aggregateData,
    });
    const receipt = await tx.wait();
    if (!receipt) {
      throw new Error("Transaction was not mined");
    }
    if (receipt.status !== 1) {
      throw new Error(`Batched transaction reverted: ${tx.hash}`);
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    simulated_results = multicall3_from.functions.aggregate3(calls).call(
        {"from": account.address}
    )
    if not all(result[0] for result in simulated_results):
        raise RuntimeError(f"Expected all simulated subcalls to succeed: {simulated_results}")

    latest_block = w3.eth.get_block("latest")
    priority_fee = w3.to_wei(1, "gwei")
    base_fee = latest_block["baseFeePerGas"]

    transaction = multicall3_from.functions.aggregate3(calls).build_transaction(
        {
            "from": account.address,
            "nonce": w3.eth.get_transaction_count(account.address),
            "chainId": w3.eth.chain_id,
            "maxPriorityFeePerGas": priority_fee,
            "maxFeePerGas": (base_fee * 2) + priority_fee,
        }
    )

    signed = account.sign_transaction(transaction)
    tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    if receipt["status"] != 1:
        raise RuntimeError(f"Batched transaction reverted: {Web3.to_hex(tx_hash)}")
    ```
  </Tab>
</Tabs>

The receipt is reused in the next step to check the emitted USDC `Transfer`
events.

## Step 7. Verify the transfer events

Decode the USDC logs from the receipt and confirm that each expected transfer is
present.

<Tabs>
  <Tab title="Viem">
    ```typescript TypeScript theme={null}
    const transferLogs = parseEventLogs({
      abi: erc20Abi,
      eventName: "Transfer",
      logs: receipt.logs.filter(
        (log) => log.address.toLowerCase() === usdcAddress.toLowerCase(),
      ),
    });

    for (const recipient of recipients) {
      const transfer = transferLogs.find(
        (log) =>
          getAddress(log.args.from) === account.address &&
          getAddress(log.args.to) === recipient &&
          log.args.value === amount,
      );

      if (!transfer) {
        throw new Error(`Missing expected USDC Transfer log to ${recipient}`);
      }
    }

    console.log(
      "Transaction:",
      `${arcTestnet.blockExplorers.default.url}/tx/${hash}`,
    );
    console.log("Block:", receipt.blockNumber.toString());
    console.log("Sender:", account.address);
    console.log(
      "Transfers:",
      recipients.map((recipient) => ({
        to: recipient,
        amount: amount.toString(),
      })),
    );
    ```
  </Tab>

  <Tab title="ethers.js">
    ```typescript TypeScript theme={null}
    const transferEvents: ethers.LogDescription[] = [];
    for (const log of receipt.logs) {
      if (log.address.toLowerCase() !== usdcAddress.toLowerCase()) continue;

      const parsed = erc20Interface.parseLog(log);
      if (parsed?.name === "Transfer") transferEvents.push(parsed);
    }

    for (const recipient of recipients) {
      const transfer = transferEvents.find(
        (event) =>
          event.args.from.toLowerCase() === wallet.address.toLowerCase() &&
          event.args.to.toLowerCase() === recipient.toLowerCase() &&
          event.args.value === amount,
      );

      if (!transfer) {
        throw new Error(`Missing expected USDC Transfer log to ${recipient}`);
      }
    }

    console.log("Transaction:", `${explorerUrl}/tx/${tx.hash}`);
    console.log("Block:", receipt.blockNumber);
    console.log("Sender:", wallet.address);
    console.log(
      "Transfers:",
      recipients.map((recipient) => ({
        to: recipient,
        amount: amount.toString(),
      })),
    );
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    transfer_events = usdc.events.Transfer().process_receipt(receipt, errors=DISCARD)
    for recipient in recipients:
        transfer = next(
            (
                event
                for event in transfer_events
                if Web3.to_checksum_address(event["args"]["from"]) == account.address
                and Web3.to_checksum_address(event["args"]["to"]) == recipient
                and event["args"]["value"] == amount
            ),
            None,
        )
        if transfer is None:
            raise RuntimeError(f"Missing expected USDC Transfer log to {recipient}")

    print("Transaction:", f"{explorer_url}/tx/{Web3.to_hex(tx_hash)}")
    print("Block:", receipt["blockNumber"])
    print("Sender:", account.address)
    print(
        "Transfers:",
        [{"to": recipient, "amount": str(amount)} for recipient in recipients],
    )
    ```
  </Tab>
</Tabs>

The `from` value in each expected `Transfer` event is your wallet address. That
check confirms that the target USDC contract saw your wallet as the sender for
each subcall.

## Step 8. Run the script

Run the command for the script you created:

<CodeGroup>
  ```bash viem theme={null}
  npx tsx --env-file=.env viem-batch.ts
  ```

  ```bash ethers.js theme={null}
  npx tsx --env-file=.env ethers-batch.ts
  ```

  ```bash Python theme={null}
  python python-batch.py
  ```
</CodeGroup>

Successful output includes the transaction URL, block number, sender, and both
recipient transfers:

```text theme={null}
Transaction: https://explorer.testnet.arc.io/tx/0x...
Block: 123456
Sender: 0xYourWallet...
Transfers: [
  { to: "0xRecipientOne...", amount: "1000000" },
  { to: "0xRecipientTwo...", amount: "1000000" }
]
```

## Step 9. Check JSON-RPC directly with curl

Use curl for read-only JSON-RPC checks, such as verifying deployed bytecode or
reading a transaction receipt. Use a client library such as viem, ethers.js, or
web3.py to sign and submit the transaction itself.

<CodeGroup>
  ```bash eth_getCode theme={null}
  MULTICALL3FROM_ADDRESS=0x522fAf9A91c41c443c66765030741e4AaCe147D0
  RPC_URL=https://rpc.testnet.arc.io

  curl --request POST "$RPC_URL" \
    --header "content-type: application/json" \
    --data '{
      "jsonrpc": "2.0",
      "method": "eth_getCode",
      "params": ["'"$MULTICALL3FROM_ADDRESS"'", "latest"],
      "id": 1
    }'
  ```

  ```bash eth_getTransactionReceipt theme={null}
  TRANSACTION_HASH=0xYOUR_TRANSACTION_HASH
  RPC_URL=https://rpc.testnet.arc.io

  curl --request POST "$RPC_URL" \
    --header "content-type: application/json" \
    --data '{
      "jsonrpc": "2.0",
      "method": "eth_getTransactionReceipt",
      "params": ["'"$TRANSACTION_HASH"'"],
      "id": 1
    }'
  ```
</CodeGroup>
