SEP: 0043
Title: Standard Web Wallet API Interface
Authors: Piyal Basu <[email protected]>, Leigh McCulloch <@leighmcculloch>, George Kudrayvtsev <[email protected]>, Enrique Arrieta <@earrietadev>, Orbit Lens <@orbitlens>
Track: Standard
Status: Draft
Created: 2024-04-11
Version: 1.1.0
Discussion: https://github.com/stellar/stellar-protocol/discussions/1467
This standard aims to enhance developer experiences by standardizing an interface for web wallet's to use when interacting with other codebases.
There are numerous Stellar wallets in the ecosystem with this number expected to grow as the ecosystem does. Wallets expose an API to allow dapps to call methods that preform such common tasks as transmitting a wallet's adress. An issue is that wallets all use slightly different API's to preform similar functions, with different method names and call signature as well as different return values. Developers have a motivation to integrate with as many as possible, but currently, they must create abstractions to handle every wallet they wish to connect to. This proposal presents a standard API interface for all wallets to implement. If all wallets have the same interface, it removes the needs for developers to create abstractions for every individual wallet they want to integrate with. Developers can safely assume a wallet uses this agreed upon interface, creating simpler codepaths that easily connect to current wallets while also simplifying the onboarding of new wallets.
The standard web wallet interface provides a structure for common methods that wallets are expected to offer. In addition, the interface defines common error message shapes to ensure wallets adhere to informative and usable error messaging. Messages are designed to be surfaced directly to the user, so they should provide a readable description of what went wrong.
Wallets will employ an API using the following format:
interface Error {
message: string, // general description message returned to the client app
code: number, // unique error code
ext?: Array<string> // optional extended details
}
{
get_address: () => Promise<{address: string;} | Error>,
sign_transaction: (xdr: string, opts?: { network_passphrase?: string, address?: string; submit?: boolean; submit_url?: string; }) => Promise<{signed_tx_xdr: string; signer_address: string;} | Error>,
sign_auth_entry: (auth_entry: string, opts?: { network_passphrase?: string, address?: string }) => Promise<{signed_auth_entry: string; signer_address: string;} | Error>,
sign_message: (message: string, opts?: { network_passphrase?: string, address?: string }) => Promise<{signed_message: string; signer_address: string;} | Error>,
get_network: () => Promise<{network: string, network_url: string, network_passphrase: string, soroban_rpc_url: string}>
}
In addition, this proposal has a standard for error interfaces. Below are examples of different kinds of errors a wallet may surface:
{
unhandled: { // internal wallet error, likely caused by the wallet logic itself
message: 'Unhandled error occurred.',
code: -1
},
external: { // external service (Horizon, RPC, etc.) returned an error
message: 'External error occurred.',
code: -2,
ext: ['Operation 2: Invalid "amount" value.', "Operation 5: Asset issuer is required."] // malformed tx error example
},
invalid: { // client app request is invalid (wrong parameters, invalid transaction XDR, etc.)
message: 'Request is invalid.',
code: -3,
ext: ['Invalid transaction XDR'] // example error
},
rejected: { // user rejected the request, client app should not try to retry the request
message: 'Rejected by the user.',
code: -4
}
}
get_address
will provide the public key the wallet is signing for. This may be the account loaded in the wallet, or it may be a different account that the wallet is the signer for.
sign_transaction
will take an XDR provided by the requester and apply a signature to it before returning a signed XDR and the signer address back to the requester. The first parameter is the XDR string while the second parameter is a set of options. Options allow a user to specify what network they intend the transaction to be signed on. They can do so by passing the network's passphrase as network_passphrase
. Options also allow a wallet to specify which account they're seeking a signature for as address
. If a wallet holds numerous addresses, it can use this param to ensure it is signing with the intended address. Options also allow a user to set a submit
flag, which will allow a user to sign a transaction and immediately submit it to a network. If a user would like to configure the URL of the network to submit to, they can do so by setting submit_url
.
Similar to its transaction counterpart, sign_auth_entry
will take an XDR provided by the requester and apply a signature to it before returning a signature and the signer address back to the requester. The first parameter is the XDR string while the second parameter is a set of options. Options allow a user to specify what network they intend the transaction to be signed on. They can do so by passing the network's passphrase as network_passphrase
. Options also allow a wallet to specify which account they're seeking a signature for as address
. If a wallet holds numerous addresses, it can use this param to ensure it is signing with the intended address.
Similar to its transaction and aither entry counterparts, sign_message
will take an arbitrary message provided by the requester and apply a signature to it before returning a signed message and the signer address back to the requester. This can be used to implement identity/ownership verification. The first parameter is the XDR string while the second parameter is a set of options. Options allow a user to specify what network they intend the transaction to be signed on. They can do so by passing the network's passphrase as network_passphrase
. Options also allow a wallet to specify which account they're seeking a signature for as address
. If a wallet holds numerous addresses, it can use this param to ensure it is signing with the intended address.
get_network
provides details about the network that the wallet is currently configured to. This allows a dapp to confirm that they are building a transaction for the correct network.
Error messaging provides clear errors to the requester. The message
field provides an informative, human readable string that a UI could surface to the end user. The 4 types of code
key dilineate between possible erroes: those caused by an internal wallet error, an error caused by external service (for ex: Horizon or Soroban RPC), invalid user input (for ex: a malformed XDR), and an error caused by the user rejecting the action requested. Finally, the ext
field is an optional value that can provide more context for the error, if needed.