Skip to main content
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.
ScriptPurpose
commitment-data-csvExport all commitment data from the sale contract to a CSV
set-allocationsSet accepted allocation amounts for each entity’s wallets
process-refundsRefund 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 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.
Verify totalAcceptedAmount() matches your expected total before calling this. The check is exact and the call will revert if there’s any discrepancy.

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:
FieldTypeDescription
saleSpecificEntityIDbytes16The sale-specific ID for the entity whose wallet is being allocated
walletaddressThe wallet address to allocate
tokenaddressThe payment token address
acceptedAmountuint256The 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 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

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

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:
FunctionDescription
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

SettlementSale Reference

Contract overview, roles, and key concepts

Settlement Strategies

How allocations are computed offchain