Staryu Lv25 — Idle overlay UX fixes#35
Open
arbuthnot-eth wants to merge 219 commits into
Open
Conversation
…alRecord The foundation. iUSD is a yield-bearing stable backed by gold, silver, equities, energy, and dollar instruments across BTC/ETH/SOL/SUI via IKA dWallet threshold signatures. - IUSD one-time witness, 6 decimals (matches USDC) - Treasury shared object: revenue balance, minter/oracle authority - CollateralRecord as dynamic fields: per-asset, per-chain, per-tranche - mint() gated by authorized minter (future: multisig/keeper) - burn() permissionless (anyone burns their own) - deposit_revenue() permissionless (Thunder/Shade/swap fees flow in) - update_collateral() oracle-gated (NAV tracking) - Events: Minted, Burned, RevenueReceived (full audit trail) Release: ⚡ Zapdos
…cascade Not a shell. Every function does what it claims. DWalletCap deposit: treasury holds the capability object — cross-chain collateral (BTC/ETH/SOL) cannot be moved without 2PC-MPC consensus. No single party has the full key. Tranching: senior (USDC, T-bills, staked SUI/SOL) absorbs losses LAST. Junior (gold, silver, equities, BTC, oil) absorbs losses FIRST. Senior must cover 100% of supply before any iUSD can be minted. Overall collateral ratio enforced at 150% minimum. Oracle-attested cross-chain values: TreasuryAgents read balances via RPC, attest values on-chain. DWalletCap deposit proves the treasury COULD control those assets; oracle confirms the amounts. Burn creates a RedeemRequest object — TreasuryAgents fulfill by releasing proportional collateral cross-chain via IKA signing. Revenue: permissionless deposit_revenue() for Thunder/Shade/swap fees. Release: ⚡ Raikou
USD1 (World Liberty Financial) at 20% senior tranche — T-bill backed, $4.7B supply, Chainlink PoR, GENIUS Act aligned. Held on Solana + Ethereum via IKA dWallets. World Liberty Markets lending for extra yield. WLFI RWA tokens (oil, gas, timber) added to junior tranche at 6% combined — when launched, held via IKA on ETH/SOL. All previous assets retained: BUIDL, VBILL, XAUM, PAXG, XAGM, TSLAx, NVDAx, SPYx, BTC, WTI perps, LITRO. Nothing removed, USD1 added as the anchor stable across chains. Release: ⚡ Thundurus
Same IKA secp256k1 dWallet that controls Ethereum controls Base (EVM). No additional key needed. Aerodrome AERO/USDC LP: 15-40% from AMM fees (Base's dominant DEX). Moonwell USDC lending: 4-8% + WELL token rewards (35-42% Base lending market share, $2.8B cumulative volume). Junior tranche now spans 6 chains: Sui, Ethereum, Solana, Bitcoin, Hyperliquid, Base. 20 assets total. Zero bridges. Release: ⚡ Voltorb
Every signal() now requires a Coin<SUI> fee (default 0.003 SUI ≈ $0.009). Fee transfers directly to the iUSD treasury address on every signal — no accumulation, no withdrawal step. Instant revenue flow. Storm holds fee config: signal_fee_mist (adjustable), fee_treasury (iusd.sui address), admin (progressive decentralization → IKA dWallet). Admin can update fee amount (price oracle adjustments), treasury address (rotation), and transfer admin to a dWallet for zero-trust governance. FeePaid event on every signal for on-chain accounting. Release: ⚡ Jolteon
execute() now takes a treasury address parameter. Splits 10% of the escrowed deposit directly to the iUSD treasury on execution. The remaining 90% returns as Coin<SUI> for SuiNS registration. Fee flows instantly — no accumulation, no withdrawal step. Same pattern as Thunder v3. ShadeExecutorAgent passes the treasury address. 10% of every Shade order → iUSD backing. Progressive decentralization: treasury address will point to IKA dWallet-controlled multisig. Release: ⚡ Luxray
buildThunderSendTx now splits 0.003 SUI (≈$0.009 iUSD) from the gas coin and passes it as the fee argument to signal(). Fee goes directly to the iUSD treasury address on every signal. No extra user interaction — fee is invisible, split from gas in the same PTB. The signal fee is the first real revenue stream flowing to iUSD backing on every Thunder conversation. Release: ⚡ Pikachu
Every name registered through SKI splits 5% of the full USD price from the gas coin and sends it directly to the iUSD treasury address. Applied to all three payment paths: NS direct, USDC swap, SUI direct. addRegistrationFee() converts USD → SUI at current price, splits from gas, transfers to IUSD_TREASURY. Zero friction — invisible to user, same PTB, no extra signing. Combined with Thunder signal fees (⚡ Pikachu) and Shade 10% cut (⚡ Luxray), all three revenue streams now flow to iUSD on every protocol interaction. Release: ⚡ Dragonite
…DKG coordination Autonomous yield agents running 24/7 on Cloudflare's edge: Arb Scanner (15s tick): Queries Bluefin aggregator for DeepBook vs Cetus price gaps on SUI/USDC. When spread > 10bps, executes NAVI 0% flash loan arb — borrow USDC, buy cheap, sell expensive, repay, keep profit. Atomic — if arb fails, flash loan reverts, zero loss. Fee Sweeper (15min tick): Checks treasury SUI balance, deposits surplus into NAVI SUI lending pool (pool 0, ~3.5% APY). Keeps 0.1 SUI for gas, sweeps the rest into productive yield. Rebalancer (24h tick): Checks reserve allocation drift. Will execute rebalancing swaps via DeepBook when drift > 5%. DKG Coordinator: Can orchestrate IKA dWallet provisioning by signaling the browser to run WASM contribution. Zero-trust dWallets require user participation — the DO coordinates, the browser contributes. Wrangler: TreasuryAgents DO binding added (v5 migration). Server: exported from index.ts. Release: ⚡ Ampharos
SKI menu: new 🏛️ Treasury button between ⚙️ and Deactivate. Slides to Treasury panel showing: - Reserve health (senior 60% / junior 40% / 150%+ collateral ratio) - Yield sources (NAVI, Kamino, Scallop, DeepBook, Full Sail, Aftermath, flash arb, USD1 World Liberty Markets) - Cross-chain IKA dWallet status (SOL balance, 20 assets / 6 chains) - Revenue streams (Thunder fees, registration 5%, Shade 10%, swap spread) TreasuryAgents DO deployed — 5 DOs now running on Cloudflare edge. Release: ⚡ Mewtwo
addSwapFee() helper: 0.1% (10 bps) of swap output → iUSD treasury. Applied to NS→USDC path as template. IUSD_TREASURY constant updated with t2000.sui agent identity reference. Release: ⚡ Gyarados
A space pirate army that fights to destroy bridges and wormholes. Each t2000 is an autonomous agent with its own IKA dWallet — threshold-signed, zero-trust, relentless. They sign natively on every chain. No bridges. No wrapping. No mercy. Armory: shared object tracking all deployed agents. T2000: owned object — proof of deployment, tracks cumulative profit. Deploy: $4.50 iUSD equivalent in SUI → treasury. Gets a designation (SuiNS subname under t2000.sui), a dWallet, and a mission. Mission reporting: DOs log profit on-chain via report_mission(). Each terminator's lifetime earnings are tracked in the T2000 object. Admin transferable to IKA dWallet for zero-trust army governance. Release: ⚡ Electabuzz
buildDeployT2000Tx: mint a t2000 agent for $4.50 SUI equivalent. Splits payment from gas, calls armory::deploy with designation, mission, and dWallet ID. Returns owned T2000 object to operator. 7 mission types: arb, sweep, snipe, farm, watch, route, storm. Each maps to a TreasuryAgents strategy running on Cloudflare DO. buildReportMissionTx: log profit on-chain per agent. getArmoryStats: query army size and total collected via GraphQL. Release: ⚡ Magneton
Contracts deployed to Sui mainnet: - iUSD: 0xf62e...5515 (Treasury: 0x7a96...6895) - Thunder v3: 0x7d2a...f782 (Storm: 0x0492...36e6, with fee config) - t2000 Armory: 0x3e70...5e33 (Armory: 0xc781...67e5) Client constants updated to new package/object IDs. Idle screensaver: after 2 min idle with SKI menu open, the pixel art GIF overlays the menu as a clickable link to @brando_sui on X. Click anywhere to dismiss, any interaction resets the timer. Release: ⚡ Nidoking
t2000 client: armory → ship naming throughout. SHIP_ID points to the on-chain Armory object (can't rename deployed structs, but the language is space pirate ship now). Idle screensaver triggers at 15 seconds (was 2 min). Animated GIF plays over the SKI menu, links to @brando_sui X post on click. Any interaction dismisses it. Release: ⚡ Raichu
wk-send-row-below gets flex-wrap + max-width + overflow hidden. When the container is narrow (small screen or large QR), the All and 0.01 buttons stack below instead of hanging off the right edge. Release: ⚡ Clefable
All and 0.01 buttons wrapped in wk-send-quick-stack (flex-column). Output selector (Au/USD/SUI) stays to the right of the stack via the existing row layout. Nothing overflows the menu edge. Release: ⚡ Mew
Idle overlay now has two elements stacked: 1. Animated GIF → links to the X post 2. Blue "Follow @brando_sui" button → X follow intent (one-click follow) Clicking the GIF opens the tweet. Clicking Follow opens X follow flow. Clicking anywhere else on the overlay dismisses it. Twitter blue button with rounded pill style. Release: ⚡ Gardevoir
New toggle left of USD/SUI toggle: flips QR code from left-justified to right-justified. QR overlays the coins area, doesn't reflow layout. Position saved to localStorage. Idle screensaver fix: must click to dismiss (not auto-dismissed by mouse movement). Timer doesn't restart while overlay is showing. Release: ⚡ Salamence
GIF now width: 100% with object-fit: cover. Media container takes full width of the overlay. Matches the Lockin/Settings/Treasury/ Deactivate button row width exactly. Release: ⚡ Rayquaza
Overlay now position:fixed on document body, spanning from left edge of header buttons to right edge. Width matches the SKI dot + wallet badge + balance pill row — wider than the dropdown menu. Height is proportional to width (1.78:1 portrait ratio) so the GIF displays naturally without stretching or cropping. Must click to dismiss — not auto-dismissed by interaction. Release: ⚡ Arceus
Top edge positioned at headerRect.bottom + 4px. The three header buttons (SKI dot, wallet badge, balance) stay visible and clickable above the overlay. Release: ⚡ Tyranitar
GIF click: dismisses overlay, opens SKI menu if not already open. No redirect — just dissipates. Follow button: only element that redirects (X follow intent). Clicking anywhere else on the overlay also dismisses + opens menu. Release: ⚡ Manectric
SuiamiMessage v2: includes btc, sol, eth addresses from IKA dWallets alongside the Sui address. One signed message proves identity across all chains the user controls. Idle overlay dismiss → triggers SUIAMI automatically. Click the GIF, overlay dissipates, SKI menu opens, SUIAMI fires — user signs once, proves they control BTC + SOL + ETH + SUI addresses in one proof. buildSuiamiMessage() now accepts crossChain parameter. The proof token contains all addresses, verifiable by anyone. Release: ⚡ Nidoqueen
The signed message the user sees in the wallet popup now reads: suiami: "I am brando" chains: "sui:0x3db4…b57 · btc:bc1q7f…3k · sol:DkV9…rN" ski: "brando.sui.ski" sui: "0x3db42086e9271787046859d60af7933fa7ea70148df37c9fd693195533eabb57" btc: "bc1q7f..." sol: "DkV9..." eth: "0x..." Truncated chain summary at the top for quick glance. Full addresses at the bottom for verification. One signature proves all chains. Server: backwards compatible — reads message.sui || message.address. Release: ⚡ Metagross
If the button says SUIAMI, it's a SUIAMI click. No complex mode detection, no state race conditions, no "enter an amount" fallthrough. _btnText === 'SUIAMI' short-circuits all other checks. The button text is what the user sees — that's what determines the action. Also: idle dismiss SUIAMI trigger retries up to 10 times (200ms each) waiting for the menu to render and the button to appear. Release: ⚡ Rotom
SUIAMI message chains field now stacks vertically: sui 0x3db4…b57 btc bc1q7f…3k sol DkV9…rN Unicode-safe base64 encoding for proof tokens (fixes btoa crash with newline characters). GIF overlay persists while SUIAMI signing is in progress — only dissipates after the suiami:signed event fires or 30s timeout. Click GIF → triggers SUIAMI → wallet popup appears over the GIF → sign → GIF disappears → menu opens with proof. Release: ⚡ Lanturn
Private thunder input sits below the GIF on the idle overlay. Clicking into it doesn't dismiss the GIF or trigger SUIAMI. Type a message, hit Enter or ⚡ — signal sends to the most- thundered name. GIF stays visible throughout. Three zones on the overlay: - GIF: click → triggers SUIAMI (GIF stays until signed) - Thunder input: click → focus (no dismiss), Enter → send signal - Follow button: click → X follow intent - Anywhere else: dismiss Release: ⚡ Mareep
Order top to bottom: 1. ...private thunder ⚡ (input + send) 2. GIF animation (click → SUIAMI) 3. Follow @brando_sui (click → X intent) Release: ⚡ Flaaffy
Order top to bottom: 1. GIF animation (click → SUIAMI) 2. ...private thunder ⚡ (input below GIF) 3. 𝕏 Follow (black button, X logo SVG, no @handle) Follow button: black background, white text, X bird logo, subtle border, hover brightens. Matches X brand. Release: ⚡ Luxio
The sky dragon wraps every action in a Prism envelope. - Prism defined as canonical TX object: intent, sender, recipient, timestamp (all Seal-encrypted), steganographic amount, Walrus payload, Thunderbun ZK proof, Thunder gate, chain identifier - Every action (TRADE/MINT/Quest/Thunder/Swap/Send/Shade/SUIAMI) → Prism - Idle overlay = Prism player (decrypted Prisms "play" as animations) - Move contract spec with create_prism, claim_prism, sweep_prism - PrismRegistry shared object, derived objects per recipient
Every transfer is an encrypted signal that carries value. Thunder(amount=0) = message. Thunder(amount>0) = payment. One primitive, not two.
…h attachments. TRADE = Thunder + coins + gate MINT = Thunder + coins + domain Quest = Thunder + coins + agent gate Send = Thunder + coins Swap = two Thunders (iUSD↔SUI) Shade = Thunder + coins + time gate SUIAMI = Thunder + ZK proof Message = Thunder (base case) No separate types. One primitive. Different attachments.
…S identity The ice bird freezes randomness into every signal. Thunder v3 (0x18734...): - SignalV3: new struct with `entropy` field — 32 bytes on-chain VRF - XOR-masked with keccak256(name_hash) — only name owner can unmask - signal_v3 + signal_v3_private: generate entropy via sui::random - claim_v3 + claim_v3_relay: unmask entropy on claim - RecipientKeyV3: separate namespace, v2 and v3 coexist - v1 + v2 functions preserved for backward compatibility - Architecture doc: unified Thunder primitive, Prism envelope, Solana infer spec
… chain@name Added Rumble component, iUSD mint/arson/attest/quest/revenue/tranche lifecycle table, Solana integration spec with Kamino/Helius/P-tokens/xStocks, chain address records (sol@squids, eth@squids, btc@squids).
…amic fields The mythical one adds powers to any SuiNS name without touching SuiNS contracts. Published: 0xd409d78129795eb9ebb839e83abc47e6e612ee5ebbd57e4e52770527365d6229 Features attached directly to SuinsRegistration NFTs: - set_chain_address: sol@name, eth@name, btc@name with IKA dWallet ID - get_chain_address: permissionless resolve chain@name - init_profile: SKI profile metadata (rumble curves, thunder count) - set_suiami: SUIAMI proof hash + NFT ID on the name - set_balance_seal: encrypted balance reference - set_points: SUIAMI Pythagoras scoring - has_suiami / has_chain_address / get_points: permissionless reads No wrapping. No waiting on SuiNS. The NFT stays in your wallet.
…low fixed The fish that evolves into Gyarados. 37.47 SUI → Scallop lending. - Sweep redirected from NAVI (version check 1400) to Scallop - 30 SUI kept liquid for trades, surplus → Scallop sSUI - NAVI entry_deposit needs updated incentiveV3 object (TODO) - Idle overlay: overflow hidden, thunder convo width constrained - Manual /api/cache/yield-rotate and /sweep-fees endpoints - Yield interval 30s for testing (restore to 15m for prod) - Sweep error messages now visible in response
…in progress Magikarp evolved. 37.47 SUI earning yield on Scallop. - SweepFees → Scallop lendSuiToScallop (NAVI version-gated) - 30 SUI kept liquid, surplus → sSUI receipt tokens - 536 DEEP acquired for iUSD/USDC pool creation - Pool creation needs DeepBook arg investigation (simulation fail) - Thunder convo absolutely positioned over idle overlay - Manual endpoints: /yield-rotate, /sweep-fees, /swap-sui-for-deep - NAVI needs updated incentiveV3 object (TODO: find current IDs)
…er random signals, cross-chain liquidity architecture Pool & Routing: - Created iUSD/USDC DeepBook v3 pool (0x38df...6ce1) — 500 DEEP spent - Fixed registry ISV, removed stale clock arg from create_permissionless_pool - acquireNsForUser now routes iUSD→USDC→NS (not SUI→USDC→NS) - Registration always routes through NS for 25% discount (AutoRoute path) - Gap-aware: existing NS balance reduces SUI→USDC swap amount - Slippage controls: 2% on stable pairs, min_out=1 on volatile pairs - Added USDC↔iUSD and NS↔XAUM swap routes to buildSwapTx Ignite (cross-chain gas via iUSD): - Published ignite::ignite contract (0x66a4...0677) with ignite_req + ignite_resp - Encrypted recipient field — privacy by default - TreasuryAgents handler + POST /api/ignite endpoint - t2000 consensus via off-chain DO voting + Walrus quilt attestation Thunder: - random_signal: on-chain dice roll (1-6) via Sui Random object — neither sender nor recipient knows until finalized - DiceRolled event emitted per signal - Read receipts from idle overlay (buildStrikeWithReceiptTx) - One-sided read detection: if counterparty's signals purged from Storm → outgoing bubbles turn white - "Decrypt" → "Purge" terminology everywhere Idle Overlay: - iUSD control panel ($ button): treasury stats, Buy/Burn/Ignite actions - Quick-action buttons: $ (iUSD), ● (green), 🦑 (Rumble squids) - Thunder convo positioned between name input and card - Address row: compact, bottom-anchored, click-outside-to-close - Rumble shows address row directly when all dWallets active (cached) - SUIAMI Roster lookup for other people's chain@name addresses - Card dismiss ✕ button, amount clear also clears name - Auto-populate input with highest signal-count name - Signal counts unified: on-chain + local combined as single ⛈️ number Pre-Rumble: - Auto-provisions chain addresses for new names on registration - Writes ultron's dWallet addresses to SUIAMI Roster - Walrus attestation blob for audit trail - Welcome Thunder sent to new name from ultron Architecture Docs: - docs/cross-chain-liquidity.md — IKA dWallet cross-chain flow + Solana dual format (SPL + P-token) - docs/ignite.md — burn iUSD for gas, t2000 consensus, quilts - docs/iusd-solana-agents.md — liquidity quest + micro quest t2000s - docs/prism-media.md — Thunder messages carrying MP3/images as P-token Walrus blobs - docs/standards.md — 8 protocol standards + anti-standards - docs/thunder-hybrid.md — relay chat + on-chain economic signals Cleanup: - Removed dead sendCoins handler, unused executeSponsored import, dead if(false) iUSD route - Hardcoded suiPrice replaced with live CoinGecko fetch + fallback - Renamed buildRumbleMint → buildAutoRoute (Rumble = DKG only) - iUSD v3 published (0xa927...573e) with 110% collateral ratio
…nvestigation Cleanup: - Treasury stub helper (34 duplicates → 1 function) - 922 lines dead CSS removed (137 unused classes) - Merged duplicate window.focus listeners - Added lsGet/lsSet/ssGet/ssSet storage helpers + IUSD_MIST_PER_USD constant - Fixed ShadeExecutor + Chronicom DO references broken by sed - Removed dead sendCoins handler, unused executeSponsored import, dead iUSD route - Renamed buildRumbleMint → buildAutoRoute (Rumble = DKG only) DeepBook v3 BalanceManager issue: - BalanceManager created as owned object — all withdraw/proof calls fail with TypeMismatch - VM rejects arg even though type is exact match (0x2c8d::balance_manager::BalanceManager) - Tried: objectRef, object(), types package, entry package, unsafe_moveCall — all fail at VM level - Hypothesis: package upgrade v5→v6 caused runtime type tag mismatch on existing objects - ~$63 (28.99 USDC + 34.74 iUSD) locked in owned BM 0x2261...4f92 - Installed @mysten/deepbook-v3 SDK (v1.2.1) — uses shared BMs, may resolve - Need to file Sui VM bug report Registration routing: - Always NS-first for 25% discount (AutoRoute: SUI→USDC→NS) - Gap-aware: existing NS balance reduces swap amount - Fresh SUI price fetch before registration
…sponsiveness Fixes #34 - Add close button to video player, remove autoplay from /superteam - Define ski-demo--hidden CSS (was referenced but never styled) - Style demo toggle as pill button, position bottom-left - Remove localStorage auto-restore for demo card (always starts collapsed) - Fix _totalThunderCount to only count pending on-chain signals, not local history - Fix idle card falling back to own name while fetching a different name - Add optimistic pricing + owned-roster detection to idle input (mirrors main SKI menu) - Persist nsLabel from idle input to localStorage - Restore idle overlay on wallet reconnect instead of requiring address at page load - Reduce idle input debounce from 400ms to 150ms
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29372226 | Triggered | Generic High Entropy Secret | 5afde3c | src/ui.ts | View secret |
| 29372226 | Triggered | Generic High Entropy Secret | 069ea3d | src/server/agents/treasury-agents.ts | View secret |
| 29372226 | Triggered | Generic High Entropy Secret | be60330 | src/server/agents/treasury-agents.ts | View secret |
| 29372226 | Triggered | Generic High Entropy Secret | be60330 | src/server/agents/treasury-agents.ts | View secret |
| 29413620 | Triggered | Generic High Entropy Secret | a186763 | src/server/solana-spl.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Replace polling-based _watchSolDeposits with Helius enhanced webhook push. Worker route validates auth, forwards to TreasuryAgents DO. Manual rescan endpoint as fallback.
Zero private keys on Cloudflare Workers. Agents sign via IKA 2PC-MPC user shares + DWalletCap wrapper. brando holds recovery copy. squids::agent Move contract gates signing to enrolled agents.
IKA WASM crypto runs in CF Workers via static import + initSync. SDK's wasm-loader is broken in Workers but raw functions work. Added ika-worker.ts wrapper pattern and full signing flow to spec.
…oofs Agents carry identity profiles with SUIAMI proofs for agent-to-agent and user-to-agent trust. Names are flexible (any SuiNS name/subname). Registry renamed to Roster (SKI vocabulary).
…ences No private key = no key to compromise. Drift-class attacks eliminated. Migration path requires verification + fund migration before key removal.
… fix IKA dWallets + squids::agent Roster solve the single-key privileged capability class: UpgradeCaps, admin keys, treasury keys. No single compromised key grants retroactive authority. References SUIPR-630.
Fork of MystenLabs/sui-stack-messaging extended with IKA cross-chain. Agents communicate via encrypted Thunder signals, not raw transactions. Sui as coordination layer, IKA as nervous system, every chain an endpoint.
Fork MystenLabs/sui-stack-messaging, extend with IKA dWallet identity. Any chain address can participate in encrypted conversations. Agents sign via squids::agent, Chronicoms relay signing intents. 4-phase implementation: fork → agent messaging → Storms → replace v1.
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.
Summary
Closes #34
Test plan