Invalid address or ENS name - ethereum

I can't understand what the problem is. When I am run the app I am getting this error:
Unhandled Runtime Error
Error: invalid address or ENS name (argument="name", value=5.050201689117535e+47, code=INVALID_ARGUMENT, version=contracts/5.5.0)
My code is given below:
import {ethers} from 'ethers'
import {useEffect, useState} from 'react'
import axios from 'axios'
import Web3Modal from 'web3modal'
import { nftaddress, nftmarketaddress } from '../config'
import NFT from '../artifacts/contracts/NFT.sol/NFT.json'
import Market from '../artifacts/contracts/Market.sol/Market.json'
export default function Home() {
const [nfts, setNFts] = useState([])
const [loadingState, setLoadingState] = useState('not-loaded')
useEffect(()=> {
loadNFTs()
}, [])
async function loadNFTs() {
// what we want to load:
// ***provider, tokenContract, marketContract, data for our marketItems***
const provider = new ethers.providers.JsonRpcProvider()
const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider)
const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, provider)
const data = await marketContract.fetchMarketTokens()
const items = await Promise.all(data.map(async i => {
const tokenUri = await tokenContract.tokenURI(i.tokenId)
// we want get the token metadata - json
const meta = await axios.get(tokenUri)
let price = ethers.utils.formatUnits(i.price.toString(), 'ether')
let item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
name: meta.data.name,
description: meta.data.description
}
return item
}))
setNFts(items)
setLoadingState('loaded')
}
// function to buy nfts for market
async function buyNFT(nft) {
const web3Modal = new Web3Modal()
// const web3Modal = new Web3Modal({
// network: "ropsten", // optional
// cacheProvider: true, // optional
// providerOptions // required
// });
const connection = await web3Modal.connect()
const provider = new ` `ethers.providers.Web3Provider(connection)
const signer = await provider.getSigner()
const contract = new ethers.Contract(nftmarketaddress, Market.abi, signer)
const price = ethers.utils.parseUnits(nft.price.toString(), 'ether')
const transaction = await contract.createMarketSale(nftaddress, nft.tokenId, {
value: price
})
await transaction.wait()
loadNFTs()
}
if(loadingState === 'loaded' && !nfts.length) return (<h1
className='px-20 py-7 text-4x1'>No NFts in marketplace</h1>)
return (
<div className='flex justify-center'>
<div className='px-4' style={{maxWidth: '1600px'}}>
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4'>
{
nfts.map((nft, i)=>(
<div key={i} className='border shadow rounded-x1 overflow-hidden'>
<img src={nft.image} />
<div className='p-4'>
<p style={{height:'64px'}} className='text-3x1 font-semibold'>{
nft.name}</p>
<div style={{height:'72px', overflow:'hidden'}}>
<p className='text-gray-400'>{nft.description}</p>
</div>
</div>
<div className='p-4 bg-black'>
<p className='text-3x-1 mb-4 font-bold text-white'>{nft.price} ETH</p>
<button className='w-full bg-purple-500 text-white font-bold py-3 px-12 rounded'
onClick={()=> buyNFT(nft)} >Buy
</button>
</div>
</div>
))
}
</div>
</div>
</div>
)
}

I had exactly the same error message. The problem is your value for nftmarketaddress is most likely invalid.
This is what it should look like:
export const nftmarketaddress = "0xcd3b766ccdd6ae721141f452c550ca635964ce71"
Exported as a string.
In my case I had an empty space after the opening quotation mark.
export const nftmarketaddress = " 0xcd3b766ccdd6ae721141f452c550ca635964ce71"
The error means the address you are passing is not in the right format hence presenting as an INVALID_ARGUMENT. It needs to be in the format 0xcd3b766ccdd6ae721141f452c550ca635964ce71(42 hexadecimal characters) and as mentioned above exported as a string.

I run into this error while trying to deploy using hardhat. Here is the fix
const charityWallet = signers[1]
const marketingWallet =signers[2]
//We Deploy
const givers = await Givers.deploy(charityWallet.address,marketingWallet.address,process.env.ROUTER02);

I did a mistake while passing the contract address I passed it as a number and that was the issue. ( do NOT do this )
This is the correct way
Now you can invoke the functions like this

From reading the other answers and resolving this issue when I encountered it, it seems to me that this error means you are passing a value which is not formatted as an Ethereum address into a function which expects an Ethereum address, i.e.
What you are passing is not an address but a different object (in my case a "Signer" object which contained an address and its private key as members) or
Your address is formatted incorrectly (for example, with extra whitespace or as a number).

I get this error by passing an undefined element to a estimateGas Contract function when an address was expected. So if anybody else has this error, check the functions params too.

I got this error while passing in the addresses as parameters to the contract. What solved the problem was:
const [deployer, acc1, acc2] = await ethers.getSigners();
and then at the contract constructor, I called:
acc1.address, acc2.address
Instead of:
acc1,acc2
So make sure you've got the .address at the end of each account.

Related

How can I start a new transaction on an existing Gnosis Safe from my react app?

Currently I have a React app which connects to a Metamask wallet. On clicking a 'Transfer' button, it transfers some ethers from the connected Metamask wallet to the one input by the user. All of this works fine and is pretty straightforward. It looks something like this (I am using ethers.js):
// fetch signer from connected metamask account
const signer = new ethers.providers.Web3Provider(ethereum).getSigner()
const contract = new ethers.Contract(contractAddress, ERC20ABI, signer)
// create a new transaction - that's it! so simple!
const txResponse = await contract.transfer(_recipientWalletAddress, utils.parseUnits(_userinput).toString())
Now, I want the same functionality but instead of transferring from the connected Metamask wallet, I want to connect to an existing Gnosis Safe and transfer funds from the safe to a recipient. I already have a test Gnosis Safe set up on gnosis-safe.io over Goerli Testnet with 3 owners. I have the Safe address. I have the addresses of the owners.
In my app, I have connected my app to the test Gnosis Safe using WalletConnect.
Now, I want that I click a button, enter a recipient address and submit the form. This should create a new transaction on the test Gnosis Safe. And then on the Gnosis Safe, the owners can approve/reject the created transaction. I am struggling with this part.
This is what I've tried
import Safe from '#gnosis.pm/safe-core-sdk'
import { ethers, utils } from 'ethers'
import EthersAdapter from '#gnosis.pm/safe-ethers-lib'
// have all addresses here
const gnosisSafeAddress = '0xsafexaddress'
const gnosisSafeOwners = ['0xsafexownerx1', '0xsafexownerx2', '0xsafexownerx3']
// create a ethers provider over goerli network
const provider = new ethers.providers.JsonRpcProvider(`https://goerli.infura.io/v3/${infuraAPIKey}`);
// create signer using the provider and private key of the one of the gnosis safe owner
const signer = new ethers.Wallet(PRIVATE_KEY_OF_SAFE_OWNER_1, provider);
// create connection to safe using the gnosis safe address
const ethAdapter = new EthersAdapter({ ethers, signer });
const safeSdk = await Safe.create({ ethAdapter, safeAddress: gnosisSafeAddress });
// create a transaction
const transaction = {
to: _recipientWalletAddress,
value: utils.parseUnits(_userinput).toString(),
data: '0x',
};
const safeTransaction = await safeSdk.createTransaction(transaction);
This does not work at all. I logged every step and every variable in between is empty objects. Kindly help me understand what I am doing wrong. I am extremely confused reading the Gnosis SDK repos.
I don't want to deploy a test Gnosis Safe programmatically. I don't want to create a Safe app. I just want to create a transaction, programmatically, on Gnosis Safe (a wallet) to transfer funds, like I do for metamask.
There are not many good resources on how to interact with Safes from react. I suggest trying to write a script in node to grok the flow first. I created a script here that deploys and sends a transaction from the safe
to do the same thing in react (without using the transaction relayer service) you can do the following
import React, { useEffect, useState } from 'react'
import { Button } from "#nextui-org/react";
import { ethers } from "ethers";
import { useSigner } from 'wagmi'
import EthersAdapter from '#gnosis.pm/safe-ethers-lib'
import Safe, { SafeFactory } from '#gnosis.pm/safe-core-sdk'
import { SafeTransactionDataPartial, TransactionResult, SafeTransaction } from '#gnosis.pm/safe-core-sdk-types'
const threshold: number = 1;
const owners = ['0x0533F9d586ABd3334a0E90cA162602D6574F0493']
const safe = () => {
const [gnosisLoaded, setGnosisLoaded] = useState<boolean>(false)
const [safeDeployed, setSafeDeployed] = useState<boolean>(false)
const [safeAddress, setSafeAddress] = useState<string>('')
const { data: signer } = useSigner()
const [safeSdk, setSafeSdk] = useState<Safe | null>(null)
const [safeFactory, setSafeFactory] = useState<SafeFactory | null>(null)
const deploySafe = async () => {
const safeSdk = await safeFactory?.deploySafe({ safeAccountConfig: { owners, threshold } })
if (!safeSdk) return
setSafeSdk(safeSdk)
setSafeAddress(safeSdk.getAddress())
setSafeDeployed(true)
}
const sendSafeTransaction = async () => {
const to = await signer?.getAddress()
const transaction: SafeTransactionDataPartial = {
to,
value: "1",
data: '0x',
};
const safeTransaction: SafeTransaction = await safeSdk?.createTransaction({ safeTransactionData: transaction });
const executeTxResponse: TransactionResult = await safeSdk?.executeTransaction(safeTransaction)
await executeTxResponse.transactionResponse?.wait()
}
useEffect(() => {
if (!signer) return
const setupGnosis = async () => {
const ethAdapter = new EthersAdapter({ ethers, signer })
const safeFactory = await SafeFactory.create({ ethAdapter })
setSafeFactory(safeFactory)
setGnosisLoaded(true)
}
setupGnosis()
}, [signer])
return (
<div>
{gnosisLoaded ? <div>gnosis loaded</div> : <div>gnosis loading...</div>}
{safeDeployed ? <div>safe deployed: {safeAddress}</div> : <div>safe not deployed</div>}
<Button disabled={!gnosisLoaded} onClick={() => deploySafe()}>
Deploy Safe
</Button>
<Button disabled={!safeDeployed} onClick={() => sendSafeTransaction()}>Send Transaction</Button>
</div>
)
}
export default safe

How to verify message in wallet connect with ethers primarily on ambire wallet?

I am trying to sign a message with wallet connect using ethers, but I am facing an issue when verifying the message with ambire wallet, it's not returning any response.
const signMessage = async () => {
try {
console.log("started");
// 1.] create a provider
const walletConnectProvider = new WalletConnectProvider({
infuraId: "3cd774e14cf34ff78167908f8377051c", // Required
// qrcode: true
});
// 2.] enable provider
await walletConnectProvider.enable();
// console.log(walletConnectProvider.wc.accounts[0]);
let rawMessage = "Hello World";
let rawMessageLength = new Blob([rawMessage]).size;
let message = ethers.utils.toUtf8Bytes(
"\x19Ethereum Signed Message:\n" + rawMessageLength + rawMessage
);
message = ethers.utils.keccak256(message);
var params = [
walletConnectProvider.wc.accounts[0],
message,
];
// 3.] sign message
const provider = new providers.Web3Provider(walletConnectProvider);
const signer = provider.getSigner();
let signature = await signer.signMessage(message);
console.log("signature", signature);
// 4.] verify message
let verified = await ethers.utils.verifyMessage(message, signature);
console.log("verified", verified);
} catch (err) {}
};
there are a couple of things you additionally need:
You need to pass the original message (before prefix) to signer.signMessage, in other words the rawMessage: await signer.signMessage(rawMessage) - because the wallet (no matter if it's Ambire or not) will add the prefix
In order to support smart wallets like Ambire, Gnosis Safe, Argent and others, you need to implement EIP 1271.
In JS (warning: not tested), this will look somewhat like this:
const signerAddr = await signer.getAddress();
if (provider.getCode(signerAddr) === '0x') {
// Regular RSV sig verification
verified = signerAddr === (await ethers.utils.verifyMessage(message, signature));
} else {
// Smart contract wallet (EIP 1271) verification: see https://eips.ethereum.org/EIPS/eip-1271 for more info
const EIP1271ABI = ['function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue)'];
const EIP1271MagicValue = '0x1626ba7e';
const signerEIP1271Contract = new ethers.Contract(signerAddr, EIP1271ABI, provider);
const rawMessageLength = new Blob([rawMessage]).size;
const message = ethers.utils.toUtf8Bytes(
"\x19Ethereum Signed Message:\n" + rawMessageLength + rawMessage
);
const messageHash = ethers.utils.keccak256(message);
verified = EIP1271MagicValue === (await signerEIP1271Contract.isValidSignature(messageHash, signature));
}
NOTE: We, the Ambire team, are currently working on a comprehensive guide on how to verify all styles of signature (EIP1271, EIP712, 712+1271, regular), which will hopefully be linked by the ethers.js documentation.
EDIT: We've published a library that makes this a whole lot easier, please check it out: https://github.com/AmbireTech/signature-validator/ - we recommend that you use that

Using local private key with Web3.js

How can I interact with smart contracts and send transactions with Web3.js by having a local private key? The private key is either hardcoded or comes from an environment (.env) file?
This is needed for Node.js and server-side interaction or batch jobs with Ethereum/Polygon/Binance Smart Chain smart contracts.
You may encounter e.g. the error
Error: The method eth_sendTransaction does not exist/is not available
Ethereum node providers like Infura, QuikNode and others require you to sign outgoing transactions locally before you broadcast them through their node.
Web3.js does not have this function built-in. You need to use #truffle/hdwallet-provider package as a middleware for your Ethereum provider.
Example in TypeScript:
const Web3 = require('web3');
const HDWalletProvider = require("#truffle/hdwallet-provider");
import { abi } from "../../build/contracts/AnythingTruffleCompiled.json";
//
// Project secrets are hardcoded here
// - do not do this in real life
//
// No 0x prefix
const myPrivateKeyHex = "123123123";
const infuraProjectId = "123123123";
const provider = new Web3.providers.HttpProvider(`https://mainnet.infura.io/v3/${infuraProjectId}`);
// Create web3.js middleware that signs transactions locally
const localKeyProvider = new HDWalletProvider({
privateKeys: [myPrivateKeyHex],
providerOrUrl: provider,
});
const web3 = new Web3(localKeyProvider);
const myAccount = web3.eth.accounts.privateKeyToAccount(myPrivateKeyHex);
// Interact with existing, already deployed, smart contract on Ethereum mainnet
const address = '0x123123123123123123';
const myContract = new web3.eth.Contract(abi as any, address);
// Some example calls how to read data from the smart contract
const currentDuration = await myContract.methods.stakingTime().call();
const currentAmount = await myContract.methods.stakingAmount().call();
console.log('Transaction signer account is', myAccount.address, ', smart contract is', address);
console.log('Starting transaction now');
// Approve this balance to be used for the token swap
const receipt = await myContract.methods.myMethod(1, 2).send({ from: myAccount.address });
console.log('TX receipt', receipt);
You need to also avoid to commit your private key to any Github repository. A dotenv package is a low entry solution for secrets management.
You can achieve what you want by using ethers.js instead of web3 with no other package needed.
First import the library:
Node.js:
npm install --save ethers
const { ethers } = require("ethers");
Web browser:
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"
type="application/javascript"></script>
Define the provider. One way is using the provider URL like this:
const provider = new ethers.providers.JsonRpcProvider(rpcProvider);
Then, in order to interact with the contract without asking for authorization, we will create a wallet using the private key and the provider like this:
const signer = new ethers.Wallet(privateKey,provider)
Now, you can create the contract with the address, ABI, and the signer we created in the previous step:
const contract = new ethers.Contract(contractAddress,ABI, signer);
Now, you can interact with the contract directly. For example, getting the balance of a token:
const tokenBalance = await nftContractReadonly.balanceOf(signer.getAddress(),tokenId);
Don't forget to store the private key in a safe place and never hardcode it in a web page.
Further reading: Provider Signer
There is a better and simple way to sign and execute the smart contract function. Here your function is addBonus.
First of all we'll create the smart contract instance:
const createInstance = () => {
const bscProvider = new Web3(
new Web3.providers.HttpProvider(config.get('bscRpcURL')),
);
const web3BSC = new Web3(bscProvider);
const transactionContractInstance = new web3BSC.eth.Contract(
transactionSmartContractABI,
transactionSmartContractAddress,
);
return { web3BSC, transactionContractInstance };
};
Now we'll create a new function to sign and execute out addBonus Function
const updateSmartContract = async (//parameters you need) => {
try {
const contractInstance = createInstance();
// need to calculate gas fees for the addBonus
const gasFees =
await contractInstance.transactionContractInstance.methods
.addBonus(
// all the parameters
)
.estimateGas({ from: publicAddress_of_your_desired_wallet });
const tx = {
// this is the address responsible for this transaction
from: chainpalsPlatformAddress,
// target address, this could be a smart contract address
to: transactionSmartContractAddress,
// gas fees for the transaction
gas: gasFees,
// this encodes the ABI of the method and the arguments
data: await contractInstance.transactionContractInstance.methods
.addBonus(
// all the parameters
)
.encodeABI(),
};
// sign the transaction with a private key. It'll return messageHash, v, r, s, rawTransaction, transactionHash
const signPromise =
await contractInstance.web3BSC.eth.accounts.signTransaction(
tx,
config.get('WALLET_PRIVATE_KEY'),
);
// the rawTransaction here is already serialized so you don't need to serialize it again
// Send the signed txn
const sendTxn =
await contractInstance.web3BSC.eth.sendSignedTransaction(
signPromise.rawTransaction,
);
return Promise.resolve(sendTxn);
} catch(error) {
throw error;
}
}

fetching data with react hook returns undefined on nested obj properties

Im trying to display data that has been fetched. but i cannot seem to display nested objects properties in react. Any ideas? if i log the data i first get a undefined, then the correct data.
my guess is that i need to wait for the data to be loaded then display it. but it does work for the title that is not in a nested obj.
function SingleBeneficiary({ match }) {
const [data, setData] = useState({ data: []});
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
{data.title} // works
{data.address.careOf} // dont work
The data
{
"title":"myTitle",
"address":{
"careOf": "my adress"
}
}
Can you try like this?
I set initial data to null, and in return I check if it is not null.
If address can be null, additional null check is required.
function SingleBeneficiary({ match }) {
const [data, setData] = useState(null);
const id = match.params.id
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
setData(jsonData)
}
fetchData();
}, [])
return (
<div>
{data && (
<div>
<p>data.title</p>
<p>data.address.careOf</p>
</div>
)}
</div>
);
}
You should check if address has careOf property before using it because first time data will be undefined and in second render it will have the data after the api call.
{data.address && data.address.careOf}
For anyone who is having a similar issue(i.e. fetching data via api and only the first time it runs, it will show the data as undefined but after manual refreshing, it works fine), here is a quick and sketchy addition you might consider alongside with 1. "Inline If with Logical && Operator" method and 2. using useState for checking if the api loading is over. With those three, mine worked.
Try fetching the desired data in the previous page of your app; in this case, add the following lines in any page you'll see before "SingleBeneficiary".
const response = await fetch(`http://localhost:8081/v1/beneficiary/${id}`);
const jsonData = await response.json()
Maybe it has to do with npm cache, but not really sure what's going on.
replace
return (
{data.title}
{data.address.careOf}
)
with
return (
{data?.title}
{data?.address?.careOf}
)

I'm getting a 404 error when trying to render my results for my API Hack assignment

I'm working on an API Hack assignment for my class with Thinkful and my issue has been that I've been trying to make a call to spoonacular's food api and render the results onto the DOM. However, when I try to do that, All I get in return is a 404 error. I'm wondering if i did something wrong or is some unforeseen problem that is beyond my control?
I've already look at manually typing the composed URL and postman as well.
function queryParams(params) {
const queryItems = Object.keys(params).map(key => `${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}`)
return queryItems.join('&');
}
function displayResults(responseJson){
console.log(responseJson);
$('#results-list').empty();
for(let i = 0; i < responseJson.results.length; i++){
$('#results-list').append(
`<li><h3>${responseJson.results[i].id},${responseJson.results[i].protein}</h3>
<p>By ${responseJson.results[i].calories}</p>
<img src='${responseJson.results[i].image}'>
</li>`
)};
$('#results').removeClass('hidden');
};
function getRecipe(query,maxResults,){
const params ={
q:query,
number: maxResults,
};
const queryString = queryParams(params)
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
console.log(url);
fetch(url,option)
.then(response =>{
if(response.ok){
return response.json();
}
throw new Error(response.statusText);
})
.then(response => console.log(responseJson))
.catch(err =>{
$('#js-error-message').text(`Something went wrong: ${err.message}`);
});
}
function watchForm() {
$('form').submit(event => {
event.preventDefault();
const searchRecipe = $('.js-search-recipe').val();
const maxResults = $('.js-max-results').val();
getRecipe(searchRecipe, maxResults);
});
}
$(watchForm);
It looks like you have a couple issues:
First, you're constructing an invalid url:
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
notice the 2 ?s
Also, when you're constructing the query params, you're adding a space between the = and the value of your param
${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}
If you're using the correct path and a valid API key, fixing those things may be enough to make it work.