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).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.
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.| 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
- Export commitments from the contract to analyze bids
- Prepare allocations by creating a CSV with accepted amounts
- Validate allocations using dry-run mode
- Submit allocations to the contract
Contract Function Reference
The following functions are available on theSettlementSale 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.
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 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=trueto modify a previously set allocation; otherwise the call reverts if a non-zero allocation already exists - Emits
AllocationSetfor each entry
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 refundskipAlreadyRefunded: iftrue, skips already-refunded entities; iffalse, reverts if any entity was already refunded- Emits
WalletRefundedper wallet+token transfer andEntityRefundedfor the entity total
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
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
SettlementSale Reference
Contract overview, roles, and key concepts
Settlement Strategies
How allocations are computed offchain