Web3 provider

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 web3 = new Web3(await sdk.ethereum);

/* 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();

Here are reference implementations of this code

📘

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

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

StatusDescription
USER_REQUEST_DENIEDThe 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_REQUESTInvalid data passed to sign operations.
Please get in touch with us if you are unable to fix this.
APP_ID_REQUIREDNo app id was provided when initializing the SDK.
You can find the app id in MetaKeep Developer Console.
APP_NOT_FOUNDProvided app id is invalid.
You can find the correct app id in MetaKeep Developer Console.
SOMETHING_WENT_WRONGAn 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.