Skip to content

docs: add deployment guide and fix issues found on staging - #263

Open
gregorydemay wants to merge 12 commits into
mainfrom
gdemay/DEFI-3029-deployment
Open

gregorydemay wants to merge 12 commits into
mainfrom
gdemay/DEFI-3029-deployment

Conversation

@gregorydemay

@gregorydemay gregorydemay commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

DEFI-3029

Adds a deployment guide (docs/deployment.md) for the ckSOL minter, ledger and index, and fixes the issues found while doing a full deposit and withdrawal round trip and a deposit stress test on the staging minter (Devnet).

Guide:

  • Minter addresses on Solana, derived offline for production and staging.
  • Initialization arguments of the minter, ledger and index.
  • How to create durable nonce accounts with the minter as nonce authority.
  • How to deposit SOL and follow the deposit status.

Fixes:

  • Finalized sweeps were never credited. getTransaction was sent with a 2 MB response size estimate, which the SOL RPC canister prices at about 220B cycles on the fiduciary subnet, while the minter attaches 50B. Every call was rejected before reaching a provider and surfaced as "Inconsistent RPC results". getTransaction and getSignatureStatuses now use the SOL RPC canister's default estimates (about 3.2B and 10.7B cycles for 256 signatures). Verified on staging: the stuck deposit was minted after the upgrade.
  • Sweeps could expire before reaching the chain. During a stress test of 50 deposits, two sweeps were rejected by all providers with BlockhashNotFound and their 18 deposits were dropped: the blockhash, fetched at finalized commitment, was already close to expiry when the transactions were sent (on Devnet, 150 blocks last about 36 s). Sweeps now fetch their blockhash at confirmed commitment and run the preflight simulation at the same commitment. The expiry check keeps using finalized. Details in the stress test report.
  • effective_transaction_fee is removed from the withdrawal status. It was always null; the user pays the fixed withdrawal_fee, while the Solana transaction fee is paid by the minter.

🤖 Generated with Claude Code

gregorydemay and others added 8 commits October 8, 2026 11:24
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nd getSignatureStatuses

The 2 MB response size estimate made the SOL RPC canister charge about
220B cycles per call on the 34-node fiduciary subnet, while the minter
attached only 50B cycles for `getTransaction`. Every call was rejected
before reaching a provider, so finalized sweeps were never credited.

The SOL RPC canister's per-method defaults fit the minter's responses:
10 KiB for `getTransaction` and 256 bytes per signature for
`getSignatureStatuses`. With them the calls cost about 3.2B and 10.7B
cycles (256 signatures) on mainnet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…l status

The field was always `None`. A user pays the fixed `withdrawal_fee`, which
is already visible as the difference between the burned amount and the
transferred amount, while the Solana transaction fee is paid by the minter
and shared by the withdrawals of a batch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 8, 2026 13:05
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new address test fails enforced Clippy checks, and the critical RPC configuration fix lacks regression coverage.

3 open findings
What changed in this PR

Adds ckSOL deployment guidance and fixes staging issues affecting sweep finalization and withdrawal status reporting.

Changes:

  • Uses SOL RPC default response-size estimates.
  • Removes the unused withdrawal transaction-fee field.
  • Documents deployment, nonce-account setup, and deposit testing.
File Description
docs/​deployment.md Adds deployment and testing guide.
libs/​types/​src/​lib.rs Updates withdrawal status type.
minter/​cksol_minter.did Updates the Candid interface.
minter/​src/​address/​tests.rs Verifies deployed minter addresses.
minter/​src/​constants.rs Removes obsolete response-size constant.
minter/​src/​rpc/​mod.rs Uses endpoint-specific RPC defaults.
minter/​src/​state/​mod.rs Updates finalized withdrawal responses.
minter/​src/​state/​tests.rs Updates state expectations.
minter/​src/​withdraw/​tests.rs Updates withdrawal expectations.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread minter/src/address/tests.rs Outdated
Comment thread minter/src/rpc/mod.rs
Comment thread minter/src/rpc/mod.rs
Copilot AI balanced review requested due to automatic review settings October 8, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The critical RPC configuration fix lacks regression coverage preventing the oversized estimate from being reintroduced.

2 open findings
1 resolved since last review

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

A sweep fetched its blockhash at finalized commitment, so the block was
already old when the minter learned about it. Together with the getBlock
calls and the threshold signatures, the transaction could reach the RPC
providers after the blockhash expired. On Devnet, where 150 blocks last
about 36 s, two sweeps were rejected with BlockhashNotFound and their 18
deposits were dropped.

The sweep now fetches the slot and the block at confirmed commitment and
runs the preflight simulation at the same commitment, since a finalized
simulation would not know the newer blockhash. The monitor keeps
fetching the current block height at finalized commitment for the
expiry check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 8, 2026 14:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The production-critical response-size fixes lack automated regression coverage.

2 open findings

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

…ocks

The sweep now fetches its block at confirmed commitment and the monitor
at finalized commitment, so the getBlock request carries a commitment
that the mocks must match.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 8, 2026 15:01
…the default response size estimate

A 2 MB estimate made the SOL RPC canister charge more cycles than the
minter attaches, so every getTransaction call was rejected. These tests
fail if an explicit estimate is set again on either call.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Regression tests should assert both affected RPC calls retain default response-size estimates.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Copilot AI balanced review requested due to automatic review settings October 8, 2026 15:05
@gregorydemay
gregorydemay marked this pull request as ready for review October 8, 2026 15:07
@gregorydemay
gregorydemay requested a review from a team as a code owner October 8, 2026 15:07
@gregorydemay
gregorydemay requested a review from eichhorl October 8, 2026 15:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The production fixes are consistently implemented with focused regression and integration coverage.

0 open findings

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@zeropath-ai

zeropath-ai Bot commented Oct 8, 2026

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to ec3970c.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► integration_tests/src/fixtures.rs
    Update imports and block commitment handling for get_block/get_slot/getTransaction usage in tests
► minter/src/deposit/sweep/timer.rs
    Introduce SWEEP_BLOCKHASH_COMMITMENT and use Confirmed commitment for recent block and transaction submission
► minter/src/deposit/sweep/timer/tests.rs
    Add tests asserting commitment handling for getSlot/getBlock/sendTransaction
► minter/src/monitor/mod.rs
    Add CommitmentLevel import for block height checks
► minter/src/monitor/tests.rs
    Update tests to use Finalized commitment in get_recent_block/get_slot/get_block calls
► minter/src/rpc/mod.rs
    Adapt get_transaction/get_signature_statuses to reflect removal of response_size_estimate setting and add commitment parameter to get_recent_block
► minter/src/rpc/tests.rs
    Update tests to pass CommitmentLevel where required and extend tests for commitment-aware behavior
► minter/src/state/mod.rs
    Support building sol_rpc_client with builder and remove immediate build; expose sol_rpc_client_builder
► minter/src/constants.rs
    Remove MAX_HTTP_OUTCALL_RESPONSE_BYTES constant and related usage
► minter/src/address/tests.rs
    Update imports and test to reflect new public key derivation/public key types and derive_mainnet/offline test block
► minter/cksol_minter.did
    Remove effective_transaction_fee field from TxFinalizedStatus::Success
► minter/src/rpc/tests.rs
    Adjust test imports for new GetBlockCommitmentLevel, GetSlotParams, GetTransactionParams, etc.
► minter/src/state/tests.rs
    Update test expectations to align with removal of effective_transaction_fee field

@mbjorkqvist mbjorkqvist left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks @gregorydemay! For the PR title, perhaps something like fix: would be more accurate than docs:, since this PR also contains production code changes.

Comment thread minter/src/constants.rs
pub const MAX_HTTP_OUTCALL_RESPONSE_BYTES: u64 = 2_000_000;

/// Cycles to attach for `getTransaction` RPC calls.
pub const GET_TRANSACTION_CYCLES: u128 = 50_000_000_000;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 With the 2 MB estimate gone, the attached cycles no longer match what the calls cost. GET_SIGNATURE_STATUSES_CYCLES (1T, line 50) was sized for the 2 MB reservation, while a call now costs about 10.7B for 256 signatures and 2.3B for one. check_transaction_statuses sends up to MAX_CONCURRENT_RPC_CALLS = 10 of them at once, so the minter needs about 10T of spare cycles above its freezing threshold for a round that actually costs at most ~107B; a minter running low would fail these calls and stall finalization, even though the unused part is refunded. GET_TRANSACTION_CYCLES (50B against ~3.2B) is harmless but has lost its rationale. Lowering both, with comments tied to the default estimates and some headroom for the SOL RPC canister doubling the reservation on an oversized response, would keep them meaningful.

Comment thread docs/deployment.md

## Test

### Deposit SOL

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 The description mentions a full deposit and withdrawal round trip on staging, but the Test section covers deposits only. Adding the withdrawal steps (icrc2_approve on the ledger, the withdrawal call, and following its status) would make the guide cover what was verified.

Comment thread docs/deployment.md
| `deposit_sol_fee` | 45B cycles | Covers the threshold signature and the RPC calls of a sweep containing a single deposit. |
| `deposit_sol_required_cycles` | 1T cycles | Must be at least `GET_BALANCE_CYCLES` (10B) plus `deposit_sol_fee`; unused cycles are refunded. |
| `minimum_deposit_amount` | 0.02 SOL (20,000,000) | Must be at least twice the rent exemption threshold plus the fee of one signature. |
| `withdrawal_fee` | 0.001 SOL (1,000,000) | Covers `getAccountInfo`, `sendTransaction`, `getSignatureStatuses` and the threshold signature. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Once #260 lands, withdrawals are no longer finalized with getSignatureStatuses but with a getAccountInfo read of the nonce account and a getTransaction call for the outcome, so this rationale becomes stale. Whichever of the two PRs lands second could update it, together with §3.3.2 of the design.

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.

3 participants