# Cosmos (updating...)

Note

  1. Only the Sei mainnet is currently supported
  2. All methods only support Sei connections

To use the Bitget Wallet in your DApp, your users must first install the Bitget Wallet extension in their browsers. The Bitget Wallet insert a Bitkeep.keplr object into the window (opens new window).

# Supported versions:

Platform Version Description
Chrome Extension >=v1.4.8
App(IOS) >=v7.3.7
App(Android) >=v7.3.7

# Supported chains

Chain Chain ID Description
Sei pacific-1

cosmosjs sdk (opens new window)

# Basic methods

# Installation status

const isBitKeepInstalled = window.bitkeep && window.bitkeep.keplr;
1

# Provider detection

function getProvider() {
  const provider = window.bitkeep && window.bitkeep.keplr;
  if (!provider) {
    window.open('https://web3.bitget.com/en/wallet-download?type=2');
    throw 'Please go to  https://web3.bitget.com/en/wallet-download?type=2 to download!!';
  }
  return provider;
}
1
2
3
4
5
6
7
8
9

# Connect to the Bitget Wallet

enable(chainId: string): Promise<void>
// Only support Sei main network
1
2

# Get address/public key

getKey(chainId: string): Promise<{
    // Name of the selected Wallet.
    name: string;
    algo: string;
    pubKey: Uint8Array;
    address: Uint8Array;
    bech32Address: string;
}>
await provider.getKey('pacific-1')
1
2
3
4
5
6
7
8
9
10
11

# Sign Amino

signAmino(chainId: string, signer: string, signDoc: StdSignDoc): Promise<AminoSignResponse>
1
2

Similar to CosmJS OfflineSigner's signAmino, Bitkeep's signAmino requires the chain ID as a required parameter. It signs the Amino-encoded StdSignDoc.

# Sign Direct/Protobuf

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<DirectSignResponse>
1
2
3
4
5
6
7
8
9
10
11
12

Similar to CosmJS OfflineDirectSigner's signDirect, Bitget Wallet's signDirect requires the chain ID as a required parameter. It signs the Proto-encoded StdSignDoc.

# sendTx

Request transaction broadcast

sendTx(
    chainId: string,
    tx: Uint8Array,
    mode: BroadcastMode
): Promise<Uint8Array>;
1
2
3
4
5

This function requests Bitget Wallet to delegate the broadcasting of the transaction to Bitget Wallet's LCD endpoint instead of broadcasting it from the webpage. If the broadcast is successful, it returns the transaction hash; otherwise, it throws an error.

# signArbitrary

signArbitrary(
    chainId: string,
    signer: string,
    data: string | Uint8Array
): Promise<StdSignature>;
verifyArbitrary(
    chainId: string,
    signer: string,
    data: string | Uint8Array,
    signature: StdSignature
): Promise<boolean>;
1
2
3
4
5
6
7
8
9
10
11
12

This is an experimental implementation of ADR-36 (opens new window). The risk of using this feature is borne by you.

Its main purpose is to prove ownership of off-chain accounts by requesting ADR-36 signatures using the signArbitrary API.

If the request uses the ADR-36 0 API signature document required by Bitget Wallet instead of using the signArbitrary API, it will act as signArbitrary.

  • It only supports signing documents in Amino format. (In the case of protobuf, ADR-36 requires no complete specification to be implemented.)
  • The sign document message should be a single message type "sign/MsgSignData."
  • The sign document "sign/MsgSignData" message should have "signer" and "data" as its values. "Data" should be encoded in base64.
  • The sign document chain_id should be an empty string ("").
  • The sign document memo should be an empty string ("").
  • The sign document account_number should be "0."
  • The sign document sequence should be "0."
  • The sign document fee should be {gas: "0", amount: []}.

Using verifyArbitrary, you can verify the results of signArbitrary API or signAmino API requests for ADR-36 specification standard requests.

verifyArbitrary is only intended for simple usage. It returns the verification result of the signature document for the currently selected account. If the account is not the currently selected account, an error will be thrown.

It is recommended to use the verifyADR36Amino function in your implementation instead of using the verifyArbitrary API.

# Change Key Store Event

keplr_keystorechange
1

When a user switches their key store/account on the webpage after receiving information about the key store/account, the key known by the webpage may not match the selected key in Bitget Wallet, which can cause interaction issues.

To prevent this situation, Bitget Wallet emits the keplr_keystorechange event to the webpage window when the key store/account changes. You can request a new key/account based on this event listener.

window.addEventListener("keplr_keystorechange", () => {
    console.log("Key store in BitKeep is changed. You may need to refetch the account info.")
})
1
2
3

# Using with CosmosJS

# Connecting with Cosmosjs

@cosmjs/launchpad (opens new window) @cosmjs/stargate (opens new window)

You can connect Bitget Wallet to CosmJS using OfflineSigner.

// Enabling before using the bitkeep.keplr is recommended.
// This method will ask the user whether or not to allow access if they haven't visited this website.
// Also, it will request user to unlock the wallet if the wallet is locked.
await window.bitkeep.keplr.enable(chainId);
const offlineSigner = window.bitkeep.getOfflineSigner(chainId);
// You can get the address/public keys by `getAccounts` method.
// It can return the array of address/public key.
// But, currently, BitKeep 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 api with the offline signer that is injected by BitKeep extension.
const cosmJS = new SigningCosmosClient(
    "https://sei-rpc.polkachu.com",
    accounts[0].address,
    offlineSigner,
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • To obtain OfflineSigner, you can use Bitkeep.keplr.getOfflineSigner(chainId) or window.Bitkeep.getOfflineSigner(chainId). (window.Bitkeep.getOfflineSigner is an alias for running Bitkeep.keplr.getOfflineSigner and returning the value.)
  • If the Bitkeep extension is locked, the window.Bitkeep.keplr.enable(chainId) method will request the user to unlock their plugin. If the user hasn't been granted permission to connect their plugin to the website, it will first ask for permission to connect to the website.
  • "If the user cancels unlocking or denies connection permission, an error will be thrown. "
  • If the extension is unlocked and the website has connection permission, no action will be taken.

# Offline Signers signature types

  • In CosmJS, there are two types of signers: OfflineSigner and OfflineDirectSigner. OfflineSigner is used to sign SignDoc serialized with Amino in Cosmos SDK Launchpad (Cosmos SDK v0.39.x or lower). OfflineDirectSigner is used to sign SignDoc encoded with Protobuf.
  • Bitget Wallet supports both types of signers. Bitkeep.keplr.getOfflineSigner(chainId) or window.Bitkeep.getOfflineSigner(chainId) returns a signer that satisfies both OfflineSigner and OfflineDirectSigner. Therefore, when using CosmJS with this signer, Amino is used for Launchpad chains, and Protobuf is used for Stargate chains.
  • However, if the message to be sent can be serialized/deserialized using the Amino codec, an Amino signer can be used. Additionally, due to some limitations of protobuf symbolic documents, Amino may be necessary in certain cases. For example, the Cosmos application on Ledger Nano currently does not support symbol documents in Protobuf format. Additionally, since protobuf symbolic documents are binary, msg that is not supported by Bitget Wallet itself may not be readable.
  • If you want to force the use of Amino, you can use the following APIs: Bitkeep.keplr.getOfflineSignerOnlyAmino(chainId) or window.Bitkeep.getOfflineSignerOnlyAmino(chainId: string). Because this will always return a signer compatible with Amino, any msg requested by CosmJS that is compatible with Amino will request an Amino SignDoc from Bitget Wallet.
  • In addition, the API Bitkeep.keplr.getOfflineSignerAuto(chainId: string): Promise<OfflineSigner | OfflineDirectSigner> or window.Bitkeep.getOfflineSignerAuto(chainId: string): Promise<OfflineSigner | OfflineDirectSigner> is also supported. Note that the returned value is asynchronous. If the account is a ledger-based account, this API automatically returns an Amino-only signer, and if the account is a mnemonic/private key-based account, it returns a signer compatible with both Amino and Protobuf. Since this API depends on the type of connected Bitget Wallet account, if you use the keplr_keystorechange event to detect account changes, you must change the signer using the API when triggering this event.

# Use together with Stargate

Bitget Wallet's OfflineSigner implements the OfflineDirectSigner interface. The SigningStargateClient will sign transactions in Proto sign doc format with Bitget Wallet's OfflineSigner.

import { SigningStargateClient } from "@cosmjs/stargate"
const denom = 'usei'
const toAddress = 'sei1jr0269wfm6ldfdtg6u9vl4hdmk8le0r46x6jkx'
const rpcUrl = 'https://xxx'
// Detect BitKeep Keplr
const keplr = window.bitkeep?.keplr
if (!keplr) {
    return alert("You need to install Bitget Wallet")
}
// Get the current state and amount of tokens that we want to transfer
// Create the signing client
const offlineSigner = window.bitkeep?.getOfflineSigner("atlantic-2")
const signingClient = await SigningStargateClient.connectWithSigner(
    rpcUrl,
    offlineSigner,
)
// Get the address and balance of your user
const account = (await offlineSigner.getAccounts())[0]
// Submit the transaction to send tokens to the faucet
const sendResult = await signingClient.sendTokens(
    account.address,
    toAddress,
    [
        {
            denom: denom,
            amount: '1',
        },
    ],
    {
        amount: [{ denom: denom, amount: "5000" }],
        gas: "200000",
    },
    ''
)
if (sendResult.code !== undefined && sendResult.code !== 0) {
    alert("Failed to send tx: " + sendResult.log || sendResult.rawLog);
} else {
    alert("Succeed to send tx:" + sendResult.transactionHash);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Last Updated: 8/31/2023, 7:45:11 PM