solana-labs / solana

Web-Scale Blockchain for fast, secure, scalable, decentralized apps and marketplaces.
https://solanalabs.com
Apache License 2.0
13.02k stars 4.19k forks source link

Define and document a URI scheme for making SOL / SPL Token payments #19535

Closed mvines closed 2 years ago

mvines commented 3 years ago

A standard URI scheme across wallets for native SOL and SPL Token payments (transfers) is desirable. This scheme for example could be encoded as a QR Code.

TrustWallet has taken the lead with solana:<ADDRESS>?amount=<AMOUNT>, which is essentially BIP 21 but with the bitcoin: scheme replaced with solana:. This is a great start.

The existing BIP 21 label= ("Label for that address (e.g. name of receiver)") and message= ("message that describes the transaction to the user ") fields are directly relevant. This labels are informative only and are not encoded into the on-chain transaction

The amount field is alway interpreted to be a decimal number of "user" units. For SOL, that's SOL and not lamports. For tokens,uiAmountString and not amount (reference: Token Balances Structure). If the provided decimal fractions exceed what's supported for SOL (9) or the token (mint specific), the URL must be considered malformed URL and rejected. Scientific notation is prohibited.

For SPL Token transfers, an additional spl-token=<MINT_ADDRESS>, is required to define the token type. If no spl-token= field is specified then the URL describes a native SOL transfer.

A memo=String field is also permitted, where the provided string should be encoded as an SPL Memo instruction in the payment transaction. It's recommended that the memo field be displayed to the user before they authorize the transaction. The SPL Memo instruction MUST be included immediately after the SOL or SPL Token transfer instruction; this placement is essential to avoid ambiguity when multiple transfers are batched together in a single transaction.

Note that for SPL Token transfers, the Associated Token Account convention must be used. Transfers to auxiliary token accounts are not supported.

The sender may optionally choose to use a confidential token transfer if the receiving address has configured a confidential token account.

Examples

URL describing a transfer for 0.01 SOL:

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId1234

URL describing a transfer for $0.01 SPL USDC

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId5678

URL describing a generic SOL transfer with a recipient name and memo. The user should be prompted for the exact amount while authorizing the transfer:

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN&label=Michael&memo=4321ABCD
Taylor123 commented 3 years ago

@mvines I'd suggest we use a url scheme that has :// in order for url parsers to pick it up more easily.

Another parameter that may be helpful for custodial clients is to have the ticker symbol of the mint.

solana://mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&symbol=USDC&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId5678
mvines commented 3 years ago

Thanks @Taylor123

I'd suggest we use a url scheme that has :// in order for url parsers to pick it up more easily.

In a vacuum I think I'd agree with this, and I see the logic. Because a subset of this scheme is already live in TrustWallet today (which is basically just BIP 21), I'm hesitant to diverge from it without a super strong reason.

Another parameter that may be helpful for custodial clients is to have the ticker symbol of the mint.

How do you see this as being useful for custodial clients? My assumption was that the clients would be aware of the token mints they support, so adding an additional symbol field felt redundant and introduces more error cases due to mismatches between the symbol= and spl-token= field values.

Taylor123 commented 3 years ago

Ok with me to forgo the //.

Currently we're using symbols on the client as it's the same across ERC20, SPL, etc. We can update to use mints though, so on board with this url scheme

mvines commented 3 years ago

Sounds good, thanks for the feedback!

mvines commented 3 years ago

Note: it does seem like supporting solana:// as a prefix in addition to only solana: actually would be useful for applications/environments that will turn "scheme://" into a link and ignore "scheme:"

t-nelson commented 3 years ago

Pedantic note: // signifies a network URI according to the RFC

A relative reference that begins with two slash characters is termed a network-path reference; such references are rarely used.

geehsien commented 3 years ago

From the same RFC, the // is also meant to be used preceding a host or authority. In other words:

URI = scheme:[//authority]path[?query][#fragment]

In this case (solana:<ADDRESS>?amount=<AMOUNT>...), the address is not really the host, so adding // to the spec could actually be seen as incorrect.

Taylor123 commented 3 years ago

After more thought and implementing the handling for it, I'm fine to remove it. The // will make url parses assume the address is the host, which could be problematic if there were multiple versions of the url scheme floating around.

mvines commented 3 years ago

I added the following text to the section discussing memo=String based on recent feedback:

"The SPL Memo instruction must be included immediately after the transfer instruction; this placement is essential to avoid ambiguity when multiple transfers are batched into a single transaction."

jordaaash commented 2 years ago

Is the amount field interpreted to always be a decimal number of units of the token / native SOL? What should happen if, for example, the token mint has 9 decimals and the sender provides amount=1.0000000001?

Should they be required to provided a trailing .0 if they provide an integer input so receivers always know they mean 1000.0 SOL and not something like 1000 lamports?

jordaaash commented 2 years ago

I guess BIP21 largely addresses this:

Transfer amount

If an amount is provided, it MUST be specified in decimal BTC. All amounts MUST contain no commas and use a period (.) as the separating character to separate whole numbers and decimal fractions. I.e. amount=50.00 or amount=50 is treated as 50 BTC, and amount=50,000.00 is invalid.

Bitcoin clients MAY display the amount in any format that is not intended to deceive the user. They SHOULD choose a format that is foremost least confusing, and only after that most reasonable given the amount requested. For example, so long as the majority of users work in BTC units, values should always be displayed in BTC by default, even if mBTC or TBC would otherwise be a more logical interpretation of the amount.

mvines commented 2 years ago

Is the amount field interpreted to always be a decimal number of units of the token / native SOL?

I suggest always using the "user unit". For SOL, that's SOL and not lamports. For tokens,uiAmount and not amount (cc: Token Balances Structure)

mvines commented 2 years ago

The SPL Memo instruction MUST be included immediately after the SOL or SPL Token transfer instruction; this placement is essential to avoid ambiguity when multiple transfers are batched together in a single transaction.

There's been some discussion about flipping this around, and requiring the memo instruction be be included immediately before the SOL or SPL Token transfer instruction, and allowing more than one memo instructions. This is to better support CPI use cases, were a program may which to make multiple transfers with a memo during it's execution.

jordaaash commented 2 years ago

I propose we close this issue and follow up @ https://github.com/solana-labs/solana-pay/pull/12.

Please reopen if you disagree :)

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any activity in past 7 days after it was closed. Please open a new issue for related bugs.