Skip to content

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

Merged
p-offtermatt merged 5 commits intorelease/v3.x-newfrom
ph/merge-v3610-to-release
Apr 2, 2026
Merged

Merge main into release/v3.x-new for v3.6.10 release#411
p-offtermatt merged 5 commits intorelease/v3.x-newfrom
ph/merge-v3610-to-release

Conversation

@p-offtermatt
Copy link
Copy Markdown
Member

Merge main (up to the v3.6.10 release prep commit) into the release branch to prepare for the v3.6.10 tag and GitHub release.

Excludes PR #395 which landed on main after the release prep.

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

dusan-maksimovic and others added 5 commits March 16, 2026 14:22
* 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
* Prepare v3.6.10 release

* Fix filename

---------

Co-authored-by: arlai-mk <arlai@moonkitt.com>
Copilot AI review requested due to automatic review settings April 2, 2026 12:34
@p-offtermatt p-offtermatt requested a review from a team as a code owner April 2, 2026 12:34
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

Merges main into release/v3.x-new to prepare the v3.6.10 release, including new contract features (CCTP adapter + claim contract) and an additional Inflow Vault query.

Changes:

  • Added DryRunDeposit query to the Inflow Vault contract + TS client/types + schema updates and tests.
  • Introduced new CosmWasm contracts: cctp-adapter and claim, plus generated TS bindings and JSON schemas.
  • Bumped workspace/contract versions to 3.6.10, updated checksums, schema generation targets, and Neutron binary version used in tooling/CI.

Reviewed changes

Copilot reviewed 78 out of 99 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ts_types/InflowVaultBase.types.ts Adds dry_run_deposit query type.
ts_types/InflowVaultBase.client.ts Adds dryRunDeposit query client method.
ts_types/InflowCCTPAdapterBase.types.ts New generated TS types for CCTP adapter.
ts_types/InflowCCTPAdapterBase.client.ts New generated TS client for CCTP adapter.
ts_types/ClaimBase.types.ts New generated TS types for claim contract.
ts_types/ClaimBase.client.ts New generated TS client for claim contract.
packages/interface/src/inflow_vault.rs Adds DryRunDeposit to Rust interface QueryMsg.
contracts/tribute/src/migration/migrate.rs Updates migration comment to v3.6.10.
contracts/tribute/schema/tribute.json Bumps schema contract version to 3.6.10.
contracts/token-info-providers/st-token-info-provider/src/migrate.rs Updates migration comment to v3.6.10.
contracts/token-info-providers/st-token-info-provider/schema/st-token-info-provider.json Bumps schema contract version to 3.6.10.
contracts/token-info-providers/lsm-token-info-provider/src/migrate.rs Updates migration comment to v3.6.10.
contracts/token-info-providers/lsm-token-info-provider/schema/lsm-token-info-provider.json Bumps schema contract version to 3.6.10.
contracts/token-info-providers/d-token-info-provider/src/migrate.rs Updates migration comment to v3.6.10.
contracts/token-info-providers/d-token-info-provider/schema/d-token-info-provider.json Bumps schema contract version to 3.6.10.
contracts/marketplace/schema/marketplace.json Bumps schema contract version to 3.6.10.
contracts/inflow/vault/src/testing.rs Adds unit test coverage for DryRunDeposit.
contracts/inflow/vault/src/migration/migrate.rs Updates migration comment to v3.6.10.
contracts/inflow/vault/src/contract.rs Implements DryRunDeposit query handler and logic.
contracts/inflow/vault/schema/vault.json Adds dry_run_deposit query + response schema; bumps version.
contracts/inflow/vault/schema/raw/response_to_dry_run_deposit.json New raw schema for DryRunDeposit response.
contracts/inflow/vault/schema/raw/query.json Adds dry_run_deposit to raw query schema.
contracts/inflow/user-registry/schema/user-registry.json Bumps schema contract version to 3.6.10.
contracts/inflow/skip-adapter/schema/skip-adapter.json Bumps schema contract version to 3.6.10.
contracts/inflow/proxy/schema/proxy.json Bumps schema contract version to 3.6.10.
contracts/inflow/mars-adapter/schema/mars-adapter.json Bumps schema contract version to 3.6.10.
contracts/inflow/ibc-adapter/schema/ibc-adapter.json Bumps schema contract version to 3.6.10.
contracts/inflow/control-center/src/migration/migrate.rs Updates migration comment to v3.6.10.
contracts/inflow/control-center/schema/control-center.json Bumps schema contract version to 3.6.10.
contracts/inflow/cctp-adapter/src/validation.rs Adds depositor/admin/executor and address validation utilities.
contracts/inflow/cctp-adapter/src/testing_standard_adapter.rs Adds standard adapter interface unit tests.
contracts/inflow/cctp-adapter/src/testing_mocks.rs Adds mock deps/helpers for CCTP adapter tests.
contracts/inflow/cctp-adapter/src/testing_custom_adapter.rs Adds custom adapter (chains/admins/executors/addresses/transfer) tests.
contracts/inflow/cctp-adapter/src/testing.rs Placeholder test module.
contracts/inflow/cctp-adapter/src/state.rs Introduces CCTP adapter state/storage types.
contracts/inflow/cctp-adapter/src/noble.rs Adds Noble Orbiter memo construction utilities + tests.
contracts/inflow/cctp-adapter/src/msg.rs Defines instantiate/execute/query messages and responses.
contracts/inflow/cctp-adapter/src/lib.rs Wires up CCTP adapter modules and tests.
contracts/inflow/cctp-adapter/src/ibc.rs Adds IBC fee query + IBC transfer message builder.
contracts/inflow/cctp-adapter/src/error.rs Defines CCTP adapter contract errors.
contracts/inflow/cctp-adapter/schema/raw/response_to_standard_query.json Raw schema for standard query binary response.
contracts/inflow/cctp-adapter/schema/raw/response_to_custom_query.json Raw schema for custom query binary response.
contracts/inflow/cctp-adapter/schema/raw/query.json Raw schema for query wrapper and query variants.
contracts/inflow/cctp-adapter/schema/raw/instantiate.json Raw schema for CCTP adapter instantiate msg.
contracts/inflow/cctp-adapter/schema/raw/execute.json Raw schema for CCTP adapter execute msg.
contracts/inflow/cctp-adapter/Cargo.toml Adds new cctp-adapter crate manifest.
contracts/hydro/src/migration/migrate.rs Updates migration comment to v3.6.10.
contracts/hydro/schema/hydro.json Bumps schema contract version to 3.6.10.
contracts/gatekeeper/schema/gatekeeper.json Bumps schema contract version to 3.6.10.
contracts/dao-voting-adapter/schema/dao-voting-adapter.json Bumps schema contract version to 3.6.10.
contracts/claim/src/testing.rs Adds unit tests for claim distributions/claims/sweeps/history.
contracts/claim/src/state.rs Adds claim contract state/storage definitions.
contracts/claim/src/query.rs Adds claim contract query messages + response types.
contracts/claim/src/msg.rs Adds claim contract instantiate/execute messages.
contracts/claim/src/lib.rs Wires up claim contract modules and tests.
contracts/claim/src/error.rs Defines claim contract errors.
contracts/claim/src/contract.rs Implements claim contract instantiate/execute/query logic.
contracts/claim/schema/raw/response_to_pending_claims.json Raw schema for pending claims response.
contracts/claim/schema/raw/response_to_distribution.json Raw schema for distribution response.
contracts/claim/schema/raw/response_to_config.json Raw schema for config response.
contracts/claim/schema/raw/response_to_claim_history.json Raw schema for claim history response.
contracts/claim/schema/raw/query.json Raw schema for claim contract queries.
contracts/claim/schema/raw/instantiate.json Raw schema for claim contract instantiate msg.
contracts/claim/schema/raw/execute.json Raw schema for claim contract execute msg.
contracts/claim/schema/claim.json Generated bundled schema for claim contract.
contracts/claim/Cargo.toml Adds new claim crate manifest.
artifacts/checksums.txt Updates wasm checksums and adds new contract artifacts.
Makefile Adds schema + ts-codegen targets for CCTP adapter and claim.
Dockerfile Updates NEUTROND_VERSION used in build image.
Cargo.toml Adds new workspace members and bumps version to 3.6.10.
CHANGELOG Adds v3.6.10 release notes and reorders one older bullet.
.github/workflows/populate-staging-contracts.yml Updates downloaded Neutron binary and removes NTRN staging steps.
.changelog/v3.6.10/summary.md Adds v3.6.10 changelog summary date.
.changelog/v3.6.10/features/408-dry-run-deposit-query.md Adds changelog entry for dry-run deposit query.
.changelog/v3.6.10/features/405-claim-contract.md Adds changelog entry for claim contract.
.changelog/v3.6.10/features/396-cctp-adapter.md Adds changelog entry for CCTP adapter.

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

Comment on lines +21 to +46
let memo = json!({
"orbiter": {
"pre_actions": [{
"id": "ACTION_FEE",
"attributes": {
"@type": "/noble.orbiter.controller.action.v2.FeeAttributes",
"fees_info": [{
"recipient": bridging_config.noble_fee_recipient,
"amount": {
"value": fee_amount.to_string()
}
}]
}
}],
"forwarding": {
"protocol_id": "PROTOCOL_CCTP",
"attributes": {
"@type": "/noble.orbiter.controller.forwarding.v1.CCTPAttributes",
"destination_domain": bridging_config.destination_domain,
"mint_recipient": mint_recipient_base64,
"destination_caller": destination_caller_base64
},
"passthrough_payload": ""
}
}
});
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.

bridging_config is a borrowed &BridgingConfig, but the JSON construction is attempting to move bridging_config.noble_fee_recipient (a String) out of it, which won’t compile. Use a borrowed value (e.g., &bridging_config.noble_fee_recipient) or clone the string before inserting into json!().

Copilot uses AI. Check for mistakes.
/// Validates that the address is exactly 40 hex characters (excluding 0x prefix).
pub fn normalize_evm_address(address: &str) -> Result<String, ContractError> {
let address = address.trim();
let hex_str = address.strip_prefix("0x").unwrap_or(address);
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.

The docstring says addresses with or without the 0x prefix are accepted, but strip_prefix("0x") only strips lowercase 0x. Inputs like 0X... will fail validation due to length. Consider stripping both 0x and 0X (or doing a case-insensitive prefix check) to match the documented behavior.

Suggested change
let hex_str = address.strip_prefix("0x").unwrap_or(address);
let hex_str = address
.strip_prefix("0x")
.or_else(|| address.strip_prefix("0X"))
.unwrap_or(address);

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +96
*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.

Uint128 arithmetic via += can overflow and wrap in release builds (Wasm), which could corrupt total_weight/per-address weights and skew claim shares. Use checked arithmetic (e.g., checked_add) and return a ContractError on overflow to avoid silent wraparound.

Suggested change
*entry += claim.weight;
total_weight += claim.weight;
*entry = entry
.checked_add(claim.weight)
.ok_or(ContractError::Overflow {})?;
total_weight = total_weight
.checked_add(claim.weight)
.ok_or(ContractError::Overflow {})?;

Copilot uses AI. Check for mistakes.
Comment on lines +292 to +302
/// 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.

coin.amount += amount can overflow and wrap in release builds, potentially producing incorrect payout amounts when aggregating across multiple distributions/denoms. Consider using checked_add and propagating an error (or otherwise handling overflow explicitly).

Copilot uses AI. Check for mistakes.
let err = execute(deps.as_mut(), env, info, msg_lowercase).unwrap_err();
assert!(
matches!(err, ContractError::DestinationAddressAlreadyExists { .. }),
"Expected MintRecipientAlreadyExists error, got: {:?}",
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.

The assertion message references MintRecipientAlreadyExists, but the actual expected error is DestinationAddressAlreadyExists. Updating the message will make test failures easier to understand.

Suggested change
"Expected MintRecipientAlreadyExists error, got: {:?}",
"Expected DestinationAddressAlreadyExists error, got: {:?}",

Copilot uses AI. Check for mistakes.
@claude
Copy link
Copy Markdown

claude bot commented Apr 2, 2026

PR Review — Merge main → release/v3.x-new (v3.6.10)

This is a release-prep merge bringing three new features: a CCTP adapter, a claim contract, and a dry-run deposit query for the vault. The review focuses on the new source code added in these three areas.


Claim Contract (contracts/claim/)

Overall: clean design, good test coverage (14 tests, 717 lines). A few edge-case concerns:

Silent success on all-expired claims

In execute_claim (contract.rs), the NoPendingClaims guard fires only when user_claims is empty. If a user has entries in CLAIMS but every distribution has expired, the loop silently skips all of them, removes the storage entries, records history, and returns Ok — with no funds sent and no error. From the caller's perspective this looks like a successful claim.

Consider returning ContractError::NoPendingClaims (or a dedicated AllClaimsExpired) when no funds were actually dispatched after iterating.

// current: silently succeeds even when total_to_send stays empty
if !total_to_send.is_empty() {
    resp = resp.add_message(BankMsg::Send { ... });
}
Ok(resp)

Claim history recorded for zero-fund events

The comment says "even for 0 funds, to leave a trace", but this means a claim call on a fully-expired distribution writes to CLAIM_HISTORY with funds_claimed: []. Querying ClaimHistory for a user will return these zero-fund records, which could confuse integrators who treat any ClaimHistory entry as evidence that funds were sent.

No migrate entry point

The contract has instantiate, execute, and query but no migrate. This means the contract cannot be upgraded after deployment (the CosmWasm router will reject a MigrateMsg). If upgradability is intentional it should be documented; otherwise a no-op migrate should be added.


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

No IBC acknowledgement / timeout handling (no sudo entry point)

execute_transfer_funds emits a NeutronMsg::IbcTransfer. If the transfer to Noble times out or receives an error acknowledgement, Neutron's ibc-callbacks system will call sudo::IbcSudoCall on the contract. Without a sudo entry point the contract panics and the funds stay locked in the contract with no recovery path.

Other adapters in the repo (e.g. ibc-adapter) do implement sudo handlers. This is the most significant gap in the CCTP adapter.

ADMINS stored as Vec<Addr> rather than Map<Addr, ()>

EXECUTORS uses Map<Addr, ()> (O(1) membership). ADMINS uses Item<Vec<Addr>> and does a linear .contains() check on every admin-gated call. For a small admin list this is fine in practice, but the inconsistency is worth noting. If the admin list ever grows, this becomes O(n).

Dead code: get_executor_exists

validation.rs contains:

#[allow(dead_code)]
pub fn get_executor_exists(...) -> StdResult<bool> { ... }

Either use it (e.g. in a query) or remove it. Suppressing the warning without addressing the root cause masks lint signal.

Bridging fee must be sent in USDC denom

let bridging_fee_amount = cw_utils::must_pay(&info, &config.denom)?;

The executor is required to send the Skip/Noble bridging fee denominated in USDC. This is a non-obvious interface contract — the fee is bundled into the single IBC transfer and routed to the fee recipient in the Noble memo. This deserves a prominent docstring or comment on TransferFunds in msg.rs to explain why an executor sending a USDC fee is correct and not a mistake.

ibc_default_timeout_seconds is not validated

On instantiate and UpdateConfig, ibc_default_timeout_seconds accepts zero without error. A timeout of zero would cause the IBC transfer to expire immediately. A > 0 guard would prevent misconfiguration.


Vault: DryRunDeposit (contracts/inflow/vault/)

The implementation is correct. The comment explaining why total_pool_value_with_deposit adds the deposit amount (because in a real deposit the tokens arrive before execute runs) is exactly the right explanation — good. The three test scenarios (empty pool, 1:1 pool, yield-accrued pool) cover the interesting cases well.

One minor note: the docstring says "Note: this does not enforce the deposit cap" — it would be worth also noting that it does not account for any fee taken on deposit, if applicable, so integrators don't mistake the returned share count for a guaranteed post-fee result.


Infrastructure / Release Bookkeeping

  • Neutrond bumped v5.0.2 → v10.1.0 in both Dockerfile and the staging workflow. This is a large version jump; worth confirming it matches the target deployment environment.
  • Removal of NTRN staging contracts (HYDRO_NTRN_*) from the workflow looks intentional.
  • All version bumps from 3.6.9 → 3.6.10 across Cargo.toml and Cargo.lock are consistent.
  • Changelog entries and artifacts/checksums.txt are present and updated.

Summary

Area Finding Severity
Claim Silent Ok when all pending claims are expired, no funds sent ⚠️ Medium
Claim Zero-fund history entries recorded for expired-claim calls ℹ️ Minor
Claim No migrate entry point ℹ️ Minor
CCTP No sudo / IBC ack+timeout handler — funds could get stuck ⚠️ Medium
CCTP ADMINS as linear Vec vs Map inconsistency ℹ️ Minor
CCTP get_executor_exists is dead code ℹ️ Minor
CCTP Bridging fee in USDC not documented in msg types ℹ️ Minor
CCTP ibc_default_timeout_seconds = 0 not rejected ℹ️ Minor
Vault Dry-run deposit implementation is correct

@p-offtermatt p-offtermatt merged commit 25a871a into release/v3.x-new Apr 2, 2026
15 checks passed
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