Hi
im trying to integrate web3js with Trezor, the idea is to sign the transactions using the hardware wallet and then send a raw transaction using web3s
this is what i have tried, i have used ethereumjs-tx for creating raw transactions
im getting that i have no balance to make the transaction, probably because web3js isnt taking one of the 10 truffle accounts and is using the trezzor public address that isnt in my local network..
is there a way to send a signed transactions (with trezor) using web3js into a local blockchain server?
kind regards
trezorLogin = async()=> {
let trezor= await this.getTrezor();
// site icon, optional. at least 48x48px
var hosticon = 'https://doc.satoshilabs.com/trezor-apps/_images/copay_logo.png';
// server-side generated and randomized challenges
var challenge_hidden = '';
var challenge_visual = '';
//use anonimous functions on callback otherwise returns cross origin errors
trezor.requestLogin(hosticon, challenge_hidden, challenge_visual, function (result){
if (result.success) {
console.log('Public key:', result.public_key); // pubkey in hex
console.log('Signature:', result.signature); // signature in hex
console.log('Version 2:', result.version === 2); // version field
console.log(result);
}else {
console.error('Error:', result.error);
}
});}
trezorSignTx= async(transaction)=> {
let trezor= await this.getTrezor();
// spend one change output
var address_n = "m/44'/60'/0'/0/0"
// var address_n = [44 | 0x80000000,
// 60 | 0x80000000,
// 0 | 0x80000000 ,
// 0 ]; // same, in raw form
var nonce = transaction.nonce.substring(2); // note - it is hex, not number!!!
var gas_price = transaction.gasPrice.substring(2);
var gas_limit = transaction.gasLimit.substring(2);
var to = transaction.to.substring(2);
// var value = '01'; // in hexadecimal, in wei - this is 1 wei
var value = transaction.value.substring(2); // in hexadecimal, in wei - this is about 18 ETC
var data = transaction.data.substring(2); // some contract data
// var data = null // for no data
var chain_id = 5777; // 1 for ETH, 61 for ETC
return new Promise (function (resolve,reject) {
trezor.ethereumSignTx(
address_n,
nonce,
gas_price,
gas_limit,
to,
value,
data,
chain_id,
function (response) {
if (response.success) {
console.log('Signature V (recovery parameter):', response.v); // number
console.log('Signature R component:', response.r); // bytes
console.log('Signature S component:', response.s); // bytes
resolve(response);
} else {
console.error('Error:', response.error); // error message
resolve(null);
}
});
})
}
getTrezorAddress = async() => {
let trezor= await this.getTrezor();
// spend one change output
var address_n = "m/44'/60'/0'/0/0";
trezor.ethereumGetAddress(address_n, function (result) {
if (result.success) { // success
console.log('Address: ', result.address);
} else {
console.error('Error:', result.error); // error message
}
});
}
getTrezor = async() => {
let trezorC;
await getTrezorConnect
.then(trezorConnect => {
trezorC= trezorConnect;
})
.catch((error) => {
console.log(error)
})
return trezorC;
}
sendTransaction= async(address, amount, id)=>{
let tokenInstance = this.props.smartContractInstance;
var getData = tokenInstance.mint.getData(address, amount);
var tx = {
nonce: '0x00',
gasPrice: '0x09184e72a000',
gasLimit: '0x2710',
to: CONTRACT_ADDRESS,
value: '0x00',
from:CONTRACT_OWNER_ADDRESS,
data: getData
};
let response = await this.trezorSignTx(tx);
let web3;
let _this = this;
if (response!=null){
getWeb3
.then(results => {
web3= results.web3;
let v = response.v.toString();
if (v.length % 2 != 0){
v="0"+v;
}
tx.r=Buffer.from(response.r,'hex');
tx.v=Buffer.from(v,'hex');
tx.s=Buffer.from(response.s,'hex');
let ethtx = new ethereumjs(tx);
console.dir(ethtx.getSenderAddress().toString('hex'), );
const serializedTx = ethtx.serialize();
const rawTx = '0x' + serializedTx.toString('hex');
console.log(rawTx);
//finally pass this data parameter to send Transaction
web3.eth.sendRawTransaction(rawTx, function (error, result) {
if(!error){
_this.props.addTokens(id)
.then(()=>{
_this.setState({modalOpen: true});
_this.props.getAllTransactions();
}
);
}else{
alert(error)
}
});
})
.catch((error) => {
console.log(error)
})
}else{
alert("There was an error signing with trezor hardware wallet")
}
}
@marcosmartinez7 By 'local blockchain server' do you mean the ganache test client truffle uses by default?
One way to seed your trezor accounts with a balance would be send them test ether from one of the default accounts that ganache launches with. You can see an example of this in these tests at truffle-contract. That example targets Web3 1.0's light wallet but the idea is the same.
Hi @cgewecke thanks for the answer
Yes, i mean starting ganache or using truffle develop
using that clients i get 10 accounts generated by truffle/ganache, each of them with 100 ethers
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
im developing an app that transfer tokens between them, but now i want to sign the transactions with trezor
the thing is that trezor has it own keys, so .. is there a way that i can integrate the address of my hardware wallet to my develop truffle/ganache network?
because right now im sending from account (0) 0x627306090abab3a6e1400e9345bc60c78a8bef57 to account (1) 0xf17f52151ebef6c7334fad080c5704d77216b732 but i want to sign the transaction with trezor.. the thing is that trezor doesnt have the 0x627306090abab3a6e1400e9345bc60c78a8bef57 address
is there any way to add a trezor account to truffle or is there another way to acomplish what i want? (send a transaction between two truffle accounts with web3js and sign it with trezor)
kind regards
Marcos
@marcosmartinez7 Ah I see. One issue is that the Truffle test accounts are unlocked by default. Is it possible to use accounts generated by the Trezor? If you send ether from the truffle account to the trezor account address over ganache (without any special signing), it will be funded for the test session and should be able to execute transactions.
await web3.eth.sendTransaction({
from: <truffleAccount>
to: <trezorAccount>
value: web3.toWei("1", 'ether')
}
const balance = await web3.eth.getBalance(<trezorAccount>) // Should have 1 ether in it.
Does this not work for your use case?
hmm but the
i didnt find anything in the truffle docs about integrating new accounts.. is there a way to include hardware wallets into truffle development network?
thanks!
@marcosmartinez7 could you please share the method getTrezorConnect
Yes
let getTrezorConnect = new Promise(function(resolve, reject) {
// Wait for loading completion
window.addEventListener('load', function() {
var trezorConnect = window.TrezorConnect
return resolve(trezorConnect)
})});
export default getTrezorConnect
it just gets the Trezor component from window object. Trezor is included on the index.html as script:
<script src="https://connect.trezor.io/4/connect.js"></script>
@marcosmartinez7 Out of curiosity, did you get this to work?
No,
we didnt found out a way to integrate a hardware wallet into truffle, to use the address in any transaction
we also tried deploying the contract into Ropsten instead of Truffle, on that network the transaction is sent and we receive a transaction hash, but that transaction hash is not found by
https://ropsten.etherscan.io/ ..
it would be nice if someone could confirm that is not possible to integrate hardware wallets into truffle (or maybe just discard trezzor) just to start making test in another environment
right now we dont know if:
Ok thanks so much for the info @marcosmartinez7. Will look into this further....
I have submit an issue in web3js and Trezor connect github too. We will continue researching, let me know if you find something
Thanks
@marcosmartinez7 , Actually I am trying to interact from the trezor wallet using node js and I dont have window object. So is there a way so that I can have the api like things so that I can send pin as request parameter and can connect to trezor.
As I have digout the connect.js Its completely using window object and playing with trezor. But I dont have the window object. I just need to make connection to trezor via node js and get xpub and sign the p2sh transaction.
I have searched various things but didnt find a way so that I can have the trezor connection object.
I have tried to use trezor.js as well but its not working as well. So could you please share any idea or things so that I can have xpub and sign the transaction?
Thanks
If you want to use Trezor connect javascript API you can just install the npm package:
https://www.npmjs.com/package/trezor-connect
and then just import TrezorConnect from "trezor-connect"
Then about getting the xpub and sign the transactions you can take the code of this issue as a reference, but i dont know if it is 100% correct.
Yeah I have imported but when I run the node then It looks for the document. Since there is no document in our node api.
With "document" do you refer to the TrezorConnect object?
I have managed to make this works but only on Ropsten. The details are here:
Using only truffle development network i couldnt add the Trezor address to the network
Wow @marcosmartinez7 !! Great work.
To be clear: if you change the provider address here to target ganache-cli on localhost it fails?
new Web3.providers.HttpProvider("https://ropsten.infura.io/your_infura_api_key")
Do you get a low balance error?
@cgewecke Thanks!
I cant test it right now, but tomorrow i will do it.
Let me explain what you have done to try Truffle, just to make sure that my process was ok for you.
-truffle develop
-compile
-migrate
At that point I have the deployed contract and its address.
Then I need my Trezor address to integrate the network, for it to execute the following:
./node_modules/.bin/testrpc -m "the 24 words mnemonic of my trezor test device"
When testrpc started It showed 10 accounts, but none of them match the Trezor address that I get in Ropsten
Anyway I tried to send a transaction with the address 0 of testrpc, also with the Trezor address that I had stored from Ropssten
In both cases I got that I did not have enough balance
Tomorrow I try again and I give you more details about the message, right now i cant remember the exact text.
Anyway, is it correct to run testrpc and wait for it to connect to the truffle development network?
There is no -m "mnemonic" option for truffle to avoid using testrpc? (Take in care that Trezor uses 24 word mnemonics)
Thanks!
truffle develop is not very configurable unfortunately.
You might try downloading/running the development server separately:
$ npm install -g ganche-cli
$ ganache-cli <options> # run
It has a mnemonic option although I would verify that the accounts you know about are generated in the initial output. I'm not sure it can use a 24 word mnemonic yet.
You can connect to it by defining a network in your truffle.js:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // Match any network id
}
}
};
And running a develop-like console like this:
truffle console --network development
Good luck!
When testing using:
1) Truffle develop, compile, migrate:
Error: sender doesn't have enough funds to send tx. The upfront cost is: 9000000000000000 and the sender's account only has: 0
at Object.InvalidResponse (errors.js:38)
at requestmanager.js:86
at XMLHttpRequest.request.onreadystatechange (httpprovider.js:128)
2) ganache cli with the mnemonic:
Error: sender doesn't have enough funds to send tx. The upfront cost is: 9000000000000000 and the sender's account only has: 0
at Object.InvalidResponse (errors.js:38)
at requestmanager.js:86
at XMLHttpRequest.request.onreadystatechange (httpprovider.js:128)
Same error, this is using the address that Trezor tells me that the device has, but that address isnt part of one of the 10 accounts of ganache cli or truffle.. i think thats the problem here.. even running ganache cli with the mnemonic of Trezor the address isnt part of the network
What happens if you launch ganache cli and send funds from one of its accounts to a trezor account before trying your transaction? Below is an example of sending ether between ganache accounts - you would just try substituting one of your trezor account number for the to field in one of the transactions:
$ truffle console --network development
truffle(development)> web3.eth.accounts
[ '0x4b3f766907f441e86949d5be1c472cf90595daab',
'0xa6ceaacc3f9cec56097c7a59e59f46eee6e5d233',
'0x2845d4955399bcaf5423c89b9928584a8a71f526',
'0xb17174cf5fdb7fc5479f9cc3f38c88b85e473ddb',
'0x16cc3257ada37cbd8ef7f0d0dac01f02273df97b',
'0xafbf7db30dd85bb03079b4f4ab63f6dba100fd28',
'0x14ff51430fa619354af8386d69e7de593a5b7e24',
'0xf4f201421d389590e73cada81cf6bb0b0c24bb95',
'0x6c39f51d02922a15106e4702b7e59dab419277c6',
'0xee59742840363edfa942a53a76576e58712b1ca9' ]
truffle(development)> web3.eth.sendTransaction({from: '0xa6ceaacc3f9cec56097c7a59e59f46eee6e5d233', to: '0x4b3f766907f441e86949d5be1c472cf90595daab', value: 500000000});
'0x1d994eebe99c8183d1d440b9ff8193901d3256062ec146d88b9472f7d148f42e'
truffle(development)> web3.eth.getBalance('0xa6ceaacc3f9cec56097c7a59e59f46eee6e5d233');
BigNumber { s: 1, e: 19, c: [ 999999, 99999499979000 ] }
truffle(development)> web3.eth.sendTransaction({from: '0xa6ceaacc3f9cec56097c7a59e59f46eee6e5d233', to: '0x4b3f766907f441e86949d5be1c472cf90595daab', value: 50000000000});
'0xd93d86fd0f20e1fd8d0b0284f1a2f833b63fb4c2412a325a0e52361bc9b4ded4'
truffle(development)> web3.eth.getBalance('0xa6ceaacc3f9cec56097c7a59e59f46eee6e5d233');
BigNumber { s: 1, e: 19, c: [ 999999, 99949499958000 ] }
truffle(development)>
Using the solution of https://stackoverflow.com/questions/50596256/send-signed-transactions-to-ropsten-or-truffle-develop-network-with-trezor-hard and send ether as @cgewecke saids works!!
one detail, the upfront cost was 9000000000000000 wei (0.009 ether), so i needed to send more than @cgewecke example
@marcosmartinez7 Yes!!!!! This is fantastic!!
Thank you so much for figuring out how to do this.
Thank you for the answers!
Most helpful comment
Using the solution of https://stackoverflow.com/questions/50596256/send-signed-transactions-to-ropsten-or-truffle-develop-network-with-trezor-hard and send ether as @cgewecke saids works!!
one detail, the upfront cost was 9000000000000000 wei (0.009 ether), so i needed to send more than @cgewecke example