I'm getting an error when calling a view function of my solidity contract from my frontend.
The error is listed in the docs as error 32:
0x32: If you access an array, bytesN or an array slice at an out-of-bounds or negative index (i.e. x[i] where i >= x.length or i < 0).
My contract:
address public owner;
struct FoodItem {
address owner;
string url;
string name;
string originCountry;
}
FoodItem[] public foodItems;
function addFoodItem(
string memory url,
string memory name,
string memory originCountry
) public {
foodItems.push(FoodItem(msg.sender, name, url, originCountry));
}
function getFoodItemsByOwner() public view returns (FoodItem[] memory) {
uint256 itemCount = 0;
for (uint256 i = 0; i < foodItems.length; i++) {
if (foodItems[i].owner == msg.sender) {
itemCount += 1;
}
}
FoodItem[] memory myfoods = new FoodItem[](itemCount);
for (uint256 i = 0; i < foodItems.length; i++) {
if (foodItems[i].owner == msg.sender) {
myfoods[i] = foodItems[i];
}
}
return myfoods;
}
And my function from react:
const getDishesByUser = async () => {
const { ethereum } = window;
if(ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(abiFoodAddress, Food.abi, signer);
const data = await contract.getFoodItemsByOwner();
console.log(data);
setDishesByuser(data)
//router.push('/');
}
};
useEffect(() => {
getDishesByUser();
}, []);
Complete error output in the console:
index.js?dd68:224 Uncaught (in promise) Error: call revert exception; VM Exception while processing transaction: reverted with panic code 50 [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="getFoodItemsByOwner()", data="0x4e487b710000000000000000000000000000000000000000000000000000000000000032", errorArgs=[{"type":"BigNumber","hex":"0x32"}], errorName="Panic", errorSignature="Panic(uint256)", reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
You can console log foodItems in addFoodItem function to be sure that you actually pushed the items. If not, you may try:
Mapping(address => FoodItem[]) public foodItems;
So you can do:
foodItems[owner].push(FoodItem(msg.sender, name, url, originCountry));
But you have to specify who the owner is
Related
I'd like to assign an array of arrays in a state.
I found a few elements about modifying an array of arrays, this is not what I want to do.
I'm first building the array of arrays (which won't change beyond construction) then try to set the state, but it stays empty ([]).
Here is the solidity part :
contract Test {
struct Bobject {
address owner;
uint amount;
}
struct Dobject {
uint id;
uint ddate;
string label;
uint quantity;
mapping(uint => Bobject) bobjs;
uint bCount;
}
uint public dCount = 0;
mapping(uint => Dobject) public dobjs;
function getBobj( uint did, uint bid) external view returns(Bobject memory) {
return dobjs[did].bobjs[bid];
}
}
And the react JS useEffect code I'm testing now, the "barray" contains the array of arrays of Bojects, no problem, but after setBobjs( bobjs => barray); bobjs is still [].
const [dobjs, setDobjs] = useState([]);
const [bobjs, setBobjs] = useState([]);
useEffect(() => {
setDobjs( dobjs => []);
setBobjs( bobjs => []);
const dCount = await contract.dCount();
const barray = Array();
for (let i = 1; i <= dCount; i++) {
const dobj = await contract.dobjects(i);
setDobjs(dobjs => [...dobjs, dobj]);
const bCount = dobj.bCount;
const sbarray = Array();
for( let j=1; j <= bCount; j++) {
let nobj = await contract.getBobj(i, j);
sbarray.push( nobj);
}
barray.push( sbarray);
}
setBobjs(bobjs => barray);
}
I came accross another consideration that is not 100% clear to me even after spending the full day in forums :
I chose to query the contract for the Bobjects and implemented a custom getter because the Dobjects I get with contract.dobjects(i); do not contain the "bobjs" mapping member
Maybe there is a better way to get the Bobjects ?
Anyway, any help is appreciated, I have to take a break ;)
Thanks !
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 am trying to send two constant variable from my onSubmit method but I get error 400
POST http://localhost:8080/MenuFiltre/filtreregioncloser 400
Code React js :
onSubmit(e) {
e.preventDefault();
const FilterClassification = {
// classification
rfx: this.state.rfx,
rfp: this.state.rfp,
rfp_x: this.state.rfp_x,
allclassification: this.state.allclassification
};
const FilterRegion = {
//Region
eu : this.state.eu,
americas : this.state.americas,
aae : this.state.aae,
ger: this.state.ger,
eu2 : this.state.eu2,
latam : this.state.latam,
empty : this.state.empty,
allregion : this.state.allregion,
}
console.log(FilterRegion);
axios.post("http://localhost:8080/MenuFiltre/filtreregioncloser",FilterClassification , FilterRegion )
}
Spring boot code :
#PostMapping("/filtreregioncloser")
public Iterable<Closerfprfx>gettab1(#RequestBody FilterClassification FilterClassification , #RequestBody FilterRegion FilterRegion)
{
//GET CLASSIFICATION
boolean rfx = FilterClassification.isRfx();
String ChaineRfx = "";
if(rfx==true)
{
ChaineRfx="rfx";
}else
{
ChaineRfx="xxxx";
}
boolean rfp =FilterClassification.isRfp() ;
String ChaineRfp = "";
if(rfp == true)
{
ChaineRfp="rfp";
}else
{
ChaineRfp="xxxx";
}
boolean rfp_x= FilterClassification.isRfp_x();
String ChaineRfp_x = "";
if(rfp_x==true)
{
ChaineRfp_x="rfp_x";
}else
{
ChaineRfp_x="xxxx";
}
boolean allclassification = FilterClassification.isAllclassification() ;
boolean eu = FilterRegion.isEu();
String ChaineEu= "";
if(eu==true)
{
ChaineEu="eu";
}else
{
ChaineEu="xxxx";
}
boolean americas = FilterRegion.isAmericas();
String ChaineAmericas = "";
if(americas==true)
{
ChaineAmericas="americas";
}
else {
ChaineAmericas="xxxx";
}
boolean aae = FilterRegion.isAae();
String ChaineAae = "";
if(aae==true)
{
ChaineAae="aae";
}else {
ChaineAae="xxxx";
}
boolean ger = FilterRegion.isGer();
String ChaineGer="";
if(ger==true)
{
ChaineGer="ger";
}else
{
ChaineGer="xxxx";
}
boolean eu2 = FilterRegion.isEu2();
String ChaineEu2="";
if(eu2=true)
{
ChaineEu2="eu2";
}else {
ChaineEu2="xxxx";
}
boolean latam = FilterRegion.isLatam() ;
String ChaineLatam = "";
if(latam=true)
{
ChaineLatam="latam";
}else {
ChaineLatam="xxxx";
}
boolean empty = FilterRegion.isEmpty();
String ChaineEmpty="";
if(empty=true)
{
ChaineEmpty="empty";
}else {
ChaineEmpty="xxxx";
}
boolean allregion = FilterRegion.isAllregion();
return null;
}
please what i should to do now i need to resolve my error please ! the first parameter works fine without error but when I try to add a second parameter I get error 400
A post request accepts one RequestBody you can't send multiple request bodies.
the axios api is the following
axios.post(url[, data[, config]])
which means that the first parameter is the url the second is data the third is a config object that configurates how axios should send the request.
all this is written in axios documentation which you could of easily googled if you put some effort in.
The solution is simple, Place your objects in a wrapper object.
axios.post("url", {
classification: {
...
},
region: {
...
}
});
In your java code
public class FilterRequest {
private Classification classification;
private Region region;
//constructor getters setters etc.
}
#PostMapping("/filtreregioncloser") // <-- This is a horrible endpoint name and it is misspelled
public Iterable<Closerfprfx>gettab1(#RequestBody FilterRequest filterRequest)
{
final Classification classification = filterRequest.getClassification();
final Region region = filterRequest.getRegion();
}
Getting error 'Cannot read property 'length' of undefined at HelperService.addCommasToArray' when trying to loop through an array that has been passed as a paramter in a helperService class [Typescript]
I'm really not sure why this is not working - I believe it should be straightforward - all I'm trying to do is pass in an array as a parameter and add a ',' to every value in the array (except the last value)
Here is my HelperService Class method:
export class HelperService {
constructor() { }
/*
* Add commas to every value in the array except for the last value
*/
addCommasToArray(array: Array<any>) : Array<any> {
for (let i = 0; array.length; i++){
array[i] += ", ";
}
return array;
}
}
I then call this method within the ngInit of another ts class
this.helperService.addCommasToArray(this.previousClubs);
Here is the ngInit method
public previousClubs: Array<any>;
constructor(private playersService: PlayersService,private
helperService: HelperService, private route: ActivatedRoute) { }
ngOnInit() {
const playerId: string = this.route.snapshot.paramMap.get('id');
this.playersService.getPlayerDetails(playerId).get()
.then(playerDetailsSnapshot=> {
this.currentPlayerDetails = playerDetailsSnapshot.data();
this.currentPlayerDetails.id = playerDetailsSnapshot.id;
});
/*
* Return Previous Clubs
*/
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
this.helperService.addCommasToArray(this.previousClubs);
}
so here:
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
// this line executes without awaiting for .then enclosed scope
this.helperService.addCommasToArray(this.previousClubs);
Basically you call addCommasToArray even before your previousClubs var gets array assigned to it and then gets all its items pushed in. To fix since your method is (.then) async you need to call for this method inside the .then execution scope:
ngOnInit() {
const playerId: string = this.route.snapshot.paramMap.get('id');
this.playersService.getPlayerDetails(playerId).get()
.then(playerDetailsSnapshot=> {
this.currentPlayerDetails = playerDetailsSnapshot.data();
this.currentPlayerDetails.id = playerDetailsSnapshot.id;
});
/*
* Return Previous Clubs
*/
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
this.helperService.addCommasToArray(this.previousClubs);
}
I'm trying to write a function into a React component, but I am stuck with this error:
Uncaught Error: Module build failed: SyntaxError: "productMap" is read-only
Why is this happening? And how can I fix this, so I can use productMap?
Here is my function:
printReceipt() {
var products = this.props.updateBasket.products;
//create a map of products
const productMap = {};
for(let product of products) {
if(!productMap[product.id]) {
productMap[product.id] = 1;
} else {
productMap = productMap + 1;
}
}
console.log(productMap);
}
This is happening because poductMap is of type const and const cannot change through reassignment
Change it to a let or var instead
printReceipt() {
var products = this.props.updateBasket.products;
//create a map of products
let productMap = {};
for(let product of products) {
if(!productMap[product.id]) {
productMap[product.id] = 1;
} else {
productMap = productMap + 1;
}
}
console.log(productMap);
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
Use let productMap={}; instead of const.
The const declaration creates a read-only reference to a value.
Reference
use ()=> FunctionName() instead of FunctionName()
When we call the function FunctionName(), it is just executed, but when we write () => FunctionName(), then it is only called when that particular operation is performed for example onPress.
FunctionName() sometimes doesn't work, and is only read-only, using () => FUnctionName, is a good way.