Skip to content

chore: Adding the architecture documentation#186

Draft
THLO wants to merge 9 commits intomainfrom
tl/add_architecture_documentation
Draft

chore: Adding the architecture documentation#186
THLO wants to merge 9 commits intomainfrom
tl/add_architecture_documentation

Conversation

@THLO
Copy link
Copy Markdown
Contributor

@THLO THLO commented Apr 27, 2026

This PR adds the architecture documentation as the single source of truth for the design of the ckSOL canister suite, in particular the ckSOL minter.

Copilot AI review requested due to automatic review settings April 27, 2026 15:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds architecture documentation intended to serve as the design reference for the ckSOL canister suite (especially the ckSOL minter).

Changes:

  • Added a comprehensive ARCHITECTURE.md describing deposit/withdrawal flows, fee model, and operational mechanisms.
  • Added EXAMPLE_TRANSACTION.md containing a concrete Solana deposit transaction example and corresponding RPC output.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 13 comments.

File Description
ARCHITECTURE.md New end-to-end architecture/design document for ckSOL minter + ledger interactions and Solana RPC usage.
EXAMPLE_TRANSACTION.md New reference example of a Solana deposit transaction and getTransaction response payload.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md Outdated
Comment on lines +101 to +106
In order to mitigate the risk of a denial-of-service attack, each account has a certain **quota** for the automatic flow, which consists of a quota for `getSignaturesForAddress` calls and a quota for `getTransaction` calls. Initially, the quotas are `MAX_GET_SIGNATURES_CALLS` and `MAX_RETRIEVED_TRANSACTIONS`, respectively. Calls of either type are only made if there is a positive remaining quota.

Since each IC account gets a newly derived deposit address, these addresses are likely involved in deposits only, i.e., there should not be many `getTransaction` calls in vain in the common case. Whenever there is a successful call that results in a mint, both quotas are increased by 2 for the following reason: They are both bumped by 1 so that calls that result in a mint do not count against the quotas. The additional bump of each quota serves to ensure that an occasional call that does not result in a mint operation does not slowly drain the free quota. Note that RPC calls may sporadically fail for various reasons such as network issues or RPC providers being unavailable. There is a ceiling of `MAX_GET_SIGNATURES_CALLS` and `MAX_RETRIEVED_TRANSACTIONS` for the `getSignaturesForAddress` quota and the `getTransaction` quota, respectively.
The mechanism to replenish a depleted quota is discussed in the next section.

The quota is meant as a deterrent but does not stop an attacker from triggering many `getTransaction` calls for different addresses. In order to limit the impact of such an attack, the constant `MAX_MONITORED_ADDRESSES` specifies the global limit on the number of addresses for which automatic deposits are allowed at any given time. This constant also limits the memory consumption. Furthermore, `update_balance` only takes a subaccount parameter, i.e., it is not possible to call the function for other principals, preventing drainage attacks against the quotas of other users.
THLO and others added 2 commits April 27, 2026 17:42
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 27, 2026 15:44
THLO and others added 2 commits April 27, 2026 17:45
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces architecture documentation intended to be the single source of truth for the ckSOL canister suite design (with emphasis on the ckSOL minter), and adds a concrete Solana deposit transaction example used by the docs.

Changes:

  • Added ARCHITECTURE.md describing deposit/withdrawal flows, timers/quotas, consolidation, fees, and the exposed API.
  • Added EXAMPLE_TRANSACTION.md with a real getTransaction RPC example and response payload for a SOL deposit transaction.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
ARCHITECTURE.md New end-to-end architecture/spec doc for ckSOL minter flows, parameters, and public API.
EXAMPLE_TRANSACTION.md Reference Solana transaction + RPC output used by the architecture doc.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ARCHITECTURE.md
Comment thread ARCHITECTURE.md Outdated
Comment on lines +402 to +407
1. `get_deposit_address(opt principal, opt subaccount)`: Returns the Solana address derived from the provided principal ID and subaccount. If no principal ID is provided, the principal ID of the caller is used.
2. `update_balance(opt subaccount)`: Returns `ok` if the address derived from the caller’s principal ID and the provided subaccount, if any, is being tracked.
3. `process_deposit(opt principal, opt subaccount, signature)`: Processes the transaction for the given signature. If the transaction is processed successfully, the deposit status is returned. Otherwise, an error is returned.
4. `withdraw(opt subaccount, amount, address)`: Burns the given amount of ckSOL from the user’s account and transfers the same amount minus a fee in SOL to the given user address. Returns the block index of the burn operation on the ckSOL ledger in case of success. Otherwise, an error is returned.
5. `withdrawal_status(block_index)`: Returns the withdrawal status (`NotFound`, `Pending`, `TxSent`, `TxFinalized`) for the withdrawal identified by the given block index.
6. `get_minter_info`: Returns information about the ckSOL minter, specifically the various fees, the minimum depot and withdrawal amounts, and the current balance of the ckSOL minter. No newline at end of file
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md

The **manual deposit fee** must only cover the cost of the signature in the consolidation transaction where the funds are transferred to the main account. This cost is 5000 lamports. Adding again a safety margin, the manual deposit fee could be set to 10,000 lamports, i.e., **0.00001 SOL**.

For either depot flow, when `x` SOL are deposited in a deposit address, the user receives `x` SOL minus the (automatic or manual) deposit fee in his/her account.
Comment thread ARCHITECTURE.md
RPC-->>Minter: transaction_id
```

All transactions are created on a timer. Since a transaction must contain a recent block hash, such a block hash must be obtained first: A `getSlot` call is used to get a recent slot, followed by a `getBlock` call to retrieve block details, in particular the block hash, for the slot received in the first step. Note that it is possible that there is no block for a certain slot, in which case `getSlot` needs to be called again, followed by another call to `getBlock`. The figure only shows the happy path of one call each. Given a recent block hash, the transaction is built, obtaining an EDDSA signature for each transfer to be made within that transaction. Once the transaction is signed and serialized, it is sent to the SOL RPC canister, which forwards it to the RPC providers.
Comment thread ARCHITECTURE.md Outdated
Comment thread ARCHITECTURE.md
Comment on lines +104 to +107
The mechanism to replenish a depleted quota is discussed in the next section.

The quota is meant as a deterrent but does not stop an attacker from triggering many `getTransaction` calls for different addresses. In order to limit the impact of such an attack, the constant `MAX_MONITORED_ADDRESSES` specifies the global limit on the number of addresses for which automatic deposits are allowed at any given time. This constant also limits the memory consumption. Furthermore, `update_balance` only takes a subaccount parameter, i.e., it is not possible to call the function for other principals, preventing drainage attacks against the quotas of other users.

Comment thread ARCHITECTURE.md
Comment on lines +175 to +177

The manual flow is triggered by calling `process_deposit` with the user’s account (principal ID and subaccount) and the signature identifying the transaction as parameters. This endpoint requires cycles to be attached. As specified in Section 2.3.2., **1T cycles** must be attached to the call.

Comment thread ARCHITECTURE.md
Comment on lines +187 to +189
Let `x`T cycles denote the left-over cycles. As shown in Section 2.3.2., depleting the quotas consumes roughly 0.44T cycles. Given that `x` is at least 0.9738, there are enough cycles to replenish both quotas, i.e., after this operation, both quotas are again at their respective maximum values.
The cost of replenishing the number of allowed `getSignaturesForAddress` calls from `y` to `MAX_GET_SIGNATURES_CALLS` is `(MAX_GET_SIGNATURES_CALLS-y)*5` G cycles (rounding up the derived cost of 4.3G). Similarly, the cost of replenishing the number of allowed `getTransaction` calls from `z` to `MAX_RETRIEVED_SIGNATURES` is `(MAX_RETRIEVED_SIGNATURES-z)*8` G cycles (rounding up the derived cost of 7.5G).
Given the suggested parameters, the cost is at most 0.45T cycles. Thus, at least 0.5238T cycles are refunded.
THLO and others added 2 commits April 27, 2026 17:54
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 27, 2026 15:54
THLO and others added 2 commits April 27, 2026 17:57
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants