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

# Smart Contract Operations

> How to manage sale stages, set allocations, process refunds, and withdraw proceeds on the SettlementSale contract

After a sale's commitment phase closes, you'll need to finalize allocations, process refunds, and withdraw proceeds. This page describes both the available tooling and the underlying contract functions.

This can be done through the Founder Dashboard, but we also provide scripts to perform these operations manually (e.g. if you haven't granted the Sonar backend the necessary roles).

## Available Scripts

Sonar provides TypeScript scripts to manage common post-commitment operations. For full usage instructions, CSV formats, and all available options, see the [Contract Scripts README](https://github.com/sunrisedotdev/sonar/blob/main/contracts/scripts/README.md).

| Script                | Purpose                                                      |
| --------------------- | ------------------------------------------------------------ |
| `commitment-data-csv` | Export all commitment data from the sale contract to a CSV   |
| `set-allocations`     | Set accepted allocation amounts for each entity's wallets    |
| `process-refunds`     | Refund the difference between committed and accepted amounts |

## Typical Workflow

1. **Export commitments** from the contract to analyze bids
2. **Prepare allocations** by creating a CSV with accepted amounts
3. **Validate allocations** using dry-run mode
4. **Submit allocations** to the contract

***

## Contract Function Reference

The following functions are available on the [`SettlementSale`](/sonar/reference/contracts/settlement-sale) contract. Functions marked **Sonar-managed** are called by the Sonar backend automatically; you don't need to call them unless you're operating independently.

### Stage Transitions

#### `openCommitment()`

**Role required**: `SALE_MANAGER_ROLE` | **Stage**: `PreOpen`

Transitions the contract to `Commitment`, enabling participants to submit bids. Called automatically by Sonar after deployment.

#### `openCancellation()`

**Role required**: `SALE_MANAGER_ROLE` | **Stage**: `Commitment`

Transitions to `Cancellation`, allowing participants to cancel their bids and receive immediate refunds. This stage is optional. Skip it by calling `openSettlement()` directly from `Commitment` if no cancellation period is needed.

#### `openSettlement()`

**Role required**: `SALE_MANAGER_ROLE` | **Stage**: `Commitment` or `Cancellation`

Transitions to `Settlement`. Once settlement opens, no further cancellations are possible.

#### `finalizeSettlement(uint256 expectedTotalAcceptedAmount)`

**Role required**: `SETTLEMENT_FINALIZER_ROLE` | **Stage**: `Settlement`

Finalizes settlement and transitions to `Done`. The `expectedTotalAcceptedAmount` must exactly match `totalAcceptedAmount()`. This acts as a sanity check to ensure all allocations are correct before closing settlement.

<Warning>
  Verify `totalAcceptedAmount()` matches your expected total before calling this. The check is exact and the call will revert if there's any discrepancy.
</Warning>

***

### Settlement

#### `setAllocations(Allocation[] allocations, bool allowOverwrite)`

**Role required**: `SETTLER_ROLE` | **Stage**: `Settlement` | **Sonar-managed**

Records the accepted amounts per wallet per payment token. Each `Allocation` specifies:

| Field                  | Type      | Description                                                                                                             |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------- |
| `saleSpecificEntityID` | `bytes16` | The [sale-specific ID](/sonar/core-features/entities#entity-identifiers) for the entity whose wallet is being allocated |
| `wallet`               | `address` | The wallet address to allocate                                                                                          |
| `token`                | `address` | The payment token address                                                                                               |
| `acceptedAmount`       | `uint256` | The accepted amount for this wallet and token                                                                           |

* Accepted amount cannot exceed the wallet's committed amount for that token
* Unset allocations are implicitly zero
* Set `allowOverwrite=true` to modify a previously set allocation; otherwise the call reverts if a non-zero allocation already exists
* Emits `AllocationSet` for each entry

The settler must explicitly set each wallet+token pair. Sonar handles this automatically, but if you hold the `SETTLER_ROLE` you can run settlement independently.

***

### Refunds

#### `processRefunds(bytes16[] saleSpecificEntityIDs, bool skipAlreadyRefunded)`

**Role required**: `REFUNDER_ROLE` | **Stage**: `Done` | **Sonar-managed**

Processes refunds for a batch of entities. For each entity, transfers the difference between committed and accepted amounts back to each wallet, per payment token.

* `saleSpecificEntityIDs`: array of [sale-specific entity IDs](/sonar/core-features/entities#sale-specific-entityid-sale-scoped) to refund
* `skipAlreadyRefunded`: if `true`, skips already-refunded entities; if `false`, reverts if any entity was already refunded
* Emits `WalletRefunded` per wallet+token transfer and `EntityRefunded` for the entity total

Sonar processes refunds automatically. You can also run refunds yourself if you hold the `REFUNDER_ROLE`.

***

### Withdrawals

#### `withdraw()`

**Role required**: `DEFAULT_ADMIN_ROLE` | **Stage**: `Done`

Withdraws all remaining accepted token balances to the `proceedsReceiver`. Safe to call multiple times; only transfers what hasn't been withdrawn yet. Emits `ProceedsWithdrawn` per token.

#### `withdrawPartial(IERC20 token, uint256 amount)`

**Role required**: `DEFAULT_ADMIN_ROLE` | **Stage**: `Done`

Withdraws a specific amount of a specific token to the `proceedsReceiver`. Useful for test withdrawals or incremental processing. Reverts if `amount` exceeds the available (accepted minus already withdrawn) balance for that token.

***

### Operational Controls

#### `pause()`

**Role required**: `PAUSER_ROLE`

Immediately halts all external user-facing functions (bidding, cancellations, refund claims). State and funds are unchanged. Use in emergencies such as suspicious activity, offchain system issues, or payment token depeg.

#### `setPaused(bool isPaused)`

**Role required**: `SALE_MANAGER_ROLE`

Pauses or unpauses the contract. Use to unpause after a `pause()` call.

#### `setClaimRefundEnabled(bool enabled)`

**Role required**: `SALE_MANAGER_ROLE`

Enables or disables self-service refund claiming by participants. If disabled, only addresses with `REFUNDER_ROLE` can process refunds.

#### `setReduceCommitmentEnabled(bool enabled)`

**Role required**: `SALE_MANAGER_ROLE`

Enables or disables partial commitment reduction via `reduceCommitment()` during the Cancellation stage. Full cancellation via `cancelBid()` is always available regardless of this setting.

#### `setProceedsReceiver(address newProceedsReceiver)`

**Role required**: `DEFAULT_ADMIN_ROLE`

Updates the address that receives sale proceeds on withdrawal. Verify this is correct before calling `withdraw()`. Only affects future withdrawals.

#### `setMaxWalletsPerEntity(uint8 max)`

**Role required**: `SALE_MANAGER_ROLE`

Updates the maximum number of wallet addresses a single entity can use. Must be greater than zero. Entities that have already registered more wallets than the new limit are unaffected.

***

### Role Management

#### `grantRole(bytes32 role, address account)`

**Role required**: `DEFAULT_ADMIN_ROLE`

Grants a role to an address. Takes effect immediately. Common uses: granting additional hot wallets `PAUSER_ROLE` for emergency response, or granting a hardware wallet `SALE_MANAGER_ROLE` for stage transitions.

#### `revokeRole(bytes32 role, address account)`

**Role required**: `DEFAULT_ADMIN_ROLE`

Revokes a role from an address. Review and revoke unused role grants after deployment.

***

### Emergency Operations

<Warning>
  The following functions are for exceptional circumstances only. Consult the Sonar team before using them.
</Warning>

#### `unsafeSetStage(Stage newStage)`

**Role required**: `DEFAULT_ADMIN_ROLE`

Forces the contract into any stage, bypassing all normal validation. Use only if the contract is stuck in an unexpected state or there's a critical security issue. Can cause accounting inconsistencies if used carelessly.

#### `forceReduceCommitment(WalletTokenAmount[] reductions)`

**Role required**: `COMMITMENT_REDUCER_ROLE`

Reduces wallet commitments bypassing stage and pause restrictions. Correctly updates all accounting state (committed/cancelled amounts, bid totals, global counters). Prefer this over `recoverTokens()` for committed payment tokens.

#### `recoverTokens(IERC20 token, uint256 amount, address to)`

**Role required**: `TOKEN_RECOVERER_ROLE`

Transfers any ERC20 token from the contract to a specified address. Intended for recovering tokens sent to the contract by mistake. Prefer `forceReduceCommitment()` for committed payment tokens, since it correctly updates accounting state. This role is not granted at deployment. Only grant it if you have a specific recovery need.

***

## Monitoring

Use these view functions to track contract state:

| Function                                   | Description                                                                                                                                                 |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stage()`                                  | Current sale stage. Check before calling any stage transition to confirm the contract is in the expected state.                                             |
| `paymentTokens()`                          | Configured payment token addresses. Useful to verify token configuration after deployment.                                                                  |
| `totalCommittedAmount()`                   | Total committed across all entities and tokens. Check during or after commitment to track overall participation.                                            |
| `totalCommittedAmountByToken()`            | Per-token breakdown of commitments.                                                                                                                         |
| `totalAcceptedAmount()`                    | Total accepted (proceeds) across all tokens. Check this before calling `finalizeSettlement()` — the expected amount must match exactly or the call reverts. |
| `totalAcceptedAmountByToken()`             | Per-token breakdown of accepted amounts.                                                                                                                    |
| `totalCancelledAmount()`                   | Total cancelled during the Cancellation stage across all tokens.                                                                                            |
| `totalCancelledAmountByToken()`            | Per-token breakdown of cancellations.                                                                                                                       |
| `totalRefundedAmount()`                    | Total refunded across all tokens. Check after processing refunds to verify all refunds have been issued.                                                    |
| `totalRefundedAmountByToken()`             | Per-token breakdown of refunds.                                                                                                                             |
| `withdrawnAmount()`                        | Total proceeds already withdrawn. Check before and after calling `withdraw()` to confirm the expected amounts were transferred.                             |
| `withdrawnAmountByToken()`                 | Per-token breakdown of withdrawn proceeds.                                                                                                                  |
| `numEntities()`                            | Number of participating entities. Useful for understanding participation scale and for paginating through entities with `entitiesIn()`.                     |
| `entityAt(index)`                          | Sale-specific entity ID at a given index.                                                                                                                   |
| `entitiesIn(from, to)`                     | Sale-specific entity IDs in an index range. Use with `numEntities()` to paginate through all participants.                                                  |
| `entityStatesByIDs(saleSpecificEntityIDs)` | Full entity state including all wallet states. Use to inspect specific entities' commitments, allocations, and refund status.                               |
| `entityStatesIn(from, to)`                 | Entity states in an index range. Use to export or audit all entity states in bulk.                                                                          |
| `walletStatesByAddresses(addresses)`       | Committed and accepted amounts per token for wallets. Use to debug or verify specific participants' state.                                                  |
| `paused()`                                 | Whether the contract is paused.                                                                                                                             |
| `claimRefundEnabled()`                     | Whether self-service refund claiming is enabled.                                                                                                            |
| `reduceCommitmentEnabled()`                | Whether partial commitment reduction is enabled during the Cancellation stage.                                                                              |
| `proceedsReceiver()`                       | Address that will receive proceeds. Verify this is correct before calling `withdraw()`.                                                                     |
| `maxWalletsPerEntity()`                    | Maximum wallets per entity.                                                                                                                                 |

***

## See Also

<CardGroup cols={2}>
  <Card title="SettlementSale Reference" href="/sonar/reference/contracts/settlement-sale" icon="file-code">
    Contract overview, roles, and key concepts
  </Card>

  <Card title="Settlement Strategies" href="/sonar/planning/settlement-strategies" icon="scale-balanced">
    How allocations are computed offchain
  </Card>
</CardGroup>
