-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trustless Signing UI Protocol #719
Comments
One thing I would like of the DSL is that it is not like natspec, in that natspec is parsed using JavaScript's The DSL should be a lot more constrained, almost down to only variable substitution, or at most with a specific set of built-in functions and arithmetic (e.g. to render units of ether or similar). |
I'm not sure any amount of the display should be configured by the requester. For example, now the requester needs to know the user's language and construct the DSL dependent on that information. There's also no way to validate that the english text accurately describes the data that's being signed. I expect a structure-only approach to be a bit more flexible. Something along the lines of how Open Graph tags work.
Then the signing interface can represent that however they'd want. |
@onbjerg Good thought on ensuring that whatever DSL we use is easily sandboxed by the implementing signer UI. Having something like freeform HTML+JS is probably too hard to sandbox effectively and therefore not worth the benefits it may provide. @shrugs You bring up a very good point about localization. I hadn't considered that, and it does introduce quite a few problems. The naive solution would be to make it so the contract can support a number of different DSL hashes (this is pretty easy) and then they can provide localized versions of the UI. When someone audits the UI, they will need to also audit all of the localized UIs though which means you need a multi-lingual group of auditers. Also, localization is often done after launch and any changes to the UI DSL (or introducing new ones) would require a new contract deployment, which is unfortunate. I'm curious if anyone has thoughts on how to securely do localization (other than the above)? @shrugs The problem with just providing objects is that then the signers need to fully understand every dApp out there. This would be like expecting your browser to know how to render every page on the internet natively, and websites just provide the browser with an object graph of data. The 0x Order you linked is actually a really good example of the problem with this:
Getting a brick of those options is way too hard for an end-user to use. They need someone to turn it into plain English (or whatever language) for them or layout the items in a way that makes it more clear what it all means. |
I like the general thrust of this proposal. Localization is an interesting problem, and yet it actually seems perfect that it would be impossible to change the displayed terms of a contract, so now a UI template proposal is a big deal, requiring careful thought of developers who hope to use it, although they can always add a new signature type they accept. Rather than choosing between multiple render types, I liked an idea by Gavin Wood a few signing discussions ago where we follow email's lead, and allow a series of signing UIs to be defined, in an order where the signer falls back to the richest view it supports. I think this could all be described as a new type for signTypedData, where the value links to a static hash (swarm or ipfs) of a config file that includes links to the different provided template types, and then their available languages. A simple text template could be a first type, then maybe markdown or something with limited styles + substitutions, and eventually maybe even richer things still. |
In my head, the contract would provide a public method like, As far as how the signer receives the un-hashed DSL, I tentatively feel like that is a separate discussion. It could be that the JSON-RPC methods take in a DSL as a parameter, leaving it up to the UI that wants something signed to provide the DSL to the signer. Alternatively, it could be done via a specific method on the contract that returns a a number of hashes of the data for lookup in external systems (e.g., IPFS hash, Swarm hash, Storj hash, MaidSafe hash, S3 address, etc.). At the moment, without compelling counterargument, I would like to leave the "how does the signer get the DSL" for a separate EIP that we can discuss after we have settled on what the DSL looks like and how it is used. I can forsee there being several different EIPs for DSL acquisition and I don't want one to hold up the others. |
Forgot to actually respond to your direct comment. I think the concept of "ordering DSLs" would be up to whatever the mechanism for acquiring DSLs is. If the UI sends the DSL as part of an RPC call, then that RPC call would perhaps take an ordered list of DSLs. If the signer fetches the DSL from a URI that the contract returns, then the contract could return an ordered array of addresses. |
I like the idea of using the hash of the DSL to allow the contract to verify the user was presented with the correct description; it neatly cuts the gordian knot of where to store the DSL data. We really need |
What you describe sounds exactly what Moon-Lang is, a very simple UI description DSL I'll be presenting at devcon. It allows you to specify interfaces as a tree of nested boxes. Each box can render pixels to screen, manage an internal state and talk to Ethereum. You can copy/paste someone else's component on your own DApp safely, making the whole web very forkable. Moon's AST has very few constructors, a compact binary format and you could write a full interpreter in any language in about 150 LOCs. Feel free to try it: https://gateway.ipfs.io/ipfs/QmSCvGcufJ38g7ELYoUHdGmjyUekgB85No4xBeDWMRMEis/ Click the fork button above and change something to see how forking works. Then click the moon button to see a simple wallet demo. Also click the links on the code to enter sub-components, which can also be safely forked by copying their hashes. |
@MicahZoltu sorry it took me so long to get back to this, I think I missed the notification. In the "OpenGraph tags" scenario, my transaction request would first conform to a type like My transaction request would also conform to Arbitrary tx types can be defined and optionally supported ( I see the need to validate the signing interface itself, though; if you delegate all display to the signing interface, there's absolutely no way for you to know for certain whether or not what you see is what's being signed (unless you look at the code or write it, blah blah). But going down the path of "validating UIs" seems like a real rabbit hole. That said, the idea of signing both the message and "this is how I presented this transaction" is pretty clever, and definitely solves the main problem. Perhaps the best move is a little of both worlds? Signing UIs present two displays, one above the other. One is a rich interface of their choosing, which we don't validate the presentation of. This could conform to the opengraph tag model. Underneath this rich display is the pure-text DSL representing the same information. This DSL is either provided by the transaction requester or looked up in the store of DSLs (with all of the localizations provided). There can be different versions of this DSL beyond the
Just a note, I don't see a point in validating markdown; it'll be presented to the user as html, which defeats the purpose. Actually, now that I think about it, there's no guarantee that the signing ui will present the correct DSL to the user, regardless of what it is, but still sign the correct one. The only way to circumvent this would be to have the user copy/paste the text shown by the signing UI into the transaction requester's interface so that they can double check that that's what was shown. (unless I'm missing something). |
@MaiaVictor Can you provide some detail as to why you decided to author a new DSL/renderer rather than using an existing one like XHTML? I looked at the moon-lang GitHub readme, it seems that you are trying to build a compile-to-javascript language (like Elm), or am I mistaken? @shrugs I'm not a fan of signing tools having baked in forms for things like ERC20 transfers or EthereumFoundationDonation because this doesn't scale at all. That would be like Chrome/Edge/Firefox having the built-in ability to render very specific pages on the internet rather than being able to render any page on the internet. Regarding the trust issue, the user already has explicitly trusted the signing UI since the signing UI has full access to the user's private keys and password. Because of this, we can assume that the UI is going to do its best to present the user with the most accurate information possible, and in this case that means presenting the user with a signing UI that is verifiably associated with the contract being interacted with. The goal here is to make it so the user only needs to trust their signing UI of choice and the contract they are interacting with, they do not also need to fully trust the dapp UI. A great example of this is EtherDelta, where the contracts are immutable and have been vetted by a number of parties. The dapp UI on the other hand is a traditional centralized interface and should not be trusted. At the moment, when the user signs something on request from the dapp UI, the user doesn't have any good way of validating that what they are signing is what they intended. They must trust that the UI isn't asking them to sign something malicious, and this is not a great trust model. Regarding Open Graph tags, without a mechanism for validation I don't think adding them really helps the situation at all. Either you trust the dapp UI, in which case we don't need anything more than "dapp has requested a signature" or you don't trust the dapp UI, in which case anything it provides without validation could be malicious. The goal of this proposal is specifically scoped to solving the untrusted dapp UI + trusted contract problem. A solution to this would allow someone to put a "donate ABC tokens" button on their blog (untrusted) and a user using an Ethereum enabled browser (Parity, MetaMask, Mist, etc.) would be able to click that button and send ABC token without having to trust the website author. They only need to trust their browser and the ABC token contract. |
I realized where my misunderstanding was: the proposal is to find a way for the contract itself to verify that the user was informed correctly, in the name of consumer protection. I personally don't think that that's the domain of a contract, but I could see situations where it would be beneficial. At the same time, though, I expect the majority of "uninformed user" issues could be solved by a comprehensive signing UI that "upgrades" raw ethereum txs into a richer representation. The dapp gives the signing ui the
and then the UI displays that information, upgrading the experience if it is able to. The dapp doesn't need to do any of the opengraph stuff because the signing ui can check to see if the In this case the opengraph stuff isn't necessary, apologies for that tangent. If having the contract verify that the user was informed correctly is necessary, the signed raw-text DSL approach (with multiple localizations) is probably a good option? Although at this point the contract is still trusting the signing ui to actually display this DSL, and if we trust the signing UI we should also just trust the transaction that it signs, defeating this whole purpose. I suppose this approach would limit users to using signing uis that know how to request and sign the dsl, which is basically a quality gateway for "signing ui that doesn't suck". I guess my opinion boils down to "we need better signing uis" rather than "we need a trust relationship between signing uis and contracts to avoid trusting the dapp middlemen". |
@shrugs How would it detect the target contract is a token? How would it get the function name and argument types from the call data? How would it deal with non-token contracts (Ethereum smart contracts are far more than just "a bunch of tokens")?
This proposal isn't about having the smart contract verify the user was informed correctly, it is about allowing the signing UI to present an informed consent signing UI to the user in a way that does not rely on trusting the dapp UI. Dapp UIs should not be trusted in most cases, dapp trust ends at the contract, so we need a mechanism that allows for the dapp to provide the signing UI to the signing tool without the dapp UI being trusted.
That is the point of this proposal. 😄 I suspect you are trying to solve the problem in the same way I was originally, which is to have the signing tool automatically present the user with transaction details, much like Parity does already. The problem is that while this may be useful to developers, it isn't useful to non-tech savvy end users because function names and parameters are not meaningful to them. By allowing the dapp to specify how the information that needs to be signed is presented to the user, the dapp author can build a signing UI that makes sense for their transactions and is user friendly. However, we need a way for the dapp to get the custom signing UI to the signing tool without having to trust the dapp UI, which is why the contract will have the ability to validate whether any particular UI DSL should be trusted. This way, the dapp UI can give the signing tool the signing UI, and then the signing tool can validate that the provided signing UI can be trusted (by validating its hash against the target contract). |
Ah, I've got a better understanding of what we're trying to do now, thank you. I don't have much more to add, then 😄 |
I’m concerned that trusting a smart contract for its own UI template could be dangerous, since a smart contract could be deployed to resemble some other smart contract, or to mis-represent what it’s really doing. While this might be a nice way to represent signing operations in the meanwhile, I think the longer-term solution to good tx review will be something more like signers that know how to actually represent the likely effects of processing a transaction. Do people really want to trust arbitrary smart contracts to provide their own approval UIs? How is that much better than trusting malicious UIs in the first place? It may not be sustainable to make custom approval UIs for each kind of operation, but it seems more trustless to me than showing whatever a contract wants. |
Is that a viable threat model, though? If you audit the code, you can determine what it does and how it presents it. If you don't, there are far easier ways that already exist for the contract to do nasty stuff - although in either case they're limited unless you're sending ether to it or authorising it to act on other contracts.
Absent a threat model that demonstrates why it's a bad idea, absolutely.
The contract has a vested incentive to represent actions on itself clearly. The UI interacting with it may not, because it may be owned by another party. |
@danfinlay Aside from the comments from @Arachnid, keep in mind that a contract can only show its own signing UI. A contract cannot define what you see when signing on behalf of a different contract. This means that if my dapp needs approval for a token, I'll get the token's approval UI and not whatever the dapp contracts would have wanted to show me. As @Arachnid indicated, the risk is with sending ETH and there is an argument for having ETH values always be part of the meta-UI so a dapp that chooses not to present the ETH being transferred can't transfer ETH on the sly. For everything else, you are interacting with the contract so there isn't anything malicious a dapp could present to you to "trick" you into signing something you otherwise wouldn't. |
It took me a while, because it's a lot safer to be cautious than confident that there are no dangers, but I think I've come around. I can't see any serious issues with this anymore, I'm on board. After seeing MoonLang at DevCon, I can see why @MaiaVictor would suggest it here, it seems like a solution to the very "untrusted DSL" question that this opening issue was asking for, and so I'm interested in exploring it a bit more for this solution. |
Wouldn’t it make sense creating a format as a successor to natspec to incorporate all this? Natspec’s aim was basically the same with the difference it operates on individial functions and cannot describe a process which involves mutliple calls. |
I think that whatever DSL we come up with can (and maybe should) be used both in NatSpec and in this. This simplifies the number of DSLs the contract author needs to learn. I am a little hesitant to assert an integration with NatSpec because that will change the set of stake holders involved in defining the spec, which will increase the chance of disagreement (different goals) as well as increase the time it takes to actually get things moving forward. NatSpec is a compiler+signer feature, whereas this is a contract+signer feature. Combining the two would mean compiler+contract+signer all need to agree on something reasonable. I'm thinking that maybe what we should do with this spec is first define the mechanisms by which we can store/transmit/validate/present DSLs, but don't actually define a DSL. We can then have a very simple DSL that just lets you have a template string with to/from/value/gas/gasprice replacement variables in it and nothing else as the v1 DSL. We can then have separate discussions for future DSLs and as long as the system supports multiple DSLs then we can iterate on them at whatever speed we want, and iterate on them separately. |
Just had a discussion in Gitter that had a result that I think is valuable to record as an example for posterity, and share with others. The following is a concrete example of the whole process of a token transfer using a fairly simple example DSL that can do constant contract calls and reference transaction variables: The token's transfer method would look something like:
The UI would send the following data to the signer via a new
The signer would present the user with the following transaction to sign:
The signer would include the following as the
|
Am I reading this right that the UI would send the hex address of the destination, and the signer would do a reverse lookup to display the ENS name? Since anyone can set their address to reverse-resolve to any name they choose, this spec should require forward resolution after reverse resolution, to confirm validity. |
Fixed the |
@MicahZoltu Do you have any thoughts on what you expect a concrete example to look like for signing arbitrary data? Something like this for a state-channel-like example? The contract's function would look something like this:
The UI would send the following data to the signer via a new eth_signArbitraryMessage RPC endpoint(?):
The signer would present the user with the following transaction to sign:
The signer would include the following as the presentationHash parameter to the underlying contract as part:
|
I think for state channel updates I would do something like,
Payment channels are tricky because the off-chain nature of them means that they we can't actually do a diff compared to the previous state channel update, so we can't say "You are sending 0.001 ETH to jstoxrocky.eth" because that requires knowing the previous state channel update. This wouldn't depend on web3, so you would probably do something like Focusing on the actual validation, after reading your comment I have realized that this thread actually has two different proposals. Under one proposal, (1) the signer would ask the contract "Is this a valid presentationHash?" and under the other proposal (2) the signer would include the presentationHash in the contract call as a final parameter (like in your example). In (1), the signer must have access to the blockchain. This means offline MEW and hardware wallets can't utilize this system. In (2), integration is much more complicated as it involves the contract having some magic parameter that a UI can't provide itself (it is always provided by the signer) yet is part of the contract definition. While (2) is a more complete solution, I worry that without adding it to the protocol (as part of the signature validation system) it is going to be more headache than it is worth. If someone wants to champion getting So, back to your example @jstoxrocky, if we assume we are going with (1) then the contract would look something like: contract MyContract {
private mapping(bytes32 => bool) validDslHashes;
MyContract() {
bytes32 hash = keccak25(‘You are signing an IOU allowing ${0xENSADDRESS.resolve(recipient)} to withdraw ${amount / 10^18} ETH from the MyDapp state-channel.’);
validDslHashes[hash] = true;
// TODO: add other localizations of presentation hash
}
validateDslHash(bytes32 hash) returns (bool) {
return validDslHashes[hash];
}
} Note that the payment channel update that the signer signs would be a regular payment channel update, only including whatever is required for the payment channel, not anything about the presentation stuff (that ends at the signer). So in your example, this would just include recipient and amount. |
Thanks for that explanation @MicahZoltu So If I understand correctly, the dapp provides the DSL + parameters to sign. The signing UI plugs the parameters into the DSL and presents it to the user. If the user signs, the signing UI then checks the DSL against the DSL verification function in the contract. If that returns Could you elaborate:
Can you elaborate on:
I think I'm confused. What is the magic parameter? In my head, my example was kind of just a reiteration of #712 but instead of having the signing UI present the raw data structure to the user, the formatted DSL is presented to the user instead - taking the place of the schema-hash when sent to the contract. If I'm not mistaken, your example (maybe the EIP itself?) is about presenting something understandable to a user when they are signing an Ethereum transaction that interacts with a contract. What I think I am mostly concerned about is asking users to sign arbitrary data offchain in a comprehensible and safe way. Cases in which this signature is then sent to the contract later by a separate user. I like the DSL approach since it is human-readable to the user that signs, but it seems not to fit in with this EIP? What are your thoughts? |
@jstoxrocky A slight correction to what you described. The signer would check the As I mentioned in #719 (comment), there are currently two proposals kind of mixed in here. One is to have
The other is to just have the signer ask the contract if the presentation hash is valid before signing. This does require that contracts supporting presentation hashes implement some well known interface (which is why this needs to be an EIP so clients can standardize on the interface they look for). However, it is much simpler than trying to do a protocol change like adding presentationHash to the transaction object. |
@MicahZoltu I like this idea a lot as it seems to kill several birds with one stone. I agree that having I know this is kind of a rehash of several older arguments in #712 but I am curious to hear your thoughts on the severity of this attack vector: Since validation of the presentation is performed by the signing UI and not by the contract itself when the transaction is sent, it seems like a malicious dapp could do something like this:
Seems like this could be solved by having the validation check for the presentation occur in the function being called (a dapp wishing to signal its trustworthiness would create a unique presentation for itself forcing all other malicious dapps to also show this presentation to users). Just curious as to how serious you think this is, is it scoped within this EIP, can this EIP solve it as is? |
Contract authors will need to make sure the acceptable presentation strings include enough details such that the user can provide informed consent. For on-chain transactions, like a token transfer, this is pretty easy to do and should come naturally. For something like a state channel, you will want to make sure that the presentation string makes it clear to the user what exactly they are signing. Contract authors should assume that the presentation string is the only information that the user has for deciding whether to sign or not and they should assume that prior to viewing the presentation string the user was duped or tricked in some way. A couple of examples: |
@MicahZoltu Sorry if I sound like a broken record but I'm just trying to get a full grasp of your idea. Even in cases where the presentation is as explicit as possible, it seems like there is a chance of fraud unless part of the presentation data is verified within the contract. Assume Alice opens two separate payment channels with Bob. One settled in ETH and one settled in ABC tokens. Alice wants to update the ABC token state-channel but not the ETH state-channel. Alice is shown a presentation of the form Is the solution to include some contextual strings like |
@jstoxrocky I don't mind back and forth with you to help make things clear. 😄 If you prefer a faster round trip time, feel free to ping me in Gitter. The problem you described is a problem with the state channel implementation, not with the presentation system. Any state channel authored the way you described and susceptible to the attack you described is a state channel with a critical security vulnerability. Such a state channel implementation should never make it into the wild and if it does it should be fixed immediately. The presentation stuff is meant to solve a very specific problem, which is informed consent from users. It is not intended to solve all possible malicious dapp attack vectors, which would include the one you have described. |
Thanks, @MicahZoltu, I appreciate you taking the time to discuss this. That makes sense that this EIP is about informed consent and not the specific attack I mentioned. Do you believe that there should be a constraint imposed on presentations DSLs so that they include all signed data within them somehow? For example, in the simplest case of a text-only DSL, a constraint could be imposed so that every piece of data to be signed must be inserted into the text. The signing UI would allow (1) but reject (2).
It seems like the user is not properly informed in case 2. This might be a difficult rabbit hole to go down. I guess alternatively we could just have the signing UI present both the value-substituted DSL along with the raw data structure to the user so that they can also see the details of what they are signing. |
If a contract author wants to create a DSL that is malicious, there are a million ways they can do so. While we could perhaps plug one or two obvious holes, it won't stop a malicious contract author. Thus the question becomes, what are you trying to protect against? I'm generally hesitant to add complexity to a system (creating requirements on what DSLs are allowed would add complexity) without a strong enough need and in this case it is unclear to me what the strong need for this feature (DSL constraints) is. Perhaps you have something in mind as to how we would benefit from constraining what the DSL can contain? |
If I understand correctly, this EIP is so the signer can use the contract to verify the UI presented to the user is whitelisted. So far I only see these methods for a contract verify this using a rich UI:
I don't think verifying the authenticity and integrity of a rich UI can be done in any single proposal. A tractable base for transactions is a standardized method for signers to query a smart contract for a human readable string of the main call. For example, a contract that contains: transfer(uint256 amount, address destination) may also have (if the plaintext of the method is available) transferAsString(uint256 amount, address destination, string lang) public view returns (string) or (if the plaintext of the method is not available) asString(uint256 funcSelector, bytes parameters) public view returns (string) (I'm almost certain there's a better way to do this!) Which can return
This also permits someone who is examining verified contract source code to easily verify the generated string is not malicious. |
All three of these can be accomplished with the same interface - returning a content hash. In the latter case, the administrator has a way to update the hash, which is out of scope for this standard.
This seems like it wouldn't be an improvement to the concerns you outlined above? My main objection to doing it this way (although it's simpler and doesn't require adding a new language to the mix) is that it bloats contract size onchain, and string manipulation in the EVM is particularly difficult and resource intensive. |
Could something like this work?
The URI could use any secured protocol (https, ipfs, etc..) that could add another layer of security over the presentation, and worse case it would fallback to the |
We could also simply point to a hash of a file that includes multiple presentation types, the way email mime types have a series of increasingly rich representations of the message. |
This protocol is really made up of 3 parts:
For (1), if we have a duplex channel between the UI and the signer then the UI can ask the signer what variations of the DSL are supported (e.g. text only or something more complex) and then only send that. If we assume that we only have a simplex channel between the UI and the signer then something like @danfinlay suggested is probably a good idea, for the same reason it is good for email. For (3), the user just calls the contract and asks it, "Is this a valid DSL hash". The contract can return true for any number of DSL hashes, so it can support both text-only and complex DSLs, or DSLs in different languages, etc. |
I have edited the original description to more accurately capture what this EIP is targeting after much of this discussion. I just realized while reading it today that it doesn't accurately represent the current iteration. |
One problem with this proposal is that the signer may not have access to the Ethereum network. For example, an offline signer or a hardware wallet signer. Consider: What if there exists a standardized way to pass the hash of the DSL into the function being called so that the signer can be confident that "someone downstream from me will validate the hash". As an example, one can imagine saying that "an EIP719 compatible function signature will have the hash of the used DSL as the last parameter". Then when a transaction is submitted to a signer along with a DSL, the signer will append the DSL as the last parameter in the In order to reduce the work of the signer (useful for limited compute constrained devices like Ledgers), a well known placeholder could be provided as the function parameter so that the signer merely needs to hash the DSL and replace those well known bytes with the DSL bytes. For example, maybe the well known bytes are:
|
Project Hydro is a layer 2 of the Ethereum platform and has this exact protocol called 'ICE' which leverages on using digital identity aggregator #1495 or ERC 1484. Instead of sending across wallet services, you're sending to an Ethereum Identity Number (unique to you and other users). ICE whitepaper (draft): https://github.com/hydrogen-dev/hydro-docs/tree/master/Ice However, i don't it can work when you have no access to the ethereum network as it requires proof from nodes. |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
Opening this as I'm seeing webauthn-eip-4337 wallets become more commonplace and they currently don't show what is actually being signed. The trend is to use the challenge field, loaded with the userop struct to sign. They initiate a signature by calling webauthn.credentials.get(). This opens a browser mediated modal, and doesn't show what you're actually signing. Even for good ol simpleaccount.sol wallets: it's not clear how web developers should be securely showing a sign interface. |
You need trusted access to the Ethereum network's EVM in order to trustlessly present signing data in a human readable way using this protocol. In the case of WebAuthN, the thing providing the signing UI would need to be trusted, and usually for hardware device signing (which I believe is what WabAuthN is commonly used for) there isn't a trusted EVM they can access. Presenting trustless signing UIs on hardware devices is quite hard, though it may be solvable if the hardware device is powerful enough to do EVM execution on its own. You could provide witness data to the hardware device along with the rendering string and then the hardware device can validate that. Then the hardware device only needs a trusted blockhash, which in theory is easier to get. |
A lot of debate has been happening around how we can make signing a more secure process for end users. One of the common arguments is that while all of the proposed solutions may resolve the problem for advanced users (developers, tech savvy users, professionals, etc.) it doesn't address the problem of naive users not understanding what they are signing. They can often be thought of as the legalese presented to people in contracts: it is better than signing a blank sheet of paper, but to the average person its mostly gibberish.
An idea that @Arachnid and I started batting around in an attempt to come up with a long-term solution to this problem is to provide a mechanism by which things can be signed (ideally transactions and arbitrary messages) such that signer can present the user with informed consent without having to trust the UI.
The general premise is that the actor wanting a signature presents the signing tool with the data they want signed as well as a DSL that describes how the data should be presented to the user. The signer would then ask the target contract if the DSL is valid, and only prompt the user to sign if the contract asserts that the DSL is in fact valid.
This is quite similar to #712, though it strives to take things a step further than just function name and parameters.
As far as the DSL itself goes, one option would be a text-only DSL that allows for replacement variables. An example DSL may be something like
An untrusted dApp would send that DSL (exactly) to the signer along with the transaction they want signed. The signer would then ask the
transaction.to
contract whether the hash of the DSL is an approved DSL. If it is, then the signer would extract data from thetransaction.data
and do aneth_call
to fetch thename()
of the two contracts (tokens in this example) and finally generate the string to present to the user. This solution is very simple and allows for devices with small screens that can only present text (e.g., Ledger) to be able to reasonably present the user with information that the contract author has deemed as enough for informed consent.Another more feature rich solution (in the extreme) would be to allow the DSL to be some form of constrained layout engine markup (e.g., HTML). The idea here would be that the signer could verify the DSL was approved just like with the text DSL, but would be able to use a basic UI to present the data to the user like the 0x OTC dApp:
For complex contracts, a full UI is much more understandable to an end user than a paragraph or two of madlibs text, and it gives the dApp developer the ability to create a generally better user experience.
The obvious disadvantage to the full GUI DSL is that it can't reasonably be rendered on a text-only display like a watch or hardware key. With the way this is proposed, a contract could support multiple DSLs so a well written contract may support both text only DSL (for small screens and screen readers) and also a GUI DSL for a better user experience for most users. This would allow dApp developers to provide high quality signing experiences to users on devices that support it with graceful degradation on devices that don't. It also allows signers to implement the presumably easier-to-implement madlibs spec fist, then expand towards the full GUI support implementation later.
Open Questions:
The text was updated successfully, but these errors were encountered: