Exceeds block gas limit when deploy the smart contract local node - smartcontracts

I have been working on Smart Contract development with the local node running. It worked two weeks ago, and I got an error when I tried to deploy the same contract to the same local node. The error exceeds block gas limit. I have a high gas in the truffle.js, but still, I am getting the same error. Why is that?
pragma solidity ^0.4.8;
contract Verifier {
bool public isSignedW = false;
address public theAddress;
function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
theAddress= ecrecover(msgHash, v, r, s);
return theAddress;
}
function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
isSignedW= ecrecover(msgHash, v, r, s) == _addr;
return isSignedW;
}
}

It is difficult to say when we can't see your Smart Contract and how you deploy it. Maybe can you provide more information ?
Can we have the information of the block in which your contract is mined ?
web3.eth.getBlock(BLOCK_NUMBER, function(error, result){
if(!error)
console.log(JSON.stringify(result));
else
console.error(error);
})
One possibility is the gas limit became too low to be able to mine your contract. Because the gas limit in a private network decrease with each mined block to the limit of 4.7 Million gas, if you use the default parameters.

Related

I need help to customize my smart contract lottery project

Things that I need to add as functions:
I want to integrate a management fee of 1% of the total pot. Execution: The management fee (going to contract owner) will be deducted to the total prize before the remaining 99% amount will be sent to the lottery winner. I need to add it to the selectWinner function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Lottery{
address public manager;
//global dynamic array for participants.
address payable[] public participants;
constructor()
{
//msg.sender is a global variable used to store contract address to manager.
manager=msg.sender;
}
//receive function only creates once in a smart comtract.
//this function help to transfer the ether.
//always use with external keyword and payable.
receive() external payable{
//require is used as a if statement. it check if ether value is 2 then only run below code.
require(msg.value==0.02 ether);
participants.push(payable(msg.sender));
}
function getBalance() public view returns(uint){
//only manager check the total balance.
require(msg.sender==manager);
return address(this).balance;
}
//this random function will genrate random value and from participant array and then return to the winnerFunction.
function random() public view returns(uint)
{
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, participants.length)));
}
//this function decide the winner randomly.
function selectWinner() public{
require(msg.sender==manager);
require(participants.length>=3);
uint r=random(); //call random function.
uint index=r % participants.length; //for making random function value in array length range.
address payable winner;
winner=participants[index];
winner.transfer(getBalance());
participants=new address payable[](0);
}
}
I need help to do it. Thank you.
I think something like this should work. I don't have time to test the function right now, but will edit this answer later today. Hope it helps you at the moment.
function selectWinner() public {
require(msg.sender==manager);
require(participants.length>=3);
uint r=random(); //call random function.
uint index=r % participants.length; //for making random function value in array length range.
address payable winner;
winner=participants[index];
uint balance = getBalance(); // balance is in wei
uint fee = balance * 0.01 ether; // 1% in wei
uint amountToTransfer = balance - fee;
winner.transfer(amountToTransfer);
_withdrawFee(fee); // transfer fee to manager
participants=new address payable[](0);
}
function _withdrawFee(uint feeAmount) payable private {
msg.sender.transfer(feeAmount);
}

Interaction with Aave V3 contract getUserAccountData

I'm trying to make a normal request to another contract from mine.
function getUserAccountData(address _miskin) internal view returns (AaveUserData memory) {
ILendingPool lendingPool = ILendingPool(aaveLendingPoolAddress);
(uint256 totalCollateralETH, uint256 totalDebtETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor) = lendingPool.getUserAccountData(_miskin);
return AaveUserData(totalCollateralETH, totalDebtETH, availableBorrowsETH, currentLiquidationThreshold, ltv, healthFactor);
}
This is pretty basic and on the line lendingPool.getUserAccountData(_miskin); I get an error: function returned an unexpected amount of data.
I don't understand why I have the correct contract address also.
This is my interface
interface ILendingPool {
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
I someone have any idea what can I do I would love thank you.
A struct is decoded differently than the list of its arguments. In particular it has extra bytes at the beginning.
So your code is expecting a output like (uint256, ..., uint256) but getting a AaveUserData struct. I'm not sure how the output of your internal function getUserAccountData is used, but I guess you're reading it using the Aave ILendingPool interface, which doesn't return a AaveUserData struct.
It's a bit of a dum answer but I forked the wrong network so whe. I tried to call the address with the good polygon address I got an error. So the solution: Fork the good network.

Ethereum lottery smart contract reverts due to insufficient funds. Where does my code consumes that much gas?

I am experimenting with solidity and I faced an issue for what I could not find a solution.
The program should let addresses buy ticket at a preset price, and the owner can start the "roll the dice" function which randomly selects the winner and transfer the funds to that address.
I beleive that this program would be easier with mapping instead of array, but getting experience with array was the main purpose of this program.
The error happens when the user calls buyTicket function. Based on the response I beleive the contract comsumes too much gas. Can someone tell me why it doesnt work? I appreciate any other helping comment regarding the rest of the code:)
Thanks in advance!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Lottery {
constructor () {
owner = msg.sender;
}
address[] public Players;
address private owner;
uint public ticketPrice;
uint public price;
uint public nonce;
uint public variations;
address payable winner;
bool hasTicketAnswer;
event Winner(address _winner);
event PriceSet(uint _setPrice);
event TicketBought();
function setTicketPrice(uint _ticketPrice) public {
require(msg.sender == owner, "Only Owner...");
ticketPrice = _ticketPrice;
emit PriceSet(_ticketPrice);
}
function hasTicket(address _sender) private returns(bool) {
hasTicketAnswer = false;
for (uint i = 0; i < Players.length; i++) {
if (Players[i] == _sender) hasTicketAnswer = true;
}
return hasTicketAnswer;
}
function buyTicket() external payable {
require(ticketPrice > 0, "Price did not set, be patient...");
require(hasTicket(msg.sender) == false, "You cannot have two tickets...");
require(msg.sender.balance <= ticketPrice, "Insufficient funds...");
payable(address(this)).transfer(ticketPrice);
Players.push(address(msg.sender));
price += msg.value;
emit TicketBought();
}
function checkBalance() public view returns(uint) {
return address(this).balance;
}
function rollTheDice() public payable {
variations = Players.length;
winner = payable(Players[uint(keccak256(abi.encodePacked(msg.sender, nonce, block.timestamp))) % variations]);
winner.transfer(price);
emit Winner(winner);
}
receive () external payable {
}
}
Besides probably finding the problem, I've read some things that I'd like to comment on.
Your problem
The reason why you're getting the "Insufficient funds" error is because the condition is returning false. You're asking the msg.sender balance to be less than or equal (<=) to ticketPrice, when it should be more than or equal (>=).
Let's say Alice has a balance of 0.05 ETH and interacts with the contract whose ticket price is 0.001 ETH...
require(0.05 ETH <= 0.001 ETH) // Reverting...
Observations
I'm curious if you're intentionally coding the buyTicket function in that way. What it actually does is checking if the msg.sender has enough ETH to buy a ticket in its wallet, which doesn't mean that the user is effectively sending ETH in the transaction (the amount of wei sent in the transaction can be checked with msg.value, you can read more about it here).
My last observation is the payable(address(this)).transfer(ticketPrice) line of code, because it's not necessary to do so, once a payable function receives ETH, it is saved into the contract... In that line you're just making the Bob's contract to send ETH to the Bob's contract, which just wastes gas without reason
I hope I've helped with you and if I wasn't completely clear in any thing I've said don't doubt in asking me

Requesting data with Chainlink, response not what expected

I've been trying to integrate Chainlink into my contract, managed to get the random number thingy working, but the API call doesn't work for me. Here's what I got:
contract ValorantCards is Ownable, ERC1155, VRFConsumerBase, ChainlinkClient {
using Chainlink for Chainlink.Request;
address private linkToken;
// Chainlink VRF
bytes32 private keyHash;
uint256 private vrfFee;
uint256 public randomResult;
// Chainlink API calls
address private oracle;
bytes32 private jobId;
uint256 private oracleFee;
uint256 public playerLevel;
constructor(
address _vrfCoordinator,
address _linkToken,
bytes32 _keyHash,
address _oracle,
bytes32 _jobId,
uint256 _oracleFee
) ERC1155("") VRFConsumerBase(_vrfCoordinator, _linkToken) {
setPublicChainlinkToken();
linkToken = _linkToken;
keyHash = _keyHash;
vrfFee = 0.1 * 10**18;
oracle = _oracle;
jobId = _jobId;
oracleFee = _oracleFee;
}
function requestUserLevel() public returns (bytes32 requestId) {
Chainlink.Request memory request = buildChainlinkRequest(
jobId,
address(this),
this.fulfill.selector
);
request.add(
"get",
"https://api.henrikdev.xyz/valorant/v1/account/draven/2023"
);
request.add("path", "data.account_level");
return sendChainlinkRequestTo(oracle, request, oracleFee);
}
function fulfill(bytes32 _requestId, uint256 _level)
public
recordChainlinkFulfillment(_requestId)
{
playerLevel = _level;
}
I'm deploying from hardhat, with the following parameters (ignoring the ones for VRF since that's working):
Oracle: 0x9C0383DE842A3A0f403b0021F6F85756524d5599
JobId: 0x3766623533366265383635623433333662323766633130313437633139336337
OracleFee: 0.1 * 10**18
The function runs fine, the transaction doesn't revert or anything, but when I check "playerLevel", it's always just 0
Looking at the Etherscan activity, it looks like the node you are using may be inactive. Try this node and jobId:
Oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
JobId = "d5270d1c311941d0b08bead21fea7747";
These were taken from the Chainlink Official Docs.
To check to see if a node may be inactive or not, check out the oracle address in a block explorer. You can see here that the original node you tried to use hasn't posted a transaction in awhile.
If a node is inactive you will need to find a new one or host one yourself. To find more nodes and jobs, you can check market.link or use the one found in the docs as mentioned earlier.

Is there a way to store addresses in the solidity contract to authorize only those addresses to do transactions?

I'm starting with contracts in solidity and a question arose, is there any way I can store addresses in the wallet so that only these stored can make the withdrawal of coins that I make available? Let me explain better, I want to airdrop for 1 month for example and after this period the people who got my coins can withdraw from my contract, but so that only the people who complied with the airdrop rules. I want to do this so they pay transaction fees. But I want only addresses authorized by the owner of the contract to be able to withdraw the currency
Another way of doing this, in order to avoid gas, is to either use merkle trees or signatures. I have implemented signatures in two NFT projects.
Basically, for every address you wish to whitelist, you sign a message offchain, by using a wallet in your possession (it can be empty, you only need to sign messages).
Example call for signing via JavaScript (by using the web3js lib):
web3.eth.accounts.sign(message, privateKey);
By using the privateKey, this allows you to sign multiple messages at once (without having to confirm in MetaMask. It is clear that: please keep that private key as safe as possible! Only execute this code locally on your machine! Do not store the privateKey in any text file, especially not in the project folder, that might get synched to github!
The other way of doing it via MetaMask:
web3.eth.personal.sign(message, from);
(where "from" is the address of the signer).
On the contract side, there are some functions that can be used to retrieve the signer of a message, by reconstructing the message and passing the signature you have generated.
Some reference code:
// used to keep track of issuer addresses, that can issue whitelists
mapping(address => bool) internal issuers;
// builds a prefixed hash to mimic the behavior of eth_sign.
function prefixed(bytes32 hash) internal pure returns(bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
// get the signer address by message and signature
function recoverSigner(bytes32 _message, bytes memory sig) internal pure returns(address){
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(sig);
return ecrecover(_message, v, r, s);
}
function signerIsIssuer(bytes memory message, bytes memory _sig, uint256 nonce) public view returns(bool){
// check the issuer
if (!issuers[recoverSigner(message, sig)]) {
return false;
} else {
return true;
}
}
// splits the signature into its components
function splitSignature(bytes memory sig) internal pure returns(uint8, bytes32, bytes32){
require(sig.length == 65);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
// first 32 bytes, after the length prefix
r:= mload(add(sig, 32))
// second 32 bytes
s:= mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v:= byte(0, mload(add(sig, 96)))
}
return (v, r, s);
}
// this has to hash the same parameters as on the offchain side
// do not reuse nonces
function hashMessage(address authorizedWallet, uint256 nonce) public returns(bytes memory){
// create the message hash
bytes32 message = prefixed(keccak256(abi.encodePacked(authorizedWallet, nonce)));
if (signerIsIssuer(message, _sig, _nonce)){
// authorizedWallet really is authorized by signature
}
}
If you want to be able to remove authorization, then you either need to invalidate the nonce, or work with expiration timestamps or keep an address blacklist. Please note, that once a signature is emitted, if the contract has no ways to be told, that that signature is not valid anymore, the wallet address will be authorized forever.
Hope this helps!
code:
contract test{
address owner;
mapping(address=>bool) authorizedAddresses;
mapping(address=>bool) isRegistered;
mapping(uint256=>address) users;
uint256 userCounter;
constructor(){
owner = msg.sender;
}
modifier isOwner(){
require(msg.sender == owner, "Access denied!");
_;
}
function changeOwner(address _to) public isOwner{
owner = _to;
}
function authorizeAddress(address _address) public isOwner{
if(isRegistered[_address]){
authorizedAddresses[_address] = true;
}else{
users[userCounter] = _address;
isRegistered[_address] = true;
authorizedAddresses[_address] = true;
userCounter ++;
}
}
function unauthorizeAddress(address _address) public isOwner{
require(authorizedAddresses[_address], "User is not authorized already");
authorizedAddresses[_address] = false;
}
modifier isAuthorizedAddress(){
require(authorizedAddresses[_address], "You are not authorized to call this function");
_;
}
I should note I did not test this code and may throw error, so if it throws any error let me know and modify it or you can do it let me know how to fix it and edit the code for others.
If you did not understand any part, simply ask to describe :)
Best regards
You can use ERC20 token standart. Just define allowance for those addresses who complied with the airdrop rules.
As others wrote, you can store addresses in a mapping like mapping(address=>bool) authorizedAddresses;
However, it is expensive and inefficient to store hundreds of addresses on the blockchain. Think about that, probably you upload a bunch of addresses you don't even need to, because people will forget that they can get the airdrop and they won't even claim it.
A better approach is to give them signed coupons. When they claim the airdrop on your website, the transaction submits a coupon and your contract will verify if the coupon is:
signed by you
belongs to the sender address
allowed to claim the amount
It all happens in the background, so users won't notice anything.
Generate coupons in JS:
const {
keccak256,
toBuffer,
ecsign,
bufferToHex
} = require("ethereumjs-util")
const { ethers } = require('ethers')
const PRIV_KEY = "YOUR_SIGNER_PRIVATE_KEY"
//utils
function generateHashBuffer(typesArray, valueArray) {
return keccak256(
toBuffer(ethers.utils.defaultAbiCoder.encode(typesArray,
valueArray))
)
}
function createCoupon(hash, signerPvtKey) {
return ecsign(hash, signerPvtKey)
}
function fromHexString(hexString) {
return Uint8Array.from(Buffer.from(hexString, 'hex'))
}
function serializeCoupon(coupon) {
return {
r: bufferToHex(coupon.r),
s: bufferToHex(coupon.s),
v: coupon.v,
}
}
//generate coupon
function generate(claimAmount, address) {
const userAddress = ethers.utils.getAddress(address) // get checksum-correct address
const hashBuffer = generateHashBuffer(
["uint256", "address"],
[claimAmount, userAddress]
)
const coupon = createCoupon(hashBuffer, fromHexString(PRIV_KEY))
console.log({
address,
claimAmount,
coupon: serializeCoupon(coupon)
})
}
Now you have the coupon, you can build an API, so when the user click Claim on your website, he can submit the amount and the signature to the blockchain in the claim transaction.
Verify signature in your contract:
contract Airdrop is
Ownable,
ReentrancyGuard
{
address private COUPON_SIGNER = 0xYOUR_SIGNER_ADDRESS;
mapping(address => bool) public CLAIMED_ADDRESSES;
struct Coupon {
bytes32 r;
bytes32 s;
uint8 v;
}
// check that the coupon sent was signed by the admin signer address
function _isVerifiedCoupon(bytes32 digest, Coupon memory coupon)
internal
view
returns (bool)
{
address signer = ecrecover(digest, coupon.v, coupon.r, coupon.s);
require(signer != address(0), "ECDSA: Invalid whitelist signature.");
return signer == COUPON_SIGNER;
}
// Claim Airdrop
function claim(uint256 amountToClaim, Coupon memory coupon) external nonReentrant {
require(
CLAIMED_ADDRESSES[msg.sender] == false,
"This address already claimed a refund."
);
require(
address(this).balance >= amountToClaim,
"Contract balance is too low."
);
bytes32 digest = keccak256(abi.encode(amountToClaim, msg.sender));
require(
_isVerifiedCoupon(digest, coupon),
"Unexcepted error: unable to verify coupon."
);
CLAIMED_ADDRESSES[msg.sender] = true;
payable(msg.sender).transfer(amountToClaim); // Send ETH
}
}
PLEASE PLEASE don't just copy this code: TEST, TEST, and TEST. Always write unit tests.