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 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.
I have already deployed a smart contract with chainlink VRFConsumerBase named game contract as shown below to get a random number. When I am calling from front-end to get random number, it is showing "undefined" as show in the picture below.
Error Message
async BelowSeven(amount){
const gameContract=this.state.gameContract
let firstDiceNumber =(await gameContract.getRandomNumber())
window.alert("Rolling Dies")
firstDiceNumber=await gameContract.randomResult
console.log(firstDiceNumber)
window.alert("Completed")
//let secondDiceNumber =(await gameContract.getRandomNumber())
//secondDiceNumber=await gameContract.randomResult
//const result= firstDiceNumber+secondDiceNumber
//console.log(secondDiceNumber)
}
Random Number Generating Contract (game Contract):
pragma solidity >=0.4.0 <0.9.0;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract game is VRFConsumerBase{
uint public randomResult;
bytes32 internal keyHash;
uint internal fee;
constructor() VRFConsumerBase(0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B,
0x01BE23585060835E02B77ef475b0Cc51aA1e0709) public
{
keyHash=0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311;
fee=0.1 *10**18;
}
function getRandomNumber() public returns(bytes32 requestId){
return requestRandomness(keyHash,fee);
}
function fulfillRandomness(bytes32 requestId,uint randomness) internal override{
randomResult=randomness%7;
}
function contractBalance() public view returns(uint){
return address(this).balance;
}
function contractFund() external payable{
}
}
This is my first experience writing a smart contract, so I am still trying to navigate how this all works. I have a smart contract on the Rinkeby test network that currently works as expected when deploying and then importing into OpenSea (their "get listed" page).
The problem is I have to mint NFTs within the constructor of the smart contract by calling the _mint() method to make them display in the collection that OpenSea generates based on my smart contract's address. I have only deployed the test smart contract with minting the first 10 NFTs of the collection and those 10 NFTs show up on OpenSea as I would expect. However, I want to utilize OpenSea's lazy minting ability to avoid the gas fees for minting each NFT(there are 10,000 of them) in the collection myself.
Is there a way to set up the smart contract that informs OpenSea(and possibly other exchanges) that I am lazy-minting and have all 10,000 NFTs display within OpenSea without actually having to mint each one upfront within the contract?
I know people can develop their own site where others can then mint each NFT they would like to purchase to accomplish lazy-minting, but I want these NFTs to all be visible and purchasable within OpenSea without them officially being minted yet(lazy-minted). I have all my NFTs and metadata out on IPFS and everything seems to be linking up properly when I perform an actual mint action, so I know that works just fine. I just need to understand if/how it is possible to set up my smart contract to enable this functionality.
Here is my current smart contract with the URLs to IPFS replaced with a placeholder:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/security/Pausable.sol";
import "#openzeppelin/contracts/utils/math/SafeMath.sol";
import "#openzeppelin/contracts/interfaces/IERC2981.sol";
import "./ContextMixin.sol";
contract MyTestContract is ERC1155, IERC2981, Ownable, Pausable, ContextMixin {
using SafeMath for uint256;
string public name;
string public symbol;
uint256 public total_supply;
address private _recipient;
constructor() ERC1155("IPFS_URL_TO_JSON_FILES_GOES_HERE") {
name = "MY Collection Name Goes Here";
symbol = "TESTING";
total_supply = 10000;
_recipient = owner();
_mint(msg.sender, 1, 1, "");
_mint(msg.sender, 2, 1, "");
_mint(msg.sender, 3, 1, "");
_mint(msg.sender, 4, 1, "");
_mint(msg.sender, 5, 1, "");
_mint(msg.sender, 6, 1, "");
_mint(msg.sender, 7, 1, "");
_mint(msg.sender, 8, 1, "");
_mint(msg.sender, 9, 1, "");
_mint(msg.sender, 10, 1, "");
}
function setURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function mint(address account, uint256 id, uint256 amount, bytes memory data)
public
onlyOwner
{
_mint(account, id, amount, data);
}
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
public
onlyOwner
{
_mintBatch(to, ids, amounts, data);
}
function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view override returns (address receiver, uint256 royaltyAmount) {
return (_recipient, (_salePrice * 500) / 10000);
}
function _setRoyalties(address newRecipient) internal {
require(newRecipient != address(0), "Royalties: new recipient is the zero address");
_recipient = newRecipient;
}
function setRoyalties(address newRecipient) external onlyOwner {
_setRoyalties(newRecipient);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, IERC165) returns (bool) {
return (interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId));
}
/**
* Override isApprovedForAll to auto-approve OS's proxy contract
*/
function isApprovedForAll(
address _owner,
address _operator
) public override view returns (bool isOperator) {
// if OpenSea's ERC1155 Proxy Address is detected, auto-return true
if (_operator == address(0x207Fa8Df3a17D96Ca7EA4f2893fcdCb78a304101)) {
return true;
}
// otherwise, use the default ERC1155.isApprovedForAll()
return ERC1155.isApprovedForAll(_owner, _operator);
}
/**
* This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
*/
function _msgSender() internal override view returns (address sender) {
return ContextMixin.msgSender();
}
// Update for collection-specific metadata.
function contractURI() public pure returns (string memory) {
return "CONTRACT_LEVEL_METADATA_URL_GOES_HERE";
}
}
Any help would be greatly appreciated.
No, that is not possible for now. When there is a website you go to mint NFTs for yourself, the website is doing the following:
You click mint and then the NFT is minted on the contract to your account.
When you go to Opensea, they are able to fetch the NFTs on your account and then to load their data.
There is, for right now, no implementation of them getting the data without the data being associated with a EOA or a Contract Account.
Basically, the NFT must be someone's. When you have the data, but no a owner, it's not someone's.
I think that what you want to do is to display a "lazy minted" NFT in one of the marketplaces right? If that's what you need, maybe this article will help you? You upload your lazy minted data to Rarible using rarible's API, and then the NFT can be viewed and minted on their site. I'm not sure if Openseas provide an API to do this too. Once the NFT is minted, I guess it can be seen in either Openseas or Rarible.
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.