Ethereum lottery smart contract with the following conditions - ethereum

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!

Related

Using the counter as ID - is it a good idea in a smart contract?

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;
}

enable 2 users to use my contract at the same time with different states in Solidity

I'm new in solidity, and I was trying to create a simple purchase contract between 2 users, with different states as below:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract purchase {
uint public value;
struct Users {
address payable seller;
address payable buyer;
}
Users public users;
uint256 public contractID;
enum State{Created, Locked, Release, Inactive}
State public state;
constructor() payable {
users.seller = payable(msg.sender);
value = msg.value / 2;
}
///The function can't be called at the current state.
error InvalidState();
///Only buyer/buyer can call this function
error Onlybuyer();
///Only Seller can call this function
error OnlySeller();
modifier inState(State state_){
if (state != state_) {
revert InvalidState();
}
_;
}
modifier onlybuyer(){
if (msg.sender != users.buyer) {
revert Onlybuyer();
}
_;
}
modifier onlySeller(){
if (msg.sender != users.seller) {
revert OnlySeller();
}
_;
}
mapping(uint => Users) public contractUsers;
mapping(uint => State) public contractState;
function confirmPurchase() external inState(State.Created) payable {
contractID ++;
require(msg.value == (2*value), "Please send in 2X the purchase amount");
users.buyer = payable(msg.sender);
state = State.Locked;
}
function confirmRecieved() external onlybuyer inState(State.Locked) {
state = State.Release;
users.buyer.transfer(value);
}
function paySeller() external onlySeller inState(State.Release){
state = State.Inactive;
users.seller.transfer(3 * value);
}
function abort() external onlySeller inState(State.Created){
state = State.Inactive;
users.seller.transfer(address(this).balance);
}
}
I would like to ask, how I can enable 2 sellers to use the contract at the same time with different states? or how I enable many users to use my contract at the same time?
for example:let's say we have seller 1, buyer 1 with price 2 ETH at state 1.
at the same time seller 2, buyer 2 with price 3 ETH at state 0.
each one of them is using the contract at the same time and they can view their contract details using the contract ID. how I can do that?
I thought about creating a function to set the state to initial state 0,then a new user can use the contract, and retrieve their data from the mapping using contract ID. but I'm not sure if this is the best practice. Can anyone advice please!
Thank you in advance.

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.

How can resolve 'Undeclared identifier' during withdraw from smart contract?

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.

Ethereum, crowdsale returns 0.00 tokens to the wallet

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!