What does it take to trust a transaction end to end?

Devcon 8 · 4 Nov 2026 · 22:56

Manuel Wedler of Argot Collective, who builds source verification infrastructure for Sourcify, breaks a single contract interaction into the remote services it trusts: RPCs, explorers, ABIs, simulation APIs and decoders. Using an open-source prototype, the talk shows how each layer can be verified on the user's device, from an embedded light client to local recompilation, and what still runs on trust.

Speakers

Topics

From Devcon 8, hosted by Ethereum Foundation.

Transcript

[music] [music] Okay. Hello everyone. Um, I'm Manuel. I built source code verification infra and tooling for the Sourcifi project. And Sourcifi is part of the AGO collective. And in this talk there are the questions when you sign a transaction um what do you trust and how much of it can you verify yourself? Um but let me start with a number. We you probably all know this um 1.46 billion um were lost in a bite attack last year. Um until last week I made my slidesh before that. It was the the

biggest scam in the biggest hack in crypto's history. So uh last week happened also for a technical different reason. Um but for private it was a hacked UI basically and the signers just believed the UI and that the transaction was a routine transfer. So I have a couple of more example of that. [clears throat] So or in all of these cases uh there was an interface that just showed an harmless transaction and there's one pattern across these namely the signers trusted but they didn't verify.

So that brings us to the question who do you actually trust when you sign? Um for that I have like a typical signing flow. a usual user that um wants to interact with Ethereum goes to a web app or a website um maybe chose some swap interface and then you hit submit and the the the website actually builds the transaction for you. So you trust the website to build a correct transaction. The transaction is then sent to the wallet um and the wallet shows a transaction preview. This is actually meant to be a first mean of defense here because the

website is already trusted. Um, but actually you also trust a bunch of remote services in the in your software wallet's transaction preview, but I'll I'll get to that in a second. Um, so if the transaction preview looks good, you sign it with your key that it's the only thing that happens then locally from your device actually. Um and after it has been mined the transaction, you want to know what uh actually happened on chain. So you check the explorer uh and then of course you trust the explorer to show a correct result. You don't verify it in a usually like um like a usual user.

Let's have a look at a transaction preview. The the most interesting thing because it's happening before the signing. Um so when so uh the transaction preview is meant to show like what the transaction will probably do but for that a couple of remote services are used first of all normal users don't run their um own RPC so a remote RPC is used um we need that for the chain state like balances and so on then you also want to know what the transaction is expected to um have of an effect for the for the state. So there's a simulation happening

like tenderly does but mostly that's also remote service that runs the simulation. Then you want to know like what contract um you're interacting with like what's the name of it what's the source code of it and that is actually fetched from the from an explorer or source code verification service such as sourceify um also you get a AI from that and AI is also useful for decoding um so some some wallets use some proprietary decoding mechanisms so you would trust the decoding service for that. Some just use the API that also comes through them from the explorer. Um

but all of that is trusted. Okay. So that brings us Oh, okay. So in this example, everything that tells you what you sign is actually remote. But a usual user doesn't verify. So none of it is proof. That brings us to the question, how can you verify locally? I I think Ethereum is meant to be verifiable. So we can do better than this. Um for that question, I'd like to introduce an application that sourcifi has started to build. Um and this will serve as a proof that all the data that uh were provided by the earlier services I showed can be

verified locally. Um and this application we call onai. Onai is a companion app for signing. Um so it's meant to verify all information about a transaction locally. Um that means it gives you um it it verifies the chain state locally. It verifies sources of a contract you're interacting with locally and it provides a locally verified simulation result. And it kind of um uses some locally verified decoding um and onai is view only to to lower the text surface. We it it doesn't hold keys

itself. How does it look technically? So um there's an onai extension that is inside your browser that listens to the window.ethereum object and intercepts transaction. it copies it over to the onai native app which is runs on your device. Um and then the unchanged transaction is just forwarded to the wallet still. So let's have a look at the first layer the chain state the most important one one I would say. So you could say you could just run your full like a full node for having your own RPC. Um but that's not very practical for the everyday users. So and and that's not working on mobile, right? So there are

light clients such as Helios. Unai uses Helios and a Helios takes an untrusted RPC and turns it into a locally verified one. It does so by starting uh from a checkpoint and from the checkpoint in it verifies all following black block headers. Um and then whenever you ask the helios like client for data it um asks for merkel proof uh the the underlying RPC and verifies that then against the block headers.

So how does it look like in onai? Whenever onai reads data from chain the chase state is verified via helios. So you can see here um a couple of contract bite codes were read from chain and the the the mergle proofs are checked for that. Okay. So now we we have locally verified chain state. Um but so bite code is not human readable. So we also want the source code for that and with that we also get a a couple of um compiler artifacts such as AI. Um and therefore we have source code verification.

Source code verification usually is run on a server such as the explorer or sourcify. Um but sourcify does a quite nice thing. It um provides an open source library called lip sourceify and that's containing the verification logic of the sourcify server and that one you can run locally. Um and then you can simply uh fetch sources from sourcify uh as well as some compilation set compiler settings and then you can run the compiler yourself and verify the sources against the bite code uh yourself. [snorts] So you have a locally verified um source code for the contract you're interacting with

and that just removes the trust on the source server. Um so how does that look like in onai? Um onai verifies sources AVI contract names via local recompilation and matches that against the verified chain state from Helios. So we now have a locally verified uh bite code the the human a machine machine readable state and not state but the [snorts] the op codes you know and the human readable source code and we can use that for um for the next layers.

Um so the next is transaction uh transaction simulation. How can we have a locally verified transaction simulation? It's pretty simple. We just run a local EVM and only use proven state. Um ina in the in the case of just the state from Helios. Um and yeah on uses Ethereum JS EVM. Um what else can we do? So when we uh record every call contract to build a call tree. So a contract also has inner calls to other contracts, right? Um we can also run local source code verification for all of the called

contracts that are in the call tree. Um so we have contract names, labels for all of these um and as well as the source code and AVI. So when I simulate your local at your transaction in a local EVM and the status program via Helios the call tree goes through local source code verification. So you can see here um the full call tree with all contract names uh which are called within one transaction. Um yeah so currently on just does call tree simulation. It would

tell you if the transaction would revert. Um we don't have state effects yet. That would be the next step. We're currently currently working on it. Um but yeah, that that would be then the much nicer thing to have. Um but the locally verified source code will become become handy for that. Um so the last layer I was talking about is decoding. For that um so we want a human readable preview of the transaction. We want to decode the call data and know what the transaction does.

For that, um there's a relatively new standard ESC 7730 clear signing. Um um my colleague Khan will talk like at 4 p.m. about it in more detail, but um so it's it's stage four if you're interested. Um but to break it down roughly um it defines a metadata format in JSON to um describe function calls and the intent of them in a human readable way. So you know how to decode call data to to make it readable for a human. These JSON files are called descriptors and are then um collected in an open registry

and the trust actually comes from auditors. Auditors attest to the correctness of a descriptor and these attestations these signatures we can uh verify locally. Um here we have it in Onai. So ONAI renders a transaction preview using ESC 7730 descriptors and verifying the descriptors at the stations locally. So you see here action swap um and amount you send and what you receive nicely human readable um and at the same time the station of an auditor that you trust is verified locally.

So this is pretty nice. We can verify a lot um but there's still limitations. So what limits local verification and what does still run on trust? First of all, the screen of uh screen to device gap. Um so the local verification runs separate from the signing key. This is intentional um to lower a text surface, but we can't really control what happens in the JavaScript world inside the browser.

What what the DAP does. So the de could still send a benign looking transaction to onai and a malicious one to the wallet. So actually the ver the signer must verify or check that the same transaction lends on both ends. Um, and yeah, it's just the the designers just asked to do a manual comparison of chain ID, target contract value, and call data. Um, call data is pretty cumbersome uh to to compare since it's a long bite array in most cases.

Um, and therefore there's a standard that Siphon proposed. It's not wildly rolled out yet, but we hope it will be soon. But um yeah, so the idea for that is uh that wallets should show a digest of the call data instead of the call data itself like on on the hardware device. Um and yeah, like the catch is much easier to compare than than the call data itself. So it would be pretty handy to have that soon. Uh so we're trying to push wallets to to implement it.

Um what else is still trusted? Um so the transaction uh creation is still trusted to the dev. We like as long as we want to have nice UX, I think we can't do much about it. Um then the chain state the the trust comes from the checkpoint. Helios uses um like [snorts] this checkpoint to verify following block headers. uh it comes with a default checkpoint but you could also provide your own checkpoint to the to Helios source code it relies on the compiler binaries compiler binaries fetch from a single server um if the single server is compromised um yeah we would rely on a compromised compiler binary maybe

decoding um you fully trust in a tester for that so you better choose your tester wisely, I'd say, but you could also say you only trust descriptors if if they are audited by multiple parties, for example. And lastly, um you your hardware, your device is trusted. If that's compromised, um [snorts] local verification means nothing anymore. Okay, so I have a short demo for how how onai looks in action. Um, so we have a swap interface here, just an example one. The user hits swap and

the onai gets a copy of the request. It runs all the checks in parallel because some of them depend depend on uh each other. Um, here we see the chain data verification. So the proofs are checked on Helios. Um, a couple of bite codes are read. Then we'll get to the transaction simulation. So we build a call tree. We ran a transaction once through the EVM. Um we have the source code verification for all call contracts. Uh so we can display the names of them.

Then we have the source code verification check itself. Um yeah we can see yeah the the source code of the target contract was verified which compiler was used. Um then we have the clear signing preview. It's again the swap. Um, and that the station is verified locally. And lastly, we ask the user to compare with the wallet. If any of the earlier checks would have failed, then we would say better don't sign this. But in this case um the wallet, yeah, we say, yeah, check that it's the same transaction and then you can sign.

Um, so now you can try it yourself. Onai is free and open source. You can go to onai.sh and um download the extension as well the [clears throat] the native app. Um so thanks for listening. Hello. We have a lot of questions. Can we get the questions on the screen? Uh so first question is if someone wants to add a check on the recipient address where would it best fit in the flow?

Um recipient address like target contract or if you send a um a transfer to someone I mean so we we actually we do that we have implement something like this already in onai. We do some trans like target address checking but that fully relies on remote data. That's why I don't have it in the um in the presentation. So we check against of against a couple of lists if it's on a blacklist if it's something malicious if it appears appeared in a hack or something. Um and then show that the recipient is uh at least according to a

remote list. um malicious. So we we have to check um if you if you try it out you will see it >> uh more brother like if I'm the user if I want to whit list certain contract for interaction how would that flow actually work? Um the if uh the flow for the user for the recipient check. Okay. Um I mean ideally the the software wallet would also already have that implemented. Um but inside the flow of uni just one additional check that appears in like in all of the checks you saw.

And then uh the next question is how do we help regular users to do all of this locally? Um I mean so on relies on a couple of open-source software that we just bundle together basically. I mean all of that was already out and we just put it together into one application and that I mean now it's easy to run it yourself and just get a verdict if a transaction is uh easy if it's safe to sign. Um [snorts] that's much easier for a regular user to do themselves. Um but still I'd say it's technical. So

yeah, I don't know like UX lags maybe still a bit um but it's Yeah, I think that's a hard problem actually. Oh yeah, definitely. And uh when a security warning comes from a source uh that user never heard of, how would they trust the warning? >> Trust what sir? the warning. >> Um, yeah, I mean, [snorts] you don't have to trust such a warning then, but um, if you're not familiar technically at all and maybe it's better

to just not sign in the end, um, it's better than than being sorry in here right? Uh one question mentions that Helios is an external service. Uh how is that local? Uh can you explain that a little bit more? Um so how is the local I mean so Helios um the like the it has a trust anchor.

So the trust anchor is a checkpoint um which is just a uh a hash tree route of a beacon block and from that it verifies all like it uses um a remote beacon like a consensus RPC and a execution RPC. So it asks a consensus RPC for the following block headers and verifies these locally. So um by verifying that against the checkpoint it exactly knows that the following block headers are correct. Right? So the the trust just comes from the checkpoint.

>> Okay. So we have time just for the one last question. Uh can you explain how would this uh prevented the by bit hack? Um yeah I mean it's simple because um I mean we don't have state effects but when we have state effects uh the transaction would have shown something different than the private signers would have expected I mean um there would be balance changes changes and these would not be like I I don't know like go to some random address that the the Bible signers don't know. So they would

[music]