Viem 2.40 adds support for `eth_fillTransaction` (if supported by the execution node) for locally signed transactions (local accounts).
Combined with `eth_sendRawTransactionSync`, this decreases the amount of RPC calls to fulfil a transaction from 5+ to only 2.
Onchain CTF Solution Writeup
Let's break down the CTF and see how the solution was there all along
Shoutout to @yum1n__ for solving first and taking home 0.1 ETH!
The contract (source linked below) was a minimal proxy with two execution branches: SET_IMPLEMENTATION and DELEGATE
The DELEGATE branch would simply delegatecall the implementation contract
Similarly, the SET_IMPLEMENTATION branch would set the storage slot as the implementation address, but only if you passed some logic
If we manage to set the implementation address, we can execute its arbitrary code to steal the ETH. So how do we set the implementation address?
SET_IMPLEMENTATION requires that we pass abi.encodePacked(implementationAddress, value)
Then, given the value, we clear an equal amount of bytes from the provided address via bitshifting, e.g. if the value provided is three, it zeroes the first 3 bytes of the address
This address with its leading bytes zeroed gets passed as the implementation contract, but only after validating that the codesize of the contract is equal to value / 3. It's also enforced that value / 3 != 0, so you can't execute the classic exploit of performing a call from the contract constructor
So to solve, we need to create a contract with 3 times as many leading zero bytes as its codesize. Deploying a contract with more than 6 or 7 leading zero bytes will be extremely expensive, so that limits us to a maximum of two bytes of codesize
But what two byte contract can transfer ETH to a designated address? A regular call requires 7 items on the stack, so it would take at least 8 bytes. Similarly, create/create2 can be used to transfer ETH to a newly deployed contract, but they would require at least 4/5 bytes respectively, plus we'd still need a way to remove the ETH from the created contract. The other problem we face is managing to get the address we want the funds transferred to pushed onto the stack, after all the address itself is 20 bytes
The solution: CALLER (33), SELFDESTRUCT/SENDALL (FF). Place the msg.sender on the stack and send all ETH to that address. This is the only way we can transfer the ETH out of the contract to the right address with only two bytes. Hence, the contract bytecode we need is 0x33ff, as was used by @yum1n__
If you're observant, you may have noticed that the CTF address was prefixed with 0x000033ff... The answer was right there all along
Lately, vm.revertTo() became one of my most used features when writing PoCs. It's very useful when you want to showcase the behavior of the same functionality under different conditions.
For example, you want to test how the liquidation behaves when the user has previously staked their tokens and compare it to what would happen if they didn't.
It's as easy as taking a snapshot of the state, performing stake and liquidation, then reverting to the snapshot and performing liquidation only.
Note that this works only for state though. For example, in the image we can see the number stays 7 even after reverting. While this makes perfect sense, I made the mistake of thinking they would be reset and lost some time exploring a false lead.
You can also use vm.revertTo() during a bull market to transition back from plumbing to auditing.
Sometimes, we just want to send ETH safely.
Enter Solady's new `safeMoveETH`.
There are many ways to send ETH on the smart contract:
- `CALL`: Opens up to gas griefing, reentrancy attacks.
- `transfer`: This is actually a `CALL` with a gas stipend of 3000 gas under the hood. If gas prices change (e.g. an L2 with custom gas costs), or if the target is a contract with a fallback function, this breaks.
- `WETH`: There's no canonical WETH contract across all L2s. Ain't nobody got bytecode space to hardcode all the different addresses). Also, you'll spend 20k gas for a fresh SSTORE, 5k gas for a SSTORE update. Very expensive.
- `SELFDESTRUCT`: We can cook something with it. After EIP-6780, this can be abused for a pretty efficient force transfer.
`safeMoveETH` uses a canonical minimal `SELFDESTRUCT` to move ETH without triggering the `fallback` ever.
If `SELFDESTRUCT` is ever bricked in the future (core devs plz don't), it gracefully degrades to a per-address-just-in-time-create2-vault to accrue ETH in a chain agnostic way.
Basically, no matter what happens, the ETH will never get stucked.
Atomic Arb bots are making great use of DFlow JIT for onchain searching
Latest strat seems to be:
2 DFlow JIT instructions, each one with 5 candidates (tessera, humidifi x 3, solfiv2) in opposite directions
sent via Jito. if not profitable, doesn't land. no failed tx fees
New signers used each to to avoid getting flagged as toxic flow
在编写单元测试时,我们常常担心编写的测试没有真正覆盖代码逻辑。但是数学归纳法指出,只需要证明 n = 0 情况下代码成立,然后证明在 n = m 情况下,n = m + 1 页成立即可。基于归纳法,我们在编写单元测试时,首先证明空状态下测试成立,然后利用 fuzz 构建任意状态,然后执行待测试函数验证执行结果
🦠Plankton is live! 🦠
Today we’re kicking off Nori’s very first testnet event. Experience seamless, secure, and trust-minimised asset transfers between the titans of DeFi and ZK
Access it at:
https://t.co/EXIhhEiuHd