MetaKeep JS is a drop-in Web3 JS provider that works alongside your existing code, with just one line of change. You don't have to change anything else to get users to sign transactions.
You can inject MetaKeep Web3 provider like this-
/* Init SDK */
const sdk = new MetaKeep({
/* App id to configure UI */
appId: "9cc98bca-da35-4da8-8f10-655b3e51cb9e",
/* Default chain to use */
chainId: 80002,
/* RPC node urls map */
rpcNodeUrls: {
// Update with your own node URL
80002: "https://rpc.ankr.com/polygon_amoy"
};
});
/* Use MetaKeep web3 provider */
const web3Provider = await sdk.ethereum;
await web3Provider.enable();
/* Initialize web3 provider */
const web3 = new Web3(web3Provider);
/* Rest of the code requires no changes */
/* Call sign. It returns a promise which returns when the operation succeeds.
Otherwise throws an error.
*/
async function web3Sign() {
try {
// Get accounts
const web3Accounts = await web3.eth.getAccounts();
// Sign message
const signResponse = await web3.eth.sign("message", web3Accounts[0]);
console.log("sign successful");
console.log(signResponse);
} catch (err) {
console.log("Error when trying to sign");
console.log(err.message || err);
}
}
web3Sign();
/* Init SDK */
const sdk = new MetaKeep({
/* App id to configure UI */
appId: "9cc98bca-da35-4da8-8f10-655b3e51cb9e",
/* Default chain to use */
chainId: 80002,
/* RPC node urls map */
rpcNodeUrls: {
// Update with your node API key
80002: "https://rpc.ankr.com/polygon_amoy"
}
});
/* Use MetaKeep web3 provider */
web3Provider = await sdk.ethereum;
await web3Provider.enable();
/* Initialize ethers provider */
const ethersProvider = new ethers.providers.Web3Provider(web3Provider);
/* Rest of the code requires no changes */
/* Get signature using web3 provider*/
async function ethersSign() {
try {
// Signer
const signer = ethersProvider.getSigner()
const signerAddress = await signer.getAddress()
console.log(signerAddress)
// Sign message
const signMessageResponse = await signer.signMessage("Hello World");
console.log("sign message successful");
console.log(signMessageResponse);
// Send txn. Will fail if there are no tokens to pay for gas fee.
const sendTxnResponse = await signer.sendTransaction({
from: signerAddress,
to: signerAddress,
value: "0x12"
});
console.log("send txn successful");
console.log(sendTxnResponse);
} catch (err) {
console.log("Error when trying to perform provider operations");
console.log(err.message || err);
}
}
ethersSign();
Please check the reference implementation mentioned below.
Here are reference implementations of this code
- web3.js: https://jsfiddle.net/passbird/cas5hvrL/
- ethers.js: https://jsfiddle.net/passbird/q1xmsdb5/
- WAGMI: https://codesandbox.io/p/devbox/black-brook-9jppdn?file=%2Fsrc%2FApp.tsx (WAGMI connector code was contributed by the ChainStarters team)
Latest supported versions
We fully support and run QA on the following versions of libraries:
- web3.js: 1.7.5
- ethers.js: 5.7.0
- WAGMI: 2.7.0
Let us know if you would like us to support a more recent version :)
Common issues
Web3.js and ethers.js behavior can change over time. MetaKeep web3 provider takes care of most of the edge cases and intricacies of web3.js and ethers.js. However, we recommend following the best practices below to have consistent and predictable behavior for you and your users.
Provide gas
You should always provide gas
when calling a contract method or sending a transaction to have consistent behavior. If you don't provide gas, web3.js, and ethers.js might estimate the gas for you. However, this doesn't always work as expected.
If the gas is not provided, the MetaKeep SDK will estimate the gas by calling the eth_estimateGas
RPC method and adding 12% buffer. However, this estimation is not always accurate. We recommend that you always provide the gas when sending a transaction.
await web3.eth.sendTransaction({
from: fromAddress,
to: toAddress,
value: "0x12",
// Make sure this is set.
// Web3.js and ethers.js provide utilities to get this.
gas: <gas>
}, web3Accounts[0]);
Provide gasPrice
Similar to gas, it's a best practice to provide gasPrice
when calling a contract method or sending a transaction to have consistent behavior.
web3.eth.sendTransaction({
from: fromAddress,
to: toAddress,
value: "0x12",
gas: 1000000,
// Make sure this is set.
// Web3.js and ethers.js provide utilities to get this.
gasPrice: <gasPrice>
}, web3Accounts[0]);
web3.eth.sendTransaction({
from: fromAddress,
to: toAddress,
value: "0x12",
gas: 1000000,
// Provide priority fee if using dynamic fee transactions.
// Web3.js and ethers.js provide utilities to get this.
maxPriorityFeePerGas: <maxPriorityFeePerGas>,
maxFeePerGas: <maxFeePerGas>
}, web3Accounts[0]);
Error status
Web3 operations return a promise which throws an error when the operation is unsuccessful. The error object looks like so-
{
status: "USER_REQUEST_DENIED"
}
Here's a table of all possible error status returned by the SDK
Status | Description |
---|---|
USER_REQUEST_DENIED | The user has denied the web3 operation(sign message/transaction/typedData). In this case, you should ask the user if they want to try again. |
INVALID_REQUEST | Invalid data passed to sign operations. Please get in touch with us if you are unable to fix this. |
APP_ID_REQUIRED | No app id was provided when initializing the SDK. You can find the app id in MetaKeep Developer Console. |
APP_NOT_FOUND | Provided app id is invalid. You can find the correct app id in MetaKeep Developer Console. |
SOMETHING_WENT_WRONG | An unknown error happened. Please get in touch with us if you continue seeing this error. |
Apart from the above errors, the web3 provider can also return the errors mentioned in the different signing operations in the documentation:
© Copyright 2024, Passbird Research Inc.