How to correctly set up a WebSocketProvider in ethers.js? - blockchain

I'm trying to switch my dapp from Web3Provider to WebSocketProvider,
form this:
const provider = new ethers.providers.Web3Provider(window.ethereum)
const accounts = await window.ethereum.request({ method: "eth_accounts" })
const account = accounts[0]
const signer = provider.getSigner()
to this:
const provider = new ethers.providers.WebSocketProvider("ws://localhost:8545") <-
const accounts = await window.ethereum.request({ method: "eth_accounts" })
const account = accounts[0]
const signer = provider.getSigner()
With this change I can interact with the Contract only with account that creates and deploy the smart contract, also, the transactions have no confirmation from the user. However, when I try to call some Contract function with another address I get this error:
On the fourth line, the value of the "from" key is different from the address actually selected in the metamask, in fact it is the address of the creator of the Smart Contract. There seems to be some problem with the signer or what? With Web3Provider everything works fine.
Can you help me in any way or tell me more about WebSocketProvider?
Thanks in advance

Related

Unable to call safeTransferFrom method from a JS api file

I have deployed my ERC721 contract on polygon testnet from owner(ox43b....81). I have created a small node server to interact with my contract through web3. I m using truffle config
//truffle-config.js
polygon-testnet: {
provider: new HDWalletProvider(privateKey, https://rpc-mumbai.maticvigil.com),
network_id: 80001,
gas: 6000000,
gasPrice: 10000000000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
}
//index.js file
function test(){
const owner = await myContract.methods.owner().call()
console.log('contract owner', owner) //ox43b....81
//miniting token
const mint = await myContract.methods
.safeMint(owner,1001, 'google.com')
.send({ from: owner, gas: 100000 }) // is this the write way of calling ??
//token transfer
const transfer = await myContract.methods
.safeTransferFrom(acc1, acc2, 1003)
.send({ from: acc1, gas: 1000000 }) // is this the write way of calling ??
}
bcz i m getting err in both function calling: Error: Returned error: unknown account.
NOTE: I am not calling my contract func from truffle console. I m calling through a JS api file index.js
I know there is another way by using web3.eth.accounts.signTransaction() to mint & transfer the token.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
Q.2 By using web3.eth.accounts.signTransaction() method i can able to mint the tokens successfully but i am facing issue in token transfer (using safeTransferFrom()). There are two cases:
case 1: i am transferring the token which is created/minted by contract owner(ox43b....81) to any other individual user address.
const fromAddress = 'ox43b....81' //owner of the contract
const toAddress = '0x26....7D'
const tokenId = 10001 // created by owner(ox43b....81)
const tx = {
from: ownerAddress, // ox43b....81 --> owner who created contract
to: contractAddress,// 0xfe.....24
nonce: nonce, // nonce with the no of transactions from our owner address
gas: 1000000, // fee estimate to complete the transaction
data: await myContract.methods
.safeTransferFrom(fromAddress, toAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m able to transfer the token successfully.
case 2: i am transferring the token which is created/minted by another(not contract owner) user(0x26....7D) to any other individual user address / or to owner.
const fromAddress = '0x26....7D' (not the owner of contract)
const toAnyAddress = '0x5e....5a' // any other user
const tokenId = 10002 // created by user '0x26....7D' (not the owner of contract)
const nonce = await web3.eth.getTransactionCount(fromAddress, 'latest')
const tx = {
from: fromAddress, // 0x26....7D -> is this right? or i put contract owner adr?
to: contractAddress,// 0xfe.....24
nonce: nonce,
gas: 1000000, // fee estimate to complete the transaction
data: await this.myContract.methods
.safeTransferFrom(fromAddress, toAnyAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m getting err - Fail with error 'ERC721: transfer caller is not owner nor approved'.
I need solution for my case 2. Is there something related with locked/unlocked accounts? How can i fix it?
Please help! Thanks in advance.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
The .send() method of the web3 Contract instance performs/requests the signature in the background. So it's always signed - just not with an explicit "sign" keyword in the code in this case.
Q.2 There are two cases:
This is not related to the way you sign the transaction.
The second case fails because the token holder has not approved the spender (i.e. the transaction sender) to spend their tokens.
You need to invoke the approve(<spender>, <tokenId>) function from the token holder address first, to be able to successfully use the transferFrom().
// assuming `acc1` is holder of the token ID `1003`
// approve the `owner` to spend the `acc1`'s token
await myContract.methods.approve(owner, 1003).send({from: acc1});
// transfer token `1003` held by `acc1` ... and send the transaction from the `owner` address
await myContract.methods.transferFrom(acc1, recipient, 1003).send({from: owner});

Cannot get the account id if connected to Mumbai RPC testnet

I have added MATIC Mumbai Testnet RPC and required info using this : https://docs.matic.network/docs/develop/remix to metamask. That is added the network to it.
Now I am using web3 and calling
const web3 = new Web3('https://rpc-mumbai.matic.today');
const network = await web3.eth.net.getNetworkType();
const accounts = await web3.eth.getAccounts();
console.log(accounts[0])
I am getting undefined in the console.
whereas if I go for
const web3 = new Web3('http:localhost:7545');
const network = await web3.eth.net.getNetworkType();
const accounts = await web3.eth.getAccounts();
console.log(accounts[0])
which is my local network it works and I get the account address
I feel like I am missing something, Can anyone help ?

How to get TRC20 transactions to an address

I am using tron web to query transactions of an address but it does not return transactions sent to that address where token transferred is TRC20.
This does not work.
I want to get the transactions on an address and get both TRX, trc10 and trc20 transactions.
What am I doing wrong or how to do that?
Here is my code block:
tronWeb.setDefaultBlock("latest");
var result = await tronGrid.account.getTransactions(address, {
only_confirmed: true,
only_to: true,
limit: 10
});
console.log(JSON.stringify(result));
})();
After a lot of research, I found out one can easily query contract events at intervals to get transactions on that contract address and you can then filter it for the address you are watching since you can't get a webhook or websocket with your trongrid/tronweb implementation.
Here is a sample file I used to achieve this and it works great for monitoring many address even with different contract addresses.
Note: In my own implementation, this node file is called from another file and other logistics are handled in the other file, but below you see how I queried the transfer events emitted by the specified contract
const TronWeb = require("tronweb");
const TronGrid = require("trongrid");
const tronWeb = new TronWeb({
fullHost: "https://api.trongrid.io"
});
const tronGrid = new TronGrid(tronWeb);
const argv = require("minimist")(process.argv.slice(2));
var contractAddress = argv.address;
var min_timestamp = Number(argv.last_timestamp) + 1; //this is stored for the last time i ran the query
(async function() {
tronWeb.setDefaultBlock("latest");
tronWeb.setAddress("ANY TRON ADDRESS"); // maybe being the one making the query not necessarily the addresses for which you need the transactions
var result = await tronGrid.contract.getEvents(contractAddress, {
only_confirmed: true,
event_name: "Transfer",
limit: 100,
min_timestamp: min_timestamp,
order_by: "timestamp,asc"
});
result.data = result.data.map(tx => {
tx.result.to_address = tronWeb.address.fromHex(tx.result.to); // this makes it easy for me to check the address at the other end
return tx;
});
console.log(JSON.stringify(result));
})();
You are free to customize the config data passed to the tronGrid.contract.getEvents method. Depending on how frequently transactions come on the contract you are monitoring you should DYOR to know at what interval is great for you and what limit value you should pass.
Refer to https://developers.tron.network/docs/trongridjs for details.
I found a API that can take TRC20 transactions, but I haven't found an implementation in webtron.
https://api.shasta.trongrid.io/v1/accounts/address/transactions
Related document:
https://developers.tron.network/reference#transaction-information-by-account-address

web3.eth.getAccounts() returns empty array when using Infura provider. Why?

I was trying to use Infura api to make an Ethereum web app. First I compiled a solidity contract and then deployed it using infura api on rinkeby network. Here is my deploy script which seems to be running successfully.
const HDWalletProvider = require("truffle-hdwallet-provider");
const Web3 = require('Web3');
const compileFactory = require('./build/CampaignFactory.json');
const provider = new HDWalletProvider(
"MY_SECRET_MNEMONIC",
"https://rinkeby.infura.io/v3/363ea9633bcb40bc8a857d908ee27094"
);
const web3 = new Web3(provider);
console.log("provider info: " + provider);
const deploy = async () => {
const accounts = await web3.eth.getAccounts();
console.log("account used: " + accounts[0]);
result = await new web3.eth.Contract(JSON.parse(compileFactory.interface))
.deploy({data: "0x"+compileFactory.bytecode})
.send({from: accounts[0]});
console.log("deployed to address: " + result.options.address);
};
deploy();
Then I created another script web3.js which creates a web3 provider using Infura api:
import Web3 from 'web3';
let web3;
if (typeof window !== 'undefined' && typeof window.web3!=='undefined') {
// we are in the browser and metamask is running.
web3 = new Web3(window.web3.currentProvider);
console.log("using metamask");
}
else {
// we are in server OR user without metamask.
const provider = new Web3.providers.HttpProvider(
"https://rinkeby.infura.io/v3/363ea9633bcb40bc8a857d908ee27094"
);
web3 = new Web3(provider);
console.log("using infura");
}
export default web3;
but when I import this web3.js file somewhere and then try to use 'web3' object, it returns empty array of accounts. For example:
import web3 from '../../ethereum/web3';
...
const accounts = await web3.eth.getAccounts();
console.log("Account list: "+accounts); // returns empty array.
But ideally it should return the accounts list associated with my mnemonic. What is the problem?
A naive solution is to use the HDWalletProvider in your second script, instead of the HttpProvider.
What exactly do you want to do with the second script? I suspect that the second script is something that you want to deploy with a DApp, so including your mnemonic there is a good way to give away all your ether to the first user who knows how to "view source".
If so, in the first script, display the addresses associated with your mnemonic using: provider.getAddresses() and then hard-code those addresses into the second script, for later usage. Naturally, you won't be able to sign any transactions in the second script, but at least you can read data associated with those addresses.
Put await window.ethereum.enable() before web3.eth.getAccounts(),
Or use requestAccounts() instead of getAccounts() :
await web3.eth.requestAccounts();

Passport Strategy to authenticate application users from local db

As per composer documentation I am able to validate my application users using github and after that redirecting to my blockchain application.
But I have to use my local db where application users will be stored and have to validate application users against stored identities in my local db.
Which passport strategy should I use and please let me know steps for it.
Thanks in advance
in case you are using composer-rest-server you can follow the comments on this link to implement local strategy.
However, in case you have your own rest server you can follow this steps:
1- Allow Participants to Register and add registration info to your database beside adding field pending = true,
so all Participants by default will be pending for admin approval.
2- Admin review user requests then run the following method.
Which creates new participant and issue identity bonded to this participant using adminCardName to sign those transactions of add and issue.
const IdentityIssue = require('composer-cli/lib/cmds/identity').Issue;
const ParticipantAdd = require('composer-cli/lib/cmds/participant').Add;
const CardImport = require('composer-cli/lib/cmds/card').Import;
const NetworkPing = require('composer-cli/lib/cmds/network').Ping;
const createParticipantCard = async (participantDetails) => {
const participantOptions = {
card: AdminCardName,
data: JSON.stringify({
$class: 'Name Space and type for your participant',
participantId: participantDetails.participantId,
email: participantDetails.email,
name: participantDetails.name,
}),
};
const issueOptions = {
card: AdminCardName,
file: `cards/identities/${participantDetails.participantId}.card`,
newUserId: participantDetails.participantId,
participantId:
`resource:org.finance.einvoice.participant.Company#
${participantDetails.participantId}`,
};
const importOptions = {
file: `cards/identities/${participantDetails.participantId}.card`,
card: participantDetails.participantId,
};
const pingOptions = {
card: participantDetails.participantId,
};
try {
await ParticipantAdd.handler(participantOptions);
await IdentityIssue.handler(issueOptions);
await CardImport.handler(importOptions);
await NetworkPing.handler(pingOptions);
return participantDetails.participantId;
} catch (err) {
throw err;
}
}
2- call this method at any file like following:
const createdParticipantId = await createParticipantCard(participantDetails);
than you can save createdParticipantId in your database and use it to query network to check if participant exists or it's identity has been revoked or submit transactions.