Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
0.1.0 - 2026-10-09
First release of the ckSOL minter, which mints ckSOL on the ckSOL ledger for SOL deposited on Solana and sends SOL back when ckSOL is burned. It is deployed on staging against Solana Devnet as ckDevnetSOL.
Added
- Deposit addresses:
get_deposit_addressderives a Solana deposit address for any ICRC-1 account, as an update call so that it can later depend on state without a breaking change. The minter’s own main address is derived separately from the master key, so no account can obtain it as a deposit address (#3, #183, #227) - Deposits:
deposit_solreads the finalized balance of the given account’s deposit address and queues it for a sweep, charging the attached cycles for the RPC call plus thedeposit_sol_fee. It rejects balances belowminimum_deposit_amount, and a second call while a deposit for the same account is in flight.deposit_sol_statusfollows a deposit throughQueued,Swept,FinalizedandMinted, orDroppedandQuarantinedon the unhappy paths (#5, #25, #208, #210, #211, #212) - Sweeps: a timer sweeps up to ten queued deposits into the main address per transaction. Once the transaction is finalized, the minter checks its outcome against the planned transfers, credits what the main address received and mints ckSOL for each deposit, with the sweep signature and deposit id in the mint memo. Sweeps that fail or expire are dropped and can be retried with
deposit_sol; sweeps whose outcome does not match the plan are quarantined and nothing is minted (#213, #214, #218, #220, #222, #230, #232) - Withdrawals:
withdraw_solburns ckSOL through an ICRC-2 approval and queues a transfer of the amount minuswithdrawal_fee;withdraw_sol_statusreportsPending,TxSentandTxFinalized. Amounts belowminimum_withdrawal_amountare rejected, and so are destinations that could never receive the transfer or would corrupt the minter’s accounting: reserved account keys such as sysvars and builtin programs, the minter’s main address, and its nonce accounts (#9, #13, #18, #29, #46, #109, #243, #262) - Durable-nonce withdrawals: queued withdrawals are batched up to ten per transaction, each built on a durable nonce account from a pool configured through the init and upgrade arguments, so a withdrawal transaction never expires. Nonce accounts can only be added, and each is verified on read. A transaction that does not reach the chain is re-broadcast unchanged, and a withdrawal is finalized from the state of its nonce account, which unlike the transaction history stays readable indefinitely. Only withdrawals the main address can pay for, including the transaction fee, are submitted (#84, #115, #202, #241, #244, #248, #252, #255, #257, #258, #260)
- Event log: every state change is recorded as an event and replayed on upgrade, and
get_eventsexposes the log. The minter’s public key is recorded on first fetch, so it is available immediately after an upgrade (#8, #20, #26, #65, #67, #70, #235) - Configuration: init and upgrade arguments for the SOL RPC canister, the ledger, the threshold key, the Solana network, fees, minimum amounts and nonce accounts, and
get_minter_infoto read them together with the minter’s balance and main address (#7, #10, #83, #86) - Observability: structured canister logs, Prometheus metrics at
/metrics, including the age of the oldest in-flight deposit and withdrawal for alerting, and a dashboard at/dashboardwith the minter’s metadata, minted and quarantined deposits, and withdrawals (#10, #64, #72, #90, #114, #127, #140, #152, #237) - Reproducible build: the release wasm is built in Docker and its SHA-256 can be checked against the published one (#80)
Fixed
- Trust RPC responses only for what was asked: a
getTransactionresponse must contain the queried transaction, andgetSignatureStatusessearches the transaction history, so a landed transaction is not reported as unknown once it leaves the recent status cache (#236, #239) - Tolerate concurrent first fetches of the master public key, which used to trap the second caller (#226)
- Fixes from a full deposit and withdrawal round trip and a deposit stress test on staging (#263)