<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: N DIVIJ</title>
    <description>The latest articles on DEV Community by N DIVIJ (@n45div).</description>
    <link>https://dev.to/n45div</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1116704%2Fc2517b17-e373-401c-b3d4-047103c31fa6.jpeg</url>
      <title>DEV Community: N DIVIJ</title>
      <link>https://dev.to/n45div</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/n45div"/>
    <language>en</language>
    <item>
      <title>The agent I trust is the one that distrusts itself</title>
      <dc:creator>N DIVIJ</dc:creator>
      <pubDate>Tue, 25 Aug 2026 14:18:23 +0000</pubDate>
      <link>https://dev.to/n45div/your-ai-agent-needs-memory-it-should-not-get-a-vote-3k7k</link>
      <guid>https://dev.to/n45div/your-ai-agent-needs-memory-it-should-not-get-a-vote-3k7k</guid>
      <description>&lt;h3&gt;
  
  
  What building a contract-cancellation agent taught me about memory, deterministic gates, and auditable autonomy
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;I created Reaper and wrote this article for the purposes of entering the All Things Agentic Hackathon.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;"Have we seen this before?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's one of the most useful questions an experienced person can ask. A lawyer remembers a clause that caused trouble. An accountant remembers a vendor that kept billing after cancellation. An engineer remembers the deployment that failed under eerily similar conditions.&lt;/p&gt;

&lt;p&gt;So when I added memory to &lt;strong&gt;Reaper&lt;/strong&gt; — an agent that carries auto-renewal cancellations to completion — I assumed retrieval would be the easy part.&lt;/p&gt;

&lt;p&gt;Embed the current clause. Search for similar ones. Show the closest matches. That took a morning.&lt;/p&gt;

&lt;p&gt;Deciding what memory was &lt;em&gt;allowed to do&lt;/em&gt; took the rest of the week.&lt;/p&gt;

&lt;p&gt;Because an agent that remembers past decisions can also inherit past mistakes. Worse, it can quietly convert resemblance into authority:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This clause looks 97% like one we blocked before, so I blocked this one too.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds like judgment. In a system that acts on contracts, it's closer to superstition.&lt;/p&gt;

&lt;p&gt;The fix wasn't better prompting. It was architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The expensive difference between "similar" and "the same"
&lt;/h2&gt;

&lt;p&gt;A contract costs $540 a month and renews for another year unless written notice arrives 60 days before the term ends. Miss that window and a small administrative failure becomes a &lt;strong&gt;$6,480 mistake&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Reaper's job is to prevent it: read the renewal clause, compute the deadline, sleep until the notice window opens, ask for one human signature, send the notice, then check whether billing actually stopped.&lt;/p&gt;

&lt;p&gt;But the model is not permitted to schedule anything just because its answer sounds confident.&lt;/p&gt;

&lt;p&gt;Gemini proposes a deadline. A separate deterministic engine — regex and calendar arithmetic, no language model inside — derives the date independently from the same text. The decision is deliberately boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model_deadline&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;engine_deadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date_engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;derive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;engine_deadline&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ambiguous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the clause cannot be derived safely&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;model_deadline&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;engine_deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the two readings disagree&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine_deadline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gate has already caught a real one-day error from the model, live. In contract work, "only one day" is another year of fees.&lt;/p&gt;

&lt;p&gt;It also refuses clauses like this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;written notice no later than sixty (90) days before renewal&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A model can invent a plausible reading of that. Reaper can't. &lt;strong&gt;The contradiction becomes the result.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That was the original trust boundary: the model may propose, deterministic code decides whether the proposal is safe to act on.&lt;/p&gt;

&lt;p&gt;Then I added precedent memory and nearly broke it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why useful memory can make an agent less trustworthy
&lt;/h2&gt;

&lt;p&gt;The memory stores clause shapes and what happened to them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the deterministic gate accept or block the clause?&lt;/li&gt;
&lt;li&gt;Did the vendor stop billing?&lt;/li&gt;
&lt;li&gt;Was a dispute opened?&lt;/li&gt;
&lt;li&gt;Did the contract require email, registered post, certified mail, or a portal?&lt;/li&gt;
&lt;li&gt;Was this a real obligation, or a labelled test fixture?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each clause is embedded with &lt;code&gt;gemini-embedding-001&lt;/code&gt; into a 768-dimension vector in BigQuery. At intake, native &lt;code&gt;VECTOR_SEARCH&lt;/code&gt; surfaces clauses with similar meaning even when the wording differs — a blocked contradiction, a clean cancellation the vendor honoured, a valid notice the vendor ignored, a contract where email was only ever a courtesy copy.&lt;/p&gt;

&lt;p&gt;That's genuinely valuable context. It's also perfectly capable of contaminating the current decision.&lt;/p&gt;

&lt;p&gt;Suppose the clause in front of you cleanly says "sixty (60) days," but a highly similar prior clause said "sixty (90) days" and was blocked. Feed that precedent to the model &lt;em&gt;before&lt;/em&gt; the gate rules, and the old contradiction anchors the new interpretation. The system starts reasoning by analogy when it should be reading the document in front of it.&lt;/p&gt;

&lt;p&gt;So Reaper enforces an ordering rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CURRENT CONTRACT
      ↓
DETERMINISTIC GATE
      ↓
VERDICT IS FIXED          ← nothing after this line can change it
      ↓
PRECEDENT LOOKUP
      ↓
ADVISORY CONTEXT FOR THE HUMAN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Memory arrives &lt;em&gt;after&lt;/em&gt; the verdict. And a test makes that boundary executable rather than aspirational: a 97%-similar blocked precedent is deliberately returned for a clean clause, and the clean clause must still schedule.&lt;/p&gt;

&lt;p&gt;The warning is allowed to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A near-identical clause was blocked before because its words disagreed with its numerals. &lt;strong&gt;This is prior history, not a verdict.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last sentence isn't interface copy. It's the permission model, written down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Store outcomes, not just documents
&lt;/h2&gt;

&lt;p&gt;A vector database full of text answers &lt;em&gt;what looks similar?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An institutional memory has to answer &lt;em&gt;what happened next?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That distinction reshaped the BigQuery schema. Every row keeps the clause &lt;strong&gt;and&lt;/strong&gt; its structured outcome: gate verdict, notice method, final status, whether billing stopped, whether a dispute opened, and the terminal receipt hash where one exists.&lt;/p&gt;

&lt;p&gt;The embedding finds the neighbours. The structured fields explain why those neighbours matter — which is how the system tells apart two contracts with nearly identical renewal language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one was cancelled, and billing stopped;&lt;/li&gt;
&lt;li&gt;the other was cancelled correctly, and the vendor charged anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The text is similar. The operational lesson is the opposite.&lt;/p&gt;

&lt;p&gt;This generalises. Building memory for a support agent? Store whether the resolution actually worked. A deployment agent? Store whether the rollout was rolled back. A collections agent? Store whether the promised payment arrived.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval without outcomes is recollection without learning.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Provenance has to survive retrieval
&lt;/h2&gt;

&lt;p&gt;Reaper ships with a labelled corpus of synthetic clause shapes so the memory system can be tested reproducibly. Those rows must never masquerade as customer history.&lt;/p&gt;

&lt;p&gt;So every precedent carries its source — &lt;code&gt;fixture&lt;/code&gt;, or a real ledger-backed obligation. A seeded example may demonstrate that registered post is required; the product must never imply a real customer previously hit that vendor.&lt;/p&gt;

&lt;p&gt;This sounds like metadata housekeeping. It's a trust boundary. Once retrieved text is condensed into a sentence, provenance evaporates — and &lt;em&gt;"a similar contract was blocked before"&lt;/em&gt; means something very different from &lt;em&gt;"a synthetic test clause of this shape is expected to be blocked."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your agent mixes fixtures, simulations, generated data and production history, provenance has to travel &lt;strong&gt;with the memory&lt;/strong&gt;, not live in a README nobody opens.&lt;/p&gt;




&lt;h2&gt;
  
  
  A missing memory is also a result
&lt;/h2&gt;

&lt;p&gt;Here's a tempting three lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;em&gt;"BigQuery was unavailable"&lt;/em&gt; and &lt;em&gt;"no similar precedent exists"&lt;/em&gt; are indistinguishable. They are not the same fact.&lt;/p&gt;

&lt;p&gt;Reaper's lookup fails open: if the table is disabled, expired, unreachable, or the embedding call fails, the contractual verdict is untouched. But the evidence chain records that memory was unavailable, and why. The system distinguishes four states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memory was consulted, nothing passed the threshold;&lt;/li&gt;
&lt;li&gt;memory was disabled;&lt;/li&gt;
&lt;li&gt;the embedding could not be created;&lt;/li&gt;
&lt;li&gt;BigQuery could not be reached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An advisory system going down should never block a valid cancellation. It should also never quietly pretend history was checked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Failure transparency is part of memory design.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The evidence should include restraint
&lt;/h2&gt;

&lt;p&gt;Every material action lands in an append-only SHA-256 hash chain: extraction, precedent consultation, the gate verdict, unprompted wakes, approval, delivery, invoice verification, dispute creation.&lt;/p&gt;

&lt;p&gt;But the more interesting receipts describe what the agent &lt;em&gt;didn't&lt;/em&gt; do.&lt;/p&gt;

&lt;p&gt;The mailbox pipeline reads headers first. Messages that fail its admission rules stay unopened — and those refusals are recorded. When the system declines to inspect a bank statement from an unrelated sender, the refusal becomes evidence of restraint.&lt;/p&gt;

&lt;p&gt;The same discipline applies to memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memory cannot change the gate;&lt;/li&gt;
&lt;li&gt;a failed lookup cannot become "no history";&lt;/li&gt;
&lt;li&gt;fixture data cannot become customer history;&lt;/li&gt;
&lt;li&gt;raw vectors never enter the operational evidence ledger.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A trustworthy agent should be able to prove not just what it did, but &lt;strong&gt;which powers it deliberately declined to use.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Long-running agents spend most of their lives doing nothing
&lt;/h2&gt;

&lt;p&gt;Cancellation exposed a less glamorous problem: waiting.&lt;/p&gt;

&lt;p&gt;The agent may read a document today and need to act six months from now. It must not burn tokens, hold a process open, or depend on someone remembering to restart a chat.&lt;/p&gt;

&lt;p&gt;So Reaper persists the obligation and sleeps. When the notice window opens it wakes and writes a receipt showing that &lt;em&gt;calendar time&lt;/em&gt; — not a human pressing continue — triggered the action. It then pauses at the single point where authority is genuinely required: signing and sending.&lt;/p&gt;

&lt;p&gt;That pause survives a process restart, because the invocation and its resume pointer live in persistent state rather than RAM. Killing the server doesn't manufacture a new approval or lose the pending one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And then production breaks the whole mechanism.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reaper runs on Cloud Run, which stops the container between requests. An in-process timer works beautifully on my laptop and does precisely nothing on a service that has scaled to zero. An agent whose autonomy depends on a container happening to still be alive is not autonomous.&lt;/p&gt;

&lt;p&gt;So the heartbeat comes from outside: Cloud Scheduler calls a &lt;code&gt;/tick&lt;/code&gt; endpoint once a minute, and that endpoint runs the &lt;strong&gt;same function&lt;/strong&gt; the local loop runs. Not a second implementation — a separate "scheduled" code path drifts from the one you demo, and then the thing you showed isn't the thing that ships. The alternative was paying for an always-on instance to preserve an illusion the architecture didn't need.&lt;/p&gt;

&lt;p&gt;Which leads to a rule I'd carry anywhere:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Human approval should be a durable state transition, not a conversational moment.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If an approval disappears when the process dies, it was never part of the workflow. It was part of the demo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Five rules I'd reuse in any high-consequence agent
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Separate proposals from permissions.&lt;/strong&gt;&lt;br&gt;
The model can recommend an action without holding the authority to execute it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Run deterministic checks before advisory retrieval.&lt;/strong&gt;&lt;br&gt;
Memory should explain a decision or warn a human — never rewrite facts already established from the current input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Store outcomes with memories.&lt;/strong&gt;&lt;br&gt;
Similar text is only useful paired with what actually happened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Preserve provenance and failure states.&lt;/strong&gt;&lt;br&gt;
"Fixture," "production history," "no match," and "search unavailable" are four different facts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Test the boundaries, not the happy path.&lt;/strong&gt;&lt;br&gt;
The important test isn't whether memory returns a match. It's whether an alarming match can improperly change the verdict.&lt;/p&gt;




&lt;h2&gt;
  
  
  The agent I trust is the one that distrusts itself
&lt;/h2&gt;

&lt;p&gt;We usually describe capable agents by listing what they can do. I've become more interested in the opposite list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model cannot schedule its own date.&lt;/li&gt;
&lt;li&gt;A contradictory clause cannot be resolved by confidence.&lt;/li&gt;
&lt;li&gt;Similar history cannot overrule current evidence.&lt;/li&gt;
&lt;li&gt;A missing lookup cannot pretend to be an empty result.&lt;/li&gt;
&lt;li&gt;A process restart cannot erase a pending human decision.&lt;/li&gt;
&lt;li&gt;A scaled-to-zero container cannot excuse a missed deadline.&lt;/li&gt;
&lt;li&gt;An unread message cannot quietly become a read one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;That negative space is where trust comes from.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Memory makes an agent more experienced. Boundaries stop that experience from hardening into prejudice.&lt;/p&gt;

&lt;p&gt;Determinism is not the opposite of agency. It is what makes agency defensible.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Reaper&lt;/strong&gt; is my solo entry for the All Things Agentic Hackathon.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://reaper-t2w3ltp6fa-uc.a.run.app" rel="noopener noreferrer"&gt;https://reaper-t2w3ltp6fa-uc.a.run.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/N-45div/Reaper" rel="noopener noreferrer"&gt;https://github.com/N-45div/Reaper&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Built with Google ADK · Gemini 3.5 Flash · Gemma 4 · &lt;code&gt;gemini-embedding-001&lt;/code&gt; · &lt;code&gt;gemini-3.5-transcribe&lt;/code&gt; · Cloud Run · Firestore · Cloud SQL · BigQuery · Cloud Scheduler&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>googlecloud</category>
      <category>ai</category>
      <category>allthingsagentichackathon</category>
    </item>
    <item>
      <title>Building Missio: An Evidence-Bound Remediation Agent with SigNoz</title>
      <dc:creator>N DIVIJ</dc:creator>
      <pubDate>Sun, 26 Jul 2026 11:51:55 +0000</pubDate>
      <link>https://dev.to/n45div/building-missio-an-evidence-bound-remediation-agent-with-signoz-47</link>
      <guid>https://dev.to/n45div/building-missio-an-evidence-bound-remediation-agent-with-signoz-47</guid>
      <description>&lt;p&gt;A production error is exactly when an AI agent should be least creative.&lt;/p&gt;

&lt;p&gt;That sentence became the design rule behind Missio, a terminal mission control system I built for the Agents of SigNoz hackathon. Missio starts with a real incident reported in Slack, reconstructs what happened from SigNoz, finds the exact source revision that produced the failure, asks an agent for a tightly bounded change, and opens a draft pull request only after a human approves the action.&lt;/p&gt;

&lt;p&gt;The entire journey stays visible in one Rust TUI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SIGNAL → EVIDENCE → CODE → PATCH → HUMAN → PR → CI → HANDOFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a dashboard with an AI summary beside it. Every stage represents something the system has actually observed or completed. If evidence is missing, the mission stops. If GitHub cannot&lt;br&gt;
resolve the production revision, it stops. If the model returns an unsafe patch, it stops.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Incident Agents Need Evidence, Not Confidence
&lt;/h2&gt;

&lt;p&gt;Observability tools are already good at showing that a request failed. The harder question is what an agent should be allowed to do next.&lt;/p&gt;

&lt;p&gt;An error message alone does not establish which code was deployed. A repository's default branch may have moved since the failure. A model can produce a convincing explanation using the wrong version of a file. It can also quietly fill missing context with assumptions.&lt;/p&gt;

&lt;p&gt;I wanted the opposite behavior. Missio should be useful only when it can build a chain from a production signal to a specific piece of source code. The agent's job is to reason inside that chain, not invent one.&lt;/p&gt;

&lt;p&gt;That made SigNoz the evidence system of record rather than a decorative integration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Turning a Real Checkout Failure Into a Mission
&lt;/h2&gt;

&lt;p&gt;For the demo, I use an instrumented checkout service. A bad discount request reaches a real HTTP endpoint and produces a failing OpenTelemetry span. The span is exported to SigNoz with the normal service and error fields, plus the details Missio needs to connect runtime behavior to source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The affected resource;&lt;/li&gt;
&lt;li&gt;The environment;&lt;/li&gt;
&lt;li&gt;The code file and function;&lt;/li&gt;
&lt;li&gt;The repository URL;&lt;/li&gt;
&lt;li&gt;The full Git commit running in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then an operator opens the incident from an allowlisted Slack channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/missio-sev SEV1 service production/checkout checkout requests are failing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slack is only the admission point. The message does not tell the agent what the root cause is, and Missio does not treat the wording as evidence. It uses the resource and incident window to query the corresponding telemetry in SigNoz.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Indexing Delay That Changed the Design
&lt;/h2&gt;

&lt;p&gt;The most useful lesson from building Missio did not come from reading documentation. It came from a demo that failed even though every individual component appeared healthy.&lt;/p&gt;

&lt;p&gt;The checkout service successfully exported its span. SigNoz accepted the telemetry. But Missio queried immediately and received no matching rows. A short time later, the same query returned the failure exactly as expected.&lt;/p&gt;

&lt;p&gt;Ingestion acceptance and query availability are not the same moment.&lt;/p&gt;

&lt;p&gt;That distinction sounds small, but it changes the behavior of an autonomous workflow. If an empty first response means “there was no incident,” the agent can discard a genuine production failure.&lt;/p&gt;

&lt;p&gt;If the system waits forever, the operator cannot tell whether it is making progress.&lt;/p&gt;

&lt;p&gt;Missio now performs bounded evidence acquisition and makes the wait visible in the TUI. It retries for a limited period while SigNoz indexes the span. If a valid evidence bundle still cannot be formed, the EVIDENCE stage fails closed. It never replaces missing telemetry with a fabricated&lt;br&gt;
incident just to keep the animation moving.&lt;/p&gt;

&lt;p&gt;This was also why I kept the signal horizon at the bottom of the interface. The operator can see whether Missio is listening, acquiring evidence, or holding because the observation is incomplete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting Telemetry Choose the Source
&lt;/h2&gt;

&lt;p&gt;Once the trace is available, Missio extracts the repository and the full deployed commit from the span. That commit matters more than the current state of the default branch: it identifies the code that actually produced the observed failure.&lt;/p&gt;

&lt;p&gt;Missio reads the repository tree at that immutable revision and selects source linked to the observed code location. In a monorepo, it can keep the investigation inside the affected service. Only that bounded context reaches the agent.&lt;/p&gt;

&lt;p&gt;This gives the model a much more honest question:&lt;/p&gt;

&lt;p&gt;Given this observed failure and the exact source that produced it, is there enough evidence for a small fix?&lt;/p&gt;

&lt;p&gt;The model can either hold the mission or propose replacement content for source it was given. It cannot add an unrelated file, edit the CI workflow, reach outside the service boundary, or claim that an external action succeeded. Those decisions are enforced by Rust after the model responds.&lt;/p&gt;

&lt;p&gt;Missio uses Rig for the agent runtime and an explicitly configured model through OpenRouter. The model never receives Slack, SigNoz, or GitHub credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the TUI an Authority Boundary
&lt;/h2&gt;

&lt;p&gt;I originally thought of the interface as the visual identity of the project: a mission-control orbit instead of another grid of cards and tables. While building the real workflow, it became something more useful.&lt;/p&gt;

&lt;p&gt;The TUI shows who currently has authority.&lt;/p&gt;

&lt;p&gt;SigNoz can provide evidence. The agent can propose a patch. Neither can create a pull request. When a proposed change passes policy, the mission pauses at HUMAN and shows the target repository. The operator must explicitly approve one draft-PR attempt.&lt;/p&gt;

&lt;p&gt;That approval is deliberately narrow. It does not authorize a merge or deployment. If GitHub rejects the request, Missio preserves the mission and returns control to the human instead of silently repeating a mutation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ending at Handoff, Not Pretending Recovery
&lt;/h2&gt;

&lt;p&gt;After approval, Missio creates a branch and draft pull request from the production revision identified by SigNoz. The evidence digest travels into the pull request, connecting the proposed change back to the incident that caused it.&lt;/p&gt;

&lt;p&gt;Missio then watches GitHub CI for the exact draft commit. When the checks pass, the final state is HANDOFF.&lt;/p&gt;

&lt;p&gt;That wording is intentional. Missio does not pretend that a green check means production has recovered. It tells the operator that an evidence-bound draft is ready for normal review, merge, and deployment. The pull request remains the place where engineers can inspect the change and make&lt;br&gt;
the final call.&lt;/p&gt;

&lt;p&gt;I considered extending the demo through automatic deployment, but it would have weakened the product's trust model. A hackathon animation should not manufacture authority that the real system&lt;br&gt;
does not have.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SigNoz Made Possible
&lt;/h2&gt;

&lt;p&gt;Without SigNoz, this would be a code agent triggered by a Slack message. With SigNoz, the agent is grounded in an observed resource, time window, trace, code location, repository, and deployed revision.&lt;/p&gt;

&lt;p&gt;That context affects every later step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It decides whether a mission exists;&lt;/li&gt;
&lt;li&gt;It decides which source can be read;&lt;/li&gt;
&lt;li&gt;It constrains what the agent can change;&lt;/li&gt;
&lt;li&gt;It binds the draft pull request back to production evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deepest lesson for me was that agent observability is not only about tracing what a model did. Observability can also control what the model is allowed to do next.&lt;/p&gt;

&lt;p&gt;Missio still leaves the final operational decision with a person. Its job is to turn a noisy incident into a reviewable, evidence-bound change without hiding the gaps along the way.&lt;/p&gt;

&lt;p&gt;You can explore &lt;a href="https://github.com/N-45div/Missio" rel="noopener noreferrer"&gt;Missio on GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you want to trace the pieces I built on, the most useful references were the SigNoz guides for&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://signoz.io/docs/userguide/query-builder-v5/" rel="noopener noreferrer"&gt;Query Builder&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://signoz.io/docs/ingestion/self-hosted/overview/" rel="noopener noreferrer"&gt;Self-hosted ingestion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://opentelemetry.io/docs/concepts/semantic-conventions/" rel="noopener noreferrer"&gt;OpenTelemetry semantic conventions&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>rust</category>
    </item>
    <item>
      <title>Building CanopySplit: A Deep Dive into Octant V2 Yield Donating Strategies</title>
      <dc:creator>N DIVIJ</dc:creator>
      <pubDate>Sun, 09 Nov 2025 22:02:34 +0000</pubDate>
      <link>https://dev.to/n45div/building-canopysplit-a-deep-dive-into-octant-v2-yield-donating-strategies-2oe4</link>
      <guid>https://dev.to/n45div/building-canopysplit-a-deep-dive-into-octant-v2-yield-donating-strategies-2oe4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CanopySplit&lt;/strong&gt; is a multi-layer DeFi protocol that transforms idle capital into climate impact. Users deposit WETH, earn yield through Aave v3, and automatically split 100% of profits among climate recipients—all while keeping their principal withdrawable at any time.&lt;/p&gt;

&lt;p&gt;This technical deep-dive covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Octant V2 Yield Donating Strategy architecture&lt;/li&gt;
&lt;li&gt;ERC-4626 vault integration with Aave v3&lt;/li&gt;
&lt;li&gt;Epoch-based donation splitting mechanics&lt;/li&gt;
&lt;li&gt;Custom Uniswap v4 hook for swap fee donations&lt;/li&gt;
&lt;li&gt;Production deployment challenges on Sepolia&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Live on Sepolia:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strategy: &lt;code&gt;0x0D1d8AE2dD0e4B06ca0Ef2949150eb021cAf6Ce9&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Splitter: &lt;code&gt;0xda5fA1c26Ec29497C2B103B385569286B30EC248&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Asset (WETH): &lt;code&gt;0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┐
│ User Wallet │
└──────┬──────┘
       │ deposit WETH
       ▼
┌──────────────────────────────┐
│ Aave4626YieldDonatingStrategy│ (ERC-4626 vault)
│ - Deposits to Aave v3        │
│ - Mints shares to users      │
│ - Reports profit → splitter  │
└──────────────┬───────────────┘
               │ mint donation shares
               ▼
┌──────────────────────────────┐
│ TriSplitDonationSplitter     │
│ - Holds strategy shares      │
│ - Epoch-based allocation     │
│ - 3 climate recipients       │
└──────┬───────────────────────┘
       │ distribute()
       ▼
┌─────────────────────────────────┐
│ Recipients (50% / 30% / 20%)    │
│ - Planters                      │
│ - MRV (Monitoring/Verification) │
│ - Maintenance                   │
└─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 1: Octant V2 Yield Donating Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Core Concept
&lt;/h3&gt;

&lt;p&gt;Octant V2 introduces &lt;strong&gt;Yield Donating Strategies&lt;/strong&gt; (YDS), which extend ERC-4626 with donation mechanics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface IYieldDonatingStrategy is IERC4626 {
    function report() external returns (uint256 profit, uint256 loss);
    function setDonationSplitter(address splitter) external;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key innovation:&lt;/strong&gt; When &lt;code&gt;report()&lt;/code&gt; is called:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate &lt;code&gt;profit = currentAssets - lastRecordedAssets&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If profit &amp;gt; 0: &lt;strong&gt;Mint shares to splitter&lt;/strong&gt; (not to users!)&lt;/li&gt;
&lt;li&gt;If loss &amp;gt; 0: &lt;strong&gt;Burn donation shares first&lt;/strong&gt;, protecting user capital&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users keep 100% of principal&lt;/li&gt;
&lt;li&gt;Donations absorb losses first&lt;/li&gt;
&lt;li&gt;No performance fees&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation: Aave4626YieldDonatingStrategy
&lt;/h3&gt;

&lt;p&gt;We built an ERC-4626 wrapper around Aave v3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Aave4626YieldDonatingStrategy is YieldDonatingTokenizedStrategy {
    IERC4626 public immutable vault; // ATokenVault

    constructor(
        IERC20 asset_,
        IERC4626 vault_,
        string memory name_,
        address management_,
        address keeper_
    ) YieldDonatingTokenizedStrategy(asset_, name_, management_, keeper_) {
        vault = vault_;
        asset_.forceApprove(address(vault_), type(uint256).max);
    }

    function totalAssets() public view override returns (uint256) {
        uint256 shares = vault.balanceOf(address(this));
        return vault.convertToAssets(shares);
    }

    function _deployFunds(uint256 amount) internal override {
        vault.deposit(amount, address(this));
    }

    function _freeFunds(uint256 amount) internal override {
        vault.withdraw(amount, address(this), address(this));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why ERC-4626?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Composability:&lt;/strong&gt; Any ERC-4626 vault can plug in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-rebasing:&lt;/strong&gt; Fixed shares, yield in &lt;code&gt;convertToAssets()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety:&lt;/strong&gt; Vault enforces supply caps and liquidity checks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The report() Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function report() external onlyKeepers returns (uint256 profit, uint256 loss) {
    uint256 currentAssets = totalAssets();
    uint256 lastAssets = lastRecordedAssets;

    if (currentAssets &amp;gt; lastAssets) {
        profit = currentAssets - lastAssets;

        // Mint shares to splitter (donation\!)
        uint256 sharesToMint = convertToShares(profit);
        _mint(donationSplitter, sharesToMint);

        emit Reported(profit, 0);
    } else if (currentAssets &amp;lt; lastAssets) {
        loss = lastAssets - currentAssets;

        // Burn donation shares first
        uint256 splitterShares = balanceOf(donationSplitter);
        uint256 splitterAssets = convertToAssets(splitterShares);

        if (splitterAssets &amp;gt;= loss) {
            uint256 sharesToBurn = convertToShares(loss);
            _burn(donationSplitter, sharesToBurn);
        } else {
            _burn(donationSplitter, splitterShares);
            // Remaining loss socialized across all shares
        }

        emit Reported(0, loss);
    }

    lastRecordedAssets = totalAssets();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Critical insight:&lt;/strong&gt; Minting shares (instead of transferring assets) means donations continue earning yield until distributed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Aave v3 Integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ATokenVault: ERC-4626 Wrapper for Aave
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract ATokenVault is ERC4626, Ownable {
    IPool public immutable aavePool;
    IERC20 public immutable aToken;

    constructor(
        IERC20 asset_,
        IPoolAddressesProvider provider
    ) ERC4626(asset_) ERC20("Aave WETH Vault", "aWETHv") {
        aavePool = IPool(provider.getPool());
        aToken = IERC20(aavePool.getReserveData(address(asset_)).aTokenAddress);
    }

    function totalAssets() public view override returns (uint256) {
        return aToken.balanceOf(address(this)); // aTokens auto-accrue
    }

    function _deposit(address caller, address receiver, uint256 assets, uint256 shares) 
        internal override 
    {
        SafeERC20.safeTransferFrom(asset(), caller, address(this), assets);
        SafeERC20.forceApprove(asset(), address(aavePool), assets);

        aavePool.supply(address(asset()), assets, address(this), 0);

        _mint(receiver, shares);
        emit Deposit(caller, receiver, assets, shares);
    }

    function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) 
        internal override 
    {
        if (caller \!= owner) {
            _spendAllowance(owner, caller, shares);
        }

        _burn(owner, shares);
        aavePool.withdraw(address(asset()), assets, receiver);

        emit Withdraw(caller, receiver, owner, assets, shares);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Deployed on Sepolia:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vault: &lt;code&gt;0x6938238e57CBe1b4B51Eb3B51389cEf8d3a88521&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Asset: WETH (&lt;code&gt;0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Aave Provider: &lt;code&gt;0x012bAC54348C0E635dCAc9D5FB99f06F24136C9A&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 3: TriSplit Donation Splitter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Epoch-Based Allocation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct Recipient {
    address addr;
    string role;
}

struct Policy {
    uint256 epoch;
    uint256[3] basisPoints; // [5000, 3000, 2000] = 50%, 30%, 20%
}

contract TriSplitDonationSplitter {
    Recipient[3] public recipients;
    Policy public currentPolicy;
    Policy public upcomingPolicy;
    IERC4626 public vault;

    function distribute() external {
        uint256 shares = vault.balanceOf(address(this));
        uint256 assets = vault.redeem(shares, address(this), address(this));

        uint256[3] memory amounts;
        for (uint256 i = 0; i &amp;lt; 3; i++) {
            amounts[i] = (assets * currentPolicy.basisPoints[i]) / 10_000;
            IERC20(vault.asset()).safeTransfer(recipients[i].addr, amounts[i]);
        }

        emit Distributed(currentPolicy.epoch, amounts, recipients);
    }

    function rollEpoch() external onlyOwner {
        currentPolicy = upcomingPolicy;
        upcomingPolicy.epoch++;
        emit EpochRolled(currentPolicy.epoch);
    }

    function setUpcomingPolicy(uint256[3] calldata bps) external onlyOwner {
        require(bps[0] + bps[1] + bps[2] == 10_000, "Must sum to 100%");
        upcomingPolicy.basisPoints = bps;
        emit UpcomingPolicySet(upcomingPolicy.epoch, bps);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why epochs?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recipients know their allocation in advance&lt;/li&gt;
&lt;li&gt;Owner can adjust future weights without disrupting current distributions&lt;/li&gt;
&lt;li&gt;Full on-chain transparency via events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Current allocation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Planters: 50% (&lt;code&gt;0xF9b2eFCAcc1B93c1bd7F898d0a8c4b34aBD78E53&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;MRV: 30% (&lt;code&gt;0x9261432cab3c0F83E86fa6e41E4a88dA06E7ecc6&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Maintenance: 20% (&lt;code&gt;0x89C13e8e5a81E775160322df9d7869893926A8Cc&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 4: Uniswap v4 Hook (Local PoC)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Extending Donations to Swap Fees
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract TriSplitDonationHook is BaseHook {
    struct HookConfig {
        address donationTarget;
        uint256 donationBps; // 100 = 1%
    }

    mapping(PoolId =&amp;gt; HookConfig) public configs;

    function afterSwap(
        address,
        PoolKey calldata key,
        IPoolManager.SwapParams calldata params,
        BalanceDelta delta,
        bytes calldata
    ) external override returns (bytes4, int128) {
        PoolId poolId = key.toId();
        HookConfig memory config = configs[poolId];

        if (config.donationTarget \!= address(0)) {
            Currency currency = params.zeroForOne ? key.currency0 : key.currency1;

            uint256 amountIn = params.zeroForOne 
                ? uint256(int256(-delta.amount0())) 
                : uint256(int256(-delta.amount1()));

            uint256 donation = (amountIn * config.donationBps) / 10_000;

            poolManager.take(currency, config.donationTarget, donation);

            emit DonationExecuted(poolId, donation, config.donationTarget);
        }

        return (this.afterSwap.selector, 0);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Testing on Anvil:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy v4 infrastructure&lt;/span&gt;
forge script script/00_DeployV4.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545

&lt;span class="c"&gt;# Deploy hook&lt;/span&gt;
forge script script/00_DeployHook.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545

&lt;span class="c"&gt;# Initialize pool&lt;/span&gt;
forge script script/05_EnsureInitialized.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545

&lt;span class="c"&gt;# Add liquidity&lt;/span&gt;
forge script script/02_AddLiquidity.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545

&lt;span class="c"&gt;# Configure hook (1% donation)&lt;/span&gt;
forge script script/04_SetHookConfig.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545

&lt;span class="c"&gt;# Execute swap (triggers donation\!)&lt;/span&gt;
forge script script/03_Swap.s.sol &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://127.0.0.1:8545
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5: Frontend Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dynamic Asset Detection
&lt;/h3&gt;

&lt;p&gt;Instead of hardcoding USDC/WETH, we read the asset dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useAssetInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strategyAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReadContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;strategyAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StrategyABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReadContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ERC20ABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;symbol&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;decimals&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReadContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ERC20ABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decimals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decimals&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works with any ERC-20 asset&lt;/li&gt;
&lt;li&gt;No frontend redeployment needed&lt;/li&gt;
&lt;li&gt;Correct decimal formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Role-Based Access Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AppPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAccount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;management&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReadContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ADDRS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sepolia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StrategyABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isManagement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;management&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DepositForm&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WithdrawForm&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isManagement&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleReport&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Report&lt;/span&gt; &lt;span class="nx"&gt;Profit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Loss&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Event Tracking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useLifetimeDonations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;splitterAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContractEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;splitterAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SplitterABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Distributed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fromBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalDonated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;epoch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amounts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;amounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;totalDonated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;eventCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real-World Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenge 1: Sepolia Gas Cap (16.7M)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Contract creation bytecode exceeded Sepolia's per-tx gas limit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# foundry.toml&lt;/span&gt;
&lt;span class="py"&gt;optimizer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;optimizer_runs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;via_ir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;bytecode_hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"none"&lt;/span&gt;
&lt;span class="py"&gt;cbor_metadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge clean &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; forge build
forge create YieldDonatingTokenizedStrategy &lt;span class="nt"&gt;--gas-limit&lt;/span&gt; 0xFD0000 &lt;span class="nt"&gt;--legacy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 2: WETH Pivot
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Aave v3 Sepolia USDC had supply cap issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Switched to WETH (18 decimals, no supply cap).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USDC_UNDERLYING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c  &lt;span class="c"&gt;# WETH\!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 3: Permit2 Allowance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Swaps reverted with &lt;code&gt;InsufficientAllowance&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt; Granted allowance to PoolManager, but Router calls &lt;code&gt;transferFrom()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Grant allowance to Router, not PoolManager
permit2.approve(address(token0), address(swapRouter), type(uint160).max, type(uint48).max);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 4: Token Decimals
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; USDC (6 decimals) vs WETH (18 decimals) mismatches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Created patching script for local testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FakeUSDC fake = new FakeUSDC(); // decimals() = 6
vm.etch(token0Addr, address(fake).code);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Innovations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Epoch-Based Splits:&lt;/strong&gt; Unlike single-recipient YDS, we route to 3 recipients with dynamic weights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Adapter Support:&lt;/strong&gt; Idle, Aave v3, and ERC-4626 strategies all feed the same splitter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Asset Detection:&lt;/strong&gt; Frontend works with any ERC-20 without hardcoding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks Integration:&lt;/strong&gt; Extended YDS concept to Uniswap v4 swap fees&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loss Protection:&lt;/strong&gt; Donation shares burn first, protecting user capital&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CanopySplit demonstrates how Octant V2's Yield Donating Strategies can be extended with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-protocol integrations&lt;/strong&gt; (Aave v3, Uniswap v4)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible donation mechanics&lt;/strong&gt; (epoch-based splits, loss protection)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production-ready UX&lt;/strong&gt; (dynamic asset detection, role-based access)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is composable, transparent, and gas-efficient. All code is open-source and ready for judges to test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways for builders:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ERC-4626 is the perfect abstraction for yield strategies&lt;/li&gt;
&lt;li&gt;Epoch-based policies provide flexibility without disrupting current operations&lt;/li&gt;
&lt;li&gt;Dynamic asset detection makes frontends future-proof&lt;/li&gt;
&lt;li&gt;Testnet gas limits are real—optimize aggressively&lt;/li&gt;
&lt;li&gt;Always verify contract addresses exist on-chain before trusting deployment logs&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/N-45div/CanopySplit" rel="noopener noreferrer"&gt;https://github.com/N-45div/CanopySplit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sepolia Strategy:&lt;/strong&gt; &lt;code&gt;0x0D1d8AE2dD0e4B06ca0Ef2949150eb021cAf6Ce9&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sepolia Splitter:&lt;/strong&gt; &lt;code&gt;0xda5fA1c26Ec29497C2B103B385569286B30EC248&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Octant V2 Docs:&lt;/strong&gt; &lt;a href="https://docs.octant.app" rel="noopener noreferrer"&gt;docs.octant.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built with ❤️ for the Octant V2 hackathon. Questions? Reach out on Twitter &lt;a href="https://twitter.com/godlovesu_n" rel="noopener noreferrer"&gt;@godlovesu_n&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>ethereum</category>
      <category>web3</category>
    </item>
    <item>
      <title>Introducing "Resilient Response" - Empowering Disaster Relief and Management</title>
      <dc:creator>N DIVIJ</dc:creator>
      <pubDate>Wed, 16 Aug 2023 08:14:21 +0000</pubDate>
      <link>https://dev.to/n45div/introducing-resilient-response-empowering-disaster-relief-and-management-4o48</link>
      <guid>https://dev.to/n45div/introducing-resilient-response-empowering-disaster-relief-and-management-4o48</guid>
      <description>&lt;p&gt;Hey there, fellow developers and enthusiasts of this beautiful Dev Community&lt;/p&gt;

&lt;p&gt;I'm thrilled to introduce you to a project that's very close to my heart - &lt;strong&gt;"Resilient Response"&lt;/strong&gt;, an open-source application designed to revolutionize disaster relief and management efforts. 🚀&lt;/p&gt;

&lt;p&gt;🔗 Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://resilient-response.vercel.app/" rel="noopener noreferrer"&gt;https://resilient-response.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: 
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/N-45div" rel="noopener noreferrer"&gt;
        N-45div
      &lt;/a&gt; / &lt;a href="https://github.com/N-45div/Resilient-Response" rel="noopener noreferrer"&gt;
        Resilient-Response
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Our team is excited to announce the development of a cutting-edge web application both for mobile and desktop for the GDSC Solution Challenge 2023. With a mission to empower communities to withstand and recover from natural disasters, our app focuses on building resilience through innovative technology.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Resilient Response&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Resilient Response is a web application developed to foster connectivity and provide vital information during periods of crisis. This application was conceived as part of the 2023 Solution Challenge, which aligns with the overarching mission to address the United Nations' 17 Sustainable Development Goals by leveraging Google technology. The Resilient Response web app offers users the ability to register and access chat interfaces to stay informed about events occurring in their geographic area. In addition to real-time weather updates, the application also displays the locations of available shelters during times of emergency.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/N-45div/Resilient-Response/public/firebase.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FN-45div%2FResilient-Response%2Fpublic%2Ffirebase.png" width="175"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/N-45div/Resilient-Response/public/tensorflow-ar21.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FN-45div%2FResilient-Response%2Fpublic%2Ftensorflow-ar21.png" width="175"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/N-45div/Resilient-Response/public/banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FN-45div%2FResilient-Response%2Fpublic%2Fbanner.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=a0wbma13RkM" rel="nofollow noopener noreferrer"&gt;Our video presentation&lt;/a&gt;         &lt;a href="https://resilient-response.vercel.app/" rel="nofollow noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Our team is excited to announce the development of a cutting-edge web application both for mobile and desktop for the GDSC Solution Challenge 2023. With a mission to empower communities to withstand and recover from natural disasters, our app focuses on building resilience through innovative technology.We believe that by harnessing the&lt;/strong&gt;…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/N-45div/Resilient-Response" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project Overview:&lt;/strong&gt;&lt;br&gt;
Disasters can strike unexpectedly and wreak havoc on communities. The key to minimizing their impact lies in effective coordination and rapid response. This is where Resilient Response comes in. It's a powerful application that combines cutting-edge technology with a user-friendly interface to streamline disaster relief operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🗺️ &lt;strong&gt;Geolocation Integration:&lt;/strong&gt; With the integration of geolocation services, "Resilient Response" allows responders to locate the nearest available shelters relative to the user's current position. This functionality ensures efficient utilization of resources and quicker response times.&lt;/p&gt;

&lt;p&gt;📱 &lt;strong&gt;Mobile Compatibility:&lt;/strong&gt; In disaster scenarios, being able to access vital information on-the-go is crucial. Resilient Response is designed to work seamlessly on mobile devices, ensuring that responders can stay connected and informed, even in challenging environments.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Open Source Collaboration:&lt;/strong&gt; Resilient Response is an open-source project, driven by collaboration and community involvement. Developers from all backgrounds can contribute to its growth, enhancing its capabilities and extending its reach.&lt;/p&gt;

&lt;p&gt;🎨 &lt;strong&gt;Design and User Experience:&lt;/strong&gt; Create intuitive interfaces that empower users to navigate through critical information effortlessly, even in stressful situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Innovative Hand Gesture Recognition&lt;/strong&gt;: Utilizing TensorFlow, a powerful machine learning framework, we've developed an intelligent algorithm that can identify and interpret hand gestures even in low-light or dark environments. This allows survivors to communicate their presence and condition to rescuers without relying solely on verbal communication, which might not be feasible in noisy or chaotic situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Hand Gestures?&lt;/strong&gt;&lt;br&gt;
Hand gestures are a universal form of communication that transcends language barriers. By incorporating this technology into "Resilient Response," we're enabling survivors, including those who might be injured or unable to speak, to make themselves understood and request assistance in a clear and intuitive way.&lt;/p&gt;

&lt;p&gt;🤖 &lt;strong&gt;Machine Learning Enthusiasts:&lt;/strong&gt; If you have expertise in machine learning, TensorFlow, or computer vision, your insights and skills can help us refine and enhance the hand gesture recognition algorithm.&lt;/p&gt;

&lt;p&gt;🧩 &lt;strong&gt;Testing and Feedback:&lt;/strong&gt; We're actively seeking individuals who can test the hand gesture recognition feature in various environments and provide valuable feedback for improvements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current Status and Future Vision of "Resilient Response"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current Status:&lt;/strong&gt;&lt;br&gt;
As of now, the "Resilient Response" project has reached a significant milestone. The core features that form the foundation of the application are in place and have been rigorously tested. Our team has poured countless hours into refining the user interface, optimizing performance, and ensuring the application's reliability, even in challenging scenarios.&lt;/p&gt;

&lt;p&gt;We've received valuable feedback from early users and collaborators, which has helped us fine-tune the user experience and identify areas for improvement. The project's &lt;a href="https://github.com/N-45div/Resilient-Response" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; has been bustling with activity, showcasing the collective efforts of developers who believe in the mission of enhancing disaster relief and management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Looking Forward:&lt;/strong&gt;&lt;br&gt;
While we've come a long way, there's still much to be done. Our vision for the future of "Resilient Response" is bold and ambitious, and we're excited to share some of the key areas we're focusing on:&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Real-time Communication:&lt;/strong&gt; Resilient Response provides a platform for real-time communication between first responders, volunteers, and affected individuals. Whether it's sending alerts, sharing critical information, or coordinating rescue missions, the application ensures that everyone is on the same page.&lt;/p&gt;

&lt;p&gt;🌟 &lt;strong&gt;Enhanced User and Community Customization:&lt;/strong&gt; We're working on expanding the application's customization options, allowing different organizations and regions to tailor the platform to their specific needs. Flexibility is key, as each disaster scenario is unique.&lt;/p&gt;

&lt;p&gt;🗺️ &lt;strong&gt;Geospatial Mapping:&lt;/strong&gt; With integrated geospatial mapping, Resilient Response enables responders to visualize affected areas, assess damage, and plan their actions more efficiently. The map-based interface enhances decision-making and resource allocation.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Integration with Emergency Services:&lt;/strong&gt; Our goal is to forge partnerships with emergency services and governmental agencies to seamlessly integrate "Resilient Response" into their operations. This collaboration can lead to more coordinated and efficient disaster response efforts.&lt;/p&gt;

&lt;p&gt;🔮 &lt;strong&gt;Predictive Analytics:&lt;/strong&gt; Leveraging the power of data, we aim to develop predictive models that can forecast disaster trends and help communities prepare in advance. This proactive approach can save lives and resources.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Comprehensive Documentation:&lt;/strong&gt; As the project evolves, we understand the importance of clear and comprehensive documentation. We're investing in creating resources that make it easy for developers to understand and contribute to the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join Us in Shaping the Future:&lt;/strong&gt;&lt;br&gt;
I'm extending an open invitation to all of you to be a part of this exciting journey. Your skills, insights, and passion can contribute to the success of "Resilient Response" in ways that are beyond measure. Whether you're a seasoned developer, a creative designer, a data aficionado, or someone who simply cares deeply about making a positive impact, there's a role for you here.&lt;/p&gt;

&lt;p&gt;Let's continue collaborating on &lt;a href="https://github.com/N-45div/Resilient-Response" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, engaging in discussions, and pushing the boundaries of what technology can achieve in disaster relief and management. Together, we can make a tangible difference in the lives of people around the world.&lt;/p&gt;

&lt;p&gt;If you have any questions, ideas, or suggestions, please don't hesitate to reach out. Together, we can make a significant impact!&lt;/p&gt;

&lt;p&gt;Once again 🔗 Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://resilient-response.vercel.app/" rel="noopener noreferrer"&gt;https://resilient-response.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/N-45div/Resilient-Response" rel="noopener noreferrer"&gt;Resilient Response&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thank you for reading the post .. Have a great day ahead !
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tensorflow</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
