I try to test this code:
contract Token {
// Some string type variables to identify the token.
string public name = "My Hardhat Token";
string public symbol = "MHT";
// The fixed amount of tokens, stored in an unsigned integer type variable.
uint256 public totalSupply = 1000;
// An address type variable is used to store ethereum accounts.
address public owner;
// A mapping is a key/value map. Here we store each account's balance.
mapping(address => uint256) balances;
// The Transfer event helps off-chain applications understand
// what happens within your contract.
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/**
* Contract initialization.
*/
constructor() {
// The totalSupply is assigned to the transaction sender, which is the
// account that is deploying the contract.
balances[msg.sender] = totalSupply;
owner = msg.sender;
}
/**
* A function to transfer tokens.
*
* The `external` modifier makes a function *only* callable from *outside*
* the contract.
*/
function transfer(address to, uint256 amount) external {
// Check if the transaction sender has enough tokens.
// If `require`'s first argument evaluates to `false` then the
// transaction will revert.
require(balances[msg.sender] >= amount, "Not enough tokens");
// Transfer the amount.
balances[msg.sender] -= amount;
balances[to] += amount;
// Notify off-chain applications of the transfer.
emit Transfer(msg.sender, to, amount);
}
/**
* Read only function to retrieve the token balance of a given account.
*
* The `view` modifier indicates that it doesn't modify the contract's
* state, which allows us to call it without executing a transaction.
*/
function balanceOf(address account) external view returns (uint256) {
return balances[account];
}
}
i use this js code
const { expect } = require("chai");
describe("Token contract", function () {
it("Deployment should assign the total supply of tokens to the owner", async function () {
const [owner] = await ethers.getSigners();
const Token = await ethers.getContractFactory("Token");
const hardhatToken = await Token.deploy();
const ownerBalance = await hardhatToken.balanceOf(owner.address);
expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
});
});
The ERROR IS:
AssertionError: expected BigNumber { value: "1000" } to equal BigNumber { value: "1000" }
Seems to be working fine for me. Try running npx hardhat clean and then try again.
Related
Problem/Clarification:
I have a NFT minting DApp that mints with multiple ERC20 tokens.
I'm having an issue with the react code which calls the smart contract minting function multiple times.
When a user mints with their preferred ERC20 token, the react code is structured in a way that a user would see 3 meta-mask popups.
The first metamask popup asks the user to approve the NFT smart contract to access their ERC20 token.
The second metamask popup asks the user to approve the transfer of the ERC20 tokens into the smart contract.
The third and final popup allows the user to go ahead and mint by calling the mintWithERCToken(mintAmount, tokenID) function in the smart contract. This part is problematic because once the ERC20 has been transferred, and then the user decides to cancel/reject the mint, the token would have already been transferred into the smart contract.
All three metamask calls requires the spending of gas.
What is the correct sequence of events? What is the correct way to write the react code?
Could someone help restructure the react code?
React Code
async function mintWithCrypto(tokenId) {
Web3EthContract.setProvider(ethereum);
let web3 = new Web3(ethereum);
//get erc20 contract address
var erc20address = await blockchain.smartContract.methods.getCryptotoken(tokenId).call();
//get token contract information
var currency = new web3.eth.Contract(TOKENABI, erc20address);
//get NFT cost
var mintRate = await blockchain.smartContract.methods.getNFTCost(tokenId).call();
//get mint amount and convert to int
var _mintAmount = Number(mintAmount);
//get total cost of NFTs minted
var totalAmount = mintRate * _mintAmount;
let gasLimit = 285000;
//get total gas
let totalGasLimit = String(gasLimit * _mintAmount);
setFeedback(`Minting your NFT, please hold on...`);
//approve contract address for ERC20 token
currency.methods.approve(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
//transfer ERC20 token to smart contract. **Problematic code**
.then(await currency.methods.transfer(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account},
async function (error, transactionHash) {
// console.log("Transfer Submitted, Hash: ", transactionHash)
let transactionReceipt = null
while (transactionReceipt == null) {
transactionReceipt = await web3.eth.getTransactionReceipt(transactionHash);
await sleep(10000)
}
}))
//mint NFT **Problematic code**
.then(blockchain.smartContract.methods.mintWithERCToken(_mintAmount, tokenId).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
.once("error", (err) => {
if (err.message == "MetaMask Tx Signature: User denied transaction signature.") {
setFeedback("Transaction cancelled.");
} else {
setFeedback("Sorry, something went wrong please try again later.");
}
})
.then((receipt) => {
console.log(receipt);
setFeedback(`Congratulations! You've minted a ${CONFIG.NFT_NAME}.`);
dispatch(fetchData(blockchain.account));
})
)
}
Smart Contract code
function mintWithERCToken(uint256 mintAmount, uint256 tokenID) public payable {
CryptoTokenInfo storage tokens = permittedCrypto[tokenID];
IERC20 paytoken;
paytoken = tokens.paytoken;
uint256 costval;
costval = tokens.costvalue;
uint256 supply = totalSupply();
require(mintAmount > 0, "You need to mint at least 1 NFT");
require(mintAmount <= maxMintAmount, "Max mint amount per session exceeded");
require(supply + mintAmount <= maxSupply, "Max NFT exceeded");
if (msg.sender != owner()) {
//check if the user is whitelisted
if(onlyWhitelisted == true) {
require(isWhitelisted(msg.sender), "Sorry, address is not whitelisted");
}
require(msg.value == costval * mintAmount, "Insufficient funds. Please add more funds to address");
}
for (uint256 i = 1; i <= mintAmount; i++) {
require(paytoken.transferFrom(msg.sender, address(this), costval));
_safeMint(msg.sender, supply + i);
}
}
I'm trying to build a frontend application using ethers.js from a smart contract that mints one of four houses of Hogwarts.
The contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
//Chainlink's VRFConsumerBase (Chainlink Verifiable Random Function)
//Link: https://docs.chain.link/docs/intermediates-tutorial/
//Github repo: https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/VRFConsumerBase.sol
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
//A ERC721 contractc alias NFT Contract will mint one of four houses of Hogwarts.
//Have you always enjoyed being part of one of the houses of Hogwarts?
//Well, you are in the right place!
//This Smart Contract will extract your Hogwarts household as the talking hat!
contract HogwartsHouses is ERC721URIStorage, VRFConsumerBase {
uint256 public tokenCounter;
bytes32 public keyhash;
uint256 public fee;
mapping(uint256 => Raffle) public tokenIdToRaffle;
mapping(bytes32 => address) public requestIdToSender;
event requestCollectible(bytes32 indexed requestId, address requester);
event raffleAssigned(uint256 indexed tokenId, Raffle raffle);
//This are the different houses that one can extract
enum Raffle {
GRYFFINDOR,
HUFFLEPUFF,
RAVENCLAW,
SLYTHERIN
}
constructor(
address _vrfCoordinator,
address _linkToken,
bytes32 _keyhash,
uint256 _fee
)
public
VRFConsumerBase(_vrfCoordinator, _linkToken)
ERC721("Houses", "HOM")
{
tokenCounter = 0;
keyhash = _keyhash;
fee = _fee;
}
function createCollectible() public returns (bytes32) {
//We want the user who called createCollectoible to be the same user
//who gets assigned the tokenId
bytes32 requestId = requestRandomness(keyhash, fee); //This is going to create our randomness request to get random Houses of Howarts.
//We can get the original caller of create collectible
requestIdToSender[requestId] = msg.sender;
emit requestCollectible(requestId, msg.sender);
}
//Function fulfillRandomness: which is the function that receives and does something
//with verified randomness.
function fulfillRandomness(bytes32 requestId, uint256 randomNumber)
internal
override
{
//Select a houses based of this randomNumber
Raffle raffle = Raffle(randomNumber % 4);
//This is the way how each tokenId is going
//to have a very specific Hogwarts Houses
uint256 newTokenId = tokenCounter;
//tokenURI based on the houses Hogwarts
tokenIdToRaffle[newTokenId] = raffle;
emit raffleAssigned(newTokenId, raffle);
address owner = requestIdToSender[requestId];
_safeMint(owner, newTokenId);
tokenCounter = tokenCounter + 1;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
//Only the owner of the tokenId can be update the tokenURI
require(
_isApprovedOrOwner(_msgSender(), tokenId), //Imported from OpenZeppelin
"ERC721: caller is not owner no approved!"
);
_setTokenURI(tokenId, _tokenURI);
}
}
I'm trying to write this function in javascript:
raffle_metadata_dic = {
"GRYFFINDOR": "https://ipfs.io/ipfs/QmXJcdftXeX9ndcmsPFijRNtyMM49yvSnb8AcveMKWq61c?filename=GRYFFINDOR.json",
"HUFFLEPUFF": "https://ipfs.io/ipfs/QmPz1mxmqUGQUUuVNFWYUPU5BF6dU5MBCQ5xmG3c63pDMN?filename=HUFFLEPUFF.json",
"RAVENCLAW": "https://ipfs.io/ipfs/QmUH9J2eY2Cuu4m5raGCg2XmGqZrd6NuvTatzgwWX1Jm6z?filename=RAVENCLAW.json",
"SLYTHERIN": "https://ipfs.io/ipfs/QmPvjuj32AFV9yye7agrxSzty4Y5nCvesNkzgmYjJciA2f?filename=SLYTHERIN.json",
}
def main():
print(f"Working on {network.show_active()}")
hogwarts_houses = HogwartsHouses[-1]
number_of_collectibles = hogwarts_houses.tokenCounter()
print(f"You have {number_of_collectibles} tokenIds")
for token_id in range(number_of_collectibles):
raffle = get_raffle(hogwarts_houses.tokenIdToRaffle(token_id))
# Check to see if already have a token
if not hogwarts_houses.tokenURI(token_id).startswith("https://"):
print(f"Setting tokenURI of {token_id}")
set_token_uri(token_id, hogwarts_houses, raffle_metadata_dic[raffle])
def set_token_uri(token_id, nft_contract, tokenURI):
account = get_account()
tx = nft_contract.setTokenURI(token_id, tokenURI, {"from": account})
tx.wait(1)
print(
f"Awesome! You can view your NFT at {OPENSEA_URL.format(nft_contract.address, token_id)}"
)
print("Please wait up to 20 minutes, and hit the refresh metadata button")
For the full code: https://github.com/Pif50/Progetto-Ethereum-Web3-di-Pier-Francesco-Tripodi
So, for tokenid in range(number of collectible):
numeber_of_collectible, is hogwarts_houses.tokenCounter(). tokenCounter is a counter of the token that already have
I'm trying to write this for loop in javascript.
I know in javascript there isn't the function Range() and I know this function is to write from scratch.
I have two contracts ERC20, and ERC721.
and everytime erc721 transferFrom function is called, I want to send some erc20 tokens to the creator (minter) of the ERC721.
After some research, I've found that I have to do two things.
call ERC20.transferfrom in ERC721 transferFrom function
Approve the spending of erc20 tokens from the frontend
it seems like the second is giving me some problems. Please see my code below:
Your help will be very much appreciated.
++ I am also not so sure if I am calling ERC20.transferFrom correctly from ERC721 contract. Is this the correct way to do it?
ERC721 contract:
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";
import "../openzeppelin-contracts/contracts/math/SafeMath.sol";
import "../openzeppelin-contracts/contracts/utils/Address.sol";
import "../openzeppelin-contracts/contracts/utils/Counters.sol";
import "./ERC20Token.sol";
contract NFTtoken is ERC721 {
.
.
.
ERC20Token Erc20Contract;
constructor(address tokenAddress) ERC721("NC NFT example", "NCNFT") {
owner = msg.sender;
decimals = 0;
Erc20Contract = ERC20Token(tokenAddress);
}
function mint(string calldata nftName) external payable {
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
nftInfo[msg.sender].name = nftName;
nftInfo[msg.sender].creator = msg.sender;
allValidTokenIndex[newItemId] = allValidTokenIds.length;
allValidTokenIds.push(newItemId);
_tokenIds.increment();
}
function transferNFT(address from, address to, uint256 tokenId) public returns (bool){
transferFrom(from, to, tokenId);
Erc20Contract.transferFrom(to, nftInfo[from].creator, 10);
}
}
.
.
.
app.js
transferNFT: function() {
NFTContract.deployed().then(function(contractInstance) {
let toAddress = $("#to-address").val();
// function transferFrom(address _from, address _to, uint256 _tokenId) public payable {
let NFTid_temp = $("#nft-id").val();
let NFTid = NFTid_temp.substring(7);
console.log("to = " + toAddress);
console.log("nftid = " + NFTid);
Voting.deployed().then(function(votingcontractInstance) { votingcontractInstance.approve(contractInstance.address, votingcontractInstance.balanceOf(web3.eth.accounts[1]))});
contractInstance.transferNFT(web3.currentProvider.selectedAddress, toAddress, NFTid, {gas: 140000, from: web3.eth.accounts[0]});
})
}
error message
app.js:10169 Uncaught (in promise) BigNumber Error: new BigNumber() not a number: [object Object]
at raise (http://localhost:8080/app.js:10169:25)
at http://localhost:8080/app.js:10157:33
at new BigNumber (http://localhost:8080/app.js:9184:67)
at new BigNumber (http://localhost:8080/app.js:9194:25)
at toBigNumber (http://localhost:8080/app.js:2084:12)
at Object.toTwosComplement (http://localhost:8080/app.js:2095:21)
at SolidityTypeAddress.formatInputInt [as _inputFormatter] (http://localhost:8080/app.js:2995:38)
at SolidityTypeAddress.SolidityType.encode (http://localhost:8080/app.js:3648:17)
at http://localhost:8080/app.js:15577:29
at Array.map (<anonymous>)
I suspect this line:
votingcontractInstance.balanceOf(web3.eth.accounts[1]))
Can you check its type? I think it returns "string" but it must be number. If it is string either wrap it with Number
Number(votingcontractInstance.balanceOf(web3.eth.accounts[1])))
Or use web3.utils.toBN()
web3.utils.toBN(votingcontractInstance.balanceOf(web3.eth.accounts[1])))
totalSupply = initialSupply * 10 ** uint256(decimals);
If the initialSupply = 21000000.000000000000000000
(21 million) Why multiply by 10?
pragma solidity ^0.4.16;
contract owned {
address public owner;
function owned() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }
contract TokenERC20 {
// Public variables of the token
string public name;
string public symbol;
uint8 public decimals = 18;
// 18 decimals is the strongly suggested default, avoid changing it
uint256 public totalSupply;
// This creates an array with all balances
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
// This generates a public event on the blockchain that will notify clients
event Transfer(address indexed from, address indexed to, uint256 value);
// This notifies clients about the amount burnt
event Burn(address indexed from, uint256 value);
/**
* Constrctor function
*
* Initializes contract with initial supply tokens to the creator of the contract
*/
function TokenERC20(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) public {
totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount
balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens
name = tokenName; // Set the name for display purposes
symbol = tokenSymbol; // Set the symbol for display purposes
}
/**
* Internal transfer, only can be called by this contract
*/
function _transfer(address _from, address _to, uint _value) internal {
// Prevent transfer to 0x0 address. Use burn() instead
require(_to != 0x0);
// Check if the sender has enough
require(balanceOf[_from] >= _value);
// Check for overflows
require(balanceOf[_to] + _value > balanceOf[_to]);
// Save this for an assertion in the future
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
// Asserts are used to use static analysis to find bugs in your code. They should never fail
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/**
* Transfer tokens
*
* Send `_value` tokens to `_to` from your account
*
* #param _to The address of the recipient
* #param _value the amount to send
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
/**
* Transfer tokens from other address
*
* Send `_value` tokens to `_to` in behalf of `_from`
*
* #param _from The address of the sender
* #param _to The address of the recipient
* #param _value the amount to send
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/**
* Set allowance for other address
*
* Allows `_spender` to spend no more than `_value` tokens in your behalf
*
* #param _spender The address authorized to spend
* #param _value the max amount they can spend
*/
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
/**
* Set allowance for other address and notify
*
* Allows `_spender` to spend no more than `_value` tokens in your behalf, and then ping the contract about it
*
* #param _spender The address authorized to spend
* #param _value the max amount they can spend
* #param _extraData some extra information to send to the approved contract
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/**
* Destroy tokens
*
* Remove `_value` tokens from the system irreversibly
*
* #param _value the amount of money to burn
*/
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
Burn(msg.sender, _value);
return true;
}
/**
* Destroy tokens from other account
*
* Remove `_value` tokens from the system irreversibly on behalf of `_from`.
*
* #param _from the address of the sender
* #param _value the amount of money to burn
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
Burn(_from, _value);
return true;
}
}
/******************************************/
/* ADVANCED TOKEN STARTS HERE */
/******************************************/
contract MyAdvancedToken is owned, TokenERC20 {
uint256 public sellPrice;
uint256 public buyPrice;
mapping (address => bool) public frozenAccount;
/* This generates a public event on the blockchain that will notify clients */
event FrozenFunds(address target, bool frozen);
/* Initializes contract with initial supply tokens to the creator of the contract */
function MyAdvancedToken(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) TokenERC20(initialSupply, tokenName, tokenSymbol) public {}
/* Internal transfer, only can be called by this contract */
function _transfer(address _from, address _to, uint _value) internal {
require (_to != 0x0); // Prevent transfer to 0x0 address. Use burn() instead
require (balanceOf[_from] >= _value); // Check if the sender has enough
require (balanceOf[_to] + _value > balanceOf[_to]); // Check for overflows
require(!frozenAccount[_from]); // Check if sender is frozen
require(!frozenAccount[_to]); // Check if recipient is frozen
balanceOf[_from] -= _value; // Subtract from the sender
balanceOf[_to] += _value; // Add the same to the recipient
Transfer(_from, _to, _value);
}
/// #notice Create `mintedAmount` tokens and send it to `target`
/// #param target Address to receive the tokens
/// #param mintedAmount the amount of tokens it will receive
function mintToken(address target, uint256 mintedAmount) onlyOwner public {
balanceOf[target] += mintedAmount;
totalSupply += mintedAmount;
Transfer(0, this, mintedAmount);
Transfer(this, target, mintedAmount);
}
/// #notice `freeze? Prevent | Allow` `target` from sending & receiving tokens
/// #param target Address to be frozen
/// #param freeze either to freeze it or not
function freezeAccount(address target, bool freeze) onlyOwner public {
frozenAccount[target] = freeze;
FrozenFunds(target, freeze);
}
/// #notice Allow users to buy tokens for `newBuyPrice` eth and sell tokens for `newSellPrice` eth
/// #param newSellPrice Price the users can sell to the contract
/// #param newBuyPrice Price users can buy from the contract
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
sellPrice = newSellPrice;
buyPrice = newBuyPrice;
}
/// #notice Buy tokens from contract by sending ether
function buy() payable public {
uint amount = msg.value / buyPrice; // calculates the amount
_transfer(this, msg.sender, amount); // makes the transfers
}
/// #notice Sell `amount` tokens to contract
/// #param amount amount of tokens to be sold
function sell(uint256 amount) public {
require(this.balance >= amount * sellPrice); // checks if the contract has enough ether to buy
_transfer(msg.sender, this, amount); // makes the transfers
msg.sender.transfer(amount * sellPrice); // sends ether to the seller. It's important to do this last to avoid recursion attacks
}
}
It's not multiplying by 10. It's multiplying by (10 ^ 18). That line is used to handle the decimal offset since fixed point numbers are not yet supported in Solidity.
An ERC20 token is not required to use 18 decimals (or any at all), but it's recommended to use some level of precision since the value of a token can fluctuate significantly. 18 is used in most examples because contracts that receive ether work with values at the wei level (1 ether = 10^18 wei).
I am trying to deploy a contract from another factory contract and then return the address of the newly created contract. The address it returns however is the transaction hash not the contract address. I believe this is because the contract is not yet mined when the address is returned. When I deploy a contract using the web3 deploy it seems to wait until the contract is deployed before outputting the address.
The factory contract:
contract Factory {
mapping(uint256 => Contract) deployedContracts;
uint256 numContracts;
function Factory(){
numContracts = 0;
}
function createContract (uint32 name) returns (address){
deployedContracts[numContracts] = new Contract(name);
numContracts++;
return deployedContracts[numContracts];
}}
This is how I am calling the createContract function.
factory.createContract(2,function(err, res){
if (err){
console.log(err)
}else{
console.log(res)
}
});
Consider the below example. There are a number of ways you can get the address of the contract:
contract Object {
string name;
function Object(String _name) {
name = _name
}
}
contract ObjectFactory {
function createObject(string name) returns (address objectAddress) {
return address(new Object(name));
}
}
1 Store the Address and Return it:
Store the address in the contract as an attribute and retrieve it using a normal getter method.
contract ObjectFactory {
Object public theObj;
function createObject(string name) returns (address objectAddress) {
theObj = address(new Object(name));
return theObj;
}
}
2 Call Before You Make A Transaction
You can make a call before you make a transaction:
var address = web3.eth.contract(objectFactoryAbi)
.at(contractFactoryAddress)
.createObject.call("object");
Once you have the address perform the transaction:
var txHash = web3.eth.contract(objectFactoryAbi)
.at(contractFactoryAddress)
.createObject("object", { gas: price, from: accountAddress });
3 Calculate the Future Address
Otherwise, you can calculate the address of the future contract like so:
var ethJsUtil = require('ethereumjs-util');
var futureAddress = ethJsUtil.bufferToHex(ethJsUtil.generateAddress(
contractFactoryAddress,
await web3.eth.getTransactionCount(contractFactoryAddress)));
We ran across this problem today, and we're solving it as follows:
In the creation of the new contract raise an event.
Then once the block has been mined use the transaction hash and call web3.eth.getTransaction:
http://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransaction
Then look at the logs object and you should find the event called by your newly created contract with its address.
Note: this assumes you're able to update the Solidity code for the contract being created, or that it already calls such an event upon creation.