You have two options for generating, signing, and brodcasting messages.
Use https://bitbadges.io/dev/broadcast - This is a visual UI that you can simply copy and paste your transaction Msg contents into. Generating all additional transaction details, gas, fees, and signing is all outsourced to the user interface. This is the recommended option if you do not require programmatically submitting TXs.
Generate, sign, and broadcast directly to a running blockchain node. This is more technical and has more steps but can be done programmatically.
If you plan to use Option 1, you may proceed to the next page because generating the transaction context is already handled via the user interface.
If you plan to use option 2, see below.
Generating Transaction Context
The first step is to fetch and identify the transaction context and the account details for who is going to sign. You will need the following information below.
import { createTxMsgSend, SupportedChain } from'bitbadgesjs-sdk'constchain= { chainId:2, cosmosChainId:'bitbadges_1-2', chain:SupportedChain.ETH//signing chain}constsender= { accountAddress:'cosmos....',//Must be the cosmos address sequence:1, accountNumber:9, pubkey:'....',//base64 public key}constfee= { amount:'20', denom:'badge', gas:'200000',}constmemo=''
Generating the fee can be tricky. It should be reasonable for the current gas prices but also not too expensive.
To get the gas, we recommend simulating the transaction right before broadcasting to see how much gas it uses on a dry run. We will walk you through how to do this in the broadcast tutorial. You can also fetch the gas prices via the BitBadgesApi.getStatus() route.
The chain details define which chain you are broadcasting to (testnet vs mainnet). You will also specify the native chain of the user signing the transaction. This lets us know how to parse the transaction and what the expected signing format is.
Sender Details
To fetch a user's account details, the easiest way is to use the routes from the BitBadges API in Users. You can also query a node directly.
This will return the user's cosmos address, account ID, sequence (nonce), and public key. If the user has previously interacted with the blockchain, all this information will already be populated.
IMPORTANT: For a user who has not yet interacted with the blockchain, the fetched public key will be null and accountNumber will be -1.
To get an account number, they need to receive $BADGE somehow (this is also a pre-requisite to pay for any gas fees).
To get the public key for an unregistered user, see below. Public keys are expected to be in base64 format.
Get Public Key - Metamask / ETH
For MetaMask and Ethereeum, you will need to get the user to sign a message and recover the public key from the signature and convert to base64. If users need to authenticate into your app, you can get the public key from that message signature as well for more optimal UX.
constgetPublicKey=async (cosmosAddress:string) => {constmessage='Please sign this message, so we can generate your public key';let sig =awaitwindow.ethereum.request({ method:'personal_sign', params: [message,cosmosToEth(cosmosAddress)], })constmsgHash=ethers.utils.hashMessage(message);constmsgHashBytes=ethers.utils.arrayify(msgHash);constpubKey=ethers.utils.recoverPublicKey(msgHashBytes, sig);constpubKeyHex=pubKey.substring(2);constcompressedPublicKey=Secp256k1.compressPubkey(newUint8Array(Buffer.from(pubKeyHex,'hex')));constbase64PubKey=Buffer.from(compressedPublicKey).toString('base64')return base64PubKey;}
Get Public Key - Keplr / Cosmos
For Keplr / Cosmos, you can simply use getKey() then convert to base64,
import { CHAIN_DETAILS } from'bitbadgesjs-sdk';constgetPublicKey=async (_cosmosAddress:string) => {constchain=CHAIN_DETAILS; //can also use BETANET_CHAIN_DETAILS or MAINNET_CHAIN_DETAILSconstaccount=awaitwindow?.keplr?.getKey(chain.cosmosChainId)if (!account) return'';constpk=Buffer.from(account.pubKey).toString('base64')return pk;}
Get Public Key - Solana
constbs58=require('bs58');//Pre: get provider from Phantom walletconstresp=awaitprovider.request({ method:"connect" });constsolanaPublicKeyBase58=resp.publicKey.toBase58(); //base58 public keyconstsolanaPublicKeyBuffer=bs58.decode(solanaPublicKeyBase58);constpublicKeyToSet=Buffer.from(solanaPublicKeyBuffer).toString('base64')
Get Public Key - Bitcoin
constgetProvider= () => {if ('phantom'in window) {constphantomWindow= window asany;constprovider=phantomWindow.phantom?.bitcoin;if (provider?.isPhantom) {return provider; }window.open('https://phantom.app/','_blank'); //Make user install it }};constprovider=getProvider();constaccounts=awaitprovider.requestAccounts();if (accounts.length===0) {thrownewError('No account found');}constaddress= accounts[0].address;if (accounts[0].addressType !=='p2wpkh') {thrownewError('Invalid account type'); //Others are not supported for BitBadges}constpublicKey= accounts[0].publicKey; //Hex public keyconstbase64PublicKey=Buffer.from(publicKey,'hex').toString('base64');