How to generate arbitrary wallet seeded with eth in hardhat tests using ethers.js? - ethereum

I'm currently trying to run a test in hardhat/waffle that requires hundreds of unique wallets to call a contract, using new ethers.Wallet.createRandom(). However, none of these wallets are supplied with eth, so I can't call/send transactions with them.
What would be the simplest/most effective way to supply an arbitrary amount of randomly generated wallets with eth? Thanks!

I think you'll probably want to use the hardhat network method hardhat_setBalance, the docs use an example like this:
await network.provider.send("hardhat_setBalance", [
"<ACCOUNT ADDRESS>",
"0x1000", # 4096 wei
]);
I'm not developing in javascript though, but I've been doing something similar in python using web3.py and eth-account with code like this:
from web3 import Web3
from eth_account import Account
chain = Web3(HTTPProvider("http://127.0.0.1:8545"))
acct = Account.create('<RANDOM VALUE>')
address = Web3.toChecksumAddress(acct.address)
print(chain.eth.get_balance(address)) # 0 wei
# add a balance of eth tokens to the address
chain.provider.make_request("hardhat_setBalance", [address, "0x1000"])
print(chain.eth.get_balance(address)) # 4096 wei

Hardhat allows to seed a custom amount of prefunded addresses using the accounts.count config option of the built-in hardhat network.
Example:
module.exports = {
networks: {
hardhat: {
accounts: {
count: 1000
}
}
}
}
Docs: https://hardhat.org/hardhat-network/reference/#config
The new ethers.Wallet.createRandom() function only creates an account from a random private key in the context of the JS application, but it doesn't communicate with the provider (Hardhat in your case).

saw this answer, and i think it solves the problem:
https://github.com/ethers-io/ethers.js/issues/686
const wallet = ethers.Wallet.createRandom().connect(provider);

Related

Get list of recent added/deployed smart contracts

Is there a way to retrieve the most recent added/deployed smart contracts to the ethereum chain?
Thanks a lot for any advice.
Regards,
JR
Newly deployed contract addresses are not directly available through the node RPC API (and its wrappers such as ethersjs and web3js), but you can build a script that
Subscribes to newly published blocks
Loops through transaction receipts on the block
And searches for contractAddress property of the transaction receipt
The contractAddress property returns null if the transaction does not deploy a contract (most transactions) or an address if the transaction deploys a contract.
The above mentioned approach only retrieves contracts that were deployed directly - by sending a transaction with empty to field and data field containing the contract bytecode.
It does not retrieve contracts that were deployed using an internal transaction. For example it would not catch the following Hello contract deployment (that is deployed by executing the deployHello() function).
pragma solidity ^0.8;
contract Hello {}
contract HelloFactory {
event Deployed(address);
function deployHello() external {
// deploys a new instance of the `Hello` contract to a new address
address deployedTo = address(
new Hello()
);
emit Deployed(deployedTo);
}
}
If you want to retrieve deployments of these contracts as well, then you'd need to debug each newly produced block and search for the create and create2 opcodes (each of them deploys a new contract, they take different input arguments).
So overall, it's not a simple task but it's doable.
It's generally discouraged to recommend any specific 3rd party APIs and tools here at StackOverflow. But I'm guessing that there are already some existing services that do all of this on their backend, and are able to return the aggregated list of newly deployed contracts as a result.
Thanks to the help of Petr Hejda I created the following Python code:
import sys
import time
from web3 import Web3
def connect():
# infura API key
API_KEY = "INFURA_API_KEY"
# change endpoint to mainnet or ropsten or any other of your account
url = f"https://mainnet.infura.io/v3/{API_KEY}"
w3 = Web3(Web3.HTTPProvider(url))
# res = w3.isConnected()
# print(res)
return w3
def get_latest_block(connection):
return connection.eth.get_block('latest')
def get_latest_block_id(block_information):
return block_information['number']
def search_new_contracts(connection, block_information):
block_transactions = block_information['transactions']
# print(block_transactions)
for transaction in block_transactions:
transaction_data = connection.eth.getTransaction(transaction)
if transaction_data['to'] == "":
print(f"Contract creation transaction: {transaction_data}")
print("Block searching done")
if __name__ == "__main__":
current_block_number = sys.maxsize
connection = connect()
while True:
latest_block = get_latest_block(connection)
latest_block_id = get_latest_block_id(latest_block)
if current_block_number is not latest_block_id:
print(f'New block detected: {latest_block_id}')
search_new_contracts(connection, latest_block)
current_block_number = latest_block_id
Problem is that it is slow so I have to see if I can speed things up.

Override the gasPrice in ethers.js contract interaction

How can I set the gasPrice in a contract interaction using ethers.js? I'm trying to override the gasPrice in the code below:
let txPromise = contract.populateTransaction.runAdventureVRF(0, false, { gasPrice: 800000 })
walletSigner.sendTransaction(txPromise)
and i'm receiving the error transaction underpriced. If i try to log txPromise.overrides it is undefined, which makes me think the gas price is never being set.
docs
additional code
const provider = new ethers.providers.AlchemyProvider('matic', process.env.ALCHEMY_API_KEY)
const wallet = new ethers.Wallet(process.env.PK)
const abi = '[{"inputs":[{"internalType":"uint256","name":"_teamId","type":"uint256"},{"internalType":"bool","name":"_energy","type":"bool"}],"name":"runAdventureVRF","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]'
const contract = new ethers.Contract(address, abi, provider);
let walletSigner = wallet.connect(provider)
One solution is to add the gas price as an override to your transaction:
walletSigner.sendTransaction(txPromise, {gasPrice: ethers.utils.parseUnits('100', 'gwei'), gasLimit: 1000000});
This is the only solution I could find as getGasPrice() and estimateGas() were returning a empty json array. I don't know if it has to do with the provider (alchemy) or why those are failing.
The specific syntax to override the gas price is here:
Ethers Override Transaction Gas Price Manually
It's also in the following Ethers docs, but not as clear (if you don't know the syntax):
Ethers Contract Functions Send
At the time of this post, the default gas value of all my transactions is 1.5 gwei which is nowhere near enough on the matic network. This will also hang up the transaction indefinitely until you send a new transaction with the same nonce value. Even if you resolve your gas issue, until you deal with the hung transaction, other transactions will stack up behind it.
If you just want to increase gasLimit by a certain amount, you can make a helper function to do so:
const increaseGasLimit = (estimatedGasLimit: BigNumber) => {
return estimatedGasLimit.mul(130).div(100) // increase by 30%
}
And use it like this:
const estimatedGas = await contract.estimateGas.method(args)
const tx = await contract.method(args, { gasLimit: increaseGasLimit(estimatedGas) })

How to inject Binance Wallet into Web3 instead of Metamask?

I started using Binance Chain Wallet in my dapp, so I can now use:
import { BscConnector } from '#binance-chain/bsc-connector'
export const bsc = new BscConnector({
supportedChainIds: [56, 97] // later on 1 ethereum mainnet and 3 ethereum ropsten will be supported
})
// invoke method on bsc e.g.
await bsc.activate();
await bsc.getAccount();
await bsc.getChainId();
but in API docs it says to do some chain operations I need to iject :
The biggest difference between Binance Chain Wallet and MetaMask is we inject BinanceChain rather than ethereum (or web3) to the web page. So user could keep two extensions at the same time.
BinanceChain.request({method: "eth_sign", params: ["address", "message"])
with metamsk I use
ethereum.request(...)
can you explain to me how to do this?
BinanceChain obj is not declared :)
So I figured out that these steps are necessarily :
// create instance of bsc wallet
const bsc = new BscConnector({
supportedChainIds: [56, 97, 1] // later on 1 ethereum mainnet and 3 ethereum ropsten will be supported
})
// get provider out of this instance:
const bsc_provider = await bsc.getProvider()
provider = new ethers.providers.Web3Provider(bsc_provider)
// from here u can use all binance wallet functions:
provider.provider.switchNetwork('eth-mainnet')
see docs:
binance wallet docs

Is it possible to export Xpub Key from Ledger Nano S Ethereum Wallet

I need to give payment ETH address to my customers for deposit ETH their accounts. I want to use a HD ETH wallet for this and I am using Ledger Nano S now. But Ledger showing me only 1 receive address so I need ETH wallet's XPub for generate many address from it for distribute to users.
If Ledger support HD, How can I export XPub? If ledger does not support, Which wallet can usable for this purpose.
Any suggestions.
You can't export the xpub directly from a ledger nano s with the default bitcoin or ethereum apps.
But you can construct an xpub using the data you can extract from the ledger.
What you need is the public key and chaincode for the bip32 path you're interested in and the public key of the parent of that path.
In the ethereum app you would use getaddress (currently there is a restriction to m/44/60', m/44'/61', and m/44'/1' and below for this app (I have an issue here to hopefully remove that restriction). In the bitcoin app you would use getwalletpublickey. There is no bip32 path restrictions in the bitcoin app.
Once you have the two public keys and the chain code, you can construct the xpub. Here is a chunk of python that can accomplish this. It uses the un-maintained pybitcointools, so user-beware.
#!/usr/bin/env python
import sys
import binascii
from bitcoin import bin_hash160
from bitcoin import bip32_serialize
from bitcoin import compress
def main(parent_pubkey, pubkey, chaincode, depth, index, network):
if (network.lower() == "main"):
network_bytes = b'\x04\x88\xb2\x1e'
elif (network.lower() == "test"):
network_bytes = b'\x04\x35\x87\xcf'
else:
sys.exit("network must be either main or test")
compressed_pubkey_bytes = binascii.unhexlify(compress(pubkey))
fingerprint_bytes = bin_hash160(binascii.unhexlify(compress(parent_pubkey)))[:4]
chaincode_bytes = binascii.unhexlify(chaincode)
deserialized = (network_bytes, int(depth), fingerprint_bytes, int(index), chaincode_bytes, compressed_pubkey_bytes)
xpub = bip32_serialize(deserialized)
print(xpub)
if __name__ == '__main__':
if (len(sys.argv) < 7):
sys.exit("USAGE: generate_xpub PARENT_PUBLICKEY PUBLICKEY CHAINCODE DEPTH INDEX (MAIN|TEST)")
main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])

How to detect if an Ethereum address is an ERC20 token contract?

If I only get an Ethereum address from the input, is there a way to find out whether it matches the ERC20 token standard?
ERC165 tackles this problem, but, unfortunately, most ERC20 implementations don't support it (as of Nov 2018, at least OpenZeppelin doesn't). This means that you could try calling the supportsInterface function, but it would revert anyway and you'd rather complicate things.
Nevertheless, here's how it's defined in ERC721:
bytes4 private constant _InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
Although it's not guaranteed for all implementations to define the interface id, there's a higher chance it will work in the case of ERC721, given the fact the community agreed on applying ERC165 right from the get-go. If the return value of the query below is true, then it means you have a compliant contract, otherwise just revert the transaction.
// you can call this in your contracts
IERC721(contractAddress).supportsInterface(0x80ac58cd)
Also, a useful resource for manually checking the bytes4 of a given method is 4byte.directory
If you are asking about off-chain, so use these functions:
getContract(url, smartContractAddress){
const Web3Eth = require('web3-eth');
const abi_ = this.getABI();
const web3Eth = new Web3Eth(Web3Eth.givenProvider || url);
return new web3Eth.Contract(abi_, smartContractAddress);
}
async getERCtype(contract){
const is721 = await contract.methods.supportsInterface('0x80ac58cd').call();
if(is721){
return "ERC721";
}
const is1155 = await contract.methods.supportsInterface('0xd9b67a26').call();
if(is1155){
return "ERC1155";
}
return undefined;
}
getABI(){
return [
{"constant":true,"inputs": [
{"internalType":"bytes4","name": "","type": "bytes4"}],
"name": "supportsInterface",
"outputs": [{"internalType":"bool","name": "","type": "bool"}],
"payable": false,"stateMutability":"view","type": "function"}
];
}
like this:
const contract = getContract(url, smartContractAddress);
const type = await getERCtype(contract);
console.log(type);
There are many possible ways to achieve this. One possible quick and dirty solution is to check if a ERC20 function exists on the contract address by calling the following:
eth.call({to:contractAddress, data:web3.sha3("balanceOf(address)")})
A non-ERC20 will return a 'null' 0x hex response whereas an ERC20 will give you a 32byte uint, in this case 0 but if you provide an address in the data then it will give you the actual token balance for that address.
This is not a guaranteed way of determining a contract is ERC20 since other contracts may expose the same function, however it is a quick and easy check. You could add additional calls on totalSupply() etc. for more confirmation.
the question states that given an Ethereum address, is this an Ethereum contract address or not?
First thing, you have to decide if this address is a contract address or an externally owned account address. How to find out if an Ethereum address is a contract
If it is a contract address, then you can only get the bytecode that is stored in the blockchain. Now you have to reverse engineer the bytecode to get the contract functions but this is almost impossible. There are some decompilers but they are not perfectly creating the contract code from the bytecode.
ERC165 just checks if the current contract signature supports the given interfaceId or not. Since you have only ethereum address, this will not help in this question.