I created an array of each address and amount of all users who have previously deposited a certain amount of ETH, then used the 'transfer' function (within : retireMyCoins()) to retrieve the amount and address of the user who is using the contract from the list. The user can then withdraw his ETH.
When compiling the contract, in the last function "retireMyCoins" the console returns the following error: 'Undeclared identifier'.
pragma solidity ^0.4.17;
contract myVault {
address[] public users;
uint[] public totalDeposited;
function sendToken(address user, uint amount) public payable {
require(msg.value > 0.001 ether);
user = msg.sender;
amount = msg.value;
users.push(msg.sender);
totalDeposited.push(msg.value);
}
function getUsers() public view returns (address[]) {
return users;
}
function getAmount() public view returns (uint[]) {
return totalDeposited;
}
function retireMyCoins() public {
require(user[msg.sender]);
require(amount[msg.value]);
user.transfer(this.amount);
}
}
You have to create amount as a store variable in the beginning of your contract. Also, to make it work as you expect, you should map the balance of each user, like the following:
...
mapping( address => uint ) balances;
function sendToken(address user, uint amount) public payable {
balances[msg.sender] = amount;
...
}
and then you can allow the withdrawal:
function retireMyCoins() public {
uint amountToWithdraw = balances[msg.sender]
balances[msg.sender] = 0;
msg.sender.transfer(amountToWithdraw);
}
Remember to zero the user balance before the transfer as above.
Related
I am practising this tutorial in Remix IDE - https://www.youtube.com/watch?v=_aXumgdpnPU
I saw in the Chainlink documentation that their Randomness VRF code has been changed since the development of the video.
I started replacing the parts and trying to deploy the class via Remix but it gives an error which I am not sure how to fix.
Would you be able to check what I have as code and I'll send a screenshot of the error?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "#chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
import "#chainlink/contracts/src/v0.8/VRFV2WrapperConsumerBase.sol";
contract Lottery is
VRFV2WrapperConsumerBase,
ConfirmedOwner
{
address public owner;
address payable[] public players;
uint public lotteryId;
mapping (uint => address payable) public lotteryHistory;
event RequestSent(uint256 requestId, uint32 numWords);
event RequestFulfilled(
uint256 requestId,
uint256[] randomWords,
uint256 payment
);
struct RequestStatus {
uint256 paid; // amount paid in link
bool fulfilled; // whether the request has been successfully fulfilled
uint256[] randomWords;
}
mapping(uint256 => RequestStatus)
public s_requests; /* requestId --> requestStatus */
// past requests Id.
uint256[] public requestIds;
uint256 public lastRequestId;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 callbackGasLimit = 100000;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;
// For this example, retrieve 2 random values in one request.
// Cannot exceed VRFV2Wrapper.getConfig().maxNumWords.
uint32 numWords = 2;
// Address LINK - hardcoded for Goerli
address linkAddress = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
// address WRAPPER - hardcoded for Goerli
address wrapperAddress = 0x708701a1DfF4f478de54383E49a627eD4852C816;
constructor()
ConfirmedOwner(msg.sender)
VRFV2WrapperConsumerBase(linkAddress, wrapperAddress)
{
owner = msg.sender;
lotteryId = 1;
}
function requestRandomWords()
external
onlyOwner
returns (uint256 requestId)
{
requestId = requestRandomness(
callbackGasLimit,
requestConfirmations,
numWords
);
s_requests[requestId] = RequestStatus({
paid: VRF_V2_WRAPPER.calculateRequestPrice(callbackGasLimit),
randomWords: new uint256[](0),
fulfilled: false
});
requestIds.push(requestId);
lastRequestId = requestId;
emit RequestSent(requestId, numWords);
return requestId;
}
function fulfillRandomWords(
uint256 _requestId,
uint256[] memory _randomWords
) internal override {
require(s_requests[_requestId].paid > 0, "request not found");
s_requests[_requestId].fulfilled = true;
s_requests[_requestId].randomWords = _randomWords;
emit RequestFulfilled(
_requestId,
_randomWords,
s_requests[_requestId].paid
);
payWinner();
}
function getRequestStatus(
uint256 _requestId
)
external
view
returns (uint256 paid, bool fulfilled, uint256[] memory randomWords)
{
require(s_requests[_requestId].paid > 0, "request not found");
RequestStatus memory request = s_requests[_requestId];
return (request.paid, request.fulfilled, request.randomWords);
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(linkAddress);
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}
function getWinnerByLottery(uint lottery) public view returns (address payable) {
return lotteryHistory[lottery];
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
function enter() public payable {
require(msg.value > .01 ether);
// address of player entering lottery
players.push(payable(msg.sender));
}
//function getRandomNumber() public view returns (uint) {
//return uint(keccak256(abi.encodePacked(owner, block.timestamp)));
//}
function pickWinner() public onlyowner {
requestRandomWords;
}
function payWinner() public {
uint index = lastRequestId % players.length;
players[index].transfer(address(this).balance);
lotteryHistory[lotteryId] = players[index];
lotteryId++;
// reset the state of the contract
players = new address payable[](0);
}
modifier onlyowner() {
require(msg.sender == owner);
_;
}
}
enter image description here
I have coded the following to keep track of deposits into a smart contract.
I need to be able to reference individual deposits in future functions.
pragma solidity ^0.8.4;
contract DepositsWithIds {
address owner;
struct Deposit {
uint256 depositAmount;
address depositor;
uint256 counter;
}
constructor() payable {
owner = msg.sender;
}
Deposit[] public activeDeposits;
event DepositMade(address, uint256, uint256);
function deposit() public payable returns (uint256 counter) {
return ++counter;
Deposit memory newDeposit = Deposit(
msg.value,
msg.sender,
counter
);
activeDeposits.push(newDeposit);
emit DepositMade(msg.sender, msg.value, counter);
}
}
Is it a good idea to use the counter as a unique deposit ID?
How would you be able to connect activeDeposits.counter to activeDeposits.depositor when writing the next function?
uint public counter;
mapping(uint = > Deposit) public ids;
function deposit() public payable {
Deposit storage _deposit = ids[_counter];
_deposit.depositAmount = msg.value;
_deposit.depositor = msg.sender;
activeDeposits.push(_deposit);
_counter++;
emit DepositMade(msg.sender, msg.value);
}
You could take the counter out of struct:
struct Deposit {
uint256 depositAmount;
address depositor;
}
You set the counter as top state variable
uint256 counter;
you could have a mapping that maps the counterId to Deposit
mapping(uint156=>Deposti) public idToDeposit;
then get the deposit by id
function getDepositByID(uint id)public view {
idToDeposit[id]
}
you might come across of openzeppelin Counters.sol to use the counter
you install npm i #openzeppelin/contracts, import the ``Counters
import "../node_modules/#openzeppelin/contracts/utils/Counters.sol";
in your contract:
contract Test{
// this means all Counters.Counter types in your contract loaded with the methods of Counters library
using Counters for Counters.Counter;
Counters.Counter private depositIds;
}
I am building a NFT Marketplace
I use 2 smart contracts to :
first, mint the token
then, call setApprovalForAll() to authorize the marketplace contract to transfer the token
strangely, the owner is address(0) when it should be the msg.sender when I created the token last
" The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC721: invalid token ID". "
This the source code of the 2 smart contracts below :
smart contract : NFT
smart contract : NFTMarketplace
Thanks for the help
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "./#openzeppelin/contracts/utils/Counters.sol";
import "./#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "./#openzeppelin/contracts/security/ReentrancyGuard.sol";
contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;
constructor(address marketplaceAddress) ERC721("NFTMarketplace", "NFTM") {
contractAddress = marketplaceAddress;
}
event TokenMinted (
uint256 indexed tokenId,
string tokenURI
);
function createToken(string memory tokenURI) public returns (uint) {
uint256 currentTokenId = _tokenIds.current();
_safeMint(msg.sender, currentTokenId);
_setTokenURI(currentTokenId, tokenURI);
setApprovalForAll(contractAddress, true);
_tokenIds.increment();
emit TokenMinted(currentTokenId, tokenURI);
return currentTokenId;
}
function getCurrentToken() public view returns (uint256) {
return _tokenIds.current();
}
}
contract NFTMarketplace is ReentrancyGuard, ERC721 {
using Counters for Counters.Counter;
//_tokenIds variable has the most recent minted tokenId
//Keeps track of the number of items sold on the marketplace
Counters.Counter private _itemsSold;
//owner is the contract address that created the smart contract
address payable owner;
//The fee charged by the marketplace to be allowed to list an NFT
uint256 listPrice = 0.01 ether;
constructor() ERC721("NFTMarketplace", "NFTM") {}
//The structure to store info about a listed token
struct Token {
uint256 tokenId;
string tokenURI;
address nftContract;
string name;
address payable owner;
uint256 price;
bool isListed;
}
//the event emitted when a token is successfully listed
event TokenListedSuccess (
uint256 indexed tokenId,
address nftContract,
address owner,
uint256 price,
bool isListed
);
//This mapping maps tokenId to token info and is helpful when retrieving details about a tokenId
mapping(uint256 => Token) private idToToken;
function updateListPrice(uint256 _listPrice) public payable {
require(owner == msg.sender, "Only owner can update listing price");
listPrice = _listPrice;
}
//The first time a token is created, it is listed here
// make it payable with money -- add require
function listToken(address nftContract, uint256 currentTokenId, string memory tokenURI, string memory name, uint256 price) public payable {
require(msg.value > 0, "Price must be at least 1 wei");
require(msg.value == listPrice, "Price must be equal to listing price");
idToToken[currentTokenId] = Token(
currentTokenId,
tokenURI,
nftContract,
name,
payable(address(this)),
listPrice,
true
);
emit TokenListedSuccess(
currentTokenId,
nftContract,
msg.sender,
listPrice,
true
);
}
function buyNFT(address nftContract, uint256 itemId) public payable nonReentrant {
uint price = idToToken[itemId].price;
uint tokenId = idToToken[itemId].tokenId;
address seller = ERC721.ownerOf(tokenId);
address buyer = msg.sender;
require(msg.value > 0, "You need to send some ether");
require(buyer != seller,"You already own this nft");
require(msg.value == price, "Please submit the asking price in order to complete the purchase");
idToToken[itemId].isListed = false;
idToToken[itemId].owner = payable(buyer);
payable(seller).transfer(price);
_itemsSold.increment();
IERC721(nftContract).transferFrom(seller, buyer, tokenId);
}
/* ...rest of smart contract */
}
I think you forget to assign "owner" value.
Typically, we set it in constructor.
like
constructor() {
i_owner = msg.sender;
}
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.
I'm trying to set up a basic crowdsale at ethereum testnet and the solidity code I'm using is the basic examples found at
https://ethereum.org/crowdsale#the-code
with steps followed as described in that guide.
The issue first was that the ethereum wallet doesn't accept the code as is to compile due to the first line:
contract token { function transfer(address receiver, uint amount){ } }
Specifically, its function returns a warning of an unused local variable and won't compile. Is there a way around this other than defining empty variables inside the function?
The second issue is after it's deployed with the modification as mentioned above, it works. But when it sends tokens to the wallet that sent the ether, the amount is always locked at 0.00 tokens.
FULL CODE:
pragma solidity ^0.4.2;
contract token { function transfer(address receiver, uint amount){ receiver; amount; } }
contract Crowdsale {
address public beneficiary;
uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price;
token public tokenReward;
mapping(address => uint256) public balanceOf;
bool fundingGoalReached = false;
event GoalReached(address beneficiary, uint amountRaised);
event FundTransfer(address backer, uint amount, bool isContribution);
bool crowdsaleClosed = false;
/* data structure to hold information about campaign contributors */
/* at initialization, setup the owner */
function Crowdsale(
address ifSuccessfulSendTo,
uint fundingGoalInEthers,
uint durationInMinutes,
uint etherCostOfEachToken,
token addressOfTokenUsedAsReward
) {
beneficiary = ifSuccessfulSendTo;
fundingGoal = fundingGoalInEthers * 1 ether;
deadline = now + durationInMinutes * 1 minutes;
price = etherCostOfEachToken * 1 ether;
tokenReward = token(addressOfTokenUsedAsReward);
}
/* The function without a name is the default function that is called whenever anyone sends funds to a contract */
function () payable {
if (crowdsaleClosed) throw;
uint amount = msg.value;
balanceOf[msg.sender] = amount;
amountRaised += amount;
tokenReward.transfer(msg.sender, amount / price);
FundTransfer(msg.sender, amount, true);
}
modifier afterDeadline() { if (now >= deadline) _; }
/* checks if the goal or time limit has been reached and ends the campaign */
function checkGoalReached() afterDeadline {
if (amountRaised >= fundingGoal){
fundingGoalReached = true;
GoalReached(beneficiary, amountRaised);
}
crowdsaleClosed = true;
}
function safeWithdrawal() afterDeadline {
if (!fundingGoalReached) {
uint amount = balanceOf[msg.sender];
balanceOf[msg.sender] = 0;
if (amount > 0) {
if (msg.sender.send(amount)) {
FundTransfer(msg.sender, amount, false);
} else {
balanceOf[msg.sender] = amount;
}
}
}
if (fundingGoalReached && beneficiary == msg.sender) {
if (beneficiary.send(amountRaised)) {
FundTransfer(beneficiary, amountRaised, false);
} else {
//If we fail to send the funds to beneficiary, unlock funders balance
fundingGoalReached = false;
}
}
}
}
EDIT: I forgot to mention the steps leading to this point aka Token creation / shareholder association work with the code as is provided in the guide.
I came across the same issue. I solved it by actually defining the transfer function as the example from ethereum.org provides an empty one.
I replaced this:
contract token { function transfer(address receiver, uint amount){ } }
By this:
contract token {
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address _to, uint256 _value) {
if (_to == 0x0) throw;
Transfer(msg.sender, _to, _value);
}
}
For your second problem, do you actually have a confirmation that the token created were actually sent? How many ether did you send to the crowd-sale contract? It seems that you are using two decimals for your token and if you defined "Ether cost of each token" of 5 like in the example, you shouldn't send less than 0.05 ether to the crowd-sale contract.
Hope it helps!