I'm trying to deploy a contract in a private Ethereum (Quorum with RAFT but executing only public tx) using solc version 0.5.1 and web3 version 1.0.0-beta.36. Number contract is deployed and contractAddress is returned upon receiving receipt.
Though might seem cumbersome, for easier reproducibility, I've written all code here. The problem I'm having is in the last block (interacting with contract).
const solc = require('solc');
const Web3 = require('web3');
const input = {
language: 'Solidity',
sources: {
solContract: {
content: `
pragma solidity ^0.5.1;
contract Number {
uint private num = 100;
function getNum() public view returns(uint) {
return num;
}
function setNum(uint _num) public returns(bool success) {
num = _num;
return true;
}
}`
}
},
settings: {
outputSelection: {
'*': {
'*': ['*']
}
}
}
}
const output = JSON.parse(solc.compile(JSON.stringify(input)))
const abi = output.contracts.solContract.Number.abi
const bytecode = `0x${output.contracts.solContract.Number.evm.bytecode.object}`
const web3 = new Web3('http://127.0.0.1:8555');
const privateKey = '0x82f74b773d7f948153d7eb8c192bd9819e3e94073d8bdc0e03d659aa42cd34ba';
// const account = web3.eth.accounts.privateKeyToAccount(privateKey);
const contract = new web3.eth.Contract(abi);
web3.eth.personal.unlockAccount('0x27f4cD26d7e4eAde2052ec5B61f6594D1481C4A2', 'passwordstring', 600)
.then(
contract.deploy({
data: bytecode,
arguments: []
})
.send({
from: '0x27f4cD26d7e4eAde2052ec5B61f6594D1481C4A2',
gas: 0x47b760
}, (error, transactionHash) => {
if (error) {
console.log(error)
} else if (transactionHash) {
web3.eth.getTransaction(transactionHash)
.then((data) => {
console.log(data)
})
}
})
.on('receipt', (receipt) => {
console.log(receipt.contractAddress)
}))
// Interacting with deployed contract
// contract address returned from above
// 0x101ea6703717Fa3CF70e96FD3C84FE74ddca50eB
contract.options.address = '0x101ea6703717Fa3CF70e96FD3C84FE74ddca50eB'
contract.methods.getNum().call({
from: 0x27f4cD26d7e4eAde2052ec5B61f6594D1481C4A2,
gas: 0x47b760
}, (err, data) => {
err ? console.log(err) : console.log(data)
})
The issue you're having here is that when you execute the last block of code, the contract has actually not yet been deployed.
You need to perform the call to getNum() within the on() block, e.g.:
.on('receipt', (receipt) => {
console.log("CONTRACT CREATED, ADDRESS = ", receipt.contractAddress)
performGetNum(receipt.contractAddress)
})
function performGetNum(contractAddress) {
sampleContract.options.address = contractAddress
sampleContract.methods.getNum().call({
from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
gas: 0x47b760
}, (err, data) => {
err ? console.log(err) : console.log("getNum() returned value: ", data)
})
}
Related
I'm building a smart contract that generates 3 random numbers using Chainlink VRF. My contract (SlotMachine.sol) implements the VRFConsumerBaseV2 and the constructor has 2 parameters: _subscriptionId and _vrfCoordinator:
constructor(
uint64 _subscriptionId,
address _vrfCoordinator
) payable VRFConsumerBaseV2(_vrfCoordinator)
I have a play() function which calls the requestRandonWords through the vrfCoordinator and I overrided the fulfillRandomWord function to use the generated random words.
I want to do 2 things: 1) create the unit tests in slotmachine.js and 2) test my contract in the hardhat network (chainId = 31337) through deploy.js
For this I'm using the VRFCoordinatorV2Mock which helps me mock an oracle's behavior (as I understand).
My unit tests in slotmachine.js are working well. The fulfillRandomWords is called and then my tests are passing. However when I add a similar logic to the deploy.js file (deploy the mock contract and then the slot machine contract) the fulfillRandomWords is not being called when I call the play() function (which has the requestRandomWords inside it) from my deployed contract.
slotmachine.js
const { ethers } = require("hardhat");
const { expect } = require("chai");
const { BigNumber } = require("ethers");
const provider = ethers.getDefaultProvider();
describe("Decentralized Slot Machine", async function () {
let myContract;
let hardhatVrfCoordinatorV2Mock;
describe("Testing Decentralized Slot Machine", function () {
//1. Contract deployment
it("Should deploy Slot Machine Contract", async function () {
const SlotMachine = await ethers.getContractFactory("SlotMachine");
let vrfCoordinatorV2Mock = await ethers.getContractFactory(
"VRFCoordinatorV2Mock"
);
hardhatVrfCoordinatorV2Mock = await vrfCoordinatorV2Mock.deploy(0, 0);
await hardhatVrfCoordinatorV2Mock.createSubscription();
await hardhatVrfCoordinatorV2Mock.fundSubscription(
1,
ethers.utils.parseEther("7")
);
myContract = await SlotMachine.deploy(
1,
hardhatVrfCoordinatorV2Mock.address,
{
value: ethers.utils.parseEther("100"),
}
);
await hardhatVrfCoordinatorV2Mock.addConsumer(1, myContract.address);
});
//2. Play
describe("First Play - First Player", function () {
it("Contract should receive random numbers", async () => {
const [account1, account2] = await ethers.getSigners();
let tx = await myContract.play(ethers.constants.AddressZero, {
value: ethers.utils.parseEther("1"),
});
let { events } = await tx.wait();
let [reqId] = events.filter((x) => x.event === "RequestedRandomness")[0]
.args;
await expect(
hardhatVrfCoordinatorV2Mock.fulfillRandomWords(
reqId,
myContract.address
)
).to.emit(myContract, "ReceivedRandomness");
let round = await myContract.rounds(reqId);
expect(round.userAddress).to.be.equal(account1.address);
expect(round.number1).to.be.equal(1);
expect(round.number2).to.be.equal(9);
expect(round.number3).to.be.equal(6);
});
});
});
});
deploy.js
const { ethers } = require("hardhat");
const localChainId = "31337";
module.exports = async ({ getNamedAccounts, deployments, getChainId }) => {
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();
const chainId = await getChainId();
await deploy("VRFCoordinatorV2Mock", {
from: deployer,
args: [0, 0],
log: true,
waitConfirmations: 5,
});
const hardhatVrfCoordinatorV2Mock = await ethers.getContract(
"VRFCoordinatorV2Mock",
deployer
);
await hardhatVrfCoordinatorV2Mock.createSubscription();
await hardhatVrfCoordinatorV2Mock.fundSubscription(
1,
ethers.utils.parseEther("7")
);
const myContract = await deploy("SlotMachine", {
from: deployer,
args: [1, hardhatVrfCoordinatorV2Mock.address],
log: true,
waitConfirmations: 5,
});
await hardhatVrfCoordinatorV2Mock.addConsumer(1, myContract.address);
console.log("Contract address: ", myContract.address);
};
module.exports.tags = ["SlotMachine"];
Question
Can I deploy my contract in the hardhat network with the expected behavior of the VRFCoordinatorV2Mock which is to call automatically fulfillRandomWords? If so, how can I do this? What do I have to change in my code? If the answer is no, is there another alternative than deploying to a testnet?
This is my batch.js file which contains the relevant code. I am importing some variables from other files but I've isolated the problem to this file:
const Web3 = require('web3')
const fs = require('fs')
const { convertToNumber, getTokens } = require('./utils')
const { abi, bathEndpoint, walletAddress, blockNumber } = require('./constant.js')
const web3 = new Web3(new Web3.providers.HttpProvider(bathEndpoint))
const generateContractFunctionList = ({ tokens, blockNumber }) => {
const batch = new web3.BatchRequest()
tokens.map(async ({ address: tokenAddress, symbol, decimals }) => {
// console.log('tokenAddress :>> ', tokenAddress)
if (tokenAddress != null && tokenAddress != '') {
const contract = new web3.eth.Contract(abi)
contract.options.address = tokenAddress
try {
batch.add(
contract.methods
.balanceOf(walletAddress)
.call.request({}, blockNumber)
)
} catch (error) {
console.error('Error adding request to batch for token ', tokenAddress)
}
}
})
return batch
}
const main = async () => {
//const { tokens } = await getTokens()
const tokens = JSON.parse(fs.readFileSync('./tokenArrayFormatted1.json'));
console.log('tokens retrieved :>> ', tokens.length)
// const batch = generateContractFunctionList({ tokens })
// query block number
const batch = generateContractFunctionList({ tokens, blockNumber: blockNumber })
const tokenBalances = {}
const tokensIgnored = []
let batchData
try {
batchData = await batch.execute()
} catch (error) {
console.error('Error retrieving balances for some tokens')
batchData = error
}
try {
batchData.response.forEach((res, index) => {
const { name, decimals, symbol } = tokens[index]
if (res && res._hex) {
tokenBalances[name] = `${convertToNumber(res._hex, decimals)} ${symbol}`
} else {
tokensIgnored.push(name)
}
})
} catch (error) {
console.error('Error retrieving balances for some tokens')
batchData = error
}
console.log(
'The following tokens returned an error when checking balance:',
tokensIgnored
)
console.log('----------')
console.log(
`Balance checked for ${Object.keys(tokenBalances).length} tokens:`
)
console.log(tokenBalances)
}
main()
tokenArrayFormatted1.json looks like this:
[
{
"chainId": 1,
"address": "0xf3AE5d769e153Ef72b4e3591aC004E89F48107a1",
"name": "Deeper Network",
"symbol": "DPR",
"decimals": 18
},
{
"chainId": 1,
"address": "0xf680429328caaaCabee69b7A9FdB21a71419c063",
"name": "Butterfly Protocol Governance Token",
"symbol": "BFLY",
"decimals": 18
}
]
When I run node batch.js I keep getting an error telling me that batchData.response is undefined when the code tries to do a forEach over it. I logged batch to the console and it looked like this.
Batch {
requestManager: RequestManager {
provider: HttpProvider {
withCredentials: false,
timeout: 0,
headers: undefined,
agent: undefined,
connected: false,
host: 'https://USERNAME:PASSWORD#BASEURLOFGETHNODE.com',
httpsAgent: [Agent]
},
providers: {
WebsocketProvider: [Function: WebsocketProvider],
HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider]
},
subscriptions: Map(0) {}
},
requests: [
{
params: [Array],
callback: undefined,
method: 'eth_call',
format: [Function: bound ]
},
{
params: [Array],
callback: undefined,
method: 'eth_call',
format: [Function: bound ]
}
]
}
Where USERNAME,PASSWORD, and BASEURLOFGETHNODE refer to my actual credentials.
And then batchData which is created by the line let batchData = await batch.execute() is undefined when logged to the console. So clearly await batch.execute() is producing nothing. I am using Chainstack Geth node API's (with an archive node) and web3js as indicated above. What seems to be the problem?
let batchData = await batch.execute()
batch.execute() does not return a promise if you read the source code, in fact it sends the JSON RPC batch request and call each request callback individually, so what you need to do is turn the execute function into asynchronous one returning an array of responses, and this is how to do it :
const Jsonrpc = require('web3-core-requestmanager/src/jsonrpc');
var { errors } = require('web3-core-helpers');
function executeAsync(batch) {
return new Promise((resolve, reject) => {
var requests = batch.requests;
batch.requestManager.sendBatch(requests, (err, results) => {
results = results || [];
var response = requests.map((request, index) => {
return results[index] || {};
}).map((result, index) => {
if (result && result.error) {
return errors.ErrorResponse(result);
}
if (!Jsonrpc.isValidResponse(result)) {
return errors.InvalidResponse(result);
}
return requests[index].format ? requests[index].format(result.result) : result.result;
});
resolve(response);
});
})
}
To use this function :
(async () => {
var batch = new web3.BatchRequest();
batch.add(web3.eth.getBlock.request("latest"));
var batchResponse = await executeAsync(batch);
console.log(batchResponse);
})()
I am making a simple block chain using the ETH blockchain technology.
I am making a simple todolist, following this tutorial.
My todolist works fine and I can see the tasks in there, how ever when I try to add a new task I get this following error:
Uncaught (in promise) Error: invalid address
v http://localhost:3000/js/web3.min.js:2
l http://localhost:3000/js/web3.min.js:2
formatInput http://localhost:3000/js/web3.min.js:2
formatInput http://localhost:3000/js/web3.min.js:2
toPayload http://localhost:3000/js/web3.min.js:2
e http://localhost:3000/js/web3.min.js:2
sendTransaction http://localhost:3000/js/web3.min.js:2
execute http://localhost:3000/js/web3.min.js:2
synchronizeFunction http://localhost:3000/vendor/truffle-contract/dist/truffle-contract.js:206
synchronizeFunction http://localhost:3000/vendor/truffle-contract/dist/truffle-contract.js:157
promise callback*synchronizeFunction/< http://localhost:3000/vendor/truffle-contract/dist/truffle-contract.js:156
createTask http://localhost:3000/js/app.js:124
onsubmit http://localhost:3000/:1
web3.min.js:2:4288
createTask http://localhost:3000/js/app.js:125
AsyncFunctionThrow self-hosted:696
(Async: async)
onsubmit http://localhost:3000/:1
this is my app.js
App = {
loading: false,
contracts: {},
load: async () => {
await App.loadWeb3();
await App.loadAccount();
await App.loadContract();
await App.render();
},
// https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8
loadWeb3: async () => {
if (typeof web3 !== "undefined") {
App.web3Provider = web3.currentProvider;
web3 = new Web3(web3.currentProvider);
} else {
window.alert("Please connect to Metamask.");
}
// Modern dapp browsers...
if (window.ethereum) {
window.web3 = new Web3(ethereum);
try {
// Request account access if needed
await ethereum.enable();
// Acccounts now exposed
web3.eth.sendTransaction({
/* ... */
});
} catch (error) {
// User denied account access...
}
}
// Legacy dapp browsers...
else if (window.web3) {
App.web3Provider = web3.currentProvider;
window.web3 = new Web3(web3.currentProvider);
// Acccounts always exposed
web3.eth.sendTransaction({
/* ... */
});
}
// Non-dapp browsers...
else {
console.log(
"Non-Ethereum browser detected. You should consider trying MetaMask!"
);
}
},
loadAccount: async () => {
// Set the current blockchain account
App.account = web3.eth.accounts[0];
console.log(App.account);
},
loadContract: async () => {
// Create a JavaScript version of the smart contract
const todoList = await $.getJSON("TodoList.json");
App.contracts.TodoList = TruffleContract(todoList);
App.contracts.TodoList.setProvider(App.web3Provider);
// Hydrate the smart contract with values from the blockchain
App.todoList = await App.contracts.TodoList.deployed();
// console.log(todoList);
},
render: async () => {
// Prevent double render
if (App.loading) {
return;
}
// Update app loading state
App.setLoading(true);
// Render Account
$("#account").html(App.account);
// Render Tasks
await App.renderTasks();
// Update loading state
App.setLoading(false);
},
renderTasks: async () => {
// Load the total task count from the blockchain
const taskCount = await App.todoList.taskCount();
const $taskTemplate = $(".taskTemplate");
// Render out each task with a new task template
for (var i = 1; i <= taskCount; i++) {
// Fetch the task data from the blockchain
const task = await App.todoList.tasks(i);
const taskId = task[0].toNumber();
const taskContent = task[1];
const taskCompleted = task[2];
// Create the html for the task
const $newTaskTemplate = $taskTemplate.clone();
$newTaskTemplate.find(".content").html(taskContent);
$newTaskTemplate
.find("input")
.prop("name", taskId)
.prop("checked", taskCompleted)
.on("click", App.toggleCompleted);
// Put the task in the correct list
if (taskCompleted) {
$("#completedTaskList").append($newTaskTemplate);
} else {
$("#taskList").append($newTaskTemplate);
}
// Show the task
$newTaskTemplate.show();
}
},
createTask: async () => {
App.setLoading(true);
const content = $("#newTask").val();
await App.todoList.createTask(content);
window.location.reload();
},
toggleCompleted: async (e) => {
App.setLoading(true);
const taskId = e.target.name;
await App.todoList.toggleCompleted(taskId);
window.location.reload();
},
setLoading: (boolean) => {
App.loading = boolean;
const loader = $("#loader");
const content = $("#content");
if (boolean) {
loader.show();
content.hide();
} else {
loader.hide();
content.show();
}
},
};
$(() => {
$(window).load(() => {
App.load();
});
});
in console it shows me the address to be: 0xc5cfa0a0345f74e26cecfd8ec3a5cfa3843955ac
I am using metamask and genache, and I tried to connect my smart contacrt to my memask wallet, so I know I am connected, but I am not sure why I am getting this error.
SHould I delete my metamask and do it again?
I tried to look for this solution here, but the solutions are mostly old and doesnt make scnese what I need to do.
Help would be really apperciated.
fixed it, in the app.js you have to replace this line:
App.account = web3.eth.accounts[0];
with the following line:
web3.eth.defaultAccount=web3.eth.accounts[0]
I am a dapp beginner. This is a demo app for a todolist
I am unable to get a connection to the blockchain in web3js. Websocket connection error
localhost is localhost:8545
using web3js CDN : https://cdn.jsdelivr.net/npm/web3#latest/dist/web3.min.js
this is my app.js
App = {
loading: false,
contracts: {},
load: async () => {
console.log('app loading ...')
console.log(web3);
await App.loadWeb3()
await App.loadAccount()
// await App.loadContract()
// await App.render()
},
// https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8
loadWeb3: async () => {
let web3 = new Web3('ws://localhost:8545');
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider
web3.setProvider('ws://localhost:8546');
web3.eth.getAccounts().then(console.log);
} else {
window.alert("Please connect to Metamask.")
}
// Modern dapp browsers...
if (window.ethereum) {
window.web3 = new Web3(ethereum)
try {
// Request account access if needed
await ethereum.enable()
// Acccounts now exposed
web3.eth.sendTransaction({/* ... */})
console.log('MetaMask is installed!');
} catch (error) {
// User denied account access...
}
}
// Legacy dapp browsers...
else if (window.web3) {
App.web3Provider = web3.currentProvider
window.web3 = new Web3(web3.currentProvider)
// Acccounts always exposed
web3.eth.sendTransaction({/* ... */})
}
// Non-dapp browsers...
else {
console.log('Non-Ethereum browser detected. You should consider trying MetaMask!')
}
},
loadAccount: async () => {
// Set the current blockchain account
App.account = web3.eth.accounts[0]
console.log(App.account)
// web3 set up by loadWeb3, includes all accounts, loading first one via MetaMask
},
loadContract: async () => {
// Create a JavaScript version of the smart contract
const todoList = await $.getJSON('TodoList.json')
App.contracts.TodoList = TruffleContract(todoList)
App.contracts.TodoList.setProvider(App.web3Provider)
// Hydrate the smart contract with values from the blockchain
App.todoList = await App.contracts.TodoList.deployed()
},
render: async () => {
// Prevent double render
if (App.loading) {
return
}
// Update app loading state
App.setLoading(true)
// Render Account
$('#account').html(App.account)
// Render Tasks
await App.renderTasks()
// Update loading state
App.setLoading(false)
},
renderTasks: async () => {
// Load the total task count from the blockchain
const taskCount = await App.todoList.taskCount()
const $taskTemplate = $('.taskTemplate')
// Render out each task with a new task template
for (var i = 1; i <= taskCount; i++) {
// Fetch the task data from the blockchain
const task = await App.todoList.tasks(i)
const taskId = task[0].toNumber()
const taskContent = task[1]
const taskCompleted = task[2]
// Create the html for the task
const $newTaskTemplate = $taskTemplate.clone()
$newTaskTemplate.find('.content').html(taskContent)
$newTaskTemplate.find('input')
.prop('name', taskId)
.prop('checked', taskCompleted)
.on('click', App.toggleCompleted)
// Put the task in the correct list
if (taskCompleted) {
$('#completedTaskList').append($newTaskTemplate)
} else {
$('#taskList').append($newTaskTemplate)
}
// Show the task
$newTaskTemplate.show()
}
},
createTask: async () => {
App.setLoading(true)
const content = $('#newTask').val()
await App.todoList.createTask(content)
window.location.reload()
},
toggleCompleted: async (e) => {
App.setLoading(true)
const taskId = e.target.name
await App.todoList.toggleCompleted(taskId)
window.location.reload()
},
setLoading: (boolean) => {
App.loading = boolean
const loader = $('#loader')
const content = $('#content')
if (boolean) {
loader.show()
content.hide()
} else {
loader.hide()
content.show()
}
}
}
$(() => {
$(window).load(() => {
App.load()
})
})
I get this error in the console :
Again I am a total newbie, any help is appreciated.
Any source of info did not help
Hey after metamask update , it no longer injects web3 .
You can check the blog below , It has shown how to connect metamask with our project .
https://dapp-world.com/blogs/01/how-to-connect-metamask-with-dapp--1616927367052
Only thing is its web application , you can relate it with your project .
Hope it works !
I'm trying to setup a Vue2js app with node.js/express, using JWT authentication.
When signing in token is generated (with bearer) and stored in the client-side (Vuex) successfully.
When reload token somehow dissapers from header and I don't know why?
So when calling fetchAccountFromToken function from helpers/token.js I have below error on the server side:
"TypeError: Cannot read property 'split' of undefined"
helpers/token.js
export function fetchAccountFromToken(token) {
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString('utf-8'))['user']
}
And I have this code in server.js
app.post('/login', async (req, res) => {
if (req.body == null) {
res.status(401).json({ error: 'Invalid login. Please try again' })
} else {
const userService = new UserService()
const token = await userService.loginUser({
email: req.body.email,
password: req.body.password
})
console.log(token)
if (token) {
res.json({ token })
} else {
res.status(401).json({ error: 'Invalid login. Please try again' })
}
}
})
UserService.js
export default class UserService {
async loginUser(loginUserRequest) {
const { email, password } = loginUserRequest
const userRepository = new UserRepository()
const userDto = await userRepository.getUserByEmail(email)
if (userDto.email === email && userDto.password === password) {
let user = {
id: userDto.id,
email: userDto.email,
firstName: userDto.firstName,
lastName: userDto.lastName,
role: userDto.role
}
return jwt.sign({ user }, 'the_secret_key') //secret key je za validacijo tokena
}
return null
// return res.status(401).json({ error: 'Invalid login. Please try again.'}) // NEEDS to send error if credentials don't match !!!! //
}
UserRepository.js
export default class UserRepository {
async getUserByEmail(email) {
let dbContext = new DbContext()
try {
const query = 'SELECT id, email, password, firstName, lastName, role FROM accounts WHERE email = ?'
const users = await dbContext.query(query, [email])
return users[0]
} finally {
dbContext.close()
}
}
And I have this code in the VueX store module user.js:
export const state = {
user: null
}
export const mutations = {
SET_USER_DATA(state, data) {
console.log('logging in with data data:', data)
let { token } = data
localStorage.setItem('token', token)
let tokenPayloadJson = atob(token.split('.')[1])
let tokenPayload = JSON.parse(tokenPayloadJson)
let user = tokenPayload.user
state.user = user
localStorage.setItem('user', JSON.stringify(user))
console.log('called set user data')
axios.defaults.headers.common['Authorization'] = `Bearer ${data.token}`
},
CLEAR_USER_DATA() {
localStorage.removeItem('token')
localStorage.removeItem('user')
location.reload()
}
}
export const actions = {
login({ commit }, credentials) {
return axios
.post('//localhost:3000/login', credentials)
.then(({ data }) => {
commit('SET_USER_DATA', data)
})
},
fetchUser(id) {
return AccountService.getUser(id)
.then(response => {
return response.data
})
},
logout({ commit }) {
commit('CLEAR_USER_DATA')
}
}
export const getters = {
loggedIn(state) {
return !!state.user
}
}
I don't see storing the token to VueX, just saving it to localStorage. Additionally I don't see how you are reading it from it (neither localStorage nor VueX store). You can load it from localStorage when initializing the store like this:
export const state = {
user: localStorage.getItem('user'),
token: localStorage.getItem('token')
}