Conversation
Adds three tables to persist Safe smart-account state per organization: - safe_wallets: one row per (org, chain) Safe deployment, owned by the org's Turnkey EOA at threshold 1. Stores address, salt nonce, deploy tx hash, factory/singleton pointers. - safe_module_installations: tracks which Safe modules are enabled per Safe. module_type is free-form text (seeded with "allowance") so future modules (Zodiac Roles, Transaction Guard) can coexist without schema churn. - safe_token_limits: per (safe, delegate, token) spending caps enforced by the Allowance Module. amount_wei is text-encoded uint256, period_minutes maps to the module's resetTimeMin field. All three are covered by the new 0052_typical_zarek migration chained after staging's 0051_rename_aave_slug_to_v3.
Introduces lib/safe/contracts.ts as the single source of truth for Safe's deployed contracts. All addresses are Nick's deterministic deployer addresses, identical across every EVM chain we support (Ethereum, Optimism, Base, Arbitrum), so one canonical map covers every target chain. - Registers Safe v1.4.1 singleton (L2 variant for event emission), proxy factory, compatibility fallback handler, MultiSend, MultiSendCallOnly - Registers the Safe Allowance Module v0.1.0 for later use in the spending-limits flow - Exposes getSafeContracts(chainId), getSafeSingletonForDeploy, and getAllowanceModuleAddress helpers with a CHAIN_OVERRIDES hook for the rare chain that ships non-canonical deployments - SUPPORTED_SAFE_CHAIN_IDS + isSafeSupportedChain() narrow chain IDs to the four we gate Safe operations to today Source: github.com/safe-global/safe-deployments
Adds the deploy flow for organization Safes: one Safe per (org, chain), owned by the org's Turnkey EOA at threshold 1. Same CREATE2 salt produces the same Safe address on every supported chain. - lib/safe/address.ts: pure helpers for setup() calldata, salt nonce derivation (keccak256 of org + chain), and ProxyCreation event parsing - lib/safe/deployment.ts: deployOrgSafe orchestrator that reuses the existing transaction-manager pipeline (nonce session, adaptive gas, RPC failover). Idempotent via (org, chain) uniqueness - app/api/user/safe/route.ts: admin-gated GET list + POST deploy - components/safe/deploy-safe-card.tsx: chain picker + deploy button + list of deployed Safes, rendered in the wallet overlay - tests/unit/safe-address.test.ts: 12 tests covering calldata encoding, salt determinism, and event parsing
Layers on-chain spending caps on top of deployed Safes via Safe's canonical Allowance Module. Limits are per (org, chain, token), enforced by the module contract, and show natively under the Spending Limits tab on app.safe.global. - lib/safe/allowance-module.ts: pure calldata helpers for enableModule, addDelegate, setAllowance, deleteAllowance, and the pre-validated-signature execTransaction wrapper for threshold-1 Safes - lib/safe/modules.ts: install + set + revoke orchestrators, plus listSafeAllowancesWithChainState which reads the module on-chain on every list call and drops DB rows that were externally revoked (reconcile-on-read) - lib/safe/auth.ts: validateSafeAdmin + getSafeForOrg helpers shared across the allowance routes - Three admin-gated API routes: POST /modules/allowance (install), GET+POST /allowances (list+set), DELETE /allowances/:token (revoke) - components/safe/spending-limits-card.tsx: renders per-safe limits with live "spent / cap", period label, and reset countdown; Add + Edit dialog share the same POST endpoint; Revoke calls DELETE - Wires the card into DeploySafeCard for every deployed Safe - tests/unit/safe-allowance.test.ts: 12 tests covering calldata round-trips, uint96/uint16 bounds, pre-validated sig format, and getTokenAllowance decoding
logSystemError forwards its context object into a Prometheus counter whose label set is fixed at init time: error_category, error_context, is_user_error, error_type, plugin_name, action_name, service, chain_id, table, endpoint, component, workflow_id, execution_id, integration_id, status_code. The Safe code was passing organizationId and operation, neither of which is in that label set, which caused prom-client to throw: Added label "organization_id" is not included in initial labelset Moves the org/safe/token identifiers into the log message string so they still appear in Sentry/Loki output, and replaces the operation label with the existing component convention. Applies to all four Safe API routes and the three orchestrator catch blocks.
Adds every EVM mainnet + testnet where (a) KeeperHub already has RPC and chain metadata seeded and (b) Safe v1.4.1 + Allowance Module are deployed at the canonical Nick's-deployer addresses. Mainnets added: BNB Smart Chain (56), Polygon (137), Avalanche (43114). Testnets added: Sepolia (11155111), Base Sepolia (84532), Arbitrum Sepolia (421614), BSC testnet (97), Polygon Amoy (80002), Avalanche Fuji (43113). Optimism (10) removed: it was in the previous SUPPORTED list but no KeeperHub chain seed row exists for it, so chainIsEnabled() would always reject it. - SUPPORTED_SAFE_CHAIN_IDS reworked with inline comments per chain - DeploySafeCard CHAIN_LABELS covers all new chains so the UI shows proper names instead of "Chain 56" - spending-limits-card COMMON_TOKENS pre-populates USDC/USDT/DAI for each mainnet and Circle testnet USDC for Sepolia / Base Sepolia / Arbitrum Sepolia. Remaining testnets (BSC / Amoy / Fuji) ship with empty arrays; admins can still deploy + enable module, just no preset token picker until Circle canonicalizes their testnets or we add chain-specific defaults
Commit 36e87a5 narrowed SUPPORTED_SAFE_CHAIN_IDS and also dropped Optimism from the CHAIN_LABELS map. If anything ever surfaces a chain-10 row (legacy Safe rows, stale caches, or the list is later reopened) the UI fell back to "Chain 10". Broadens CHAIN_LABELS to cover every chain we might render -- not just the deploy-supported subset -- so the label is always correct. Adds Optimism (10) and Optimism Sepolia (11155420) while I'm in here.
Wires Optimism (10) and Optimism Sepolia (11155420) end-to-end so chainIsEnabled() no longer rejects Safe deploys on these chains. - lib/rpc/rpc-config.ts: adds OP_MAINNET / OP_MAINNET_FALLBACK / OP_SEPOLIA / OP_SEPOLIA_FALLBACK public RPCs and the two CHAIN_CONFIG entries mapping chain IDs to the op-mainnet / op-sepolia keys - scripts/seed/seed-chains.ts: adds chain rows for both networks plus matching Etherscan V2 explorer configs and the canonical name map - lib/safe/contracts.ts: re-adds 10 and 11155420 to SUPPORTED_SAFE_CHAIN_IDS now that the backend resolves them; drops the "Optimism intentionally excluded" comment that is no longer true Seeding is idempotent; running pnpm seed-chains on any env picks up the new rows without impact on existing orgs.
logUserError forwards its context object into a Prometheus counter whose label set is fixed at init time: error_category, error_context, is_user_error, error_type, plugin_name, action_name, service, chain_id, table, endpoint, component, workflow_id, execution_id, integration_id, status_code. executeTransaction and executeContractTransaction were passing `nonce` and `method` which blow up with: Added label "nonce" is not included in initial labelset Moves those identifiers into the log message string so they still appear in Sentry/Loki output, and keeps only approved metric labels. Affects any write-tx error path, not just Safe; surfaced while testing the Safe deploy flow.
Three related fixes to the per-token spending-limits flow: Decimals: lib/contracts/tokens.ts had no Sepolia/Base-Sepolia/ Arbitrum-Sepolia/OP-Sepolia entries. When an admin set a limit on testnet USDC the server fell back to decimals=18, so "200 USDC" got stored as 200e6 wei paired with decimals=18 and the edit dialog later showed 0.0000000002. Adds the four Circle testnet USDC rows so new limits resolve correctly. Reconcile on read: the allowances GET now overlays fresh getTokenInfo output on each row so previously-miscoded rows (from before the fix above) display with correct symbol/decimals without a DB repair. Known tokens in the server registry always win over the DB cache. Case-insensitive catalog match: the DB stores lowercase addresses while the UI catalog uses EIP-55 checksummed ones, which broke the Edit dialog's <Select /> pre-fill. Normalizes both sides when matching and when pre-filling the selection. Custom token support: adds a "Custom token..." entry at the bottom of the picker that reveals address + symbol + decimals inputs. Validated client-side (address format, decimals range, symbol required); the POST body forwards the client-supplied metadata and the server uses it only when the token is not in its registry. Also adds USDS (Sky Protocol) to the Ethereum mainnet and Base catalogs.
# Conflicts: # components/overlays/wallet-overlay.tsx
Adds the per-(org, chain) signing switch infrastructure so workflow
writes can execute from the Safe instead of the Turnkey EOA. This
commit lands only the backend plumbing; UI toggle + balance display +
transfer step wiring follow in separate commits.
Schema:
- safe_wallets.is_signing_active boolean, default false. Additive,
zero-risk migration; every existing row defaults to eoa mode.
Resolver (lib/safe/signer-resolver.ts):
- resolveSignerMode(orgId, chainId) returns either "eoa" (current
behavior) or "safe" (Safe address + owner address) based on the
new flag plus status = "deployed".
Execution helper (lib/safe/execute-as-safe.ts):
- executeContractCallAsSafe and executeNativeTransferAsSafe wrap
an inner call in safe.execTransaction using the existing
buildExecTransactionCalldata + pre-validated signature plumbing
from the Allowance Module helpers. Turnkey EOA signs the outer
tx and still pays gas; on-chain msg.sender at the target becomes
the Safe.
API:
- PATCH /api/user/safe/[safeId] admin-gated toggle endpoint with
body { isSigningActive: boolean }. Rejects activation when the
Safe is not yet status = "deployed".
- GET /api/user/safe now includes is_signing_active per Safe.
Write-contract-core wiring:
- Resolves signer mode early. In safe mode we skip the ERC-4337
sponsored path (would change msg.sender away from the Safe) and
route through executeContractCallAsSafe inside the existing
nonce session. EOA path is unchanged.
Transfer-funds / transfer-token / approve-token cores still execute
from the EOA and will be wired in subsequent commits.
Adds the same EOA vs Safe branching landed for write-contract-core to the three remaining web3 write steps. In safe mode each step wraps the inner call in safe.execTransaction via executeContractCallAsSafe (or executeNativeTransferAsSafe for native value), skips the ERC-4337 sponsored path (the bundler would change msg.sender away from the Safe), and submits the outer tx with the Turnkey EOA as signer. - transfer-funds-core.ts: native transfer from the Safe's balance - transfer-token-core.ts: ERC-20 transfer from the Safe's token balance - approve-token-core.ts: ERC-20 approval where the Safe is the owner whose allowance the spender gets All four web3 writes now respect the per-(org, chain) signing toggle.
Ships the Phase 3 UI on top of the backend routing committed earlier.
SafeSigningToggle component:
- Per (org, chain) switch in each deployed Safe card
- PATCH /api/user/safe/[safeId] { isSigningActive }
- Admin-gated; disabled while in-flight; toasts on success/failure
- Explanatory copy about where funds need to live and who pays gas
DeploySafeCard rework:
- Each deployed Safe is an inner DeployedSafeRow component
- Safe address row has copy button, explorer link, and "View on Safe"
deep-link (app.safe.global/home?safe=<prefix>:<addr>)
- "Active signer" badge appears next to chain label when the toggle
is on
- Status chip uses the same muted badge style as other wallet cards
- "Deploy on new chain" is now a single button that opens a Dialog
with the chain picker, matching the Add-Token flow on the balances
tab
chain-prefixes module:
- getSafeAppUrl(chainId, address) maps to app.safe.global EIP-3770
slugs (eth, base, arb1, oeth, sep, basesep, etc.)
- getExplorerAddressUrl / getExplorerTxUrl return the canonical
Etherscan V2 / Snowtrace / BscScan URL; unknown chains return null
and the UI hides the link
SpendingLimitsCard polish:
- Limit rows are flex-col with three zones: amount line, period +
reset, token address + copy/explorer links
- Period labels capitalized (Daily / Weekly / Monthly)
- Token address renders as font-mono code with copy + explorer-link
icons, matching the wallet-address-card pattern
Tests:
- tests/unit/safe-signer-resolver.test.ts covers eoa/safe branching
based on row presence, status, and flag; plus chain-prefix helpers
- tests/unit/approve-token.test.ts mocks the two new Safe modules so
the existing tests continue to exercise the eoa path
- Filter the Add dialog's token dropdown to exclude tokens that already have a limit. Allowance Module stores one row per (delegate, token), so picking an already-limited token silently overwrote the existing one -- users should Edit an existing row instead. Custom token option still appears regardless. - Dropdown alignment: both Token and Period selects open with their start edge anchored to the trigger's left edge (align="start") rather than the default center-ish popper alignment.
Same fix applied to approve-token.test.ts -- the core now imports resolveSignerMode and executeContractCallAsSafe which transitively load ethers.Interface() at module init, and the test's lightweight ethers mock doesn't support the constructor shape. Add shallow mocks for the two Safe modules so the core's eoa path exercises normally and the CI test-unit job goes green.
Drops the ceremonial Allowance Module (it did not enforce anything on-chain beyond a per-token cap) in favour of the Zodiac Roles Modifier v2, which scopes every workflow call through a pre-audited permission tree: per-target contract allowlist, per-function selector allowlist, per-parameter conditions (recipient pinned to the Safe, token in the allowed set, amount within the role allowance). Adds: - lib/safe/roles-orchestrator.ts: installs Roles proxy, assigns role to Turnkey EOA, applies per-protocol permissions and per-token allowances in a single MultiSend. Flattens the new per-protocol TokenLimitInput[] payload with max-amount / min-period conflict resolution. - lib/safe/condition-templates.ts: per-protocol preset builders backed by karpatkey's defi-kit, plus a target-only fallback and a trivial WETH template. - lib/safe/protocol-registry.ts: 18-entry catalog with enforcement level (full / target-only) and per-chain availability. - lib/safe/protocol-targets.ts: per-chain target contract addresses consumed by the target-only fallback. - lib/safe/zodiac-contracts.ts / zodiac-roles.ts: canonical address registry, calldata builders, MultiSend packing. - lib/safe/simulate.ts: desired-role builder used by the SDK's diffing path. - lib/safe/chain-state.ts: on-chain reconciliation helpers for role and allowance state. - lib/safe/price-oracle.ts: Chainlink native/USD conversion for the simulate endpoint gas breakdown. - app/api/user/safe/[safeId]/role: GET / POST / allowances CRUD / simulate routes. Accept both the new ProtocolInput[] shape and the legacy shape during the wizard migration. Routes workflow steps through the Safe when signing is active: transfer-funds, transfer-token, approve-token, write-contract now delegate to the orchestrator path when the Safe has an active role. execute-as-safe and signer-resolver updated accordingly. Removes the superseded surface: - app/api/user/safe/[safeId]/allowances/* and modules/allowance - components/safe/spending-limits-card.tsx - lib/safe/modules.ts - tests/unit/safe-allowance.test.ts
…ement badges
Consolidates the deploy-with-policies flow and the post-deploy install
dialog behind one component, PolicyWizard. Both render the same UI for
the 18-protocol catalog and emit the same payload shape:
{ protocols: [{ slug, tokens: [{ tokenAddress, tokenSymbol,
tokenDecimals, amountHuman, periodSeconds }] }] }
Per-protocol cards show:
- Full policy / Target-only enforcement badge sourced from the catalog
- Target-contract list with explorer Verify links (built via
buildAddressUrl + the chain's explorer config)
- A structured token row editor: symbol badge, truncated address with
explorer link, amount input, Daily / Weekly / Monthly period select,
remove. Replaces the CSV-of-symbols textbox.
Token selection goes through a shared TokenPicker that merges the
system supportedTokens list, the org's organizationTokens for that
chain, and offers a Paste-custom-address fallback wired to
POST /api/user/wallet/tokens (reads symbol / name / decimals on-chain
and persists).
Deploy wizard deletes the duplicated policies step and renders the
shared PolicyWizard inside step 2, so deploy + install behave
identically. Review step surfaces applied / skipped / conflictedTokens
returned by the simulate and install endpoints.
Files:
- New: policy-wizard.tsx, policy-protocol-card.tsx, policy-token-row.tsx,
token-picker.tsx, role-permissions-card.tsx
- Modified: deploy-safe-card.tsx
Replace role-wide-per-token allowance buckets with per-(protocol, token) buckets so each enabled protocol owns its own spending cap on chain. Removes the cross-protocol conflict-resolution path; each protocol card in the wizard now persists independent allowances. - tokenAllowanceKey now hashes (roleKey, protocolSlug, tokenAddress) - safe_role_allowances gains a protocol_slug column; unique index swaps to (role_id, protocol_slug, token_address) - flattenInstallInput emits one allowance per (protocol, token) with no cross-protocol dedup; ConflictedToken removed from the install result and every API response - setRoleTokenAllowance + revokeRoleTokenAllowance now require a protocolSlug; revoke endpoint takes it as a ?protocolSlug= query - role + simulate route schemas updated; simulate's enforcement-level comparison repaired against the renamed "contract-allowlist" value Migration drops existing safe_role_allowances rows and the old unique index; greenfield drop authorised since no production rows exist.
…onflict UI - Extract `ProtocolTokenAllowances` so the Add-token + token-rows pattern can be reused outside the wizard. Fully controlled, all state lives in the parent. - Refactor `PolicyProtocolCard` so the chevron collapses the entire body (token rows + scoped-contracts list). Tokens persist through any combination of expand/collapse/enable/disable. Newly enabling a protocol auto-expands its card so the seeded tokens are visible. - Cap the deploy and install dialogs at 85vh with vertical scroll so the modal does not overflow the viewport. - Drop the conflict UI now that allowances are per-(protocol, token): the "Token conflicts resolved" review block, the SimulationPlan conflictedTokens field, the install-toast warning, and the obsolete bullet in the wizard's "How this works" panel. Replaces the bullet with copy explaining per-protocol independence.
…g merge Staging shipped its own 0052_agentic_wallets and 0053_sleepy_franklin_richards under the same numbers we used for Safe role tables and per-protocol allowances. Those numbers are about to collide on merge. Drop our 0052_military_photon and 0053_futuristic_living_lightning, fix the broken journal entry for idx 51 (was pointing at a tag whose .sql had been renamed to 0051_rename_aave_slug_to_v3), and let staging land cleanly. The Safe schema will be re-emitted as a single consolidated migration after the merge.
…-wallet-integration # Conflicts: # .gitignore # components/overlays/wallet/manage-tab.tsx # plugins/web3/steps/approve-token-core.ts # plugins/web3/steps/transfer-funds-core.ts # plugins/web3/steps/transfer-token-core.ts # plugins/web3/steps/write-contract-core.ts # pnpm-lock.yaml
Replaces the two branch-only migrations dropped pre-merge (military_photon + futuristic_living_lightning) with one migration that creates safe_wallets, safe_roles, safe_role_protocols, safe_role_allowances against staging's post-0064 baseline. The per-(role, protocol_slug, token_address) unique index on safe_role_allowances is part of this migration; no separate ALTER step needed since the column lands at table-creation time. Also two post-merge fixups: - lib/db/schema-agentic-wallets.ts: bigint default switched from BigInt(0) to sql\`0\`. Identical runtime semantics, but JSON-serialisable so drizzle-kit generate can emit a snapshot. Pre-existing issue surfaced while generating this migration; the staging code path that uses this column never hit it because no new generate ran. - lib/safe/execute-as-safe.ts: RpcProviderManager import path moved to @/lib/rpc/providers (canonical export site after staging's RPC refactor).
…own overlay sub-view
Two fixes plus a UI restructure.
Direct rules
- The wizard's Direct transfers and approvals section already collected ERC20
transfer / ERC20 approve / native transfer rules into PolicyConfig.directRules.
Both /role install and /simulate-deploy were silently ignoring them, so any
rule configured there was lost on the way to chain. Threading them now:
- InstallRoleInput grows a directRules field; flattenInstallInput emits
one allowance per ERC20 rule keyed by (role, "direct", token).
- installRolesWithInitialConfig adds target-level permissions for each
rule (ERC20 contract for transfer/approve; recipient address for
native) on top of the protocol presets, before the MultiSend.
- /api/user/safe/[safeId]/role POST validates and forwards the new
directRules body field.
- /api/user/safe/simulate-deploy adds a "Scope N direct rules"
operation summary so the wizard's review step shows them.
- Per-parameter calldata constraints on transfer/approve are a
follow-up; today the on-chain enforcement is target-only, matching
the existing native-transfer banner.
Token selector
- The Direct rule's token chip looked like a static label; users could not
tell it was clickable. Replaced with a proper select-styled trigger:
full-width row with chevron, hover/focus states, "Pick a token" placeholder.
Manage tab restructure
- The Safe section was rendered inline inside the Manage tab and grew
linearly with the chain count. Moved it into its own wallet-overlay
sub-view ("safe" tab) reachable via a new SafeWalletsEntryCard summary
in Manage. Back arrow returns to Manage. No new modal, the overlay
stays open.
Stale conflict toast
- deploy-safe-card no longer reads installData.conflictedTokens (the
field was dropped on the server back when allowances became
per-(protocol, token)).
Tighten the Zodiac Roles orchestrator and the workflow signer routing so the install / read / execution paths all converge on the same on-chain state instead of trusting a possibly-stale DB cache. Install path now wraps the post-tx DB writes in db.transaction with onConflictDoUpdate upserts keyed by the existing unique constraints, so a partial failure rolls back instead of leaving the chain ahead of the cache. ERC-20 direct rules are now scoped via FunctionPermission + matches([eq(counterparty), withinAllowance(key)]) so the recipient or spender is pinned at the calldata level, not just the target. Adds reconcileSafeRoleFromChain that probes the Roles modifier on chain, upserts every live allowance bucket, and marks revoked targets. The role read path (getSafeRoleWithBackfill) auto-runs reconcile when the DB has a role row but no protocols/allowances, recovering from silent-write failures without user interaction. resolveSignerMode gains a parallel chain-probe so workflows hitting a Safe whose role row was lost route through execTransactionWithRole and a background reconcile fills the cache for next time. Includes a new updateRolesConfig orchestrator path that diffs current DB state against desired input via callsPlannedForApplyRole, applies the delta in a single Safe.execTransaction, and persists row-level deltas inside one db.transaction.
POST /api/user/safe/[safeId]/role/reconcile: runs the orchestrator's reconcile-from-chain path so admins can repair a drifted DB cache without redeploying the modifier. POST /api/user/safe/[safeId]/role/update: accepts the full desired state and routes through updateRolesConfig, which computes the diff against current DB rows and submits one Safe.execTransaction. GET /api/user/safe/[safeId]/role now uses getSafeRoleWithBackfill so the response always reflects on-chain state, falling back to a synchronous reconcile when the DB cache is empty but a modifier is enabled on chain. Simulate routes: - /role/simulate detects an active safe_roles row and switches to diff mode -- skips deploy / enable / assign / setDefault gas, only counts new protocols and changed allowance buckets so the wizard preview matches what the orchestrator's diff actually submits. - /safe/simulate-deploy uses per-kind direct-rule gas constants (transfer / approve scopeFunction vs native scopeTarget) instead of one flat estimate. Allowance and period formatting moved into lib/safe/format-allowance so both simulate routes show "1 USDC every week" instead of raw wei.
fix(mcp): correct validate_workflow false-positive on flat outputMapping
Adds BNB mainnet plus 4 testnets (BNB Testnet, Polygon Amoy, Arbitrum Sepolia, OP Sepolia) to SUPPORTED_SPONSORSHIP_CHAINS. Each addition is verified to have Pimlico bundler coverage and EIP-7702 support. Extracts the chain list to a client-safe meta module so the UI can render network names without importing server-only code. Surfaces the supported networks in two places: - Info tooltip next to "Gas sponsorship credits" on the billing status card. - New "Sponsored gas" row in the pricing comparison table, with an info tooltip listing mainnets and testnets.
…ip-chains feat(web3): expand sponsored gas chains, surface in billing UI
…nction-name-alias fix(web3): KEEP-371 reject missing abiFunction with descriptive error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.