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

# Quickstart

> Create a smart account and send your first crosschain transaction with the Rhinestone SDK.

Create a smart account, fund it on Base Sepolia, and send USDC on Arbitrum Sepolia.

## Prerequisites

Run this example in a secure server-side environment. You need:

* A `RHINESTONE_API_KEY` from the [Rhinestone dashboard](https://dashboard.rhinestone.dev)
* A funding account with Base Sepolia ETH and its private key in `FUNDING_PRIVATE_KEY`

Get Base Sepolia ETH from the [QuickNode faucet](https://faucet.quicknode.com/drip) or [Alchemy faucet](https://www.alchemy.com/faucets). Keep both environment variables private.

Install the public SDK release used by this guide:

<CodeGroup>
  ```bash npm theme={null}
  npm install viem@^2.55.0 @rhinestone/sdk@2.16.1 && npm install --save-dev tsx @types/node
  ```

  ```bash pnpm theme={null}
  pnpm add viem@^2.55.0 @rhinestone/sdk@2.16.1 && pnpm add --save-dev tsx @types/node
  ```

  ```bash bun theme={null}
  bun add viem@^2.55.0 @rhinestone/sdk@2.16.1 && bun add --dev tsx @types/node
  ```
</CodeGroup>

Create `quickstart.ts` and paste the TypeScript blocks below into it in order. The blocks form one complete script.

<Steps>
  <Step title="Create an account">
    Create a smart account with a generated ECDSA owner:

    ```ts theme={null}
    import { RhinestoneSDK } from '@rhinestone/sdk'
    import {
      createPublicClient,
      createWalletClient,
      encodeFunctionData,
      erc20Abi,
      http,
      parseEther,
      parseUnits,
      type Hex,
    } from 'viem'
    import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
    import { arbitrumSepolia, baseSepolia } from 'viem/chains'

    const apiKey = process.env.RHINESTONE_API_KEY
    const fundingPrivateKey = process.env.FUNDING_PRIVATE_KEY

    if (!apiKey || !fundingPrivateKey) {
      throw new Error('RHINESTONE_API_KEY and FUNDING_PRIVATE_KEY are required')
    }

    const sourceChain = baseSepolia
    const targetChain = arbitrumSepolia
    const ownerPrivateKey = generatePrivateKey()
    const owner = privateKeyToAccount(ownerPrivateKey)

    const rhinestone = new RhinestoneSDK({
      auth: { mode: 'apiKey', apiKey },
    })
    const account = await rhinestone.createAccount({
      owners: {
        type: 'ecdsa',
        accounts: [owner],
      },
    })
    const address = account.getAddress()

    console.log('Smart account address:', address)
    ```

    Store `ownerPrivateKey` securely if you need to access this account again. The owner key determines the counterfactual account address.

    Nothing is onchain yet. The account deploys lazily on each chain when it first sends a transaction there.
  </Step>

  <Step title="Fund the account">
    Send Base Sepolia ETH to the smart account:

    ```ts theme={null}
    const publicClient = createPublicClient({
      chain: sourceChain,
      transport: http(),
    })
    const fundingAccount = privateKeyToAccount(fundingPrivateKey as Hex)
    const fundingClient = createWalletClient({
      account: fundingAccount,
      chain: sourceChain,
      transport: http(),
    })

    const txHash = await fundingClient.sendTransaction({
      to: address,
      value: parseEther('0.001'),
    })
    await publicClient.waitForTransactionReceipt({ hash: txHash })
    ```
  </Step>

  <Step title="Send a crosschain transaction">
    Transfer 0.1 USDC on Arbitrum Sepolia, using the ETH funded on Base Sepolia as the source:

    ```ts {25-28} theme={null}
    const usdcAmount = parseUnits('0.1', 6)
    const arbitrumSepoliaUsdc = '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d'
    const recipient = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'

    const prepared = await account.prepareTransaction({
      sourceChains: [sourceChain],
      targetChain,
      calls: [
        {
          to: arbitrumSepoliaUsdc,
          value: 0n,
          data: encodeFunctionData({
            abi: erc20Abi,
            functionName: 'transfer',
            args: [recipient, usdcAmount],
          }),
        },
      ],
      tokenRequests: [
        {
          address: arbitrumSepoliaUsdc,
          amount: usdcAmount,
        },
      ],
    })
    const signed = await account.signTransaction(prepared)
    const submitted = await account.submitTransaction(signed)
    const result = await account.waitForExecution(submitted)

    console.log('Result:', result)
    ```

    `submitTransaction` returns an intent handle. `waitForExecution` resolves after every operation reaches a terminal state.
  </Step>
</Steps>

Run the completed script:

```bash theme={null}
npx tsx quickstart.ts
```

## Expected outcome

The result has the status `COMPLETED`. The account is deployed on Base Sepolia and Arbitrum Sepolia, and 0.1 USDC is transferred to the recipient on Arbitrum Sepolia.

## Next steps

<CardGroup cols={3}>
  <Card title="Configure the account" icon="settings" href="/wallets/custom-signer/account-setup/create-an-account">
    Choose an owner and account implementation.
  </Card>

  <Card title="Send another transaction" icon="arrow-right" href="/transactions/multichain/send-a-transaction">
    Learn the complete multichain transaction flow.
  </Card>

  <Card title="Sponsor fees" icon="fuel" href="/transactions/sponsorship/set-up">
    Cover selected transaction costs for your users.
  </Card>
</CardGroup>
