diff --git a/.eslintignore b/.eslintignore index ced4f6b92a..edc59a8dbb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,6 +9,7 @@ **/*.woff2 **/*.secret **/*.md +**/*.mdx **/*.webm .DS_Store diff --git a/.prettierignore b/.prettierignore index e262ac9d09..7daffb201b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,6 +5,7 @@ **/*.woff2 **/*.secret **/*.md +**/*.mdx **/*.webm .DS_Store diff --git a/docs/docs/01-intro.md b/docs/docs/01-intro.md deleted file mode 100644 index 89ca1f0a78..0000000000 --- a/docs/docs/01-intro.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Introduction -description: Keplr is a non-custodial blockchain wallets for webpages that allow users to interact with blockchain applications. -aside: true ---- - -# Keplr wallet Documentation - -## Introduction - -Keplr is a non-custodial blockchain wallets for webpages that allow users to interact with blockchain applications. - -## Why Keplr? - -- Private keys are stored locally. This removes the friction and risk of webpages having to manage user private keys safely and securely. -- As the user's private key is not managed by the website, users do not have to worry about the level of security of the website. The user only has to trust the security guarantees of Keplr, and freely interact with various web applications as they wish (and verify the contents of the transaction). -- Keplr can easily connect to libraries such as CosmJS, simplifying the process of connecting webpages to blockchains. - -## Sections -[Integrate with Keplr](./02-basic-api.md) describes how to integrate with Keplr in the webpage. - -[Use with cosmjs](./03-cosmjs.md) describes how to use cosmjs with Keplr. - -[Use with secretjs](./04-secretjs.md) describes how to use secretjs with Keplr if you need to use secret-wasm feature. - -[Suggest chain](./05-suggest-chain.md) describes how to suggest the chain to Keplr if the chain is not supported natively in Keplr. - -[EVM-based chains support](./06-evm.md) describes how to support EVM-based chains with Keplr. - -[Starknet Support](./07-starknet.md) describes how to support Starknet chains with Keplr. diff --git a/docs/docs/02-basic-api.md b/docs/docs/02-basic-api.md deleted file mode 100644 index 4394e2e1a0..0000000000 --- a/docs/docs/02-basic-api.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -title: Basic API -order: 1 ---- - -## How to detect Keplr - -You can determine whether Keplr is installed on the user device by checking `window.keplr`. If `window.keplr` returns `undefined` after document.load, Keplr is not installed. There are several ways to wait for the load event to check the status. Refer to the examples below: - -You can register the function to `window.onload`: - -```javascript -window.onload = async () => { - if (!window.keplr) { - alert("Please install keplr extension"); - } else { - const chainId = "cosmoshub-4"; - - // Enabling before using the Keplr is recommended. - // This method will ask the user whether to allow access if they haven't visited this website. - // Also, it will request that the user unlock the wallet if the wallet is locked. - await window.keplr.enable(chainId); - - const offlineSigner = window.keplr.getOfflineSigner(chainId); - - // You can get the address/public keys by `getAccounts` method. - // It can return the array of address/public key. - // But, currently, Keplr extension manages only one address/public key pair. - // XXX: This line is needed to set the sender address for SigningCosmosClient. - const accounts = await offlineSigner.getAccounts(); - - // Initialize the gaia api with the offline signer that is injected by Keplr extension. - const cosmJS = new SigningCosmosClient( - "https://lcd-cosmoshub.keplr.app", - accounts[0].address, - offlineSigner, - ); - } -} -``` - -or track the document's ready state through the document event listener: - -```javascript -async getKeplr(): Promise { - if (window.keplr) { - return window.keplr; - } - - if (document.readyState === "complete") { - return window.keplr; - } - - return new Promise((resolve) => { - const documentStateChange = (event: Event) => { - if ( - event.target && - (event.target as Document).readyState === "complete" - ) { - resolve(window.keplr); - document.removeEventListener("readystatechange", documentStateChange); - } - }; - - document.addEventListener("readystatechange", documentStateChange); - }); -} -``` - -There may be multiple ways to achieve the same result, and no preferred method. - -## Keplr-specific features - -If you were able to connect Keplr with CosmJS, you may skip to the [Use Keplr with CosmJS](./03-cosmjs.md) section. - -While Keplr supports an easy way to connect to CosmJS, there are additional functions specific to Keplr which provide additional features. - -### Using with Typescript -**`window.d.ts`** -```javascript -import { Window as KeplrWindow } from "@keplr-wallet/types"; - -declare global { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface Window extends KeplrWindow {} -} -``` - -The `@keplr-wallet/types` package has the type definition related to Keplr. -If you're using TypeScript, run `npm install --save-dev @keplr-wallet/types` or `yarn add -D @keplr-wallet/types` to install `@keplr-wallet/types`. -Then, you can add the `@keplr-wallet/types` window to a global window object and register the Keplr related types. - -> Usage of any other packages besides @keplr-wallet/types is not recommended. -> - Any other packages besides @keplr-wallet/types are actively being developed, backward compatibility is not in the scope of support. -> - Since there are active changes being made, documentation is not being updated to the most recent version of the package as of right now. Documentations would be updated as packages get stable. - -### Enable Connection - -```javascript -enable(chainIds: string | string[]): Promise -``` - -The `window.keplr.enable(chainIds)` method requests the extension to be unlocked if it's currently locked. If the user hasn't given permission to the webpage, it will ask the user to give permission for the webpage to access Keplr. - -`enable` method can receive one or more chain-id as an array. When the array of chain-id is passed, you can request permissions for all chains that have not yet been authorized at once. - -If the user cancels the unlock or rejects the permission, an error will be thrown. - -### Get Address / Public Key - -```javascript -getKey(chainId: string): Promise<{ - // Name of the selected key store. - name: string; - algo: string; - pubKey: Uint8Array; - address: Uint8Array; - bech32Address: string; -}> -``` - -If the webpage has permission and Keplr is unlocked, this function will return the address and public key in the following format: - -```javascript -{ - // Name of the selected key store. - name: string; - algo: string; - pubKey: Uint8Array; - address: Uint8Array; - bech32Address: string; - isNanoLedger: boolean; -} -``` - -It also returns the nickname for the key store currently selected, which should allow the webpage to display the current key store selected to the user in a more convenient mane. -`isNanoLedger` field in the return type is used to indicate whether the selected account is from the Ledger Nano. Because current Cosmos app in the Ledger Nano doesn't support the direct (protobuf) format msgs, this field can be used to select the amino or direct signer. [Ref](./03-cosmjs.md#types-of-offline-signers) - -### Sign Amino - -```javascript -signAmino(chainId: string, signer: string, signDoc: StdSignDoc): Promise -``` - -Similar to CosmJS `OfflineSigner`'s `signAmino`, but Keplr's `signAmino` takes the chain-id as a required parameter. Signs Amino-encoded `StdSignDoc`. - -### Sign Direct / Protobuf - -```javascript -signDirect(chainId:string, signer:string, signDoc: { - /** SignDoc bodyBytes */ - bodyBytes?: Uint8Array | null; - - /** SignDoc authInfoBytes */ - authInfoBytes?: Uint8Array | null; - - /** SignDoc chainId */ - chainId?: string | null; - - /** SignDoc accountNumber */ - accountNumber?: Long | null; - }): Promise -``` - -Similar to CosmJS `OfflineDirectSigner`'s `signDirect`, but Keplr's `signDirect` takes the chain-id as a required parameter. Signs Proto-encoded `StdSignDoc`. - -### Request Transaction Broadcasting - -```javascript -sendTx( - chainId: string, - tx: Uint8Array, - mode: BroadcastMode -): Promise; -``` - -This function requests Keplr to delegate the broadcasting of the transaction to Keplr's LCD endpoints (rather than the webpage broadcasting the transaction). -This method returns the transaction hash if it succeeds to broadcast, if else the method will throw an error. -When Keplr broadcasts the transaction, Keplr will send the notification on the transaction's progress. - -### Request Signature for Arbitrary Message - -```javascript -signArbitrary( - chainId: string, - signer: string, - data: string | Uint8Array -): Promise; -verifyArbitrary( - chainId: string, - signer: string, - data: string | Uint8Array, - signature: StdSignature -): Promise; -``` - -This is an experimental implementation of [ADR-36](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-036-arbitrary-signature.md). Use this feature at your own risk. - -Its main usage is to prove ownership of an account off-chain, requesting ADR-36 signature using the `signArbitrary` API. - -If requested sign doc with the `signAmino` API with the ADR-36 that Keplr requires instead of using the `signArbitrary` API, it would function as `signArbitrary` -- Only supports sign doc in the format of Amino. (in the case of protobuf, [ADR-36](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-036-arbitrary-signature.md) requirements aren't fully specified for implementation) -- sign doc message should be single and the message type should be "sign/MsgSignData" -- sign doc "sign/MsgSignData" message should have "signer" and "data" as its value. "data" should be base64 encoded -- sign doc chain_id should be an empty string("") -- sign doc memo should be an empty string("") -- sign doc account_number should be "0" -- sign doc sequence should be "0" -- sign doc fee should be `{gas: "0", amount: []}` - -When using the `signArbitrary` API, if the `data` parameter type is `string`, the signature page displays as plain text. - -Using `verifyArbitrary`, you can verify the results requested by `signArbitrary` API or `signAmino` API that has been requested with the ADR-36 spec standards. - -`verifyArbitrary` has been only implemented for simple usage. `verifyArbitrary` returns the result of the verification of the current selected account's sign doc. If the account is not the currently selected account, it would throw an error. - -It is recommended to use `verifyADR36Amino` function in the `@keplr-wallet/cosmos` package or your own implementation instead of using `verifyArbitrary` API. - -### Interaction Options - -```javascript -export interface KeplrIntereactionOptions { - readonly sign?: KeplrSignOptions; -} - -export interface KeplrSignOptions { - readonly preferNoSetFee?: boolean; - readonly preferNoSetMemo?: boolean; -} -``` -Keplr v0.8.11+ offers additional options to customize interactions between the frontend website and Keplr extension. - -If `preferNoSetFee` is set to true, Keplr will prioritize the frontend-suggested fee rather than overriding the tx fee setting of the signing page. - -If `preferNoSetMemo` is set to true, Keplr will not override the memo and set fix memo as the front-end set memo. - -You can set the values as follows: -```javascript -window.keplr.defaultOptions = { - sign: { - preferNoSetFee: true, - preferNoSetMemo: true, - } -} -``` - -## Custom event - -### Change Key Store Event - -```javascript -keplr_keystorechange -``` - -When the user switches their key store/account after the webpage has received the information on the key store/account the key that the webpage is aware of may not match the selected key in Keplr which may cause issues in the interactions. - -To prevent this from happening, when the key store/account is changed, Keplr emits a `keplr_keystorechange` event to the webpage's window. You can request the new key/account based on this event listener. - -```javascript -window.addEventListener("keplr_keystorechange", () => { - console.log("Key store in Keplr is changed. You may need to refetch the account info.") -}) -``` diff --git a/docs/docs/getting-started/connect-to-keplr.mdx b/docs/docs/getting-started/connect-to-keplr.mdx new file mode 100644 index 0000000000..cb378b52ce --- /dev/null +++ b/docs/docs/getting-started/connect-to-keplr.mdx @@ -0,0 +1,100 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Connect to Keplr + +Integrating your dApp with Keplr allows you to provide seamless interactions for your users. To meet various development needs, Keplr offers flexible integration methods, as detailed below: + +- [Direct Integration](#direct-integration) +- [Keplr Wallet SDK](#keplr-wallet-sdk) + +--- + +## Direct Integration + +The most straightforward approach to connect your dApp to Keplr is by utilizing the provider that Keplr injects directly into your web application. This provider is globally available at `window.keplr`. With this integration, you'll always have access to the latest functionality provided by Keplr. + +### How to Detect Keplr + +To check if Keplr is installed on a user's device, you can verify the presence of `window.keplr`. If `window.keplr` is `undefined` after the `document.load` event, Keplr is not installed. Below are some examples of how to wait for the load event to check the status. + +Register a function to `window.onload`: + +```javascript +window.onload = async () => { + if (!window.keplr) { + alert("Please install the Keplr extension."); + return; + } + + const keplr = window.keplr; + + const chainId = "cosmoshub-4"; + await keplr.enable(chainId); +}; +``` + +Or track the document's ready state through the document event listener: + +```javascript +async getKeplr(): Promise { + if (window.keplr) { + return window.keplr; + } + + if (document.readyState === "complete") { + return window.keplr; + } + + return new Promise((resolve) => { + const documentStateChange = (event: Event) => { + if ( + event.target && + (event.target as Document).readyState === "complete" + ) { + resolve(window.keplr); + document.removeEventListener("readystatechange", documentStateChange); + } + }; + + document.addEventListener("readystatechange", documentStateChange); + }); +} +``` + +--- + +## Keplr Wallet SDK + +For a more modular approach, you can use the Keplr client by using the JavaScript SDK. This allows you to connect your dApp to Keplr by installing the SDK via package managers. The client provides an easy-to-use interface for interacting with Keplr, making integration simpler and more scalable for complex projects. + +#### Installation Steps + +1. Install `@keplr-wallet/provider-extension` via package managers. + + + + ```bash + npm i @keplr-wallet/provider-extension + ``` + + + ```bash + yarn add @keplr-wallet/provider-extension + ``` + + + +2. Import the SDK into your application. + + ```tsx + import { Keplr } from "@keplr-wallet/provider-extension"; + ``` + +3. Initialize the SDK. + + ```tsx + export const getKeplrFromProvider = async () => { + return await Keplr.getKeplr(); + }; + ``` diff --git a/docs/docs/getting-started/typescript-support.md b/docs/docs/getting-started/typescript-support.md new file mode 100644 index 0000000000..2d3a3cfd79 --- /dev/null +++ b/docs/docs/getting-started/typescript-support.md @@ -0,0 +1,21 @@ +--- +title: TypeScript Support +--- + +**`window.d.ts`** +```javascript +import { Window as KeplrWindow } from "@keplr-wallet/types"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface Window extends KeplrWindow {} +} +``` + +The `@keplr-wallet/types` package has the type definition related to Keplr. +If you're using TypeScript, run `npm install --save-dev @keplr-wallet/types` or `yarn add -D @keplr-wallet/types` to install `@keplr-wallet/types`. +Then, you can add the `@keplr-wallet/types` window to a global window object and register the Keplr related types. + +> Usage of any other packages besides @keplr-wallet/types is not recommended. +> - Any other packages besides @keplr-wallet/types are actively being developed, backward compatibility is not in the scope of support. +> - Since there are active changes being made, documentation is not being updated to the most recent version of the package as of right now. Documentations would be updated as packages get stable. diff --git a/docs/docs/guide/broadcast-tx.md b/docs/docs/guide/broadcast-tx.md new file mode 100644 index 0000000000..af3630ced1 --- /dev/null +++ b/docs/docs/guide/broadcast-tx.md @@ -0,0 +1,71 @@ +# Broadcast a Transaction + +## Overview + +Now that you’ve learned [how to get a signed result](./sign-a-message), let’s explore how to broadcast a signed transaction. + +- Cosmos-based Chains + - Continue from the next section. +- EVM-based Chains + - Continue from the [EVM-based Chains](../multi-ecosystem-support/evm#sending-ethereum-transactions) section. +- Starknet + - Continue from the [Starknet](../multi-ecosystem-support/starknet#signing-transactions-on-starknet) section. + +--- + +The `sendTx` method allows developers to broadcast a transaction via Keplr's LCD endpoints. Keplr handles the entire broadcasting process, including notifications on the transaction's progress(e.g., pending, success, or failure). If the transaction fails to broadcast, the method throws an error. + +## Function Signature + +```typescript +sendTx( + chainId: string, + tx: Uint8Array, + mode: BroadcastMode +): Promise +``` + +### Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| **`chainId`** | `string` | The unique identifier of the chain where the transaction will be sent. | +| **`tx`** | `Uint8Array` | The binary representation of the transaction to be broadcasted. This can include Amino-encoded or Protobuf-encoded transactions. | +| **`mode`** | `BroadcastMode` | The mode in which the transaction should be broadcasted. Options include:
- `BroadcastMode.Block`(block): Waits for the transaction to be included in a block.
- `BroadcastMode.Async`(async): Returns immediately after putting the transaction in the mempool.
- `BroadcastMode.Sync`(sync): Returns after broadcasting the transaction without waiting for block confirmation. | + +### Return Value + +The method returns a `Promise` that resolves to the **transaction hash** if the broadcasting succeeds. + +--- + +## Example Usage + +```typescript +import { TxRaw } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx"; + +// Please refer to "Sign a Message" page for detailed signing methods +const protoSignResponse = await keplr.signDirect( + this.chainId, + this.bech32Address, + signDoc, + signOptions, +); + +// Build a TxRaw and serialize it for broadcasting +const protobufTx = TxRaw.encode({ + bodyBytes: protoSignResponse.signed.bodyBytes, + authInfoBytes: protoSignResponse.signed.authInfoBytes, + signatures: [ + Buffer.from(protoSignResponse.signature.signature, "base64"), + ], +}).finish(); + +try { + // Send the transaction + const txResponse = await keplr.sendTx("cosmoshub-4", protobufTx, "block"); + const txHash = Buffer.from(txResponse, "hex"); +} catch (error) { + console.error("Failed to broadcast transaction:", error.message); +} +``` diff --git a/docs/docs/guide/custom-event.md b/docs/docs/guide/custom-event.md new file mode 100644 index 0000000000..cb73449e85 --- /dev/null +++ b/docs/docs/guide/custom-event.md @@ -0,0 +1,21 @@ + +# Custom Event + +## Key Store Change + +To ensure your application stays updated with the current key store or account, Keplr emits a `keplr_keystorechange` event whenever the user switches their account. + +#### Event Name + +```javascript +keplr_keystorechange +``` + +#### Example Usage + +```javascript +window.addEventListener("keplr_keystorechange", () => { + console.log("Keplr key store has changed. Refetching account info..."); + // Refetch account or key information here +}); +``` \ No newline at end of file diff --git a/docs/docs/guide/enable-connection.mdx b/docs/docs/guide/enable-connection.mdx new file mode 100644 index 0000000000..8afa188d6f --- /dev/null +++ b/docs/docs/guide/enable-connection.mdx @@ -0,0 +1,43 @@ +import EnableChainExampleImage from "@site/static/img/guide/enable-chain-example.png"; + +# Enable Connection + +The `enable` method is used to request Keplr to unlock if it is currently locked. If the webpage has not been granted permission to access Keplr, this method prompts the user to grant the necessary permissions. + +--- + +## Function Signature + +```javascript +enable(chainIds: string | string[]): Promise +``` + +### Parameters + +- **`chainIds`** (`string | string[]`): + - A single chain ID as a string, or multiple chain IDs as an array of strings. + - When multiple chain IDs are provided, the method requests permissions for all specified chains in a single operation. + +:::note +Note that the chain IDs must correspond to Keplr's natively supported Cosmos SDK-based chains. A "native chain" refers to any blockchain that is officially supported by Keplr without requiring custom integration. For a complete list of native chains and their respective chain IDs, explore our [public API](https://keplr-chain-registry.vercel.app/api/native-chains). +::: + +--- + +## Example Usage + +In the following example, the `enable` method requests access to the `cosmoshub-4` and `juno-1` chains: + +```javascript +await keplr.enable(["cosmoshub-4", "juno-1"]); +``` + +When the enable method is called, the user will see a popup similar to the one shown below. This allows them to grant or deny permissions for the requested chain IDs: + +Keplr - Enable Chain Example + + diff --git a/docs/docs/guide/get-key.md b/docs/docs/guide/get-key.md new file mode 100644 index 0000000000..77b2b7b554 --- /dev/null +++ b/docs/docs/guide/get-key.md @@ -0,0 +1,96 @@ +# Get Address / Public Key + +The `getKey` function is used to retrieve addresses and its associated public key. This function is a crucial part of interacting with blockchain accounts, enabling developers to obtain account details securely. + +--- + +## Function Signature + +```javascript +getKey(chainId: string): Promise +``` + +### Parameters + - `chainId` (string): The unique identifier of the blockchain chain from which the key information should be retrieved. + - Cosmos-based chainIds (e.g., cosmoshub-4) + - EVM-based chainIds (e.g., eip155:1) + - Starknet chainIds (e.g., starknet:SN_MAIN) + +If the webpage has the necessary permissions to access the key and Keplr is unlocked, invoking `getKey` will return the address and public key with information aside in the following structure: + +### Return Type + +```typescript +interface Key { + readonly name: string; + readonly algo: string; + readonly pubKey: Uint8Array; + readonly address: Uint8Array; + readonly bech32Address: string; + readonly ethereumHexAddress: string; + readonly isNanoLedger: boolean; + readonly isKeystone: boolean; +} +``` + +### Key Properties Table + +| **Property** | **Type** | **Description** | +|---------------------|-------------|---------------------------------------| +| `name` | `string` | The name of the currently selected key store. This is a descriptive label set by the user.| +| `algo` | `string` | The algorithm used to generate the key (e.g., `secp256k1`).| +| `pubKey` | `Uint8Array`| The public key of the account, provided in binary format (`Uint8Array`).| +| `address` | `Uint8Array`| The account address, represented in binary format (`Uint8Array`).| +| `bech32Address` | `string` | The Bech32-encoded address, commonly used in Cosmos-based blockchains.| +| `ethereumHexAddress`| `string` | The Ethereum-compatible address, formatted as a hexadecimal string.| +| `isNanoLedger` | `boolean` | Indicates whether the selected account is from a Ledger Nano hardware wallet.| +| `isKeystone` | `boolean` | Indicates whether the selected account is from a Keystone hardware wallet.| + +
+ +:::info +Hardware Wallet Support: +- Ledger wallets typically use the Amino JSON sign mode due to limited support for Protobuf-based SIGN_MODE_DIRECT. Check more details [here](../use-with/cosmjs#types-of-offline-signers). +- Use the `isNanoLedger` and `isKeystone` properties to determine the appropriate signing mode for hardware wallets. +::: + +--- + +## Example Usage + +Here’s an example of how to use the `getKey` function: + +#### Cosmos-based chain +```javascript +(async () => { + try { + const chainId = "cosmoshub-4"; + const key = await getKey(chainId); + + console.log("Account Name:", key.name); + console.log("Public Key (Hex):", Buffer.from(key.pubKey).toString("hex")); + console.log("Bech32 Address:", key.bech32Address); + console.log("Ethereum Address:", key.ethereumHexAddress); + console.log("Is from Ledger:", key.isNanoLedger); + } catch (error) { + console.error("Error retrieving key:", error); + } +})(); +``` + +#### EVM-based chain +```javascript +(async () => { + try { + const chainId = "eip155:1"; // e.g., Ethereum Mainnet + const key = await getKey(chainId); + + console.log("Account Name:", key.name); + console.log("Public Key (Hex):", Buffer.from(key.pubKey).toString("hex")); + console.log("Ethereum Address:", key.ethereumHexAddress); + console.log("Is from Ledger:", key.isNanoLedger); + } catch (error) { + console.error("Error retrieving key:", error.message); + } +})(); +``` diff --git a/docs/docs/guide/sign-a-message.md b/docs/docs/guide/sign-a-message.md new file mode 100644 index 0000000000..cfcca6dcf3 --- /dev/null +++ b/docs/docs/guide/sign-a-message.md @@ -0,0 +1,214 @@ +import SignMessageExampleImage from "@site/static/img/guide/sign-message-example.png"; +import SignMessageEvmExampleImage from "@site/static/img/guide/sign-message-evm-example.png"; + +# Sign a Message + +## Overview + +Before submitting a transaction, users are required to review and sign a message to ensure their approval. Keplr simplifies this process by providing methods for signing messages across various blockchain networks. When a signing request is initiated, a popup appears prompting the user to confirm the action. Below is an example of the popup that users will encounter: + +
+
+
For a Cosmos-based Chain Tx
+ Signing Message For Cosmos-based Chains +
+
+
For a EVM-based Chain Tx
+ Signing Message For EVM-based Chains +
+
+ +- Cosmos-based Chains + - Keplr provides methods to sign messages using two distinct signing modes: **Amino** and **Protobuf (Direct)**. Each mode has its own use cases and compatibility considerations, as described in the next section. +- EVM-based Chains + - Continue from the [EVM-based Chains](../multi-ecosystem-support/evm#requesting-ethereum-signatures) section. +- Starknet + - Continue from the [Starknet](../multi-ecosystem-support/starknet#requesting-a-starknet-signature) section. + +--- + +## Signing Modes in the Cosmos SDK + +1. **Amino Signing**:
+ Amino is the legacy JSON-based signing format used by Cosmos SDK. It encodes transactions in a human-readable JSON structure and is widely supported across Cosmos-based blockchains. + - **Pros**: + - Highly compatible with older wallets and hardware devices, such as Ledger. + - Easier to debug due to its JSON representation. + - **Cons**: + - Larger transaction sizes compared to Protobuf. + - Limited efficiency due to its JSON-based structure. + +2. **Protobuf-Based Signing (Direct)**:
+ Protobuf is the modern binary-based signing format for the Cosmos SDK, introduced with `SIGN_MODE_DIRECT`. It is more efficient and compact than Amino. + - **Pros**: + - Smaller transaction sizes. + - Faster serialization and deserialization. + - **Cons**: + - Requires updated wallet and device firmware (e.g., Ledger may not support it fully in some cases). + - More challenging to debug due to its binary format. + +Developers should choose the signing mode based on the target chain's requirements and the compatibility of wallets or hardware devices. + +More details about the signing modes can be found in the Cosmos SDK documentation. + +--- + +## Amino Signing + +### Function Signature + +```javascript +signAmino( + chainId: string, + signer: string, + signDoc: StdSignDoc, + signOptions?: KeplrSignOptions +): Promise; +``` + +The `signAmino` method signs an Amino-encoded `StdSignDoc`. Unlike CosmJS's `OfflineSigner`, Keplr's `signAmino` requires the `chainId` parameter to ensure the transaction is linked to the correct chain. + +#### Parameters + +- **`chainId`** (`string`): The chain ID of the chain where the transaction is being signed. +- **`signer`** (`string`): The Bech32 address of the signer. +- **`signDoc`** (`StdSignDoc`): The transaction document to be signed, encoded in Amino format. + ```typescript + interface StdSignDoc { + chain_id: string; + account_number: string; + sequence: string; + timeout_height?: string; + fee: StdFee; + msgs: Msg[]; + memo: string; + } + ``` +- **`signOptions`** (`KeplrSignOptions`, optional): Additional signing options. + - `preferNoSetFee`: If true, the fee configured by the dApp will be prioritized over the fee set by the user. + - `preferNoSetMemo`: If true, the memo will be set by the dApp and the user will not be able to modify it. + - `disableBalanceCheck`: If true, the transaction won't be blocked even if the balance is insufficient. + +#### Return Type + +```typescript +interface AminoSignResponse { + readonly signed: StdSignDoc; + readonly signature: StdSignature; +} +``` + +### Example Usage + +```javascript +const signDoc = { + "account_number": "227917", + "chain_id": "celestia", + "fee": { + "gas": "96585", + "amount": [{ "amount": "966", "denom": "utia" }] + }, + "msgs": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + // msg value objects here + } + } + ], + "sequence": "84", + "memo": "Test transaction", +}; + +const signOptions = { + preferNoSetFee: false, + preferNoSetMemo: true, + disableBalanceCheck: true, +}; + +const signedResponse = await keplr.signAmino( + "celestia", + "celestia1...", + signDoc, + signOptions, +); + +console.log("Signed Doc:", signedResponse.signed); +console.log("Signature:", signedResponse.signature); +``` + +--- + +## Protobuf-Based Signing (Direct) + +### Function Signature + +```javascript +signDirect( + chainId: string, + signer: string, + signDoc: SignDoc, + signOptions?: KeplrSignOptions +): Promise; +``` + +The `signDirect` method signs a Protobuf-encoded transaction (`StdSignDoc`) using `SIGN_MODE_DIRECT`. Similar to CosmJS's `OfflineDirectSigner`, Keplr's `signDirect` also requires the `chainId` parameter. + +#### Parameters + +- **`chainId`** (`string`): The chain ID of the chain where the transaction is being signed. +- **`signer`** (`string`): The Bech32 address of the signer. +- **`signDoc`** (`SignDoc`): The Protobuf-encoded transaction document, including: + - `bodyBytes`: Encoded transaction body (messages and memo). + - `authInfoBytes`: Encoded authorization information (fees, signer info). + - `chainId`: The chain ID of the transaction. + - `accountNumber`: The account number of the signer. + +#### Return Type + +The method returns a `DirectSignResponse` containing the signed transaction and its signature. + +**`DirectSignResponse` Interface** + +```typescript +interface DirectSignResponse { + readonly signed: SignDoc; + readonly signature: { + readonly signature: StdSignature; + readonly pub_key: PubKey; + }; +} +``` + +### Example Usage + +```javascript +const signDoc = { + bodyBytes: new Uint8Array(), // Add encoded messages + authInfoBytes: new Uint8Array(), // Add encoded fee and signer info + chainId: "celestia", + accountNumber: 12345, +}; + +const signOptions = { + preferNoSetFee: true, +}; + +const directResponse = await keplr.signDirect( + "celestia", + "celestia1...", + signDoc, + signOptions, +); + +console.log("Signed Doc:", directResponse.signed); +console.log("Signature:", directResponse.signature); +``` diff --git a/docs/docs/guide/sign-arbitrary.md b/docs/docs/guide/sign-arbitrary.md new file mode 100644 index 0000000000..9d85a9be26 --- /dev/null +++ b/docs/docs/guide/sign-arbitrary.md @@ -0,0 +1,165 @@ +import SignArbitraryExampleImage from "@site/static/img/guide/sign-arbitrary-example.png"; + +# Sign an Arbitrary Message + +The `signArbitrary` and `verifyArbitrary` APIs enable off-chain proof of account ownership and message verification, adhering to the [ADR-36 specification](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-036-arbitrary-signature.md). + +--- + +## `signArbitrary` + +### Function Signatures + +This method allows you to request an ADR-36-compliant signature, primarily used for off-chain account ownership proofs. The signature is generated based on the provided `data`. + +```javascript +signArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array +): Promise; +``` + +#### Parameters + +| **Parameter** | **Type** | **Description** | +|---------------|--------------------|-----------------------------------------------------------------------------------------------------------| +| `chainId` | `string` | The chain ID of the chain for which the signature is being requested. | +| `signer` | `string` | The Bech32 address of the account that will sign the message. | +| `data` | `string \| Uint8Array` | The arbitrary message to sign. If provided as a string, it will be displayed as plain text in the confirmation popup. | + + +#### Return Value + +It returns a `Promise` that resolves to the signature object. + +**`StdSignature` Interface** + +```typescript +interface StdSignature { + readonly pub_key: PubKey; + readonly signature: string; +} +``` + +### Example Usage + +```javascript +const chainId = "cosmoshub-4"; +const signer = "cosmos1..."; +const data = "This is a test message"; + +const signature = await keplr.signArbitrary(chainId, signer, data); +console.log("Generated Signature:", signature); +``` + +It displays the popup as follows: + +Keplr - Sign Arbitrary Example + +--- + +## ADR-36 Signing with `signAmino` + +If you use the `signAmino` API with a sign doc formatted to meet ADR-36 requirements, it functions equivalently to `signArbitrary`. The required sign doc format is as follows: + +1. **Message Requirements**: + - The message should be a single message of type `"sign/MsgSignData"`. + - The message must include: + - `"signer"`: The account performing the signature. + - `"data"`: The message content, encoded in Base64. + +2. **Sign Doc Fields**: + - **`chain_id`**: Must be an empty string (`""`). + - **`memo`**: Must be an empty string (`""`). + - **`account_number`**: Must be `"0"`. + - **`sequence`**: Must be `"0"`. + - **`fee`**: Must be `{ gas: "0", amount: [] }`. + +Essential details about `signAmino` can be found in [Amino Signing section](./sign-a-message#amino-signing) in "Sign a Message" page. + +### Example Usage +```javascript +const adr36SignData = async (chainId, signerAddress, message) => { + // Base64 encode the message as required by ADR-36 + const base64Data = Buffer.from(message).toString("base64"); + + // Create a sign doc compliant with ADR-36 + const signDoc = { + chain_id: "", + account_number: "0", + sequence: "0", + fee: { gas: "0", amount: [] }, + memo: "", + msgs: [ + { + type: "sign/MsgSignData", + value: { + signer: signerAddress, + data: base64Data, + }, + }, + ], + }; + + const signResponse = await keplr.signAmino(chainId, signerAddress, signDoc); + + console.log("Signed Document:", signResponse.signed); + console.log("Signature:", signResponse.signature); + + return signResponse; +}; +``` + + +--- + +## `verifyArbitrary` + +### Function Signatures + +This method verifies the result of an ADR-36 signature generated via the `signArbitrary` or `signAmino` API. +`verifyArbitrary` is designed for simple usage and verifies the signature of the currently selected account only. + +:::note +**Recommendation**: Use the `verifyADR36Amino` function from the `@keplr-wallet/cosmos` package or implement your own verification logic for more robust use cases. +::: + + +```javascript +verifyArbitrary( + chainId: string, + signer: string, + data: string | Uint8Array, + signature: StdSignature +): Promise; +``` + +#### Parameters + +| **Parameter** | **Type** | **Description** | +|---------------|--------------------|-----------------------------------------------------------------| +| `chainId` | `string` | The chain ID of the chain for which the signature was created. | +| `signer` | `string` | The Bech32 address of the account used to create the signature. | +| `data` | `string \| Uint8Array` | The original message that was signed. | +| `signature` | `StdSignature` | The signature object to verify. | + +### Example Usage + +```javascript +const chainId = "cosmoshub-4"; +const signer = "cosmos1..."; +const data = "This is a test message"; +const signature = { + pub_key: { type: "tendermint/PubKeySecp256k1", value: "..." }, + signature: "...", +}; + +const isValid = await keplr.verifyArbitrary(chainId, signer, data, signature); + +console.log("Is signature valid?", isValid); +``` diff --git a/docs/docs/05-suggest-chain.md b/docs/docs/guide/suggest-chain.md similarity index 95% rename from docs/docs/05-suggest-chain.md rename to docs/docs/guide/suggest-chain.md index 7f94739399..8a3bcdd816 100644 --- a/docs/docs/05-suggest-chain.md +++ b/docs/docs/guide/suggest-chain.md @@ -1,13 +1,6 @@ ---- -title: Suggest Chain -order: 4 ---- +# Suggest Chain -### Suggest Chain - -*Warning: This is an experimental feature.* - -Keplr's 'suggest chain' feature allows front-ends to request adding new Cosmos-SDK based blockchains that aren't natively integrated to Keplr extension. +This `suggestChain` feature allows front-ends to request adding new Cosmos-SDK based blockchains that aren't natively integrated to Keplr extension. If the same chain is already added to Keplr, nothing will happen. If the user rejects the request, an error will be thrown. This allows all Cosmos-SDK blockchains to have permissionless, instant wallet and transaction signing support for front-ends. diff --git a/docs/docs/intro/index.md b/docs/docs/intro/index.md new file mode 100644 index 0000000000..3467ee5975 --- /dev/null +++ b/docs/docs/intro/index.md @@ -0,0 +1,38 @@ +--- +title: Introduction +description: Keplr is a non-custodial blockchain wallets for webpages that allow users to interact with blockchain applications. +aside: true +--- + +# Keplr wallet Documentation + +## Introduction + +Keplr is a non-custodial blockchain wallets for webpages that allow users to interact with blockchain applications. + +## Why Keplr? + +#### User Security and Trust +Keplr enhances user security by storing private keys locally, removing the need for websites to manage sensitive user data. This eliminates the risks associated with external key management and ensures that users only need to trust Keplr's security guarantees. With this approach, users can freely interact with web applications while independently verifying transaction details. + +#### Developer Convenience +Keplr simplifies blockchain integration for developers by offering seamless compatibility with libraries like CosmJS. This eliminates complex connection processes, making it easier for developers to link web applications to blockchains and focus on creating user-centric experiences. + +#### Multi-Chain Support Across Ecosystems +Keplr supports a wide range of blockchains, including Cosmos SDK-based chains, EVM-based chains, and Starknet, making it a versatile wallet for dApp developers. Additionally, Keplr is actively expanding its boundaries to support other major blockchain ecosystems, providing developers with a future-proof solution to reach broader audiences. + +#### Cross-Platform Accessibility +Available as both a browser extension and mobile app, Keplr ensures users can securely access their wallets and interact with dApps on their preferred platform. This comprehensive accessibility empowers developers to build scalable and user-friendly dApps that meet modern multi-platform demands. + +## Sections +[Connect to Keplr](../getting-started/connect-to-keplr) describes how to integrate with Keplr in the webpage. + +[Use with cosmjs](../use-with/cosmjs) describes how to use cosmjs with Keplr. + +[Use with secretjs](../use-with/secretjs) describes how to use secretjs with Keplr if you need to use secret-wasm feature. + +[Suggest chain](../guide/suggest-chain) describes how to suggest the chain to Keplr if the chain is not supported natively in Keplr. + +[EVM-based chains support](../multi-ecosystem-support/evm) describes how to support EVM-based chains with Keplr. + +[Starknet Support](../multi-ecosystem-support/starknet) describes how to support Starknet chains with Keplr. diff --git a/docs/docs/06-evm.md b/docs/docs/multi-ecosystem-support/evm.md similarity index 99% rename from docs/docs/06-evm.md rename to docs/docs/multi-ecosystem-support/evm.md index d603020c8a..cdfc8f5ae0 100644 --- a/docs/docs/06-evm.md +++ b/docs/docs/multi-ecosystem-support/evm.md @@ -1,5 +1,5 @@ --- -title: EVM-based Chains Support +title: EVM-based Chains order: 5 --- diff --git a/docs/docs/07-starknet.md b/docs/docs/multi-ecosystem-support/starknet.md similarity index 99% rename from docs/docs/07-starknet.md rename to docs/docs/multi-ecosystem-support/starknet.md index cb042d9840..5695b94491 100644 --- a/docs/docs/07-starknet.md +++ b/docs/docs/multi-ecosystem-support/starknet.md @@ -1,5 +1,5 @@ --- -title: Starknet Support +title: Starknet order: 6 --- diff --git a/docs/docs/03-cosmjs.md b/docs/docs/use-with/cosmjs.md similarity index 90% rename from docs/docs/03-cosmjs.md rename to docs/docs/use-with/cosmjs.md index e049951c69..e421673e0f 100644 --- a/docs/docs/03-cosmjs.md +++ b/docs/docs/use-with/cosmjs.md @@ -1,11 +1,13 @@ --- -title: Use with CosmJs +title: CosmJs order: 2 --- +# Use with CosmJs + ## How to detect Keplr Keplr API may be undefined right after the webpage is shown. -Please check the [How to detect Keplr](./02-basic-api.md#how-to-detect-keplr) first before reading this section. +Please check the [How to detect Keplr](../getting-started/connect-to-keplr#how-to-detect-keplr) first before reading this section. ## Connecting with CosmJS @@ -55,7 +57,7 @@ However, if the msg to be sent is able to be serialized/deserialized using Amino If you’d like to enforce the use of Amino, you can use the following APIs: `keplr.getOfflineSignerOnlyAmino(chainId)` or `window.getOfflineSignerOnlyAmino(chainId: string)`. Because this will always return an Amino compatible signer, any CosmJS requested msg that is Amino compatible will request an Amino SignDoc to Keplr. -Also, `keplr.getOfflineSignerAuto(chainId: string): Promise` or `window.getOfflineSignerAuto(chainId: string): Promise` API is supported. Please note that the value returned is async. This API automatically returns a signer that only supports Amino if the account is a Ledger-based account, and returns a signer that is compatible for both Amino and Protobuf if the account is a mnemonic/private key-based account. Because this API is affected by the type of the connected Keplr account, if [keplr_keystorechange](./02-basic-api.md#change-key-store-event) event is used to detect account changes the signer must be changed using the API when this event has been triggered. +Also, `keplr.getOfflineSignerAuto(chainId: string): Promise` or `window.getOfflineSignerAuto(chainId: string): Promise` API is supported. Please note that the value returned is async. This API automatically returns a signer that only supports Amino if the account is a Ledger-based account, and returns a signer that is compatible for both Amino and Protobuf if the account is a mnemonic/private key-based account. Because this API is affected by the type of the connected Keplr account, if [keplr_keystorechange](../guide/custom-event#key-store-change) event is used to detect account changes the signer must be changed using the API when this event has been triggered. ## Use with Stargate @@ -65,7 +67,7 @@ Keplr's `OfflineSigner` implements the `OfflineDirectSigner` interface. Use `Sig Refer to the [keplr-example](https://github.com/chainapsis/keplr-example/blob/master/src/main.js) repository for example code on how to integrate Keplr with CosmJS. ### Interaction Options -You can use Keplr native API’s to set interaction options even when using CosmJS. Please refer to [this section](./02-basic-api.md#interaction-options). +You can use Keplr native API’s to set interaction options even when using CosmJS. Please refer to [signOptions](../guide/sign-a-message#sign-options). ### Adding a custom blockchain to Keplr -If Keplr doesn't natively support your blockchain within the extension, please refer to the [Suggest chain](./05-suggest-chain.md#suggest-chain) section. +If Keplr doesn't natively support your blockchain within the extension, please refer to the [Suggest chain](../guide/suggest-chain) section. diff --git a/docs/docs/04-secretjs.md b/docs/docs/use-with/secretjs.md similarity index 87% rename from docs/docs/04-secretjs.md rename to docs/docs/use-with/secretjs.md index 76ff572b86..a366112a6e 100644 --- a/docs/docs/04-secretjs.md +++ b/docs/docs/use-with/secretjs.md @@ -1,16 +1,17 @@ --- -title: Use with SecretJs +title: SecretJs order: 3 --- +# Use with SecretJS ## How to detect Keplr Keplr API may be undefined right after the webpage shown. -Please check the [How to detect Keplr](./02-basic-api.md#how-to-detect-keplr) first before reading this section. +Please check the [How to detect Keplr](../getting-started/connect-to-keplr.mdx#how-to-detect-keplr) first before reading this section. ## Connecting with SecretJS SecretJS link: [https://www.npmjs.com/package/secretjs](https://www.npmjs.com/package/secretjs) -The basics of using SecretJS are similar to CosmJS. Refer to the [Use with CosmJs](./cosmjs) section for more information. +The basics of using SecretJS are similar to CosmJS. Refer to the [Use with CosmJs](../use-with/cosmjs) section for more information. One difference between CosmJS and SecretJS is that we recommend using Keplr's `EnigmaUtils`. By using Keplr's `EnigmaUtils`, you can use Keplr to encrypt/decrypt, and the decrypted transaction messages are shown to the user in a human-readable format. @@ -59,4 +60,4 @@ Returns the viewing key of a SNIP-20 token registered in Keplr. If the SNIP-20 of the contract address doesn't exist, it will throw an error. ### Interaction Options -You can use Keplr native API’s to set interaction options even when using SecretJS. Please refer to [this section](./02-basic-api.md#interaction-options). +You can use Keplr native API’s to set interaction options even when using SecretJS. Please refer to [this section](../guide/sign-a-message#sign-options). diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 918b108b0a..aca6098e7a 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -23,6 +23,8 @@ const config: Config = { locales: ["en"], }, + staticDirectories: ["public", "static"], + presets: [ [ "classic", diff --git a/docs/sidebars.ts b/docs/sidebars.ts index 574ed394cd..371d5a1300 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -13,21 +13,47 @@ import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"; Create as many sidebars as you want. */ const sidebars: SidebarsConfig = { - // By default, Docusaurus generates a sidebar from the docs folder structure - tutorialSidebar: [{ type: "autogenerated", dirName: "." }], - - // But you can create a sidebar manually - /* tutorialSidebar: [ - 'intro', - 'hello', + "intro/index", + { + type: "category", + label: "Getting Started", + collapsed: false, + items: [ + "getting-started/connect-to-keplr", + "getting-started/typescript-support", + ], + }, + { + type: "category", + label: "Guide", + collapsed: false, + items: [ + "guide/enable-connection", + "guide/get-key", + "guide/sign-a-message", + "guide/broadcast-tx", + "guide/suggest-chain", + "guide/sign-arbitrary", + "guide/custom-event", + ], + }, + { + type: "category", + label: "Multi-Ecosystem Support", + collapsed: true, + items: [ + "multi-ecosystem-support/evm", + "multi-ecosystem-support/starknet", + ], + }, { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], + type: "category", + label: "Use with", + collapsed: true, + items: ["use-with/cosmjs", "use-with/secretjs"], }, ], - */ }; export default sidebars; diff --git a/docs/static/img/guide/enable-chain-example.png b/docs/static/img/guide/enable-chain-example.png new file mode 100644 index 0000000000..0b1cb3e21c Binary files /dev/null and b/docs/static/img/guide/enable-chain-example.png differ diff --git a/docs/static/img/guide/sign-arbitrary-example.png b/docs/static/img/guide/sign-arbitrary-example.png new file mode 100644 index 0000000000..853b725ec6 Binary files /dev/null and b/docs/static/img/guide/sign-arbitrary-example.png differ diff --git a/docs/static/img/guide/sign-message-evm-example.png b/docs/static/img/guide/sign-message-evm-example.png new file mode 100644 index 0000000000..3868e3852e Binary files /dev/null and b/docs/static/img/guide/sign-message-evm-example.png differ diff --git a/docs/static/img/guide/sign-message-example.png b/docs/static/img/guide/sign-message-example.png new file mode 100644 index 0000000000..f6351deace Binary files /dev/null and b/docs/static/img/guide/sign-message-example.png differ