Is it possible to sign a user in web3 without MetaMask? I am trying to execute a smart contract I created and I'm using Infura to connect to the Kovan test network, but web3.eth.accounts[0] is undefined. How can I sign a user in without having to use MetaMask? Is this even possible? If not, how should I approach this problem? Please and thank you!
2 Answers
What you should do in this case is use the web3-provider-engine. An example code snippet functioning with a custom private key and Infura API URL (Or even TestRPC) would be the following:
//Provider Engine sub-modules
const ProviderEngine = require('web3-provider-engine')
const CacheSubprovider = require('web3-provider-engine/subproviders/cache.js')
const FixtureSubprovider = require('web3-provider-engine/subproviders/fixture.js')
const FilterSubprovider = require('web3-provider-engine/subproviders/filters.js')
const VmSubprovider = require('web3-provider-engine/subproviders/vm.js')
const NonceSubprovider = require('web3-provider-engine/subproviders/nonce-tracker.js')
const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js')
//EthereumJS Wallet Sub-Provider
const WalletSubprovider = require('ethereumjs-wallet/provider-engine')
const walletFactory = require('ethereumjs-wallet')
//Web3 Module
const Web3 = require('web3')
//Wallet Initialization
var privateKey = "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"
var privateKeyBuffer = new Buffer(privateKey, "hex")
var myWallet = walletFactory.fromPrivateKey(privateKeyBuffer)
//Engine initialization & sub-provider attachment
var engine = new ProviderEngine();
engine.addProvider(new FixtureSubprovider({
web3_clientVersion: 'ProviderEngine/v0.0.0/javascript',
net_listening: true,
eth_hashrate: '0x00',
eth_mining: false,
eth_syncing: true,
}))
// cache layer
engine.addProvider(new CacheSubprovider())
// filters
engine.addProvider(new FilterSubprovider())
// pending nonce
engine.addProvider(new NonceSubprovider())
// vm
engine.addProvider(new VmSubprovider())
// Here the URL can be your localhost for TestRPC or the Infura URL
engine.addProvider(new RpcSubprovider({
rpcUrl: 'https://mainnet.infura.io/YOUR_ACCESS_TOKEN',
}))
// Wallet Attachment
engine.addProvider(new WalletSubprovider(myWallet))
// network connectivity error
engine.on('error', function(err){
// report connectivity errors
console.error(err.stack)
})
// start polling for blocks
engine.start()
//Actual Initialization of the web3 module
var web3 = new Web3(engine)
You will be able to sign any transactions you want with your supplied private key by specifying your public key as the "from" value in the settings object of each perspective web3 function call.
EDIT: I personally despise the web3 library and as a result, I decided to revamp the snippet to use the ethers.js library which has a more human-readable API:
//Provider Engine sub-modules
const ethers = require('ethers');
const Wallet = ethers.Wallet;
const Contract = ethers.Contract;
const utils = ethers.utils;
const providers = ethers.providers;
//Note the "0x" appended at the start
let privateKey = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266";
let network = "http://192.168.1.1:8545";
//let network = "kovan";
//let network = "ropsten";
//let network = "rinkeby";
//let network = "homestead";
//let infuraAPIKey = "9LPi9fDukz8phfLXdy5K";
let provider = new providersJsonRpcProvider(network, 'homestead');
//let provider = new providers.InfuraProvider(network, infuraAPIKey);
let serverWallet = new Wallet(privateKey, provider);
That's basically it. You can now send transactions with it or construct Contract objects to interact with contracts with it. Refer to the ethers.js documentation for more.
-
I think something has changed. First, I had to add
myWallet
this way:engine.addProvider(new WalletSubprovider(myWallet, {}))
, probably just an API change. I can call read-only contract methods with this engine, but sending transactions results in[Error: Method not found] message: 'Method not found', code: -32601
– sudoCommented Apr 8, 2018 at 22:44 -
1@sudo I would suggest using an alternative library. I have added an alternative code snippet to the original topic using ethers.js which I find quite user intuitive. Commented Apr 11, 2018 at 16:35
-
Thanks. A couple of days ago, I ended up figuring out how to manually sign my transactions with web3 instead of using MetaMask's library, and yes, it was horribly painful. I'll try your ether.js setup next time because it looks much nicer. Anyway, this is what I got working for web3: gist.github.com/AlecZadikian9001/…– sudoCommented Apr 11, 2018 at 17:41
maybe this helps https://github.com/MetaMask/provider-engine and some info here http://truffleframework.com/tutorials/using-infura-custom-provider
-
1Whilst this may answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.– user47887Commented Nov 9, 2018 at 15:57