Programmable Ethereum Transactions Without Smart Contracts.
Turn your manual transactions into programmable, composable, and reusable actions with Plug. No more tedious contract writing or one-off scripts. Just simple, powerful sentences at your fingertips powered by:
Using Mirror in the Plug unlocks a world where you can build a piece of onchain logic once and never build it again. Write the logic that sizes a trade a single time and it becomes a function: a self-contained, reusable block that drops into any strategies you make after. It's like a sauce you make once that becomes the base of a hundred dishes at a restaurant. You do the work a single time, and from then on it's ready to be used wherever you want it.
In part one of my Mirror journey I broke one long strategy plug into separate named functions so other people could find them in Discovery and fork them into their own strategies. I thought I'd cracked the code, but I hadn't. My "function" only worked inside a leverage loop like mine and was doing multiple jobs. It took me a few days to realize that this wasn't ideal and to reason about what I'd done wrong. And after sinking a lot of boats, I realized if I made each of my logic blocks specific enough to stand on their own, I could use them to power a bunch of other strategies I was planning to assemble.
I don't want you to have to take the detour I took to start reaping the benefits of Mirror, so let's walk through what Mirror functions really are, how they work, and how to build them right. That way, by the time you're done reading this post, you're ready to cook.
When it comes to functions, whether they're onchain or offchain, the most important thing to know is that they're meant to do one specific job. Not "rebalance my loop," but a single narrow task: like turning a health factor into a target debt, or sizing a trade from a value, or stopping a move too small to bother with.
Having single points of concern is what makes a functions reusable, and Mirror gives function plugs three ways to talk to each other. The names are worth knowing, because they're the actions you'll use in the app to assemble a stack of single-concern blocks into a working strategy.
Take is how a function gets its inputs. Instead of hardcoding a token or an amount, it asks to be handed them, so the same logic runs on whatever you point it at.
Bubble is how it returns its answer. It does its one job and bubbles the result up for whatever uses it.
Use is how a plug calls a function inside itself. You don't hard code logic in, you point at a function and let it run, and a hundred plugs can point at the same one.
So the shape of the system is simple: a function takes what it needs, does its one job, and bubbles any results it needs to so any other plugs can use it.
For my leverage loop, I built one block called Wind or Unwind to Maintain Target Health Factor, and I was proud of it. It worked. But it was quietly doing four jobs at once: calculating my target debt based on my target health factor, measuring how far off I was, converting that gap from debt into collateral, and then winding or unwinding. I thought I built a function, but now I know a real function doesn't do four jobs.
In this state, none of my logic could travel. The target_debt math couldn't help any other strategy because it was fused to three other jobs and a pile of decisions that only made sense inside my loop. So here's the question I always ask myself now: does this block do more than one job? If it does, it's not a function yet, and needs to be broken apart until each piece holds a single concern. Ask youself this up front, and you never build logic that can't travel.
So here's the same logic from my original block rebuilt into its distinct pieces. The clearest way to see it is to walk that one long block job by job, because each job became its own function for a reason worth knowing.
The first job was working out my target_debt. This math block earns its own function because anything with a health factor target needs it, not just a loop. So I built Target Health Factor to Target Debt which takes the health factor you want to maintain, divides your collateral's liquidation-adjusted value by it, and bubbles up the target_debt that holds you right where you want to be.
The second job was measuring how far my current debt sat from that target. I first split it by direction, one function to wind toward the target and another to unwind toward it, until I noticed they were mirror images using the same math with the operations flipped.
To be clear, two functions that are mirror images aren't two concerns, they're one concern pointed in two directions: how far am I from target, and am I over or under? So they should fold into one function, Target Debt to Debt Delta, that bubbles up both the size of the debt_delta and the direction as a simple true or false. Now anything that needs to steer a debt toward a target can use it, in either direction.
Notably, this function also clears a wall I spent an afternoon on: a plug can't hold a negative number, so you can't subtract your current debt from the target and read the sign. Instead, this block subtracts the smaller from the larger and reports direction on its own, so whoever forks it never hits that wall.
The third job was converting that debt_delta into the equivalent amount of collateral, which I did by dividing it by the collateral token's price. Another single job called Value to Token Amount that nearly every strategy needs at some point: anything that buys, sells, or sizes a position.
The fourth job, the winding and unwinding moves, also became their own small functions doing nothing but their onchain steps: supplying and borrowing, or repaying and withdrawing. Because once again, this pointed logic can be used in a variety of places.
Then lastly, I added one more piece that was never in the original block at all: stop the plug from firing on a move too small to be worth the gas.When I went to build a function to handle this job I noticed that my teammate had already built a Dust Guard. Amazing, Discovery is doing its job. So I quickly forked his and moved on.
By the end, the bloated four-job block became a handful of single-concern functions, and my loop simply became a plug that uses them in order: working out the target debt, measuring the gap, sizing the move, guarding against dust, and unwinding or winding accordingly. The strategy stopped living inside any one function and lived only in how each of them was wired together.
It's been a week since I built these functions and none of them need to be touched to do something new. The one that sizes a trade from a value works in any strategy, not just a loop. The one that turns a health factor into a target debt works for a plain borrow position too. So the moment I want a new strategy, I won't start from a blank canvas. Much of the work I need is already done.
That's the shift Mirror is really for: build a function once and you never have to write that logic again. And neither does anyone who forks it. You stop writing a strategy as one long wall of steps and start working a level above it. Figure out what jobs your strategy needs to do, build or fork a function for each one, and assemble all of them however you need. The strategy itself is just the wiring.
To be clear, you don’t have to master building functions to win on Plug. Everything me and my team have built is in Discovery now, single-concern and ready to fork. But if you want to go further, the door is open, and the principles that helped me level up over the past week are yours to run with now too.