> ## 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.

# Migration guide

## Migrating from 1.x SDK

To use the latest version of the SDK:

```bash theme={null}
npm i @rhinestone/sdk
```

### ESM-only build

The SDK is now ESM-only. `require('@rhinestone/sdk')` no longer works — use ESM `import` syntax. Internal subpath imports were also removed; use the curated entry points (`./actions/*`, `./errors`, `./utils`, `./smart-sessions`, `./jwt-server`).

### `sendTransaction` removed

The `account.sendTransaction(transaction)` shortcut is gone. Use the explicit `prepareTransaction → signTransaction → submitTransaction` flow:

```ts theme={null}
// Before
const result = await rhinestoneAccount.sendTransaction({
  targetChain,
  calls,
  tokenRequests,
})

// After
const prepared = await rhinestoneAccount.prepareTransaction({
  targetChain,
  calls,
  tokenRequests,
})
const signed = await rhinestoneAccount.signTransaction(prepared)
const result = await rhinestoneAccount.submitTransaction(signed)
```

`sendUserOperation` for ERC-4337 flows is unchanged.

### Session permissions are ABI-driven

`Session.actions` is gone. Build sessions with `toSession({ chain, owners, permissions })` instead — an ABI-driven definition the SDK resolves into a low-level `Session`. Each permission is an `{ abi, address, functions }` entry; function selectors and param calldata offsets are derived from the ABI, and param value types are checked against ABI input types:

```ts theme={null}
import { toSession } from '@rhinestone/sdk/smart-sessions'

// Before
const session: Session = {
  chain: base,
  owners: { type: 'ecdsa', accounts: [sessionOwner] },
  actions: [
    {
      target: usdcAddress,
      selector: toFunctionSelector(
        getAbiItem({ abi: erc20Abi, name: 'transfer' }),
      ),
      policies: [
        {
          type: 'universal-action',
          rules: [
            {
              condition: 'equal',
              calldataOffset: 0n,
              referenceValue: recipient,
            },
          ],
        },
      ],
    },
  ],
}

// After
const session = toSession({
  chain: base,
  owners: { type: 'ecdsa', accounts: [sessionOwner] },
  permissions: [
    {
      abi: erc20Abi,
      address: usdcAddress,
      functions: {
        transfer: {
          params: {
            recipient: { condition: 'equal', value: recipient },
          },
        },
      },
    },
  ],
})
```

The hand-written shape is now `SessionDefinition`; `Session` is the resolved output of `toSession`.

### Session policies are declarative

In 1.x, each `action` carried a raw `policies` array that you assembled by hand. Those arrays are gone — policies are now expressed through fields on the permission's function config, and `toSession` compiles them into the right on-chain policies:

* `params: { x: { anyOf: [a, b] } }` — allowlist a parameter against several values (compiles to an arg-policy OR chain). A single `{ condition, value }` stays a cheaper universal-action.
* `maxUses` — cap how many times the function may be called.
* `validUntil` / `validAfter` — restrict the function to a time window (`Date`).
* `valueLimit` — cap cumulative ETH value (payable functions only; rejected at compile time otherwise).
* `spendingLimit: { token, amount }` — cap cumulative ERC-20 spend (only on `transfer` / `transferFrom` / `approve` / `increaseAllowance`-shaped functions).

```ts theme={null}
const session = toSession({
  chain: base,
  owners: { type: 'ecdsa', accounts: [sessionOwner] },
  permissions: [
    {
      abi: erc20Abi,
      address: usdcAddress,
      functions: {
        transfer: {
          params: { recipient: { anyOf: [alice, bob] } },
          spendingLimit: { token: usdcAddress, amount: 1_000_000n },
          maxUses: 10n,
        },
      },
    },
  ],
})
```

Passing a raw `policies` array on a permission now throws instead of being silently dropped. See [Policies](../smart-sessions/policies/sudo) for the full set.

### Session policy addresses

The smart session policies were redeployed, and `toSession` now bakes the new addresses into the session digest by default. If an account already enabled sessions against the previous deployments, trying to use the existing session with the new policies results in an onchain revert due to the digest mismatch.

Pin the affected policies back to the addresses the account was enabled against via `SessionDefinition.policyAddresses`:

```ts theme={null}
const session = toSession({
  chain: base,
  owners: { type: 'ecdsa', accounts: [sessionOwner] },
  permissions: [/* … */],
  policyAddresses: {
    // legacy V1 sudo policy
    sudo: '0x0000003111cD8e92337C100F22B7A9dbf8DEE301',
  },
})
```

The singletons that changed between V1 and V2 — pin the ones your account's sessions were enabled against:

| Policy                                                      | Key               | V1 address                                   | V2 address (default)                         |
| ----------------------------------------------------------- | ----------------- | -------------------------------------------- | -------------------------------------------- |
| [Sudo](../smart-sessions/policies/sudo)                     | `sudo`            | `0x0000003111cD8e92337C100F22B7A9dbf8DEE301` | `0x0000000000FEEc8D74e3143fBaBbca515358d869` |
| [Call](../smart-sessions/policies/call)                     | `universalAction` | `0x0000006DDA6c463511C4e9B05CFc34C1247fCF1F` | `0x0000000000714Cf48FcF88A0bFBa70d313415032` |
| Arg policy                                                  | `argPolicy`       | — (new in V2)                                | `0x0000000000167edE64D8751daACDdC0312565a73` |
| [Spending limit](../smart-sessions/policies/spending-limit) | `spendingLimits`  | `0x00000088D48cF102A8Cdb0137A9b173f957c6343` | `0x000000000033212E272655D8a22402Db819477A6` |
| [Timeframe](../smart-sessions/policies/timeframe)           | `timeFrame`       | `0x8177451511dE0577b911C254E9551D981C26dc72` | `0x0000000000D30f611fA3bf652ac6879428586930` |
| [Usage limit](../smart-sessions/policies/usage-limit)       | `usageLimit`      | `0x1F34eF8311345A3A4a4566aF321b313052F51493` | `0x00000000001d4479FA2A947026204d0283ceDe4B` |
| Value limit                                                 | `valueLimit`      | `0x730DA93267E7E513e932301B47F2ac7D062abC83` | `0x000000000021dC45451291BCDfc9f0B46d6f0278` |

### Quote selection

`prepareTransaction` now returns `quotes: { best, all }` instead of a single `quote`. Existing `prepare → sign → submit` code keeps working — `signTransaction` defaults to `quotes.best`:

```ts theme={null}
const prepared = await rhinestoneAccount.prepareTransaction({
  // …
})
const signed = await rhinestoneAccount.signTransaction(prepared)
const result = await rhinestoneAccount.submitTransaction(signed)
```

To sign a non-default route, pass an `intentId` from `prepared.quotes.all`:

```ts theme={null}
const prepared = await rhinestoneAccount.prepareTransaction({
  // …
})
const chosen =
  prepared.quotes.all.find((q) => q.settlementLayer === 'across') ??
  prepared.quotes.best
const signed = await rhinestoneAccount.signTransaction(prepared, {
  intentId: chosen.intentId,
})
```

`getTransactionMessages(prepared, { intentId })` accepts the same selection so external signers see the route `signTransaction` will sign.

### Settlement layer filter

`settlementLayers` is no longer a bare array. It's a discriminated union with `include` / `exclude` so you can blacklist a single layer without listing all the others:

```ts theme={null}
// Before
await rhinestoneAccount.prepareTransaction({
  // …
  settlementLayers: ['ACROSS', 'ECO'],
})

// After
await rhinestoneAccount.prepareTransaction({
  // …
  settlementLayers: { include: ['ACROSS', 'ECO'] },
})
```

The same shape applies to `splitIntents`. See [Settlement Layers](../chain-abstraction/multi-chain-intent#settlement-layers) for usage patterns.

### `submitTransaction` options bag

`submitTransaction` now takes an options object instead of positional arguments:

```ts theme={null}
// Before
await rhinestoneAccount.submitTransaction(signed, authorizations)

// After
await rhinestoneAccount.submitTransaction(signed, { authorizations })
```

### `waitForExecution` no longer accepts preconfirmations

The `acceptsPreconfirmations` parameter is removed. `waitForExecution` always waits for `FILLED` / `COMPLETED` and never treats `PRECONFIRMED` as terminal:

```ts theme={null}
// Before
await rhinestoneAccount.waitForExecution(result, false)

// After
await rhinestoneAccount.waitForExecution(result)
```

### `verifyExecutions` removed from session signers

`SingleSessionSignerSet`, `PerChainSessionSignerSet`, and `ChainSessionConfig` no longer accept `verifyExecutions`. The SDK now derives it from the session shape — sessions with `permissions` use emissary execution validation, claim-only sessions use the EIP-1271 path — so the flag is redundant. Drop it from your signer set:

```ts theme={null}
// Before
const signers = {
  type: 'experimental_session',
  session,
  verifyExecutions: true,
  enableData,
}

// After
const signers = {
  type: 'experimental_session',
  session,
  enableData,
}
```

### Passport account removed

`account.type: 'passport'` is no longer accepted. The `PassportAccount` type and the `passport` member of `AccountType` / `AccountProviderConfig` are removed.

### Intent status by ID

`getIntentStatus` now takes a `string` instead of a `bigint`. If you persist intent IDs across runs, switch the storage type to string.

### Portfolio shape

`PortfolioToken` no longer carries a token-level `decimals` or aggregate `balances`. `decimals` now lives on each per-chain `chains[]` entry alongside `address` and `amount`, since the same logical token can have different decimals across chains (e.g., USDC is 6 on Ethereum, 18 on BSC). Read the per-chain entry directly when rendering balances.

### Permit2 claim policy renames

If you constructed `Permit2ClaimPolicy` values directly, the type tag and field names changed to be chain-aware:

```ts theme={null}
// Before
const policy: Permit2ClaimPolicy = {
  type: 'permit2-claim',
  arbiters: [spender],
  tokensIn: [{ chainId: base.id, token: usdcAddress }],
  tokensOut: [{ chainId: base.id, token: outputToken }],
  recipients: [{ chainId: base.id, recipient: 'any' }],
  recipientIsSponsor: true,
  expiryBounds: { min: 1n, max: 100n },
  fillExpiryBounds: [{ chainId: base.id, min: 1n, max: 100n }],
}

// After
const policy: Permit2ClaimPolicy = {
  type: 'permit2',
  spenders: [spender],
  sourceTokens: [{ chain: base, address: usdcAddress }],
  destinationTokens: [{ chain: base, address: outputToken }],
  recipients: [{ chain: base, address: 'any' }],
  recipientIsAccount: true,
  permitDeadline: { min: 1n, max: 100n },
  fillDeadline: [{ chain: base, min: 1n, max: 100n }],
}
```

### Token registry helpers removed

`getSupportedTokens`, `getTokenAddress`, `getTokenDecimals`, and `getAllSupportedChainsAndTokens` are removed. Fetch the equivalent data from the orchestrator's `/chains` endpoint:

```ts theme={null}
const response = await fetch('https://v1.orchestrator.rhinestone.dev/chains', {
  headers: { 'x-api-key': apiKey },
})
const chains = await response.json()
```

### `deployAccountsForOwners` removed

Create a backend deployer account, take a view-only reference to each user account, and submit a sponsored intent that calls `deploy(userAccount)`. Pass multiple `deploy(...)` calls in one intent to batch deployments.

```ts theme={null}
import { RhinestoneSDK } from '@rhinestone/sdk'
import { deploy } from '@rhinestone/sdk/actions'
import { toViewOnlyAccount } from '@rhinestone/sdk/utils'

const rhinestone = new RhinestoneSDK({ apiKey })

const deployerAccount = await rhinestone.createAccount({
  owners: { type: 'ecdsa', accounts: [deployerSigner] },
})

const userAccount = await rhinestone.createAccount({
  owners: {
    type: 'ecdsa',
    accounts: [toViewOnlyAccount(userAddress)],
  },
})

const prepared = await deployerAccount.prepareTransaction({
  chain,
  calls: [deploy(userAccount)],
  sponsored: true,
})
const signed = await deployerAccount.signTransaction(prepared)
await deployerAccount.submitTransaction(signed)
```

### `checkERC20AllowanceDirect` removed

Read allowances directly with viem's `readContract`:

```ts theme={null}
const allowance = await publicClient.readContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [owner, spender],
})
```

### ENS validator owner set

`ENSValidatorConfig` couples each owner with its expiry instead of using parallel arrays. Omit `expiration` for an owner that never expires:

```ts theme={null}
// Before — parallel arrays, expirations in unix seconds
const validator = {
  type: 'ens',
  accounts: [alice, bob],
  ownerExpirations: [1893456000, 1893456000],
}

// After — each owner carries its own expiry (omit `expiration` to never expire)
const validator = {
  type: 'ens',
  owners: [
    { account: alice, expiration: new Date('2030-01-01') },
    { account: bob, expiration: new Date('2030-01-01') },
  ],
}
```

### Removed and relocated helpers

* **`createRhinestoneAccount`** is removed. Use `new RhinestoneSDK({ apiKey }).createAccount(config)`.
* **Account recovery.** The `@rhinestone/sdk/actions/recovery` subpackage (`enable`, `recoverEcdsaOwnership`, `recoverPasskeyOwnership`), the `recovery` field on the account config, and the guardian signer set are removed.
* **`account.deploy()` session param.** The unused `session` option on `account.deploy()` is removed (it was a no-op).
* **Compact-bound surface.** The `@rhinestone/sdk/actions/compact` subpackage, the `lockFunds` transaction option, and `Account.emissaryConfig` are removed alongside the orchestrator's compact-based deposit/withdrawal flow.
* **Permit2 signing helpers.** `signPermit2Batch`, `signPermit2Sequential`, and the related `MultiChainPermit2Config` / `MultiChainPermit2Result` / `BatchPermit2Result` types are removed. Signing now uses orchestrator-provided EIP-712 typed data internally.
* **`getPermit2Address`** is removed. Permit2 lives at `0x000000000022D473030F116dDEE9F6B43aC78BA3` on every supported chain — hardcode the constant.
* **`walletClientToAccount` and `wrapParaAccount`** moved from the package root to `@rhinestone/sdk/utils`.

## Migrating from 1.x Alpha SDK

### New entry point

`RhinestoneSDK` is now the main entry point to the SDK functionality.

To migrate, change the account creation code:

```ts theme={null}
const rhinestoneAccount = await createRhinestoneAccount({
  // Optional
  account: {
    'type': 'nexus'
  },
  owners: {
    type: "ecdsa" as const,
    accounts: [owner],
  },
  // …
  // Optional
  rhinestoneApiKey,
  // Optional
  orchestratorUrl,
});
```

to this:

```ts theme={null}
const rhinestone = new RhinestoneSDK({
  apiKey: rhinestoneApiKey,
  // Optional
  endpointUrl: orchestratorUrl,
})
const rhinestoneAccount = await rhinestone.createAccount({
  // Optional
  account: {
    'type': 'nexus'
  },
  owners: {
    type: "ecdsa" as const,
    accounts: [owner],
  },
  // …
});
```

### Transaction utilities (actions)

Action utilities related to using modules and resource locking (e.g., `installModule`, `addOwner`, `recoverEcdsaOwnership`) were moved to separate subpackages:

```ts theme={null}
// Before
import { addPasskeyOwner } from '@rhinestone/sdk'
// After
import { addOwner as addPasskeyOwner } from '@rhinestone/sdk/actions/passkeys'
```

Additionally, you don't need to pass `rhinestoneAccount`, `address`, `chain`, and `provider` params anymore when using actions:

```ts theme={null}
// Before
await rhinestoneAccount.sendTransaction({
  calls: [
    ...installModule({
      rhinestoneAccount,
      module,
    })
  ],
  // …
})

// After
await rhinestoneAccount.sendTransaction({
  calls: [
    // Note that you don't need to spread the actions anymore
    installModule(module)
  ],
  // …
})
```

<Accordion title="All actions">
  * `/actions`:
    * `installModule` to install a module
    * `uninstallModule` to uninstall a module
  * `/actions/compact` (resource locking with TheCompact):
    * `depositEther` to deposit ETH into TheCompact
    * `enableEtherWithdrawal` to enable permissionless ETH withdrawal (starts reset period)
    * `disableEtherWithdrawal` to cancel permissionless ETH withdrawal
    * `withdrawEther` to withdraw ETH after the reset period
    * `approveErc20` to approve an ERC-20 token for deposit
    * `depositErc20` to deposit ERC-20 into TheCompact
    * `enableErc20Withdrawal` to enable permissionless ERC-20 withdrawal (starts reset period)
    * `disableErc20Withdrawal` to cancel permissionless ERC-20 withdrawal
    * `withdrawErc20` to withdraw ERC-20 after the reset period
  * `/actions/ecdsa` (ECDSA validator):
    * `enable` to enable the validator
    * `disable` to disable the validator
    * `addOwner` to add an owner
    * `removeOwner` to remove an owner
    * `changeThreshold` to change the signature threshold
  * `/actions/mfa` (multi-factor authorization):
    * `enable` to enable the validator
    * `disable` to disable the validator
    * `setSubValidator` to add a sub-validator to the MFA set
    * `removeSubValidator` to remove a sub-validator from the MFA set
    * `changeThreshold` to change the MFA signature threshold
  * `/actions/passkeys` (passkey validator):
    * `enable` to enable the validator
    * `disable` to disable the validator
    * `addOwner` to add an owner
    * `removeOwner` to remove an owner
    * `changeThreshold` to change the signature threshold
  * `/actions/recovery` (social recovery):
    * `enable` to enable the validator
    * `recoverEcdsaOwnership` to recover ownership to a new ECDSA owner
    * `recoverPasskeyOwnership` to recover ownership to a new passkey owner
</Accordion>

### Errors

Error classes were moved to a separate subpackage:

```ts theme={null}
// Before
import { isAccountError, AccountError, SigningNotSupportedForAccountError } from '@rhinestone/sdk'
// After
import { isAccountError, AccountError, SigningNotSupportedForAccountError } from '@rhinestone/sdk/errors'
```

### Using ERC-4337 flow

All transactions executed with `sendTransaction` and `prepareTransaction` now use Rhinestone intents.

Using the ERC-4337 user operations (for example, when using a social recovery) now requires a separate flow.

This change lets us improve type-safety and DX around using intents.

To keep using user operations for specific flows, change your code from:

```ts theme={null}
const result = await rhinestoneAccount.sendTransaction(
  // …
)
```

and

```ts theme={null}
const data = await rhinestoneAccount.prepareTransaction({
  // …
})
const signedData = await rhinestoneAccount.signTransaction(data)
const result = await rhinestoneAccount.submitTransaction(signedData)
```

to:

```ts theme={null}
const result = await rhinestoneAccount.sendUserOperation(
  // …
)
```

and:

```ts theme={null}
const data = await rhinestoneAccount.prepareUserOperation({
  // …
})
const signedData = await rhinestoneAccount.signUserOperation(data)
const result = await rhinestoneAccount.submitUserOperation(signedData)
```

## Migrating from 0.x SDK

To use the latest version of the SDK, install it with the `alpha` tag:

```bash theme={null}
npm i @rhinestone/sdk@alpha
```

Note that the `deployerAccount` parameter has been removed, as all deployments are now handled via [the Orchestrator](../../home/introduction/rhinestone-intents#the-orchestrator).

Also, `sourceChains` now accepts a list of chains instead of a single chain.

<Info>Due to the module address changes, you'd need to redeploy and refund the accounts.</Info>

## Migrating from Orchestrator SDK

This guide provides a detailed breakdown of the changes between the Orchestrator SDK and the new SDK. If you're looking for a fresh start, see our [Quickstart](../quickstart).

### Installation

Previously:

```bash theme={null}
npm i @rhinestone/module-sdk @rhinestone/orchestrator-sdk permissionless viem
```

Now:

```bash theme={null}
npm i @rhinestone/sdk viem
```

### Account Creation

#### Choosing an account implementation

Before, you'd need to construct a smart account client with `permissionless`:

```ts theme={null}
const sourceSafeAccount = await toSafeSmartAccount({
  version: "1.4.1",
  entryPoint: {
    address: entryPoint07Address,
    version: "0.7",
  },
  // …
});
 
const smartAccountClient = createSmartAccountClient({
  account: sourceSafeAccount,
  chain: sourceChain,
  // …
}).extend(erc7579Actions());
```

Now:

```ts theme={null}
const account = await createRhinestoneAccount({
  account: {
    type: 'safe'
  }
})
```

<Info>The `account` object is multi-chain; you don't need to create separate instances for each chain.</Info>

See [Smart Account Providers](../customize/smart-account-providers) for details on choosing the account implementation.

#### Choosing a validator

Before, you'd specify the validator config in your smart account setup:

```ts theme={null}
const owner = privateKeyToAccount(generatePrivateKey());

const ownableValidator = getOwnableValidator({
  owners: [owner.address],
  threshold: 1,
});

const sourceSafeAccount = await toSafeSmartAccount({
  validators: [
    {
      address: ownableValidator.address,
      context: ownableValidator.initData,
    },
  ],
  // …
});

const sourceSmartAccountClient = createSmartAccountClient({
  account: sourceSafeAccount,
  chain: sourceChain,
  bundlerTransport: http(
    `https://api.pimlico.io/v2/${sourceChain.id}/rpc?apikey=${pimlicoApiKey}`,
  ),
  paymaster: sourcePimlicoClient,
  userOperation: {
    estimateFeesPerGas: async () => {
      return (await sourcePimlicoClient.getUserOperationGasPrice()).fast;
    },
  },
}).extend(erc7579Actions());
```

Now, you can use `owners` when creating the account:

```ts theme={null}
const owner = privateKeyToAccount(generatePrivateKey());

const account = await createRhinestoneAccount({
  owners: {
    type: 'ecdsa',
    accounts: [owner],
  },
})
```

Learn more about using the [ECDSA](../core/ecdsa-signer) and [passkey](../core/passkeys) validators as the account owner.

If you are using Smart Sessions, see the relevant [guide](../smart-sessions/overview).

#### Setting up Omni Account modules

Before, you'd need to provide the module configurations for the Omni Account manually:

```ts theme={null}
const sourceSafeAccount = await toSafeSmartAccount({
  // …
  executors: [
    {
      address: getSameChainModuleAddress(targetChain.id),
      context: "0x",
    },
    {
      address: getTargetModuleAddress(targetChain.id),
      context: "0x",
    },
    {
      address: getHookAddress(targetChain.id),
      context: "0x",
    },
  ],
  hooks: [
    {
      address: getHookAddress(targetChain.id),
      context: encodeAbiParameters(
        [
          { name: "hookType", type: "uint256" },
          { name: "hookId", type: "bytes4" },
          { name: "data", type: "bytes" },
        ],
        [
          0n,
          "0x00000000",
          encodeAbiParameters([{ name: "value", type: "bool" }], [true]),
        ],
      ),
    },
  ],
  fallbacks: [
    {
      address: getTargetModuleAddress(targetChain.id),
      context: encodeAbiParameters(
        [
          { name: "selector", type: "bytes4" },
          { name: "flags", type: "bytes1" },
          { name: "data", type: "bytes" },
        ],
        ["0x3a5be8cb", "0x00", "0x"],
      ),
    },
  ],
});
```

Now, that is handled automatically for you.

<Info>Under the hood, the SDK installs a single executor module that handles chain abstraction operations.</Info>

### Initializing the Orchestrator Client

Before, you'd initialize an Orchestrator API client:

```ts theme={null}
const orchestrator = getOrchestrator(orchestratorApiKey);
```

Now, you need to pass the API key directly to the account instance:

```ts theme={null}
const account = privateKeyToAccount(generatePrivateKey());

const account = await createRhinestoneAccount({
  rhinestoneApiKey: orchestratorApiKey,
  // …
})
```

### Funding

As before, you can send the tokens or ETH directly to the account to fund it.

### Deploying

Before, you'd deploy the smart account using an ERC-4337 bundler:

```ts theme={null}
const opHash = await sourceSmartAccountClient.sendTransaction({
  to: zeroAddress,
  data: "0x11111111",
});

await sourcePublicClient.waitForTransactionReceipt({
  hash: opHash,
});
```

Now, you can use the `deploy` method:

```ts theme={null}
await rhinestoneAccount.deploy(chain)
```

### Fetching the Order Path

Before, you define the intent and use `getOrderPath` to get the path.

```ts theme={null}
const usdcAddress = getTokenAddress("USDC", targetChain.id);
const usdcAmount = 2n;
const recipient = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045';

const metaIntent: MetaIntent = {
  targetChainId: targetChain.id,
  tokenRequests: [
    {
      tokenAddress: usdcAddress,
      amount: usdcAmount,
    },
  ],
  targetAccount: targetSafeAccount.address,
  targetExecutions: [
    {
      to: usdcAddress,
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "transfer",
        args: [recipient, usdcAmount],
      }),
    },
  ],
};

const orderPath = await orchestrator.getOrderPath(
  metaIntent,
  targetAccount.address,
);
```

Now, you can call `prepareTransaction`:

```ts theme={null}
const usdcAmount = 2n;
const recipient = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045';

const transactionData = await rhinestoneAccount.prepareTransaction({
  targetChain,
  calls: [
    {
      to: 'USDC',
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: 'transfer',
        args: [recipient, usdcAmount],
      }),
    },
  ],
  tokenRequests: [
    {
      address: 'USDC',
      amount: usdcAmount,
    },
  ],
})
```

### Signing the Intent

Before, you'd craft the packed signature and pass that to the bundle structure:

```ts theme={null}
const orderBundleHash = getOrderBundleHash(orderPath[0].orderBundle);
 
const bundleSignature = await owner.signMessage({
  message: { raw: orderBundleHash },
});
const packedSig = encodePacked(
  ["address", "bytes"],
  [ownableValidator.address, bundleSignature],
);
 
const signedOrderBundle: SignedMultiChainCompact = {
  ...orderPath[0].orderBundle,
  originSignatures: Array(orderPath[0].orderBundle.segments.length).fill(
    packedSig,
  ),
  targetSignature: packedSig,
};
```

Now, you can use the `signTransaction` method:

```ts theme={null}
const signedTransactionData =
  await rhinestoneAccount.signTransaction(transactionData)
```

### Sending the Intent

Before, you'd use the `postSignedOrderBundle` to submit the intent to the orchestrator:

```ts theme={null}
const bundleResults: PostOrderBundleResult = await orchestrator.postSignedOrderBundle([
  {
    signedOrderBundle,
  },
]);
```

Now, you can use the `submitTransaction` method:

```ts theme={null}
const result = await rhinestoneAccount.submitTransaction(signedTransactionData)
```

### Getting the Intent Status

Before, you'd poll the `getBundleStatus` method to get bundle status updates:

```ts theme={null}
const bundleStatus = await orchestrator.getBundleStatus(
  bundleResults[0].bundleId,
);
```

Now, you can use the `waitForExecution` method:

```ts theme={null}
const status = await rhinestoneAccount.waitForExecution(result)
```

### Using with Existing Accounts

For now, using the SDK with existing accounts is not possible. Users would need to create a new smart account.

We're working on making it possible to use the SDK with existing (deployed) smart accounts.

[Reach out](http://t.me/kurt_larsen) if you need this.
