Call constructor and deploy with web3 and ropsten - blockchain

I have created a test contract which has been compiled successfully and want to broadcast on ropsten test network using web3js. I have a metmask account which i am using. I would like to know how can i call constructor of my contract and then broadcast on ropsten.
I did broadcast one of my contract without constructor and do have my transaction hash key which is 0xf7e5a8e93db9989b033b85323cdff713ba88b547ef64a544550e145961999aac but i am getting a following error Error encountered during contract execution [Reverted] and Transaction has been reverted by the EVM on console. I would like to know also why i am getting this error after broadcast has been done
const fs = require('fs')
var Tx = require('ethereumjs-tx').Transaction
const Web3 = require('web3')
const web3 = new Web3('https://ropsten.infura.io/v3/KEY')
deploy()
function deploy () {
const privateKey = 'PRIVATE_KEY'
const account1 = 'ACCOUNT_NUMBER'
const privateKey1 = Buffer.from(privateKey, 'hex')
const contractData = fs.readFileSync('../../build/contracts/Testcontract.json')
const contract = JSON.parse(contractData)
const byteCode = contract['bytecode']
web3.eth.getTransactionCount(account1, (err, txCount) => {
const txObject = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('0.004', 'gwei')),
data: byteCode
}
let tx = new Tx(txObject, {'chain':'ropsten'})
tx.sign(privateKey1)
const serializedTx = tx.serialize()
const raw = '0x' + serializedTx.toString('hex')
web3.eth.sendSignedTransaction(raw, (err, txHash) => {
console.log('err: ', err, 'txHash: ', txHash)
})
})
}
My contract with constructor looks like this
pragma solidity ^0.5.11;
contract Testcontract {
string public senderName;
string public receiverName;
uint public transferAmount;
constructor (string memory _sender, string memory _receiver, uint _amount) public {
senderName = _sender;
receiverName = _receiver;
transferAmount = _amount;
}
}

UPDATE
A simple way to deploy a contract through an Infura node is using Truffle. In your project's root directory
$ npm install truffle
$ truffle init
Here is a tutorial on how to configure Truffle to use your Infura project. In short, install Truffle's hd-wallet-provider
$ npm install #truffle/hdwallet-provider
Replace truffle-config.js with
const HDWalletProvider = require("#truffle/hdwallet-provider");
const mnemonic = "orange apple banana...";
module.exports = {
networks: {
ropsten: {
provider: () => new HDWalletProvider(mnemonic, 'https://ropsten.infura.io/v3/<YOUR INFURA PROJECT ID>'),
network_id: 3, // Ropsten's id
},
},
compilers: {
solc: {
version: "0.5.11", // Fetch exact version from solc-bin (default: truffle's version)
}
}
}
The previous code configures Truffle to connect to Infura an use your account. In ./migrations directory (created by truffle init) create a new file 2_deploy_testContrac.js where you can define how to deploy your contract and provide the arguments needed by TestContract.
var TestContract = artifacts.require("./TestContract");
module.exports = function(deployer) {
deployer.deploy(TestContract, "AliceSender", "BobSender", 120);
}
Finally, deploy your contract by executing
$ truffle migrate --network ropsten
The reason why your transaction has been reverted is because the constructor of TestContract expected three arguments but you have given zero. Since the constructor couldn't be executed, your deploying transaction was reverted as well.
Instead of manually creating your deploying transaction, you can use web3.eth.Contract.deploy. With this method you can conveniently provide all parameters required by the contract's constructor.
UPDATE: The solution below won't work with Infura because the Infura API does not expose web3.eth.personal functions and it only allows sending rawTranscations.
You should be able to deploy your contract with the following code. Note that it was mainly copy-pasted from the official web3 documentation.
var contractData = fs.readFileSync('../../build/contracts/Testcontract.json');
var contract = JSON.parse(contractData);
var abi = contract['abi'];
var bytecode = contract['bytecode'];
var testContract = eth3.eth.Contract(abi);
var account = ...;
var password = ...;
web3.eth.personal.unlockAccount(account, password);
testContract.deploy({
data: bytecode,
arguments: ['SenderAlice', 'ReceiverBob', 120]
})
.send({
from: account,
gas: 1500000,
gasPrice: '30000000000000'
}, function(error, transactionHash){
console.log(error, transactionHash);
})
.on('error', function(error){
console.log(error);
})
.on('transactionHash', function(transactionHash){
console.log(transactionHash);
})
.on('receipt', function(receipt){
console.log(receipt.contractAddress) // contains the new contract address
})
.on('confirmation', function(confirmationNumber, receipt){
console.log(confirmationNumber, transactionHash);
})
.then(function(newContractInstance){
console.log(newContractInstance.options.address) // instance with the new contract address
});

Related

Owner of smart contract on hardhat development network is being returned 0x00000

I was trying to deploy my smart contract through unit testing using hardhat. The owner upon deployment is being returned as 0x0000.. although when writing my js script i assign a certain address from the hardhat network as the owner.
const hre = require('hardhat')
const { expect, assert } = require('chai')
describe('ProperSubsetFund', async function () {
// Initialize Contract Var
let deployERC20, deployer, user1, user2, trader1, trader2
let signers
beforeEach(async function () {
// Getting all the signers
signers = await hre.ethers.getSigners()
// console.log(signers.map(item => item.address));
// Assign addresses to roles for later use
deployer = signers[0].address
user1 = signers[1].address
user2 = signers[2].address
trader1 = signers[3].address
trader2 = signers[4].address
// Read Contract ERC20
const contractERC20 = await hre.ethers.getContractFactory('ProperSubsetERC20')
// Read Contract Launchpad
const contractLaunchpad = await hre.ethers.getContractFactory('ProperSubsetFactory')
// Read Contract Funds
const contractFunds = await hre.ethers.getContractFactory('ProperSubsetFund')
// Deploy the three contracts
deployERC20 = await contractERC20.connect(signers[0]).deploy(true)
});
describe('Deployment and Ownership', function () {
it('Check if the owner is the deployer', async function () {
expect(await deployERC20.owner()).to.equal(deployer)
});
});
})
These are the results
ProperSubsetFund
Deployment and Ownership
Deployment
Should set the right owner:
AssertionError: expected '0x00000000000000000000000000000000000…' to equal '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb…'
+ expected - actual
-0x0000000000000000000000000000000000000000
+0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
at Context.<anonymous> (test/ProperSubsetFund.test.js:71:49)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Hardhat is not returning address(0), your contract owner() is returning address(0). If you read the terminal it says
AssertionError: expected '0x00000000000000000000000000000000000…' to equal '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb…'
since you set this:
expect(await deployERC20.owner()).to.equal(deployer)
your deployer address by hardhat is '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb…'. But deployERC20.owner() is '0x00000000000000000000000000000000000…'

SyntaxError: Unexpected token o in JSON at position 1. In Solidity version ^0.8.7

Hey Guys, I'm using latest solidity version 0.8.7. I'm getting this SyntaxError: Unexpected token o in JSON at position 1. Please help me regarding this problem. When I run npm run test command, it gives me this error. I really need help to get rid of this issue. That's why I'm not able to proceed further in learning solidity. Thanks a lot
**Lottery.sol File - **
pragma solidity ^0.8.7; // latest solidity version...
contract Lottery
{
address public manager;
address[] public players;
constructor()
{
manager = msg.sender;
}
function enter() public payable
{
require(msg.value > .01 ether);
players.push(msg.sender);
}
function random() private view returns (uint256)
{
return
uint256(keccak256(abi.encodePacked(block.difficulty, block.timestamp, players)));
}
function pickWinner() public restricted
{
require(msg.sender == manager);
uint256 index = random() % players.length;
uint256 amount = address(this).balance;
payable(players[index]).transfer(amount);
players = new address[](0);
}
modifier restricted()
{
require(msg.sender == manager);
_;
}
function getPlayers() public view returns (address[] memory)
{
return players;
}
}
Compile.js File -
const path = require("path");
const fs = require("fs");
const solc = require("solc");
const lotteryPath = path.resolve(__dirname, 'contracts', 'Lottery.sol');
const source = fs.readFileSync(lotteryPath, "utf8");
var input = {
language: 'Solidity',
sources: {
'lottery.sol' : {
content: source
}
},
settings: {
outputSelection: {
'*': {
'*': [ '*' ]
}
}
}
};
const output = JSON.parse(solc.compile(JSON.stringify(input))); // error on this line probably
const interface = output.contracts['lottery.sol'].lotteryPath.abi;
const bytecode = output.contracts['lottery.sol'].lotteryPath.evm.bytecode.object;
module.exports = {
interface,
bytecode,
};
lottery.test.js File
const assert = require("assert");
const ganache = require("ganache-cli");
const Web3 = require("web3");
const web3 = new Web3(ganache.provider());
const { interface, bytecode } = require("../compile");
let lottery;
let accounts;
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
lottery = await new web3.eth.Contract(JSON.parse(interface)) // error on this line probably
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: '1000000' });
});
describe("Lottery Contract", () => {
it("deploys a contract", () => {
assert.ok(lottery.options.address);
});
});
deploy.js File -
const HDWalletProvider = require("#truffle/hdwallet-provider");
const Web3 = require("web3");
const { interface, bytecode } = require("./compile");
const provider = new HDWalletProvider(
"*******************************************",
"https://rinkeby.infura.io/v3/********************"
);
const web3 = new Web3(provider);
const deploy = async () => {
const accounts = await web3.eth.getAccounts();
console.log("Attempting to deploy from accoutns", accounts[0]);
const result = await new web3.eth.Contract(JSON.parse(interface))
.deploy({ data: bytecode})
.send({ gas: '1000000', from: accounts[0] });
console.log("Contract deployed to", result.options.address);
};
Follow these steps.
Step 1: Check the solidity compiler version
Go to your package.json file. Under the dependencies object you will find the solc version.
Here make sure the solidity version is the same that you used in your Lottery.sol file.
If the version is not the same then please install the right version using npm
In my case, I am using ^0.8.8 in my solidity file. So I run the following command:
npm install solc#0.8.8
Step 2: Update your lottery.test.js file
In your lottery.test.js file update this line
lottery = await new web3.eth.Contract(JSON.parse(interface))
to this
lottery = await new web3.eth.Contract(interface)
Step 3: Update your deploy.js file
In your deploy.js file update this line
const result = await new web3.eth.Contract(JSON.parse(interface))
to this
const result = await new web3.eth.Contract(interface)
Also, it's a good practice to add your deployment code into a try/catch block like this:
try {
const accounts = await web3.eth.getAccounts();
console.log("Attempting to deploy from accoutns", accounts[0]);
const result = await new web3.eth.Contract(interface)
.deploy({ data: bytecode})
.send({ gas: '1000000', from: accounts[0] });
console.log("Contract deployed to", result.options.address);
} catch(error) {
console.log(error);
}
Note: Finally ensure in your deployment account you have enough ethers to test with. If you don't then get some ethers using faucets

Error: Expected private key to be an Uint8Array with length 32

Following the guide from https://ethereum.org/vi/developers/tutorials/hello-world-smart-contract/
I am getting this error when trying to run my deploy script. I am absolutely lost as to why this is not working as I have copied every piece of code directly from the guide.
My hardhat.config.js
require('dotenv').config();
require("#nomiclabs/hardhat-ethers");
const { API_URL, PRIVATE_KEY } = process.env;
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.7.3",
defaultNetwork: "ropsten",
networks: {
hardhat: {},
ropsten: {
url: API_URL,
accounts: [`0x${PRIVATE_KEY}`]
}
},
}
My deploy.js
async function main() {
const HelloWorld = await ethers.getContractFactory("HelloWorld");
// Start deployment, returning a promise that resolves to a contract object
const hello_world = await HelloWorld.deploy("Hello World!");
console.log("Contract deployed to address:", hello_world.address);}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
my .env
API_URL = "https://eth-ropsten.alchemyapi.io/v2/[REDACTED]"
PRIVATE_KEY = "[REDACTED]". // my private key goes here, not including the 0x
It compiles fine but gives me the error when I use the command
npx hardhat run scripts/deploy.js --network ropsten
You don't need the 0x in the private key, just put the exact key you got from metamask :)
https://github.com/ethereumjs/ethereumjs-tx
As per usage example we need to add chain name while creating Transaction.
const tx = new Tx(txObject , { chain: 'rinkeby' })

Sign a transaction to smart contract from migrations

I want to call smart contract method via sendTransaction from one of migrations. I'm using Truffle. During this migration I create a new wallet with a mnemonic.
const seed = bip39.mnemonicToSeed(mnemonic)
const hdk = hdkey.fromMasterSeed(seed)
const addrNode = hdk.derivePath("m/44'/60'/0'/0/0")
const walletAddr = wallet.getAddressString()
await someFactory.createProfile.sendTransaction(detailsHash, { from: walletAddr })
During the transaction I receive an exception
Returned error: sender account not recognized
How to send transaction with a newly created from a mnemonic profile?
You can set your provider to your contract instance then
const HDWalletProvider = require("#truffle/hdwallet-provider");
const mnemonic = "Your mnemonic"; //
module.exports = function(deployer) {
deployer.deploy(SomeFactory).then(someFactory => {
provider = new HDWalletProvider(mnemonic, "YourURL", 0);
someFactory.contract.setProvider(provider);
someFactory.createProfile.sendTransaction(detailsHash, { from:provider.addresses[0] })
});
};

Truffle contract works with Ganache but not on Testnet

I was able to create and deploy a contract locally to Ganache using Truffle. I could set and get a value successfully as well. I deployed this contract to both Rinkeby and Ropsten and was able to call the get function, but the set function failed with the error:
Error: Invalid JSON RPC response: ""
Using MyEtherWallet/MetaMask, I was able to call both get and set functions successfully on Rinkeby. Is there anything that jumps out as to why it would work locally, but not on the testnets?
Set function:
ProcessHistoryStoreInstance.setStore(
uuid,
attribute,
value,
{from: account}
).then(function(result) {
console.log('TX Hash: ' + result.tx);
response.status(200).json({success: true, msg: result.tx});
}, function(error) {
console.log('Error setting attribute: ' + error);
response.status(500).json({success: false, msg: error});
});
Get function:
ProcessHistoryStoreInstance.getFromStore.call(uuid, attribute).then(function(result) {
console.log('Result: ' + result);
response.status(200).json({success: true, msg: result});
}, function(error) {
console.log('Error getting attribute: ' + error);
response.status(500).json({success: false, msg: error});
});
Solidity contract:
pragma solidity^0.4.11;
import "./AttributeStore.sol";
contract ProcessHistoryStore {
AttributeStore.Data store;
function getFromStore(bytes32 _UUID, string _attrName) public constant returns (uint) {
return AttributeStore.getAttribute(store, _UUID, _attrName);
}
function setStore(bytes32 _UUID, string _attrName, uint _attrVal) public {
AttributeStore.setAttribute(store, _UUID, _attrName, _attrVal);
}
}
Figured it out. I was using web3 to set my provider instead of truffle-hdwallet-provider.
web3 (wasn't working):
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:7545"));
}
truffle-hdwallet-provider (now works):
new HDWalletProvider(mnemonic, "http://127.0.0.1:7545");