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

# Send transactions with Swift

> Submit EVM transactions and Solana transfers through the Swift SDK transaction lifecycle.

Transaction writes require an active wallet session. `sendTransaction` and `callContract` are alternate inputs to one lifecycle: prepare, resolve any fee requirement, execute, and wait for status by default.

## Send native value

Amounts are raw base-unit integer strings. Use `parseUnits` to convert display values without floating-point arithmetic.

```swift theme={null}
let value = try parseUnits(value: "0.01", decimals: 18)

let transaction = try await omsWallet.wallet.sendTransaction(
    network: .polygonAmoy,
    to: "0x1111111111111111111111111111111111111111",
    value: value
)

print(transaction.txnId)
print(transaction.txnHash ?? "Hash not available yet")
```

The default transaction mode is `.relayer`, and `waitForStatus` defaults to `true`.

## Send encoded calldata

Use `SendTransactionRequest` when you already have calldata. `value` remains a raw base-unit string.

```swift theme={null}
let transaction = try await omsWallet.wallet.sendTransaction(
    network: .polygonAmoy,
    request: SendTransactionRequest(
        to: "0x2222222222222222222222222222222222222222",
        value: "0",
        data: "0xa9059cbb000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000f4240"
    )
)
```

`parseUnits` defaults to 18 decimals and rounds excess fractional precision to the nearest base unit. Invalid values and negative decimal counts throw `UnitConversionError`.

## Call an ABI method

Use `callContract` when you have a method signature and typed arguments instead of encoded calldata.

```swift theme={null}
let amount = try parseUnits(value: "1", decimals: 6)

let transaction = try await omsWallet.wallet.callContract(
    network: .polygonAmoy,
    contract: "0x2222222222222222222222222222222222222222",
    method: "transfer(address,uint256)",
    args: [
        AbiArg(
            type: "address",
            value: .string("0x1111111111111111111111111111111111111111")
        ),
        AbiArg(type: "uint256", value: .string(amount))
    ]
)
```

Both forms prepare and execute through the same fee and status code path.

## Send a Solana transfer

Use `sendSolanaTransfer` with a selected Solana wallet. Set `asset` to `SOL` for a native transfer or to an SPL token mint address. `amount` is an integer string in the asset's smallest unit: lamports for SOL or base units for an SPL token.

```swift theme={null}
let transaction = try await omsWallet.wallet.sendSolanaTransfer(
    network: .devnet,
    asset: "SOL",
    to: "3gFktQX6vki5M2DzN8Y1ESPUJ4fJ8o6hVQWf8vYvPypD",
    amount: "1000000"
)
```

For an SPL transfer, `to` is the recipient wallet address, not an associated token account. Solana transfers accept the same execution mode, fee selector, wait setting, and polling options.

## Resolve fees during preparation

Preparation tells the SDK whether the transaction is sponsored. When you provide a selector, a sponsored preparation calls it with an empty array. Return `nil` to continue with the sponsored transaction, or throw to stop execution. `.firstAvailable` handles the empty array. An unsponsored preparation must include fee options.

Whether a transaction is sponsored is decided by your project's settings, not by your application. See [Gas Sponsorship](/wallets/gas-sponsorship).

With no selector, the SDK chooses the first fee option returned by OMS. This default does not compare the option with the wallet's balance.

Use `.firstAvailable` to query indexer balances and choose the first option whose raw available balance covers its quoted fee.

```swift theme={null}
let transaction = try await omsWallet.wallet.sendTransaction(
    network: .polygon,
    to: "0x1111111111111111111111111111111111111111",
    value: "0",
    selectFeeOption: .firstAvailable
)
```

Use a custom selector when your UI or policy chooses the fee token.

```swift theme={null}
let transaction = try await omsWallet.wallet.sendTransaction(
    network: .polygon,
    to: "0x1111111111111111111111111111111111111111",
    value: "0",
    selectFeeOption: .custom { options in
        options.first { $0.feeOption.token.symbol == "USDC" }?.selection
    }
)
```

`FeeOptionWithBalance.availableRaw` is the base-unit balance used for comparison. `available` is formatted for display when token decimals are known.

<Note>
  These fee-selection examples use Polygon mainnet. Fund the wallet for any returned fee option your app selects.
</Note>

## Interpret the result

`SendTransactionResponse` always contains the OMS `txnId`, the latest `status`, and `statusResolution`. `txnHash` is optional until an onchain hash is available.

| Resolution      | Meaning                                                                                                                                         |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `.resolved`     | Polling observed `.executed`, `.failed`, or an onchain transaction hash. A hash can resolve a response whose latest status is still `.pending`. |
| `.timedOut`     | The polling deadline elapsed. The response contains the last status and hash observed. The transaction may continue.                            |
| `.notRequested` | `waitForStatus` was `false`, so the SDK returned the execute response without polling.                                                          |

A resolved result can still have `status == .failed`. Check both status and resolution.

## Return after execution

Set `waitForStatus: false` when your app wants to persist `txnId` immediately after the execute call and manage status separately.

```swift theme={null}
let submitted = try await omsWallet.wallet.sendTransaction(
    network: .polygonAmoy,
    to: "0x1111111111111111111111111111111111111111",
    value: "0",
    waitForStatus: false
)

let status = try await omsWallet.wallet.getTransactionStatus(
    txnId: submitted.txnId
)
```

`getTransactionStatus` also requires the active wallet session and credential.

To change the default wait, pass `TransactionStatusPollingOptions`. The SDK defaults to a 60-second timeout, uses short initial intervals, and then polls every two seconds.

```swift theme={null}
let transaction = try await omsWallet.wallet.sendTransaction(
    network: .polygonAmoy,
    to: "0x1111111111111111111111111111111111111111",
    value: "0",
    statusPolling: TransactionStatusPollingOptions(
        timeoutMs: 120_000,
        intervalMs: 3_000
    )
)
```

## Handle uncertain execution and cancellation

The SDK preserves `CancellationError` instead of wrapping it. Cancelling a Swift task stops the local SDK operation or status wait. It does not cancel a transaction that may already have been submitted. When your UI needs a cancellable wait with a durable identifier, submit with `waitForStatus: false`, persist `txnId`, and poll in a separate task.

Transaction-specific `OMSWalletError` codes carry recovery context:

```swift theme={null}
do {
    _ = try await omsWallet.wallet.sendTransaction(
        network: .polygonAmoy,
        to: "0x1111111111111111111111111111111111111111",
        value: "0"
    )
} catch is CancellationError {
    // Do not assume cancellation reversed a submitted transaction.
} catch let error as OMSWalletError {
    switch error.code {
    case .transactionExecutionUnconfirmed:
        // Preparation produced txnId, but submission could not be confirmed.
        print("Execution unconfirmed:", error.txnId ?? "unknown")
    case .transactionStatusLookupFailed:
        // Execution was submitted. Retry status lookup with txnId.
        print("Retry status lookup:", error.txnId ?? "unknown")
    default:
        throw error
    }
}
```

Do not automatically resend after `.transactionExecutionUnconfirmed`; the original transaction may have been submitted.
