> ## 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 native transfers and contract calls 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.

## Resolve fees during preparation

Preparation tells the SDK whether the transaction is sponsored. Sponsored preparations execute without a fee selection. An unsponsored preparation must include fee options.

Testnet transaction fees are sponsored. On mainnet, the preparation response may instead require fee selection.

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.
