Skip to content

B34-36-40-42-59 - #199

Merged
matteoettam09 merged 22 commits into
mainfrom
b40
Apr 29, 2026
Merged

B34-36-40-42-59#199
matteoettam09 merged 22 commits into
mainfrom
b40

Conversation

@ojasarora77

@ojasarora77 ojasarora77 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Users can claim pending underlying amounts for failed redemptions; failed transfers are recorded for later claim.
    • Vaults now report ERC‑4626 capability limits (deposit/mint/redeem/withdraw behaviors).
  • Bug Fixes

    • Redemption batches no longer abort due to individual transfer failures.
    • Asset removal now preserves failed assets for retry and processes failures earlier.
  • Security

    • Strategy intent submission restricted to contract owner.
  • Tests

    • Tests updated to reflect owner-only intent submission.
  • Chores

    • Version bumped to 2.3.4.

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Redemption transfers now catch failures and record per-user pending claims; users can claim held underlying later. Orchestrator authorizes decommissioned vaults and forwards failed tokens to config. Config preserves failed decommissioning assets for retry. Strategist submitIntent made owner-only; TVL normalization updated; interfaces and tests adjusted.

Changes

Cohort / File(s) Summary
Redemption failure & user claims
contracts/vaults/OrionVault.sol, contracts/interfaces/IOrionVault.sol
Wraps transferRedemptionFunds in try/catch during redeem fulfillment; on transfer failure records pendingUnderlyingClaims[user], emits RedemptionFailed, and continues. Adds claimUnderlying() and RedemptionClaimed. ERC4626 max* hooks added.
Orchestrator caller auth & epoch flow
contracts/LiquidityOrchestrator.sol
transferRedemptionFunds access check now permits decommissioned vaults as well as Orion vaults. Final minibatch forwards _failedEpochTokens to config.completeAssetsRemoval(failedTokens) and clears _failedEpochTokens earlier.
Asset removal with retry
contracts/OrionConfig.sol, contracts/interfaces/IOrionConfig.sol
completeAssetsRemoval(address[] calldata failedTokens) added; skips removal for addresses in failedTokens, removes others with swap-and-pop and per-asset WhitelistedAssetRemoved emits; no longer clears entire _decommissioningAssets unconditionally.
Strategist access & TVL normalization
contracts/strategies/KBestApyStrategist.sol, contracts/strategies/KBestTvlWeightedAverage.sol
submitIntent() made onlyOwner for both strategists. KBestTvlWeightedAverage now computes normalized per-asset TVL using vault totalAssets(), underlying decimals(), and price registry, with safe fallbacks and clamping.
Interface & docs updates
contracts/interfaces/IOrionStrategist.sol, contracts/interfaces/IOrionConfig.sol, contracts/interfaces/IOrionVault.sol
NatSpec tweaks; completeAssetsRemoval signature changed to address[] calldata failedTokens; IOrionVault adds RedemptionFailed, RedemptionClaimed, and claimUnderlying() to the interface.
Tests & messaging
test/StrategistLinking.test.ts, test/NewStrategies.test.ts, test/LiquidityOrchestratorSlippage.test.ts
Tests updated to call submitIntent as owner and assert OwnableUnauthorizedAccount for strangers; changed “on-chain” → “onchain” in descriptions.
Repo metadata & tooling
package.json, scripts/run-slither.sh
Package version bumped 2.3.32.3.4; Slither --filter-paths extended to include contracts/morpho.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant OrionVault
    participant LiquidityOrchestrator
    participant OrionConfig

    User->>OrionVault: fulfillRedeem(batch)
    loop per redeem
        OrionVault->>LiquidityOrchestrator: transferRedemptionFunds(user, amount)
        alt success
            LiquidityOrchestrator-->>OrionVault: success
            OrionVault->>OrionVault: emit Redeem
        else failure
            LiquidityOrchestrator--x OrionVault: revert/failed
            OrionVault->>OrionVault: pendingUnderlyingClaims[user] += amount
            OrionVault->>OrionVault: emit RedemptionFailed
        end
    end

    Note over User,OrionVault: later
    User->>OrionVault: claimUnderlying()
    OrionVault->>LiquidityOrchestrator: transferRedemptionFunds(user, amount)
    LiquidityOrchestrator-->>OrionVault: success
    OrionVault->>OrionVault: emit RedemptionClaimed

    Note over LiquidityOrchestrator,OrionConfig: epoch final minibatch
    LiquidityOrchestrator->>OrionConfig: completeAssetsRemoval(failedTokens)
    loop per decommissioning asset
        alt asset in failedTokens
            OrionConfig->>OrionConfig: skip removal (retain)
        else
            OrionConfig->>OrionConfig: remove whitelist entry & emit WhitelistedAssetRemoved
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through ledgers, ledger and log,

When transfers stumble I stash each cog.
Failed tokens nap until claim day bright,
Owners call, I pass them back what's right.
Hop—redeem again beneath the moonlight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'B34-36-40-42-59' appears to be a ticket reference number and does not convey meaningful information about the actual changes in the pull request. Replace the title with a clear, descriptive summary of the main changes, such as 'Add redemption failure handling and ERC4626 capabilities' or similar to reflect the primary objectives.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch b40

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contracts/price/ChainlinkPriceAdapter.sol (1)

172-202: ⚠️ Potential issue | 🟡 Minor

Add NatSpec documentation to getPriceData explaining staleness validation strategy.

The removal of answeredInRound < roundId checks is aligned with Chainlink's current best practices (as of 2025–2026, answeredInRound is deprecated in favor of updatedAt-based staleness). Modern Chainlink feeds guarantee answeredInRound == roundId, making the check redundant. Your implementation correctly relies on updatedAt staleness validation via the per-feed configurable maxStaleness threshold.

However, getPriceData currently lacks NatSpec documentation explaining this staleness strategy. Add a brief note clarifying that freshness relies solely on updatedAt comparison, so that operators understand the requirement to tune maxStaleness conservatively (e.g., heartbeat + safety margin per feed).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/price/ChainlinkPriceAdapter.sol` around lines 172 - 202, Add
NatSpec to getPriceData documenting the staleness strategy: explain that
freshness is determined solely by comparing updatedAt against block.timestamp
using the per-feed maxStaleness threshold (no answeredInRound checks are used),
note operators must tune maxStaleness conservatively (heartbeat + safety
margin), and mention that this applies to both primary feed and optional
quoteFeed checks (see variables updatedAt, qUpdatedAt, maxStaleness, and the
function getPriceData which returns (price, PRICE_DECIMALS)).
test/StrategistLinking.test.ts (1)

171-189: ⚠️ Potential issue | 🟠 Major

Update the strategist submitIntent tests for owner-only access.

This suite expects non-owner callers to submit intents successfully, but the PR changes strategist submitIntent() to owner-gated behavior. Both KBestTvlWeightedAverage and KBestApyStrategist now enforce onlyOwner on submitIntent(). Update tests to assert owner success and non-owner OwnableUnauthorizedAccount reverts:

  • Line 189: strategy.connect(user).submitIntent() should revert
  • Line 215: strategy.connect(user).submitIntent() should revert
  • Line 313: strategyB.connect(user).submitIntent() should revert
  • Line 361: Already correctly checks for ZeroAddress
  • Lines 369–401: The "submitIntent permissionlessness" test suite is now stale and should be renamed/restructured to test owner-only behavior instead
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/StrategistLinking.test.ts` around lines 171 - 189, Update the tests to
reflect that submitIntent() is now owner-only: for KBestTvlWeightedAverage and
KBestApyStrategist replace assertions that non-owner calls succeed (e.g.,
strategy.connect(user).submitIntent(), strategyB.connect(user).submitIntent())
with assertions that the call reverts with the
OwnableUnauthorizedAccount/owner-unauthorized error, and change the
corresponding positive assertions to use the owner signer
(owner.connect(...).submitIntent()) to assert success; also rename/restructure
the stale "submitIntent permissionlessness" test suite to indicate and test
owner-only behavior instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/interfaces/IOrionConfig.sol`:
- Around line 116-120: The NatSpec for function completeAssetsRemoval is too
narrow: update its `@param` description to state that failedTokens represents
tokens that failed to be sold or purchased (i.e., failures from both SellingLeg
and BuyingLeg) during the epoch so it matches how _failedEpochTokens is
populated; reference the completeAssetsRemoval function and the
_failedEpochTokens variable when making the wording change.

In `@contracts/LiquidityOrchestrator.sol`:
- Line 510: The call to config.completeAssetsRemoval(_failedEpochTokens) is
being invoked every minibatch during ProcessVaultOperations even though
_decommissioningAssets and _failedEpochTokens are stable, wasting gas; change
the flow so completeAssetsRemoval is only called once when the phase transitions
to Idle (i.e., after ProcessVaultOperations completes). Concretely, move or gate
the completeAssetsRemoval invocation so it runs on the phase transition to Idle
(check the phase change from ProcessVaultOperations to Idle) rather than inside
the per-minibatch loop, and rely on existing invariants around
removeWhitelistedAsset and isSystemIdle to ensure the asset lists are stable.
- Around line 509-510: The bug is that delete _failedEpochTokens is executed
inside _processMinibatchVaultsOperations (when i1 == vaultsEpoch.length), so
control returns to config.completeAssetsRemoval(_failedEpochTokens) with an
empty array; fix by preserving the failed tokens before the delete or by
reordering so completeAssetsRemoval is called while _failedEpochTokens is still
populated: e.g., inside the caller that invokes
_processMinibatchVaultsOperations(states.vaults) and then
config.completeAssetsRemoval(_failedEpochTokens), either take a local snapshot
(uint[] memory failedSnapshot = _failedEpochTokens) and pass that to
completeAssetsRemoval, or move the delete _failedEpochTokens out of
_processMinibatchVaultsOperations and only delete it after
config.completeAssetsRemoval(...) completes; reference symbols:
_processMinibatchVaultsOperations, _failedEpochTokens,
config.completeAssetsRemoval, and the delete _failedEpochTokens call.

In `@contracts/strategies/KBestTvlWeightedAverage.sol`:
- Line 50: The submitIntent() function in KBestTvlWeightedAverage should be
hardened with the nonReentrant modifier to match KBestApyStrategist and prevent
future reentrancy risks; update the contract declaration to inherit
OpenZeppelin's ReentrancyGuard (or import it if missing) and add nonReentrant to
the submitIntent() signature, ensuring any required constructor or import
adjustments for ReentrancyGuard are applied so the modifier compiles and behaves
as expected.
- Around line 95-131: The call to IERC20Metadata(vaultUnderlying).decimals()
inside _normalizedTvl is not protected and can revert (or vaultUnderlying may be
address(0)), breaking the intended "fallback to 1 on any external failure";
update _normalizedTvl to wrap the decimals lookup in a try/catch (similar to the
existing totalAssets/asset/getPrice calls), and if the call reverts or
vaultUnderlying == address(0) return 1; ensure you reference the same symbols
(function _normalizedTvl, IERC4626.asset, IERC4626.totalAssets,
priceRegistry.getPrice, IERC20Metadata.decimals) so every external call that can
fail returns the fallback value 1 instead of bubbling a revert.

In `@contracts/vaults/OrionVault.sol`:
- Around line 746-753: claimUnderlying zeroes
pendingUnderlyingClaims[msg.sender] then calls
liquidityOrchestrator.transferRedemptionFunds(msg.sender, amount) and is
protected by nonReentrant, but the function is callable in any system phase
which can cause confusing transient reverts if the LO lacks buffer; either add a
phase check or document the retry behavior. Fix options: 1) add a gate at the
top of claimUnderlying using the existing config.isSystemIdle() (or similar
phase predicate) to require the system be idle before proceeding, referencing
claimUnderlying, pendingUnderlyingClaims, and
liquidityOrchestrator.transferRedemptionFunds; or 2) update the IOrionVault
NatSpec for claimUnderlying to explicitly state callers must expect and retry on
transient transfer reverts (mention pendingUnderlyingClaims and
transferRedemptionFunds) so user expectations are clear. Make only one change
(gate OR NatSpec) and keep nonReentrant and CEI ordering as-is.

---

Outside diff comments:
In `@contracts/price/ChainlinkPriceAdapter.sol`:
- Around line 172-202: Add NatSpec to getPriceData documenting the staleness
strategy: explain that freshness is determined solely by comparing updatedAt
against block.timestamp using the per-feed maxStaleness threshold (no
answeredInRound checks are used), note operators must tune maxStaleness
conservatively (heartbeat + safety margin), and mention that this applies to
both primary feed and optional quoteFeed checks (see variables updatedAt,
qUpdatedAt, maxStaleness, and the function getPriceData which returns (price,
PRICE_DECIMALS)).

In `@test/StrategistLinking.test.ts`:
- Around line 171-189: Update the tests to reflect that submitIntent() is now
owner-only: for KBestTvlWeightedAverage and KBestApyStrategist replace
assertions that non-owner calls succeed (e.g.,
strategy.connect(user).submitIntent(), strategyB.connect(user).submitIntent())
with assertions that the call reverts with the
OwnableUnauthorizedAccount/owner-unauthorized error, and change the
corresponding positive assertions to use the owner signer
(owner.connect(...).submitIntent()) to assert success; also rename/restructure
the stale "submitIntent permissionlessness" test suite to indicate and test
owner-only behavior instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a7fa6fb5-6d7c-45a2-9c31-30e1cfe5f83b

📥 Commits

Reviewing files that changed from the base of the PR and between 54fc102 and 6fc9837.

📒 Files selected for processing (14)
  • contracts/LiquidityOrchestrator.sol
  • contracts/OrionConfig.sol
  • contracts/execution/UniswapV3ExecutionAdapter.sol
  • contracts/interfaces/IOrionConfig.sol
  • contracts/interfaces/IOrionStrategist.sol
  • contracts/interfaces/IOrionVault.sol
  • contracts/price/ChainlinkPriceAdapter.sol
  • contracts/strategies/KBestApyStrategist.sol
  • contracts/strategies/KBestTvlWeightedAverage.sol
  • contracts/test/MockOrionConfig.sol
  • contracts/vaults/OrionTransparentVault.sol
  • contracts/vaults/OrionVault.sol
  • test/LiquidityOrchestratorSlippage.test.ts
  • test/StrategistLinking.test.ts

Comment thread contracts/interfaces/IOrionConfig.sol
Comment thread contracts/LiquidityOrchestrator.sol Outdated
Comment thread contracts/LiquidityOrchestrator.sol Outdated
Comment thread contracts/strategies/KBestTvlWeightedAverage.sol Outdated
Comment thread contracts/strategies/KBestTvlWeightedAverage.sol Outdated
Comment thread contracts/vaults/OrionVault.sol
@matteoettam09 matteoettam09 changed the title B40 B34-36-40-42 Apr 25, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/StrategistLinking.test.ts (1)

400-409: 🧹 Nitpick | 🔵 Trivial

Determinism test is now tautological under owner-only access control.

With submitIntent restricted to the owner, comparing two consecutive owner calls against unchanged state is equivalent to asserting the function is idempotent. The previous "output depends on state not caller" semantics can no longer be exercised. Consider strengthening the test by mutating intermediate state (e.g., depositing more TVL between calls) and validating the relationship between the two intents, or rename it to clarify it now asserts idempotency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/StrategistLinking.test.ts` around lines 400 - 409, The test "Owner
produces deterministic intent — output depends on state not caller" is now
tautological because submitIntent is owner-only; either rename the test to
assert idempotency or change it to mutate intermediate state between calls so
you exercise state-dependence: keep the first submitIntent()/vault.getIntent()
call, then change TVL (e.g., call a deposit function on the vault/strategy or
directly modify totalValueLocked via an available helper) and call
submitIntent()/vault.getIntent() again, then assert the relationship expected
given the TVL change (or if you prefer the simpler approach, rename the test to
something like "Owner submitIntent is idempotent" and keep the existing
assertions). Ensure you reference submitIntent, vault.getIntent, and whichever
deposit helper (e.g., deposit/transferToVault) you use when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/strategies/KBestTvlWeightedAverage.sol`:
- Around line 118-138: The code uses 10 ** underlyingDecimals (where
underlyingDecimals comes from IERC20Metadata.decimals()) which can overflow for
attacker-controlled large decimals; guard this by validating/clamping
underlyingDecimals before exponentiation: after the try that sets
underlyingDecimals, if underlyingDecimals > 77 then return 1 (or set
underlyingDecimals = 77) so that uint256 denominator = 10 **
uint256(underlyingDecimals) cannot overflow, then use that denominator in
Math.mulDiv(rawTvl, underlyingPrice, denominator); reference
IERC20Metadata.decimals, underlyingDecimals, and Math.mulDiv to locate and apply
the check.

In `@contracts/vaults/OrionVault.sol`:
- Around line 769-779: The vault records failed-redemption amounts in
pendingUnderlyingClaims when liquidityOrchestrator.transferRedemptionFunds
reverts, but the LiquidityOrchestrator's bufferAmount (and
pendingProtocolFees/pendingVaultFees) aren’t updated, so update the LO or vault
to maintain the invariant: either (A) increment a tracked counter in
LiquidityOrchestrator (e.g., pendingClaimsTotal) whenever
transferRedemptionFunds fails and ensure all LO methods that spend from balance
(withdrawLiquidity, _executeBuy/_updateBufferAmount, any rescue/rebalance)
factor in pendingClaimsTotal, or (B) explicitly document the invariant and add
defensive checks in LiquidityOrchestrator methods to prevent using balance
beyond bufferAmount - pendingClaimsTotal; locate uses around
transferRedemptionFunds, pendingUnderlyingClaims, bufferAmount,
withdrawLiquidity, _executeBuy/_updateBufferAmount and claimUnderlying to
implement the chosen fix.

---

Outside diff comments:
In `@test/StrategistLinking.test.ts`:
- Around line 400-409: The test "Owner produces deterministic intent — output
depends on state not caller" is now tautological because submitIntent is
owner-only; either rename the test to assert idempotency or change it to mutate
intermediate state between calls so you exercise state-dependence: keep the
first submitIntent()/vault.getIntent() call, then change TVL (e.g., call a
deposit function on the vault/strategy or directly modify totalValueLocked via
an available helper) and call submitIntent()/vault.getIntent() again, then
assert the relationship expected given the TVL change (or if you prefer the
simpler approach, rename the test to something like "Owner submitIntent is
idempotent" and keep the existing assertions). Ensure you reference
submitIntent, vault.getIntent, and whichever deposit helper (e.g.,
deposit/transferToVault) you use when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e124243b-1d5f-43c9-9fd4-2a4ed1801415

📥 Commits

Reviewing files that changed from the base of the PR and between 6fc9837 and e099c34.

📒 Files selected for processing (8)
  • contracts/LiquidityOrchestrator.sol
  • contracts/OrionConfig.sol
  • contracts/interfaces/IOrionVault.sol
  • contracts/strategies/KBestTvlWeightedAverage.sol
  • contracts/vaults/OrionVault.sol
  • package.json
  • test/NewStrategies.test.ts
  • test/StrategistLinking.test.ts

Comment thread contracts/strategies/KBestTvlWeightedAverage.sol
Comment thread contracts/vaults/OrionVault.sol Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/vaults/OrionVault.sol`:
- Around line 250-268: The decommissioned check in maxRedeem is inverted:
currently it returns 0 when config.isDecommissionedVault(address(this)) is true,
but redeem() is only allowed when the vault IS decommissioned; change the branch
to return 0 when the vault is NOT decommissioned (i.e., use the negation of
config.isDecommissionedVault(address(this))). Update maxRedeem(address owner) so
it still checks system idle and minRedeemAmount as before, and ensure
maxWithdraw() behavior (which calls maxRedeem and convertToAssets) will then
correctly reflect redeem availability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: cb8ca3ba-3a6b-4052-b2a5-e3744f8efffe

📥 Commits

Reviewing files that changed from the base of the PR and between 2fc10de and d504217.

📒 Files selected for processing (1)
  • contracts/vaults/OrionVault.sol

Comment thread contracts/vaults/OrionVault.sol
@matteoettam09 matteoettam09 changed the title B34-36-40-42 B34-36-40-42-59 Apr 29, 2026
@matteoettam09
matteoettam09 merged commit 2314894 into main Apr 29, 2026
4 checks passed
@matteoettam09
matteoettam09 deleted the b40 branch April 29, 2026 15:01
@coderabbitai coderabbitai Bot mentioned this pull request Jun 5, 2026
Merged
@coderabbitai coderabbitai Bot mentioned this pull request Jul 18, 2026
Merged
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