I recently started studying how to develop web3 dapps and I am building a NFT martketplace.
I have been following some tutorials using solidity and web3/ethers and I managed to display the NFTs of the currently connected wallet.
My next step is to display the NFTs of any given address (not of the connected wallet) as in a gallery. I am trying to build this gallery from the code I have that displays the NFTs of the connected wallet, but I don't fully understand the code, and hence don't know how/what to change.
This is the function to load the NFTs on the page of the connected wallet:
const web3Modal = new Web3Modal({
network: "mainnet",
cacheProvider: true,
});
const connection = await web3Modal.connect()
const provider = new ethers.providers.Web3Provider(connection)
const signer = provider.getSigner()
const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer)
const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider)
const data = await marketContract.fetchMyNFTs()
const items = await Promise.all(data.map(async i => {
const tokenUri = await tokenContract.tokenURI(i.tokenId)
const meta = await axios.get(tokenUri)
let price = Web3.utils.fromWei(i.price.toString(), 'ether');
let item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
}
return item
}))
setNfts(items)
}
nfts will have all the metadata of the NFTs.
The function fetchMyNFTs, defined in the smart contract, is as follows:
uint totalItemCount = _itemIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
So I guess I have two questions:
Do we always need to use the smart contract when fetching NFTs metadata?
How can we display the NFTs of any given account, like zapper.fi or context.app?
I understand that this can be a very broad question but any help or direction to tutorials would be great!
Thanks!
well, most of nft contracts have structures or functions that you can use to get the information you need, like ownerOf that is usually a function that receive the token id and returns the owner, usually the contracts have mappings of the token id to the owner or the address of the owner to an array of the tokens, in this case the contract you are using have a function to return the tokens of the owner but most contracts don't have one, so you will need to understand how all this data is stored and the relation with each other
Related
I am trying to send a variable amount of ether from my React front end to my smart contract. In remix, I can do this no problem by just selecting the amount and sending it with the function
In my front end, this is the function where values.amount is 100wei
const sendEth = async(e) => {
e.preventDefault()
try {
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const connectedContract = new ethers.Contract(CONTRACT_ADDRESS, escrowAbi.abi, signer);
let nftTxn = await connectedContract.depositEth(values.amount);
console.log("Mining...please wait.", nftTxn)
await nftTxn.wait();
console.log(`Mined, see transaction: https://rinkeby.etherscan.io/tx/${nftTxn.hash}`);
// console.log(connectedContract)
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
console.log(error)
}
}
In my smart contract this is my depositEth function - however msg.value is argument i want to pass but I can't pass this as an argument to this function?
FYI in my app, once you they pay eth to the contract it will release an NFT.
function depositEth() public payable hasToken(address(this), nftAddress) {
require(msg.value == amountOwed, 'You ow more money');
buyerAddress = payable(msg.sender);
if(walletHoldsToken(address(this),nftAddress)) {
ERC721(nftAddress).safeTransferFrom(address(this), buyerAddress, tokenID);
}
}
So what I am asking is how do I send x amount of eth to a contract with that value defined in the front end?
In your smart contract define a function to return the amount that owed:
function getOwedAmount() public view returns (uint256) {
// i am assuming " amountOwed" is state variable, uint256
return amountOwed;
}
After creating the contract.
const connectedContract = new ethers.Contract(CONTRACT_ADDRESS, escrowAbi.abi, signer)
get the owned amount
let owedAmount = await contract.getOwedAmount();
owedAmount=owedAmount.toString()
let transaction=await connectedContract.depositEth({value:owedAmount})
await transaction.wait();
since depositEth is payable we can pass last argument as an object specifying how much we send and solidity will automatically assign that amount to msg.value
Your depositEth() function takes 0 params, so the JS snippet also needs to pass 0 params.
There's the overrides object in ethers, always passed after the regular function params (in your case on the 1st place as there are 0 params), allowing to modify certain fields of the transaction invoking the function, including its value.
let nftTxn = await connectedContract.depositEth({
value: values.amount
});
I'm new to Flutter and I'm trying to store contact list as name and number in local database. The code I wrote works on the Samsung A21S device that I use as an emulator, but it does not work on devices like Xiaomi, where did I go wrong?
void getContacts() async {
List<Contact>? _contacts;
List<String> contactList = [];
final bool isConnected = await InternetConnectionChecker().hasConnection;
if (isConnected) {
_contacts = await FlutterContacts.getContacts(
withThumbnail: false, withPhoto: false, withProperties: true);
for (var i = 0; i < _contacts.length; i++) {
//Error this line
var num = _contacts[i].phones.first.normalizedNumber;
var name = _contacts[i].displayName;
var nameNum = "$name,$num";
contactList.insert(i, nameNum);
}
print(contactList);
print(contactList.length);
String json = jsonEncode(contactList);
}
}
I've successfully integrated the Torus wallet and now I am trying to display the NFTs that a person has in the wallet. I am doing it successfully with MetaMask but I am having troubles making it work with Torus. I am guessing I have a problem with the provider? I get the following errors on the browser:
index.ts:225 Uncaught (in promise) Error: unsupported provider (argument="provider", value="[object Object]", code=INVALID_ARGUMENT, version=providers/5.5.2)
at Logger.makeError (index.ts:225)
at Logger.throwError (index.ts:237)
at Logger.throwArgumentError (index.ts:241)
at new Web3Provider (web3-provider.ts:156)
at loadNFTs (UsersNFTs.js:112)
and
VM9765:2 Uncaught ReferenceError: process is not defined
at Object.4043 (<anonymous>:2:13168)
at r (<anonymous>:2:306599)
at Object.8048 (<anonymous>:2:9496)
at r (<anonymous>:2:306599)
at Object.8641 (<anonymous>:2:1379)
at r (<anonymous>:2:306599)
at <anonymous>:2:315627
at <anonymous>:2:324225
at <anonymous>:2:324229
at HTMLIFrameElement.e.onload (index.js:1)
And this is my code:
*** UsersNFTs.js ***
let [torusSdkInstance,setTorusSdkInstance] = useState()
// Import dynamically torus wallet object
useEffect(()=>{
const initialize = async () => {
const torus = (await import("#toruslabs/torus-embed")).default;
setTorusSdkInstance(new torus({}));
}
initialize();
}, [])
const providerOptions = {
"custom-Torus": { //Torus wallet
display: {
logo: 'https://miime.io/images/wallet-login-torus-logo.png',
name: "Torus",
description: "Connect to Torus Wallet"
},
package: torusSdkInstance,
options: {
// apiKey: "EXAMPLE_PROVIDER_API_KEY"
},
connector: async (_, options) => {
await torusSdkInstance.init({
enableLogging: false,
});
await torusSdkInstance.login();
const web3 = new Web3(torusSdkInstance.provider);
return web3;
}
}
}
const web3Modal = new Web3Modal({
network: "mainnet",
cacheProvider: true,
providerOptions
});
const connection = await web3Modal.connect()
const provider = new ethers.providers.Web3Provider(connection)
const signer = provider.getSigner()
const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer)
const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider)
const data = await marketContract.fetchMyNFTs()
*** fetchMyNFTs function in the smart contract ***
function fetchMyNFTs() public view returns (MarketItem[] memory) {
uint totalItemCount = _itemIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
I found the way to display the minted NFTs (not the purchased ones) of a wallet, so I want to share my solution!
I have a fetchNFTs function in my smart contract that gets the tokens made available in the market place but not sold yet (address(0)):
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint itemCount = _itemIds.current();
uint unsoldItemCount = _itemIds.current() - _itemsSold.current();
uint currentIndex = 0;
MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(0)) {
uint currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
And in the frontend after I call this function, I just had to map through the items and select the ones which the seller address equals the address of the connected wallet, so I get the NFTs that the address has minted but not sold yet.
I can't randomly get user from firebase
I'm doing dating app with react native and firebase.
Users can log in with google and set their accounts, but I can't match users.
I can pick 1 user but cant display user's data.
I tried:
i tried get all users from firebase realtime database
i can pick 1 user and log user's details but cant display in app
And sometimes user.uid returns null even if i logged in.
function getRandomUser() {
const numberOfUsers = 15;
const randomIndex = Math.floor(Math.random() * numberOfUsers);
var ref = firebase.database().ref("/users/");
ref
.limitToFirst(1)
.once("value")
.then((snapshot) => {
var randomUser = snapshot.val();
console.log(randomUser);
console.log(randomUser.bio);//this is not even display in console
});
}
I believe you should change the way you are referencing your database, so it should be var ref = firebase.database().ref("users"); and not var ref = firebase.database().ref("/users/");.
After that, are some changes related to the random number number and to the comparing issues that you need to perform, so values are returned. Please, give it a try using the below code.
var dbUser = firebase.database();
var refUser = dbUser.ref("<collection>");
refUser.orderByChild("online").equalTo(1).on("value", function(Data){
var numberOfUsers = 15;
var randomIndex = Math.random() * numberOfUsers;
var userIndex = parseInt(randomIndex, 10); //parse the random number from double to integer
var currentIndex = 0;
var BreakException = {};
try
{
Data.forEach(function(snap){
if(currentIndex==userIndex){
var randomUser = snap.val();
//Do something with your random user
throw BreakException;
}
currentIndex++;
});
}
catch(e){
if(e!== BreakException) throw e;
}
While this code is untested, it was based in this successful use case here and I believe should help you. Besides that, you can get another way of returning random users, but with indexes now, by checking this similar case here, with a very complete answer from a Product Lead from Firestore.
I've been trying to create a system that automatically sets the slowmode in a channel to a certain amount depending on how many messages have been sent. Lua is my primary language, and not Node.js, therefore I'm having quite a bit of trouble as to how I would go about this. If anyone had any suggestions, please let me know.
Two ways to go about it:
Use discord.js's <TextChannel>.setRateLimitPerUser(number)
https://discord.js.org/#/docs/main/stable/class/TextChannel?scrollTo=setRateLimitPerUser
Not sure if this actually does what you want though, the other option is creating a session storage of the text channels msgCount and compare it to time, i found setRateLimitPerUser in the middle of writing the code so didn't finish it, be here's a start:
const { Client, Collection } = require("discord.js");
const client = new Client();
client.slowdown = new Collection();
client.on("message", msg => {
const id = msg.channel.id;
const attempt = client.slowdown.get(id);
//4 messages at most per second
const ratio = 4;
//look at last how many seconds
const timeSpace = 5;
//TODO: check if channel already has cooldown
if (attempt) {
attempt.msgCount++;
const currentTime = Date.now();
const timePassed = (currentTime - attempt.time) / 1000;
if (attempt.msgCount >= ratio && attempt.msgCount / timePassed >= ratio) {
//setCoolDown
}
if (timePassed >= timeSpace) {
attempt.time = currentTime;
attempt.msgCount = 0;
}
} else {
client.slowdown.set(id, {
time: Date.now(),
msgCount: 1
});
}
});