#Simple Summary
This Stellar Ecosystem Proposal introduces a URI Scheme that can be used to generate a URI that will serve as a request to sign a transaction. The URI (request) will typically be signed by the user’s trusted wallet where she stores her secret key(s).
#Abstract
Proposal for a URI Scheme that can be used to generate standardized URIs that will represent a request to sign a specific transaction on the Stellar Network. These URIs will be generated by applications that do not hold secret keys and need to delegate signing to a third-party system that is trusted by the user. These URIs can be interpreted by any application or wallet that complies with this SEP. The signing applications (wallets) should follow the recommended security best practices in this SEP when handling these transactions to be deemed as fully-compliant wallets.
#Motivation
Non-wallet applications want a way to have their users sign a transaction that is generated by it without requiring it to ever see the user’s secret key in any form. Users already have their preferences for a trusted wallet where they are storing their secret keys.
This leaves room for a common protocol that can be implemented by both applications that want transactions to be signed as well as wallets that can sign transactions. The common protocol needs to have the following properties for it to be successful and widely accepted:
- Open and Decentralized - The specification needs to be open in that it can be easily read and implemented by anyone. All the dependencies to implement such a specification should be easily accessible, free of cost, and free from a central authority or service. This will ensure that there is no single point of failure in the system and the system can remain permissionless.
- Standardized - The specification should not require any special handling for specific operations on the network. This will ensure that there is only a nominal amount of effort needed for developers on both ends (URI generation and signing) to implement all operations on the network. It should also be independent of a specific platform and it should be possible to easily implement in any programming language.
- Secure - The specification should not expose secret keys in any form. It should include requirements on how wallets can keep their users secure by ensuring that the user has enough visibility into the transaction that she is about to sign.
- Future-Proof - The specification and its implementation should be designed in a way that allows operations that may be added to the Stellar Network in the future to be easily incorporated into the proposed specification. This will ensure that developers need to make minimal upgrades to their applications and wallets to support additions to the network protocol. The specification should also leave room for expansion to accommodate future use cases that were not anticipated at the time of writing.
#Specification
A standardized URI Scheme can achieve the goals laid out above. The syntax of the scheme will contain all the information needed to make the necessary payment to the application’s account.
The scheme name will be web+stellar and should always be followed by a colon
to look like this: web+stellar: (no forward-slashes). The syntax for the URI
will look like this:
web+stellar:<operation>?<param1>=<value1>&<param2>=<value2>, where
operation, and the options for the query params are defined below. We have
included web+ in the scheme name so it can be handled by web pages (see
here
for more details on web+).
#Operation tx
The tx operation represents a request to sign a specific XDR
TransactionEnvelope. The parameters for the tx op are as follows:
xdr(required) - A StellarTransactionEnvelopein XDR format that is base64 encoded and then URL-encoded.replace(optional) - A URL-encoded value that identifies the fields to be replaced in thexdrusing the [Txrep (SEP-0011)](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0011.md) representation. This will be specified in the format of txrep_tx_field_name_1:reference_identifier_1,txrep_tx_field_name_2:reference_identifier_2;reference_identifier_1:hint_1,reference_identifier_2:hint_2. Metadata fields such as_present, andlenshould not be included. Onlytxfields should be included without the"tx."prefix, i.e. you cannot specify that asignatureshould be replaced in thexdr. When wallets request the user to fill in the blanks they will display the hint to inform the user of the context, therefore the hint should be a brief and clear explanation of the context for the reference_identifier. An example of this issourceAccount:X,operations[0].sourceAccount:Y,operations[1].destination:Y;X:account from where you want to pay fees,Y:account that needs the trustline and which will receive the new tokens. This translates into the following URL-encoded form:sourceAccount%3AX%2Coperations%5B0%5D.sourceAccount%3AY%2Coperations%5B1%5D.destination%3AY%3BX%3Aaccount%20from%20where%20you%20want%20to%20pay%20fees%2CY%3Aaccount%20that%20needs%20the%20trustline%20and%20which%20will%20receive%20the%20new%20tokens. This tells us that the wallet will replace two accounts: 1) the first account (X) will be set on the source account of the transaction and 2) the second account (Y) will be used for both the source account on the first operation and the the destination account on the second operation. Thereplacevalue is considered invalid unless thereference_identifiers are balanced on both sides of the separating semicolon. For example,sourceAccount:X;Y:The accountshould be rejected because{X} != {Y}.callback(optional) - If this value is omitted then the URI handler should sign the given XDR and submit it to the network. If the value is present then it should be interpreted as a URL-encoded callback. The URL-encoded callback will start with a prefix to denote whether this is aurlcallback or some other form of callback. In the case where it is a url callback (denoted byurl:, i.e.url%3Aafter encoding) the URI handler should send the signed XDR to this url in aPOSTrequest withContent-Typeset toapplication/x-www-form-urlencodedwith the data fieldsxdrcontaining the signed XDR (URL-encoded). If there are any query params specified in the URL callback then those should be included in the URL when submitting. For now onlyurlcallback types are supported.pubkey(optional) - Specify which public key you want the URI handler to sign for. Useful with thecallbackparameter above for example with multisig coordination.chain(optional) - There can be an optionalchainquery param to include a single SEP-0007 request that spawned or triggered the creation of this SEP-0007 request. This will be a URL-encoded value. The goal of this field is to be informational only and can be used to forward SEP-0007 requests. You cannot mutate a SEP-0007 request as it would break its signature so forwarding the SEP-0007 request can be useful in this case, which will allow you to wrap an existing SEP-0007 request in a new SEP-0007 URI with altered parameters such as thecallbackparam. Note that the embedded SEP-0007 request of course can itself contain another embedded SEP-0007 request in its ownchainfield, but caution should be exercised when doing so since this can easily explode the length of the final SEP-0007 request. To prevent attacks against this field, wallets can expect this field to have no more than 7 nested levels. Receivers of a SEP-0007 request with thechainparam can verify integrity of the full signature chain of past SEP-0007 requests. Future SEPs can use this fundamental building block to provide stronger security in their protocols.msg(optional) - There can be an optionalmsgquery param to indicate any additional information that the website or application wants to show the user in her wallet. The value for this query param should be URL-encoded as well and should not be longer than 300 characters before the URL-encoding. Note that themsgfield is different from thememofield that is included in a transaction. Themsgfield will not be put on-chain, but thememofield will be put on-chain.network_passphrase(optional) - Only need to set if this transaction is for a network other than the public network (URL-encoded).origin_domain(optional) - A fully qualified domain name that specifies the originating domain of the URI request. Wallets must validate the URI request against the includedsignaturebefore they display theorigin_domainto the user. See the Request Signing section for more details.signature(optional) - A signature of the hash of the URI request (excluding thesignaturefield and value itself). Wallets should use theURI_REQUEST_SIGNING_KEYspecified in the domain'sstellar.tomlfile to validate this signature. If the verification fails, wallets must alert the user. See the Request Signing section for more details.
Example 1 - Change Trust Operation with callback endpoint specified:
web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024
Example 2 - Change Trust Operation with the Source Account requiring replacement:
web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline
#Operation pay
The pay operation represents a request to pay a specific address with a
specific asset, regardless of the source asset used by the payer. If the payer
decides to use a different source asset then the wallet should leverage the
path payment operation
to achieve this.
The pay operation is different from the tx operation when used with the
replace param. The pay operation specifies the asset and amount that the
payee shall receive regardless of the method of payment (direct or path
payment). The tx operation with replace specifies an exact mechanism of
payment which is bound to either a direct payment or a specifically chosen
path. Therefore, the pay operation is more flexible when it comes to
payments.
The parameters for the pay operation are as follows:
destination(required) - A valid account ID or payment addressamount(optional) - Amount that destination will receive. If not specified then the wallet should ask the user to enter the amount before signing. The use case for leaving this out is to support donations of arbitrary amounts.asset_code(optional) - Asset code (XLM if not present) destination will receiveasset_issuer(optional) - Account ID of asset issuer (XLM if not present) destination will receivememo(optional) - Can be a memo to be included in the payment / path payment. Memos of typeMEMO_HASHandMEMO_RETURNshould be base64 encoded and then URL encoded. Memos of typeMEMO_TEXTshould be URL-encoded.memo_type(optional) - One ofMEMO_TEXT,MEMO_ID,MEMO_HASH,MEMO_RETURN. See transaction guide for a description of these values.callback(optional) - If this value is omitted then the URI handler should sign the given XDR and submit it to the network. If the value is present then it should be interpreted as a URL-encoded callback. The URL-encoded callback will start with a prefix to denote whether this is aurlcallback or some other form of callback. In the case where it is a url callback (denoted byurl:, i.e.url%3Aafter encoding) the URI handler should send the signed XDR to this url in aPOSTrequest withContent-Typeset toapplication/x-www-form-urlencodedwith the data fieldsxdrcontaining the signed XDR (URL-encoded). If there are any query params specified in the URL callback then those should be included in the URL when submitting. For now onlyurlcallback types are supported.msg(optional) - There can be an optionalmsgquery param to indicate any additional information that the website or application wants to show the user in her wallet. The value for this query param should be URL-encoded as well and should not be longer than 300 characters before the URL-encoding. Note that themsgfield is different from thememofield that is included in a transaction. Themsgfield will not be put on-chain, but thememofield will be put on-chain.network_passphrase(optional) - Only need to set if this transaction is for a network other than the public network (URL-encoded).origin_domain(optional) - A fully qualified domain name that specifies the originating domain of the URI request. Wallets must validate the URI request against the includedsignaturebefore they display theorigin_domainto the user. See the Request Signing section for more details.signature(optional) - A signature of the hash of the URI request (excluding thesignaturefield and value itself). Wallets should use theURI_REQUEST_SIGNING_KEYspecified in the domain'sstellar.tomlfile to validate this signature. If the verification fails, wallets must alert the user. See the Request Signing section for more details.
Example 1 - Request for a payment with lumens:
web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens
Example 2 - Request for a payment with a specific asset:
web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD
#Future operations
By introducing a namespace to the URI in the form of the operation we are leaving the syntax for this URI Scheme open and flexible for future modification.
#Transaction Submission
The application that generated the request URI should check the Stellar Network
directly to confirm receipt of the transaction unless it has specified a
callback in the callback query param. Here are three suggestions for the
workflow of how an application can achieve this:
- The application should generate the URI dynamically so it can include a unique ID in the memo field. This unique ID can be used to identify the receipt of a specific payment when deciding whether to move the user onto the next state in the application workflow.
- The application can ask the user for her account ID from which she plans to make the payment. The application can then check for a new payment for the requested amount that is made by the user’s account ID. This is slightly more tedious for the user than (1) suggested above and therefore it is recommended that approach (1) be used if it is possible to generate dynamic payment request URIs.
- Specify the
callbackquery param with a dynamically generated unique URL endpoint callback. The endpoint will listen for the signed transaction and submit it to the Stellar Network on behalf of the user. This would allow the listener endpoint to interact with the application as needed to record the payment by the user.
#Request Signing
Applications that want to increase trust with the end user should include the
origin_domain param along with a signature param, as described in the
operation sections above. This will allow wallets to validate the URI request
against the provided signature and therefore display this origin_domain to
the user.
This is how applications should create the signature field:
- Ensure that your domain's stellar.toml file has the field
URI_REQUEST_SIGNING_KEYwith the public key that wallets should use to validate request signatures. - Generate the URI request with the
origin_domainparam set to the application's domain. - Convert the URI request into the
payloadthat will be signed. The first 35 bytes of thepayloadare all0, the 36th byte is4. Then we concatenate the URI request with the prefixstellar.sep.7 - URI Scheme(no delimiter) and convert that to bytes to give use the finalpayloadto be signed. - Sign this payload with the application's private signing key corresponding
to the
URI_REQUEST_SIGNING_KEYpublic key. We will need to convert the signature to base64 and then URL-encode it so we can include it in the URI-Request. Take a look at the sample code here for reference. - Append the URL-encoded base64 signature to the URI Request as the value for
the
signatureparam. This should be the last param to make it easier for wallets to extract out thepayloadfor signature verification.
This is how a wallet should handle the origin_domain and signature
fields:
- If the
origin_domainfield does not exist then do not display anorigin_domainto the user; no need to proceed further. - If the
signaturefield is missing then do not allow the user to sign the transaction. This is not a valid URI request, display an appropriate message to the user; no need to proceed further. - If the
origin_domainis not a valid fully qualified domain name then do not allow the user to sign the transaction. This is not a valid URI request, display an appropriate message to the user; no need to proceed further. - Fetch the
stellar.tomlfile from the domain:https://<origin_domain>/.well-known/stellar.toml. If thestellar.tomlfile does not exist then do not allow the user to sign the transaction. This is not a valid URI request, display an appropriate message to the user; no need to proceed further. It is recommended that wallets do not cachestellar.tomlfiles and that they always fetch the lateststellar.tomlfiles as part of processing signatures so that if signing keys of a domain are ever changed then the wallet can alert the user accordingly using the cachedURI_REQUEST_SIGNING_KEYfor comparison as described below. - Extract out the
URI_REQUEST_SIGNING_KEYfield from thestellar.toml. If this key does not exist then do not allow the user to sign the transaction. This is not a valid URI request, display an appropriate message to the user; no need to proceed further. Wallets should cache the last usedURI_REQUEST_SIGNING_KEYfor a given domain and only use the cached value to compare it to the latest signing key retrieved, if the latest signing key differs from the cached value for that domain then the wallet must alert the user of this change so they are aware that the signing key has changed which poses a security risk to the user. - Once you have the domain's
URI_REQUEST_SIGNING_KEYyou can use it to verify the URI request against the provided signature. In order to do this, you will need to convert the URI Request into thepayloadas described above. It is this payload that is verified using theURI_REQUEST_SIGNING_KEY. Take a look at the sample code here for reference. - If the signature verification fails then do not allow the user to sign the transaction. This is not a valid URI request, display an appropriate message to the user; no need to proceed further.
- If the signature verification succeeds then the wallet should display the
origin_domainto the user so the user knows which domain created this URI request. The user is then free to choose whether she wants to proceed with signing a request that originated from that domain. This is the only point at which a wallet should display theorigin_domainto the user since it has completely verified the URI Request against the includedsignature.
Example:
Assume this URI request needs signing (notice that the origin_domain is part
of the request along with other query params, however the signature param is
missing):
web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com
Let's use the
sample code
to sign this URI Request with the private key
SBPOVRVKTTV7W3IOX2FJPSMPCJ5L2WU2YKTP3HCLYPXNI5MDIGREVNYC. The base64 encoded
signature is:
tbsLtlK/fouvRWk2UWFP47yHYeI1g1NEC/fEQvuXG6V8P+beLxplYbOVtTk1g94Wp97cHZ3pVJy/tZNYobl3Cw==.
When we URL-encode that, we get:
tbsLtlK%2FfouvRWk2UWFP47yHYeI1g1NEC%2FfEQvuXG6V8P%2BbeLxplYbOVtTk1g94Wp97cHZ3pVJy%2FtZNYobl3Cw%3D%3D.
This is the signature.
The complete URI request can be compiled by appending the signature to the
original URI Request which gives:
web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com&signature=tbsLtlK%2FfouvRWk2UWFP47yHYeI1g1NEC%2FfEQvuXG6V8P%2BbeLxplYbOVtTk1g94Wp97cHZ3pVJy%2FtZNYobl3Cw%3D%3D
In order to verify the signature
tbsLtlK%2FfouvRWk2UWFP47yHYeI1g1NEC%2FfEQvuXG6V8P%2BbeLxplYbOVtTk1g94Wp97cHZ3pVJy%2FtZNYobl3Cw%3D%3D
against our URI request, we first separate out the signature field and value
from the URI Request. Then we use what is remaining from the URI Request and
verify it against the signature value. The signature needs to first be
URL-unescaped and then decoded from base64 into its byte form before it can be
used to verify the remaining portion of the URI request against the public key.
If there is no error then we know that the signature is valid and the
origin_domain is the originator of this URI request. Wallets should then
display the origin_domain to the user if signature verification succeeds. If
signature verification fails then wallets should disallow the user from signing
the URI request and display an appropriate message to alert the user.
#Security Best Practices for Compliance with this SEP
Here are some specific attacks that would compromise the security of the user. We have listed out ways in which wallets should handle these situations. This list is not comprehensive and is only a starting point for wallet developers to think about security. We strongly encourage all wallet developers to take some time to think about this and share any learnings with the community. Without further ado, here's the list:
-
Threat: URI Request Modification. This is when an attacker changes part of the URI Request. This is possible in a man-in-the-middle scenario.
Suggested Precaution: If the URI is modified, then the
signaturecheck will fail and the wallet should not allow the user to sign the transaction and should alert the user of possible tampering with the URI request. If theorigin_domainandsignaturefields do not exist then this is a red flag! Your wallet should make it harder for users to sign such a request by making them go through additional steps to confirm that they understand the risks of signing a transaction that originated from an unsigned URI request. If theorigin_domainexists but thesignaturefield does not exist then it is not a valid request. An unsigned URI Request is equivalent to usinghttpvs. signed URI Requests being equivalent to usinghttpsand should be treated as such by wallets from a UI perspective. -
Threat: URI Request Hijacking. It is possible that a man-in-the-middle could completely replace the URI Request with another valid request from a different domain. This would result in all the signature checks passing.
Suggested Precaution: If signature verification succeeds then the wallet should display the
origin_domainin a prominent position on the same page/view where the user is signing the transaction. This will allow the user to know the referrer of the request and can be useful in mitigating such an attack since the user will be more careful before signing a request from an untrusted domain. Wallets should alert the user if they are transacting with anorigin_domainfor the first time as an additional precaution. -
Threat: The originating website creates a different URI Request compared to what the user was shown on their website (charging a higher amount for the same item, adding additional items to the bill, etc.)
Suggested Precaution: Wallets need to display details of the transaction to be signed, including any
msgsent by the originating domain. The originating domain should include details of the transaction (items in shopping cart, etc.) in themsgfield. -
Threat: The domain of the originating requestor is compromised and the attacker has updated the
URI_REQUEST_SIGNING_KEYin the domain'sstellar.tomlto one that they have access to allowing them to create signed URI Requests.Suggested Precaution: Wallets should keep a map/dictionary of
origin_domaintoURI_REQUEST_SIGNING_KEYand alert the user if there is ever a mismatch. Pinning the domain'sURI_REQUEST_SIGNING_KEYin this manner can be very effective as long as the originalURI_REQUEST_SIGNING_KEYwas not compromised to begin with. -
Threat: The destination address owned by a trusted domain is compromised.
Suggested Precaution: Wallets should keep track of all destination addresses that the user has paid to in the past and should alert the user if they are trying to pay to an address that they have not seen before. This can be combined with the map/dictionary of
origin_domaintoURI_REQUEST_SIGNING_KEY. Additionally, wallets should also maintain adenylistof addresses which they should update regularly. This will ensure that the community can be proactive about identifying malicious actors on the network. -
Threat: A malicious application tricks the user and registers as the default handler for the
web+stellarscheme name.Suggested Precaution: If the wallet was the default handler when it was last opened then it is reasonable for the wallet to expect that it is still the default handler. If this is not the case, then the wallet should alert the user and actively re-request to be made the default handler. However, if the user dismisses this alert then the wallet should not actively request to be made the default handler as that can become annoying for the user. This will ensure that the user is alerted if such an attack is ever attempted.
-
Threat: Homograph attack - A malicious domain registers a name that looks similar to another trusted domain and uses this to impersonate the trusted domain's URI requests. For example, replacing
l(i.e. lowercaseL) withI(i.e. uppercasei) or using Cyrrillic letters instead of Latin letters. Learn more about Homograph Attacks here.Suggested Precaution: Wallets should be very careful about the fonts they use when displaying the
origin_domain,memoandmsg. Some fonts do not clearly distinguish between certain characters so it is easy to confuse these characters. Wallets should use a font that allows to clearly distinguish between characters so that users can clearly identify malicious domains that are pretending to be trusted domains. Consider testing your wallet's UI with characters ranging across Unicode (particularly Cyrillic) and not just ASCII.
#Multisig
For multisig accounts the wallet is responsible for coordinating the collection of signatures and submitting to the network/callback. Supporting multisig accounts would require the wallet to have a backend service to support this coordination or to use a third-party service. Wallets should keep in mind to correctly display details of the transaction and metadata appropriately to all signers even for multisig transactions.
The multisig coordination service should replace/add a callback to the URI
Request using an endpoint in it's own backend service so the signer's wallet
can return the signature to it. The multisig service should always sign the
URI Request it is forwarding and include it's own domain as the
origin_domain and the orignal origin_domain as the msg in addition to
any other information already included so each signer can see the original
origin_domain before signing. This is by all means a new URI Request that
is sent out to signers. Signers that trust the multisig coordination service
and will sign transactions based on that trust only, not based on the msg
included.
The multisig coordination service should handle collating signatures from the signers before submitting it in a single transaction that is signed by all signers to the network or callback endpoint. See the sample code here for reference on how to collate signatures.
#Register to handle the URI Scheme
Here are suggestion on how to register your wallet to handle the new URI Scheme based on your platform:
- Linux: Creating custom URL handlers in Ubuntu 11.04, 11.10, GNOME 3.0
- Windows: Handle URI activation (on Windows)
- Mac: Make Your Own URL Protocol and Handler
- iOS: Implementing Custom URL Schemes and Simpler reference to implement custom URL Schemes on iOS
- Android: https://stackoverflow.com/a/4085365/1484710
- Web: Navigator.registerProtocolHandler()
#Rationale
The choice to go with this URI Scheme and syntax allows us to achieve some of the goals outlined above in the Motivation section. Here is a description of how this particular specification meets those needs:
- Open and Decentralized - The specification uses a URI Scheme that is not linked to a particular domain or entity. The specification itself is public and the tools needed to create these URIs are also free and publicly available (XDR format, Stellar SDK).
- Standardized - The specification allows creating requests for any transaction that is possible on the Stellar Network. This means that we do not need operation-specific handling, like payments vs. change trust as an example. URI Schemes are generic and not tied to a specific programming language or platform and can therefore be implemented on any platform and in any programming language.
- Secure - The syntax for the URI scheme does not expose any secret keys. To be fully compliant with the specification, wallets are required to display the transaction that the user will sign and also save well-known destination addresses to alert the user if she encounters a new recipient. These protections will give the user increased visibility into the transaction they are signing and greater confidence when using wallets that comply with these specifications.
- Future-Proof - Since the syntax allows for including a Stellar transaction directly it will work for operations that are added to the Stellar Network in the future. This will ensure that existing wallets will continue to function as expected as these new operations are added. Since the syntax includes a namespace we can further expand it to include information that we did not think of at the time when this specification was defined.
#User Experience
When the user opens their preferred wallet that implements this SEP, the wallet
will request to handle the web+stellar URI scheme. If there is already a
registered default handler for this URI scheme then the wallet should not
request to handle this URI scheme so as to not pose an annoyance to the user.
Depending on the platform used by the wallet (web browser, application, mobile)
this request will be surfaced to the user and can be highlighted by the wallet.
The user can then confirm the application's request, making it the default
handler for this URI scheme. From this point on any URIs with the web+stellar
scheme name that are clicked will trigger the preferred wallet to be opened by
the user's OS.
When a URI request is clicked, the wallet should parse the URI request and present the user with the details as specified in this SEP when requesting a signature. Under no circumstance should the wallet automatically sign requests without the user's express consent.
#QR Codes
Alternative forms of transmitting payment requests, such as QR codes, should follow this URI Scheme so it is compatible with existing wallets. In order to communicate a SEP-0007 payment request via a QR-code you should encode the whole SEP-0007 URI into the image rendered by the QR-code. Thus, on reading the QR-code you will get a SEP-0007 encoded URI as the output without having to do any additional processing. Any error correction should be taken care of by the QR-code generator.
#Backwards Compatibility
There is no common pattern of usage that are currently employed by the community so there is no issue with backwards compatibility.
#Test Cases
There are two parts to the reference implementation (below). The second one (transaction xdr extraction and signing) serves as an effective test case for the first one (URI generation).
#Reference Implementation
The reference implementations only serve to demonstrate how the generated XDR can be signed and submitted to the test network along with some of the other code snippets included. The work of displaying the details of the transaction that the user will sign have not been implemented and has been left for wallet developers to implement. Furthermore, the pattern to start the signing script is not a secure pattern as it would expose the user’s secret key to the command line history and potentially to keyloggers as well and we strongly recommend that you do not use the same pattern in any of your own code. When looking over the reference implementation files please keep in mind that they are not tested and are designed only to serve as a Proof-Of-Concept for this SEP specification and are not meant to be used for anything other than that.
- Reference Implementation to generate an XDR
Transactionfor a payment operation and sign it - Sample code to create the
signaturefield for the URI request and verify it - Sample code to collate signatures for a multi-signature transaction using base64-encoded signed transaction XDRs
- Sample web handler demonstrates how to parse the payment request
xdrfor thetxoperation
#Other Implementations
- iOS and macOS SDK: https://github.com/Soneso/stellar-ios-mac-sdk/blob/master/README.md#7-uri-scheme-to-facilitate-delegated-signing
- JS SDK: https://www.npmjs.com/package/@stellarguard/stellar-uri