While Comet exposes the standard (thorified) web3 API, there are few things to keep in mind. Below are requirements for Comet support as well as some best practices.
Comet injects thor
object into the javascript context.
Look for this before using your fallback strategy
import { thorify } from 'thorify'
import { extend } from 'thorify/dist/extend'
const Web3 = require("web3"); // Recommend using require() instead of import here
window.addEventListener('load', function() {
// Checking if Thor has been injected by the browser
if (typeof thor !== 'undefined') {
// Use thor provider
web3js = new Web3(thor);
// Extend web3 to connect to VeChain Blockchain
extend(web3js)
} else {
// Fall back to default thorified construction
web3js = thorify(new Web3(), "http://localhost:8669");
}
// Now you can start your dApp
startApp()
})
See more at the thorify docs on "usage"
Comet does not expose user account addresses by default; instead a dApp must first request access which the user must approve. We recommend only requesting access after the user has interacted with your dApp for a better user experience (see best practices below).
async function enableThor () {
try {
const [cometAccount] = await thor.enable();
return cometAccount;
} catch (e) {
console.log(`User rejected request ${e}`);
// handle error
}
}
As Comet handles all authorization, your dApp likely won't need to call sendRawTransaction
anymore.
Any time you make a call that requires a private key to sign something (sendTransaction
, personal.sign
), Comet will automatically prompt the user for permission, and then forward the signed request on to the blockchain (or return it to you, if it was a call to personal.sign
).
web3.eth.sendTransaction
will return a PromiseEvent which will resolve
when the transaction is confirmed. It will also emit events like transactionHash
and receipt
when they happen. Read more at the thorify API docs
The user does not have the full blockchain on their machine, so data lookups can be a little slow. For this reason, we are unable to support most synchronous methods.
Using synchronous calls is both a technical limitation and a user experience issue. They block the user's interface. So using them is a bad practice, anyway. Think of this API restriction as a gift to your users.
Comet will only provide account information after user authorization to protect user privacy. When a dApp requests access, a confirmation screen will appear to the user similar to a transaction or sign flow. In order to avoid popups randomly appearing, your dApp should only call thor.enable
upon user interaction with your dApp.
When a user interacts with a dApp via Comet, they may be on the mainnet or testnet. As a best practice, your dApp should inspect the current network via the getChainTag
call. Then, the dApp can use the correct deployed contract addresses for the network, or show which network is expected in a message.
For example:
web3.eth.getChainTag().then(chainTagHex => {
const chainTag = parseInt(chainTagHex, 16)
switch (chainTag) {
case 74:
console.log('This is mainnet')
break
case 39:
console.log('This is testnet')
break
case 199:
console.log('This is localhost.')
break
default:
console.log('This is an unknown network.')
}
})
Many dApps have a built-in identity management solution as a fallback. When a Thor Browser environment has been detected, the user interface should reflect that the accounts are being managed externally.
When a user selects an account in Comet, that account becomes available via the web3.eth.getAccounts
async call. It is the only account returned by that call.
web3.eth.getAccounts(([cometAccount]) => {
console.log(`The user address is ${cometAccount}`)
})
Since these variables reflect user intention, but do not (currently) have events representing their values changing, we recommend using an interval to check for account changes.
For example, if your application only cares about the web3.eth.getAccounts[0]
value, you might add some code like this somewhere in your application:
const [cometAccount] = await web3.eth.getAccounts();
const accountInterval = setInterval(function() {
const [currentAccount] = await web3.eth.getAccounts();
if (currentAccount !== cometAccount) {
cometAccount = currentAccount
updateInterface();
}
}, 300);