Skip to content

Merge main into release/v3.x-new for v3.6.10 release#410

Closed
p-offtermatt wants to merge 10 commits intorelease/v3.x-newfrom
main
Closed

Merge main into release/v3.x-new for v3.6.10 release#410
p-offtermatt wants to merge 10 commits intorelease/v3.x-newfrom
main

Conversation

@p-offtermatt
Copy link
Copy Markdown
Member

Merge main into the release branch to prepare for the v3.6.10 tag and GitHub release.

Important: Merge this PR with a merge commit (not squash).

arlai-mk and others added 10 commits February 27, 2026 14:33
* Implement CCTP Inflow Adapter

* added changelog

* addresses PR comments, recompiled contracts, regenerated schema

* recompile contracts

* removed DestinationAddress struct- keep just the EVM address instead

* Contracts after recompilation with `make compile`
* Add claim contract for weight-based fund distribution

A CosmWasm contract that allows an admin to create distributions by
sending funds along with a list of (address, weight) pairs. Users
claim their proportional share across all active distributions in a
single transaction. Expired distributions can be swept by anyone,
returning unclaimed funds to a configured treasury address.

Supports multi-denom distributions, duplicate address accumulation,
lazy cleanup of expired claim entries, and proper storage error
propagation.

* Fix formatting and add Cargo.lock

* Add PR link to changelog entry

* Add paginated claim history query

Records what each user claimed (amounts, timestamp, distribution ID)
and exposes it via a ClaimHistory query with start_after/limit pagination.

* Address PR review comments

- Fix claim cleanup rollback: return Ok (no BankMsg) when only expired
  entries are cleaned up, instead of Err which rolls back state changes
- Rename DistributionAlreadySwept to NoFundsToSweep (covers both swept
  and fully-claimed cases)
- Use Addr as HashMap key to avoid double addr_validate
- Sum weights during iteration instead of separate pass
- Filter out zero-weight claim entries
- Add funds attribute to create_distribution response
- Add swept_funds attribute to sweep_expired response
- Record claim history even for 0 funds claimed (leaves a trace)
* Add dry run deposit query to inflow vault contract

Add a DryRunDeposit query that calculates how many vault shares would be
minted for a given deposit amount without executing the deposit. This
allows users and frontends to preview share amounts before committing.

Closes #407

* Update changelog entry to reference PR #408

* Document that DryRunDeposit does not enforce the deposit cap
Resolve conflicts in artifacts and regenerate schemas and binaries.
* Prepare v3.6.10 release

* Fix filename

---------

Co-authored-by: arlai-mk <arlai@moonkitt.com>
…unds-deposit-denom

Fix move_adapter_funds failing with InsufficientBalance
@p-offtermatt p-offtermatt requested a review from a team as a code owner April 2, 2026 12:32
Copilot AI review requested due to automatic review settings April 2, 2026 12:32
@claude
Copy link
Copy Markdown

claude bot commented Apr 2, 2026

PR Review: Merge main into release/v3.x-new for v3.6.10

This is a release merge PR pulling several features and a bug fix into the release branch. I reviewed the three main code changes: the new claim contract, the new CCTP adapter, and the vault contract bug fix + dry-run query. Schema/artifact regeneration and changelog entries look correct.


Vault Contract (contracts/inflow/vault/)

MoveAdapterFunds bug fix

The skip_vault_balance_check flag cleanly solves the issue where the vault hasn't yet received funds from the source adapter at message-building time. The flag is documented and its usage is narrow (one call site). Minor: it is a boolean flag on an internal function which is a mild code smell — a named helper or a split function would be marginally cleaner — but it's totally acceptable here.

DryRunDeposit query

The implementation correctly mirrors the deposit logic by adding deposit_amount_base_tokens to total_pool_value before calling calculate_number_of_shares_to_mint, and the doc comment clearly warns that the deposit cap is not enforced. The test covers both the empty-pool case and the existing-pool case.


Claim Contract (contracts/claim/)

⚠️ No migrate entry point

The contract has no migrate entry point. Every other contract in the repo has one. Since CosmWasm contracts require the current admin to upgrade them, this means any future on-chain upgrade would need a full re-deploy rather than a migration. Even a no-op migration should be added now.

⚠️ Zero-amount claim history entries possible

In execute_claim (contract.rs:152–185), for a non-expired distribution where every share.min(remaining) rounds to zero (e.g. due to a dust leftover after many prior claims), dist_funds_claimed will be an empty Vec<Coin>. The code still saves a CLAIM_HISTORY entry and removes the pending CLAIM record. The user gets nothing but loses their claim slot. This is subtle: it means a user with a very small weight relative to total funds can have their claim silently consumed with a zero-fund history record. Consider either skipping the history save (and not removing the claim) when dist_funds_claimed is empty, or returning an error/warning.

⚠️ No pagination on query_pending_claims

query_pending_claims (contract.rs:319–338) iterates all distributions for a user without any limit/pagination. For a user across many distributions this could hit gas limits in a query context. Consider adding start_after / limit parameters consistent with how query_claim_history is done.

ℹ️ execute_sweep_expired leaves a stale DISTRIBUTIONS entry

After sweeping, remaining_funds is cleared to [] but the DISTRIBUTIONS entry itself is never removed. This is benign (the entry is effectively dead) but leaves tombstone entries in storage forever. Optionally remove the distribution entry on sweep.


CCTP Adapter (contracts/inflow/cctp-adapter/)

❌ Unused error variant

DestinationAddressDoesNotExist is defined in error.rs:79 but is never referenced anywhere in the codebase. DestinationAddressNotAllowed covers the same case. The dead variant should be removed to avoid confusion.

⚠️ Misleading error for disabled depositors

ContractError::Unauthorized in error.rs:17 has the message "Unauthorized - only a registered depositor can call this function", but it is returned in validation.rs:24 when the depositor is registered but disabled (!depositor.enabled). A more accurate variant like DepositorDisabled would make debugging much clearer.

⚠️ IBC fee filtering may be overly strict (ibc.rs:26–29)

The code retains only untrn fees in ack_fee and timeout_fee. If Neutron's min-IBC-fee response contains a fee requirement for a non-untrn denom (e.g. uatom), filtering those out means the submitted IBC packet will carry fees below the minimum, and the IBC module will reject it. This is a latent runtime failure mode that may only manifest after a Neutron parameter change. Consider either asserting that only untrn fees are present, or passing the full fee struct.

⚠️ No validation on ibc_default_timeout_seconds

instantiate (contract.rs:138–140) stores ibc_default_timeout_seconds without checking it is non-zero. A zero timeout means the IBC packet expires immediately. Add a > 0 guard.

⚠️ testing.rs is a placeholder

contracts/inflow/cctp-adapter/src/testing.rs contains only a comment. The meaningful tests are in testing_custom_adapter.rs and testing_standard_adapter.rs, but testing.rs appears to have been the intended home for integration-style tests. Either populate it or remove it to avoid confusion.

ℹ️ ADMINS as sorted Vec<Addr> in Item

Storing admins as a Vec in a single Item means every admin add/remove loads and saves the full list. For the expected small number of admins this is fine, but it's worth noting that a Map<Addr, ()> (like EXECUTORS) would be more consistent and scale better.


Minor / Style

  • contracts/claim/src/lib.rs: error and state are private (mod error, mod state). This is fine for a standalone contract but inconsistent with how hydro and other contracts expose them as pub mod.
  • The serde_json dependency in noble.rs is used only for memo construction. Ensure it appears in Cargo.toml and isn't accidentally pulling in a std-only feature for a wasm target.

Summary

The vault bug fix is clean and correct. The dry-run query is well-implemented. The claim and CCTP contracts are solid overall, but have a few issues worth addressing before this ships — particularly the missing migrate entrypoint in the claim contract, the unused error variant in CCTP, and the IBC fee filtering risk.

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

Merge main into release/v3.x-new to prep the v3.6.10 release, bringing in new contracts (CCTP adapter + claim), an Inflow vault query addition, and repository-wide version/schema/artifact updates aligned with the new tag.

Changes:

  • Bump workspace/contract versions to 3.6.10 and update schemas/changelog/artifact checksums accordingly.
  • Add new CosmWasm contracts: inflow/cctp-adapter and claim, plus generated TS types/clients.
  • Extend Inflow vault with DryRunDeposit query and fix MoveAdapterFunds message-building by skipping an incorrect vault-balance check.

Reviewed changes

Copilot reviewed 80 out of 101 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ts_types/InflowVaultBase.types.ts Add dry_run_deposit query type
ts_types/InflowVaultBase.client.ts Add dryRunDeposit() query client
ts_types/InflowCCTPAdapterBase.types.ts Generated CCTP adapter TS types
ts_types/InflowCCTPAdapterBase.client.ts Generated CCTP adapter TS client
ts_types/ClaimBase.types.ts Generated claim contract TS types
ts_types/ClaimBase.client.ts Generated claim contract TS client
packages/interface/src/inflow_vault.rs Add DryRunDeposit query variant
Makefile Include claim/CCTP schema + ts-codegen
Dockerfile Update neutrond version used
contracts/tribute/src/migration/migrate.rs Migration comment version bump
contracts/tribute/schema/tribute.json Contract version to 3.6.10
contracts/token-info-providers/st-token-info-provider/src/migrate.rs Migration comment version bump
contracts/token-info-providers/st-token-info-provider/schema/st-token-info-provider.json Contract version to 3.6.10
contracts/token-info-providers/lsm-token-info-provider/src/migrate.rs Migration comment version bump
contracts/token-info-providers/lsm-token-info-provider/schema/lsm-token-info-provider.json Contract version to 3.6.10
contracts/token-info-providers/d-token-info-provider/src/migrate.rs Migration comment version bump
contracts/token-info-providers/d-token-info-provider/schema/d-token-info-provider.json Contract version to 3.6.10
contracts/marketplace/schema/marketplace.json Contract version to 3.6.10
contracts/inflow/vault/src/testing.rs Add DryRunDeposit unit tests
contracts/inflow/vault/src/testing_adapters.rs Regression test for move funds
contracts/inflow/vault/src/migration/migrate.rs Migration comment version bump
contracts/inflow/vault/src/contract.rs Add query + balance-check skip
contracts/inflow/vault/schema/vault.json Schema: add dry_run_deposit
contracts/inflow/vault/schema/raw/response_to_dry_run_deposit.json New query response schema
contracts/inflow/vault/schema/raw/query.json New query schema entry
contracts/inflow/user-registry/schema/user-registry.json Contract version to 3.6.10
contracts/inflow/skip-adapter/schema/skip-adapter.json Contract version to 3.6.10
contracts/inflow/proxy/schema/proxy.json Contract version to 3.6.10
contracts/inflow/mars-adapter/schema/mars-adapter.json Contract version to 3.6.10
contracts/inflow/ibc-adapter/schema/ibc-adapter.json Contract version to 3.6.10
contracts/inflow/control-center/src/migration/migrate.rs Migration comment version bump
contracts/inflow/control-center/schema/control-center.json Contract version to 3.6.10
contracts/inflow/cctp-adapter/src/validation.rs Address/admin/executor validation helpers
contracts/inflow/cctp-adapter/src/testing.rs Placeholder test module
contracts/inflow/cctp-adapter/src/testing_standard_adapter.rs Standard adapter interface tests
contracts/inflow/cctp-adapter/src/testing_mocks.rs Custom mock deps + setup helpers
contracts/inflow/cctp-adapter/src/testing_custom_adapter.rs Custom CCTP adapter tests
contracts/inflow/cctp-adapter/src/state.rs CCTP adapter state + storage
contracts/inflow/cctp-adapter/src/noble.rs Noble Orbiter memo construction
contracts/inflow/cctp-adapter/src/msg.rs Messages/queries + response types
contracts/inflow/cctp-adapter/src/lib.rs Module wiring
contracts/inflow/cctp-adapter/src/ibc.rs IBC transfer helpers + min fee query
contracts/inflow/cctp-adapter/src/error.rs CCTP adapter errors
contracts/inflow/cctp-adapter/src/bin/inflow_cctp_adapter_schema.rs Schema generator binary
contracts/inflow/cctp-adapter/schema/raw/response_to_standard_query.json Generated response schema
contracts/inflow/cctp-adapter/schema/raw/response_to_custom_query.json Generated response schema
contracts/inflow/cctp-adapter/schema/raw/query.json Generated query schema
contracts/inflow/cctp-adapter/schema/raw/instantiate.json Generated instantiate schema
contracts/inflow/cctp-adapter/schema/raw/execute.json Generated execute schema
contracts/inflow/cctp-adapter/Cargo.toml New crate manifest
contracts/hydro/src/migration/migrate.rs Migration comment version bump
contracts/hydro/schema/hydro.json Contract version to 3.6.10
contracts/gatekeeper/schema/gatekeeper.json Contract version to 3.6.10
contracts/dao-voting-adapter/schema/dao-voting-adapter.json Contract version to 3.6.10
contracts/claim/src/testing.rs Claim contract unit tests
contracts/claim/src/state.rs Claim contract state/storage
contracts/claim/src/query.rs Claim contract queries/responses
contracts/claim/src/msg.rs Claim contract msgs
contracts/claim/src/lib.rs Claim crate module wiring
contracts/claim/src/error.rs Claim contract errors
contracts/claim/src/contract.rs Claim contract implementation
contracts/claim/src/bin/claim_schema.rs Claim schema generator binary
contracts/claim/schema/raw/response_to_pending_claims.json Generated response schema
contracts/claim/schema/raw/response_to_distribution.json Generated response schema
contracts/claim/schema/raw/response_to_config.json Generated response schema
contracts/claim/schema/raw/response_to_claim_history.json Generated response schema
contracts/claim/schema/raw/query.json Generated query schema
contracts/claim/schema/raw/instantiate.json Generated instantiate schema
contracts/claim/schema/raw/execute.json Generated execute schema
contracts/claim/schema/claim.json Consolidated claim IDL
contracts/claim/Cargo.toml New claim crate manifest
CHANGELOG Add v3.6.10 release notes
Cargo.toml Add new members + bump version
Cargo.lock Lockfile updates for new crates
artifacts/checksums.txt Update wasm checksums list
.github/workflows/populate-staging-contracts.yml Update neutrond + staging workflow steps
.changelog/v3.6.10/summary.md Release summary entry
.changelog/v3.6.10/features/408-dry-run-deposit-query.md Feature changelog entry
.changelog/v3.6.10/features/405-claim-contract.md Feature changelog entry
.changelog/v3.6.10/features/396-cctp-adapter.md Feature changelog entry
.changelog/unreleased/bug-fixes/395-fix-move-adapter-funds-deposit-denom.md Bugfix changelog entry

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

Comment on lines +90 to +97
let mut weight_by_addr: HashMap<Addr, Uint128> = HashMap::new();
let mut total_weight = Uint128::zero();
for claim in &claims {
let addr = deps.api.addr_validate(&claim.address)?;
let entry = weight_by_addr.entry(addr).or_default();
*entry += claim.weight;
total_weight += claim.weight;
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

In execute_create_distribution, weight accumulation uses += on Uint128 (*entry += claim.weight and total_weight += claim.weight). Uint128 addition can overflow and wrap in release builds, which could corrupt total_weight and lead to incorrect claim proportions. Use checked_add/checked_add_assign-style logic and return a ContractError (or StdError) on overflow.

Copilot uses AI. Check for mistakes.
Comment on lines +292 to +300
/// Helper to accumulate coins into a vec, merging same denoms.
fn add_coin(coins: &mut Vec<Coin>, denom: &str, amount: Uint128) {
if let Some(coin) = coins.iter_mut().find(|c| c.denom == denom) {
coin.amount += amount;
} else {
coins.push(Coin {
denom: denom.to_string(),
amount,
});
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

add_coin merges amounts with coin.amount += amount, which can overflow Uint128 and wrap, producing an incorrect payout amount. Prefer checked_add and error out (or saturate) if the sum exceeds Uint128::MAX.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +57
#[error("Cannot remove the last admin")]
CannotRemoveLastAdmin {},

#[error("Unauthorized - only executors or admins can call this function")]
UnauthorizedExecutor {},

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

UnauthorizedExecutor's message says "only executors or admins", but validate_executor_caller only checks membership in EXECUTORS (admins are not accepted). Either update the error text to match the actual authorization rules, or extend the validation to allow admins if that’s intended.

Copilot uses AI. Check for mistakes.
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.

4 participants