New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Warptoad | A mixer for nfts, that's stupid right? - Jimjim Valkema | Common S3nse - 2026

CryptoCanalFri, Sep 25, 2026, 12:00 AM

Transcript

All

[music]

right, we'll start. Hi, my name is Jim Jim and uh I'm the co-founder at Warp Toad uh and I want to talk to you about shielded swaps. So, the title on the agenda was mixer for NFDs. That's stupid, right? And it kind of is, but there's something more to it.

Uh yeah, so I've been researching shielded swaps mainly for Warp and crosschain infrastructure. Uh but turns out NFTTS are fun and uh there's another application for it. Uh the goal is to unify anonymity sets uh between chains for warp, but uh shielded swaps can also do that. Uh, so yeah, our NFD. I got my NFD right here.

This NFD is mine. And I want to throw it in Tornado Cache. Um, does that work? Well, no. Uh, Tornado Cash does not support NFDs.

It's just your C20s and yeah, won't fit. Can we use rail gun? Who here has used rail gun before? All right. Who here has used real gun at NFTs?

Well, guess what? It does work. You can deposit an NFT in real gun and get it out. But maybe you see an issue here. These guys are linked, it's pretty obvious that this is the same guy, right?

Or is it is the same ID the same owner? Well, if you assume that this image is like tornado cash and tornado cash, you deposit and you withdraw. But in real gun, you can actually make internal shielded transfers. So it could have been a gift. So let's say Alice deposits this little NFT.

Then inside rail gun makes an encrypted transfer, a shielded transfer to someone anonymous, giving away this NFT. Then that anomous anonymous person withdraws. uh from the outside you might want to say this is just Alice but this could have happened but the thing is it we don't know for sure so Alice can plausibly claim this person is not me even if it is her and even it's not the problem is this is not a likely scenario like Alice just gave away her NFD for free it's kind of expensive so we cannot really plausibly assume that this happened. However, uh what we do all with NFTs a lot is trading. So, what could have happened is that uh this person traded the NFD for some ETH.

So, this anonymous guy sent back some ETH to Alice and this is a swap and this is great and you can do this in real today. But there's one problem with this. This is not trust trustful trustless sorry. Uh if Alice sends the NFT, the uh the counterparty might not send the ETH back. So, how do we make this trust so we can make this plausible claim that actually Alice did not withdraw the NFD?

Yeah, it's not trustless. How do we make it trustless? So, OpenC already does it. It's pretty simple. The UX is really nice.

You take your NFD, you approve uh the OpenC contract to transfer it, and then you sign an offchain listing saying if you have one ETH, you can get this NFT provided you verify my signature. And then your counterparty, Bob, for instance, will just take your signature, take one E and settle it, send one E to Alice, we're done. Bob gets NFT and we're cool. Uh so how do we do that privately? Well, we'll just do the same thing but with ZK.

It sounds uh a little bit uh handwavy, but it's true. Like the entire flow, we could just build it in ZK. Uh and the goal here is to make that transaction as private as the shielded transaction that happened here in real gun, right? We because in real gun if that NFT moves inside real gun it looks like just hashes and encrypted blobs and it looks exactly the same as when that one even moves. And we want that as well.

We want to be able to say that any transaction that happened on our privacy pool could have been a trade, not just like a specific transaction type. Uh I'll get back to it that point again. Um but yeah, what are our tools now? We're constrained by only the tools that a normal shielded transfer, normal shielded circuit has. Uh and there are a couple main things.

It has commitments. So these are hashes of secrets. Uh if you're familiar with tornado cache, uh this will sound familiar to you or Zcash. Nullifiers again are hashes. I guess you can see a pattern here.

But these hashes are also publicly emitted. They're uh hashes of private things, but they can only exist once. Uh and then we have encrypted blob. And this is just a message for the recipient saying, "Oh, these hashes have secrets. These are the secrets in the encrypted message."

And of course, we have a zk proof and we can do our crazy logic here. Um, and here's the the way we're going to make a shielded swap look exactly the same as a shielded transfer. Um, so here you see a screenshot of some pseudo code in noir. You have our public inputs, all those hashes and encrypted blobs and some secrets. Uh and there's also this um this uh input called which logic a string uh a bit hand wavy but yeah that is basically what kind of logic are we executing are we going to execute normal shield transfer or are we going to execute a swap and we keep that secret that's the important point and then we just have an if statement If logic is regular regular shield, if it's a swap, we swap.

Uh but yeah, there are like multiple steps. So locking it and settling it. Um but we're not going to tell the chain what we did. Uh so step one, how do we do that approval step? So in OpenC, you just publicly say I approve this NFT.

We cannot do that of course. So what we do is we take our NF that's our regular commitment and we send the shield of transfer to a new commitment that says uh the owner of this commitment is Alice. Alice can get this NFD out anytime she wants or uh the the listing if the listing condition is met you can also get the NFD and that is like where the signature comes in that is where we check in that listing condition condition did Alice receive one it uh yeah so Alice has locked up her NFD in this new commitment that transaction is just a bunch of hashes And one of the hashes contains her NFT now. Uh, and that and inside that hash, it says this can also be in locked by Alice's listing signature. And Alice signs a signature now saying anyone that sends me one ETH can receive this NFT.

And then the circus is going to check that one ETH was actually sent to Alice uh and uh that the signature is correct. Uh and then Alice and this is a little bit different than open C. So in openc you just sign it and announce it to the public. Anyone can buy it from one ETH. Alice will only send it to Bob.

And this is key here. You want that you want this kind of interaction to be uh to leak as minimal amount of data as possible. So only Alice and Bob know about this trade. And Alice and Bob need to know about the trade because they're the participants in it. So, Alice sends that signature to Bob in an encrypted offchain channel that somehow is also um as anonymous as possible, of course.

Um yeah, so Bob gets that signature and step three is a settlement. And here it gets a little more complicated than OpenC, but in in essence, it's pretty simple. So Bob receives that signature and says, "Oh, I like this NFT. I like this price. I intend to do it."

So he clicks on uh fill out the transaction uh complete the settlement. So in one transaction and in one zero knowledge proof, uh Bob will create that new commitment saying Alice owns now one ETH my one ETH. Uh then he proves that that ETH is one ETH is part of that signature. Verifies that signature. Uh and therefore the condition is met and then uh the signature proves that he can claim the NFD and he gets a new commitment where he privately owns that NFD.

Now uh and then we nullify the lock commitment because that lock is now spent basically. Uh yeah, and that is basically it. But there are a couple technical details. Uh but before I continue, I would like to ask, does anyone have questions? All right.

All right. So that was the happy case, right? But we in crypto also think about the unhappy case. Uh Bob should not be able to claim when Alice cancelled. So remember when I said Alice owns this log, but also the condition is met.

So there are two people that can claim one commitment. Therefore, you kind of need uh them to share a nullifier. So if Alice wouldn't if if Alice wouldn't tell Bob this is my nullifier, Bob wouldn't know when the trade has been cancelled. So they both need to know that nullifier and create the same nullifier whenever they spending that commitment. So Alice cancels uh the lock cancels a trade same nullifier when Bob settles the contract and actually makes a trade you need to emit the same nullifier and that nullifier is like a number a hash that can only exist on the chain once.

If the chain sees it again you know that is spent doing it anymore. Uh, but that creates a little silly quirk. And uh, the question is, what if Bob is a Fed? Because Bob now knows something. So, here's how a Fed would maybe analyze Alice's uh, decisions.

So, uh, so imagine a Fed asking, "Hey, you got an NFT. What is your price? Make a listing." So, Alice will say, "Oh, this is my listing. I locked it up.

Here's my nullifier. And then Bob never buys it. Now has a little number he can look for. He can now see whenever the trade is either cancelled or when it's uh settled. But the key thing here, he does not know if it's canceled or settled.

And Alice after can cancelling or or Alice after Alice notices that Bob never buys anything, Alice can also just cancel her trade and make a new nullifier. So Bob the Fed will not be able to track her. Um what if Bob is trolling? So there's another gap in our system now. um send me encrypted money is not enough.

If you send me an encrypted message, that's great. And if you say that message contains one E, that's awesome. But how do I get that one E? I don't know how to decrypt it. So most protocols don't actually enforce that that encrypted message is contains actually the things you need because they don't need to.

If I send you money over real gun or Zcash, I want to send you money. I'll encrypt it properly. But Bob could be trolling here. And what would that trolling look like? Well, Alice makes the listing.

Bob buys it, gets the NFT, Alice owns one ETH, but it's encrypted and she can never get it back because Bob didn't decide to share the keys. So, we need to enforce that. But how do we do that? Um well actually all the secret things that Alice needs to know is already known to Alice. Uh what token she wants, how much she wants, that's all exactly the same.

There's only the nons that blinds the commitment that that's the only thing she still needs. The the decryption key to put it simply. So whenever Alice signs her listing, she says, "I want one ETH uh and I'll give you this NFT and you have to use this decryption key and should make that decryption key specific to Bob because remember if Bob is a Fed, you know, he can decrypt stuff. So we'll do one key per person. Uh yeah, and then we got basically the trade secure as far as I know.

Uh yeah, I would like to ask uh anyone got questions or comments? Right. So he asked what if I ne what if Bob claims he never got the NFD? Uh so the trade is actually atomic. So what happens is Alice locks up her NFT that is one transaction and then Bob claims it and sends the ETH all in one transaction.

Uh, so there's not no claims Bob can make. He can claim it, but he didn't get it though. Uh, yeah. Any other questions? All right.

Um, so, so why why why all these NFDs and funny things? Aren't you like from Warp? Isn't like crosschain your problem? And yes, that's exactly it. Um so in in Warpto there are many things that uh that this swap mechanism will solve problems for.

Uh I guess I'll just go to the next slide. Um yeah, I guess I told it before, but currently uh every chain has its own privacy protocol and those are all separated and anonymity sets and we join them together by creating a joined crosschain private state. Um but there are limitations to that. Uh let's see. Oh yeah, here's the example.

So for instance, rail gun is deposited on Ethereum mainet but also on polygon. Uh if you want to move to the from Ethereum to Polygon, we have to unshield one uh bridge it another transaction and then shield it. Now what is the biggest problem here is that well first of all that bridge transaction is public but also on Ethereum there's 21,000 E deposited over many users but on polygons only six E over very little users. Um so yeah you have basically this issue where on mainet you're in a big crowd and on polygon it's only one guy. Um yeah and our warp toad we fix that by creating a shielded pool where the anonymity set is on all of the chains and moving from let's say arbitum or zk sync uh is much simpler you shield on arbitum you send a shielded transaction to zk sync and then you just unshield uh and this is a lot better because your anonymity that withdrawing from zk sync is not just everyone on zk sync it's everyone on warp out including archen L1 um but we have one silly little accounting uh issue here and this is why we needed the swaps is uh for instance our anet can be 1 million ETH uh our dream uh but we have the issue of canonical bridges right now in zk sync uh rollups in general.

Uh which means that we're basically com our bridge is basically competing with the bridge canonically built on arbitrum on ZK sync already where all the liquidity already is uh and that causes some for some awkward wrapping names. So this is our current wpping naming uh wrapped warp toad ETH from at arbitum from arbitum. Uh we wrap it, we shield it and then we unshield it and on our destination it says from arbitrum. Well then it's pretty obvious where we're from and that's not really the point of warp toad. So if we're able to shield do a shielded swap here, we can swap it out for zk sync e And then we get back our uh crosschain anonymity set.

So you might be like why can't you just unwrap arbitum e into zk sync? Why can't it just do that for you? Um there's a lot of issues with it. Uh so the biggest the biggest issue is that if someone deposits on arbitrum at that point the the public contract the public logic does not know where they're going to go. So for instance if I shield on arbitum but I'm going to withdraw on Ethereum uh then I can't just send the ETH along with that my commitment.

So what happens under the hood is I I shield arbitron ethan arbitum. Uh then the roots will move across from arbitrum to the layer one get aggregated into a bigger tree and that bigger tree gets sent to every chain because the system does not know I'm going to zync it I can also go to um uh let's say optimism. Uh so we can't just do the one accounting. Uh you might also think like oh can't you do something like hop protocol where or automatically balance things and that that breaks kind of these uh defy interactions I want to do where you unshield let's say die deposit in a get shielded tokens back here I can basically in this image I can basically anonymously deposit in a which is really cool but if I don't have oneonone counting uh that becomes really unpredictable for the user. So we have to keep all that uh shielded arbitrum e on arbitum because there we want to do that oneonone accounting and when the user moves uh we'll uh make the user have shielded zk synies instead if they want to do interactions like that.

Uh oh yeah I basically talked about this slide, but yeah, we can also do other things with this. We can just swap ETH for die, which is also a cool interaction. And that isn't is not just a neat little swap you can make. Uh it also plausibly connects the anonymity set of every token. So, for instance, if you're in rail gun, you deposit uh let's say a memecoin like I don't know doge whatever you deposit one doge, but you're only the only person that ever deposits do those into rail gun.

You're probably the same guy who unshielded it. But in warp toad, you could have sold your doge to someone else. So, your anonymity set of Doge becomes plausibly connected with the rest of the ecosystem. Um yeah, that's basically it. Uh but what's next for me and Danish is to implement a demo.

We're gonna publish a demo where you can where we make our own little NFT where you can have fun and swap with your friends IRL uh before Defcon and of course get funding, deploy it, audit it, uh do the rest. Uh and of course we need more funding for that liquidity part to facilitate these swaps. Uh and there's more research to be done. I think we can extend this swapping mechanism to also work across chain something like atomic swaps. It would require more logic maybe nullifier tree or something but I think it can make can be done.

Uh and if we can build crosschain shield swaps, we can export our anonymity set to any other protocol that integrates it. We can for instance go from Ethereum on warp toad and then swap to Zcash for instance if they decide to implement it and then Zcash is anonymity set and warp to anonymity set come joined which I think would be really cool. Yeah. And that's it.

Automatic transcript — names and jargon may be misspelled.