I want to store unique addresses in the array and then increment the count. But I am not able to do it. The count variable is not incremented and returns 0. Also redundant addresses are stored in the array.
Can you please help?
function placeBid() public payable notOwner afterStart beforeEnd returns(bool){
require(auctionState == State.Running);
uint currentBid = 0;
if(totalBidder>0)
{
currentBid = bids[msg.sender] + msg.value;
require(currentBid > highestBindingBid);
}
else{
require(msg.value > startBid && msg.value > highestBindingBid);
currentBid = msg.value;
}
bids[msg.sender] = currentBid;
for(uint i=0; i<bidders.length; i++){
if(msg.sender!=bidders[i])
bidders.push(payable(msg.sender));
totalBidder++;
}
}
highestBindingBid = currentBid;
highestBidder = payable(msg.sender);
return true;
}
An easy (and cheaper compared to your snippet) way to push only unique items to a storage array is to duplicate the values in a mapping, and then validate against the mapping.
pragma solidity ^0.8;
contract MyContract {
address payable[] public bidders;
mapping (address => bool) isBidder; // default `false`
// only add `msg.sender` to `bidders` if it's not there yet
function placeBid() public {
// check against the mapping
if (isBidder[msg.sender] == false) {
// push the unique item to the array
bidders.push(payable(msg.sender));
// don't forget to set the mapping value as well
isBidder[msg.sender] = true;
}
}
}
When I am compiling with truffle it is giving me this error
I got this error after adding payable
prior to that it was
winners[j].transfer(betwa*(10000+(LoserBet*10000/WinnerBet))/10000);
I had to add it because I was getting another error
Which was
TypeError: "send" and "transfer" are only available for objects of type "address payable", not "address".
My Complete Contract :
pragma solidity ^0.5.16;
contract Betting {
address public owner;
uint256 public minimumBet;
uint256 public totalBetsOne;
uint256 public totalBetsTwo;
address[] public players;
struct Player {
uint256 amountBet;
uint16 teamSelected;
}
// The address of the player and => the user info
mapping(address => Player) public playerInfo;
function() external payable {}
constructor() public {
owner = msg.sender;
minimumBet = 100000000000000;
}
function kill() public {
if(msg.sender == owner) selfdestruct(msg.sender);
}
function checkPlayerExists(address player) public view returns(bool){
for(uint256 i = 0; i < players.length; i++){
if(players[i] == player) return true;
}
return false;
}
function bet(uint8 _teamSelected) public payable {
//The first require is used to check if the player already exist
require(!checkPlayerExists(msg.sender));
//The second one is used to see if the value sended by the player is
//Higher than the minimum value
require(msg.value >= minimumBet);
//We set the player informations : amount of the bet and selected team
playerInfo[msg.sender].amountBet = msg.value;
playerInfo[msg.sender].teamSelected = _teamSelected;
//then we add the address of the player to the players array
players.push(msg.sender);
//at the end, we increment the stakes of the team selected with the player bet
if ( _teamSelected == 1){
totalBetsOne += msg.value;
}
else{
totalBetsTwo += msg.value;
}
}
// Generates a number between 1 and 10 that will be the winner
function distributePrizes(uint16 teamWinner) public {
address[1000] memory winners;
//We have to create a temporary in memory array with fixed size
//Let's choose 1000
uint256 count = 0; // This is the count for the array of winners
uint256 LoserBet = 0; //This will take the value of all losers bet
uint256 WinnerBet = 0; //This will take the value of all winners bet
address playerAddress;
//We loop through the player array to check who selected the winner team
for(uint256 i = 0; i < players.length; i++){
playerAddress = players[i];
//If the player selected the winner team
//We add his address to the winners array
if(playerInfo[playerAddress].teamSelected == teamWinner){
winners[count] = playerAddress;
count++;
}
}
//We define which bet sum is the Loser one and which one is the winner
if ( teamWinner == 1){
LoserBet = totalBetsTwo;
WinnerBet = totalBetsOne;
}
else{
LoserBet = totalBetsOne;
WinnerBet = totalBetsTwo;
}
//We loop through the array of winners, to give ethers to the winners
for(uint256 j = 0; j < count; j++){
// Check that the address in this fixed array is not empty
if(winners[j] != address(0)){
address add = winners[j];
uint256 betwa = playerInfo[add].amountBet;
//Transfer the money to the user
payable(winners[j]).transfer( (betwa*(10000+(LoserBet*10000/WinnerBet)))/10000 );
}
}
delete playerInfo[playerAddress]; // Delete all the players
players.length = 0; // Delete all the players array
LoserBet = 0; //reinitialize the bets
WinnerBet = 0;
totalBetsOne = 0;
totalBetsTwo = 0;
}
function AmountOne() public view returns(uint256){
return totalBetsOne;
}
function AmountTwo() public view returns(uint256){
return totalBetsTwo;
}
}
What I have tried is making the address payable in this function but It is not working I have tried to replace memory with payable but still it isn't working
My versions
Truffle v5.4.18 (core: 5.4.18)
Solidity v0.5.16 (solc-js)
Node v14.15.1
Web3.js v1.5.3
The payable() conversion from address to address payable was introduced in Solidity 0.6.
Source: https://docs.soliditylang.org/en/latest/060-breaking-changes.html#new-features
Since your contract is using (deprecated) version 0.5.16, it doesn't allow this conversion. So you need to define the winners array already as address payable:
// added `payable`
address payable[1000] memory winners;
Then you'll be able to use the .transfer() method of the address payable type:
// `winners[j]` is payable
winners[j].transfer(...);
source code:https://github.com/laronlineworld/bettingMatch/blob/main/bettingMatch.sol
How to open and close bet per match
function bet(uint16 _matchSelected, uint16 _resultSelected) public payable {
//Check if the player already exist
// require(!checkIfPlayerExists(msg.sender));
//Check if the value sended by the player is higher than the min value
require(msg.value >= minimumBet);
//Set the player informations : amount of the bet, match and result selected
playerInfo[msg.sender].amountBet = msg.value;
playerInfo[msg.sender].matchSelected = _matchSelected;
playerInfo[msg.sender].resultSelected = _resultSelected;
//Add the address of the player to the players array
players.push(msg.sender);
//Finally increment the stakes of the team selected with the player bet
if ( _resultSelected == 1){
totalBetHome[_matchSelected] += msg.value;
}
else if( _resultSelected == 2){
totalBetAway[_matchSelected] += msg.value;
}
else{
totalBetDraw[_matchSelected] += msg.value;
}
}
This is the code for opening the betting
/* Function to enable betting */
function beginVotingPeriod() public onlyOwner returns(bool) {
bettingActive = true;
return true;
}
how about opening the bet per match?
also closing the bet per match
/* Function to close voting and handle payout. Can only be called by the owner. */
function closeVoting() public onlyOwner returns (bool) {
// Close the betting period
bettingActive = false;
return true;
}
The linked code recognizes a match as index of these arrays: totalBetHome, totalBetAway and totalBetDraw.
You can add a mapping where the key is the match ID, and the value is a flag signalizing whether there's a betting enabled on the match or not.
// default value for each is `false`
mapping (uint256 => bool) isMatchEnabled;
function enableBetting(uint256 _matchId) external onlyOwner {
isBettingEnabled[_matchId] = true;
}
function disableBetting(uint256 _matchId) external onlyOwner {
isBettingEnabled[_matchId] = false;
}
Then you can amend the bet() function - add a condition requiring betting for this match to be enabled.
function bet(uint16 _matchSelected, uint16 _resultSelected) public payable {
require(isBettingEnabled[_matchSelected] == true);
// rest of your code
}
Note: Solidity v0.4.2 that you're using in the linked code, is few years old and has few security issues. The current version (August 2021) is 0.8.7. Consider upgrading to the latest version.
I am trying to return a list of addresses by declaring an array and pushing to it in a for loop. However, Solidity doesn't like when I try to return a dynamic array.
function listMyPromises() public returns(uint256[] memory ){ //lists all my past promises
uint256[] memory List;
for(uint i=0; i<table.length; i++){
if(table[i].userAddress==msg.sender){
List.push(uint256(table[i].friendAddress));
}
}
return List;
}
Solidity is not allowing me to return a array stating that
TypeError: Data location must be "memory" or "calldata" for return parameter in function, but none was given.
However When I add memory in the return parameter I get the error:
TypeError: Member "push" is not available in uint256[] memory outside of storage
I have no clue what to do.
Solidity doesn't allow resizing (e.g. by using .push()) a memory array.
You need to calculate the size beforehand and then create a fixed-size memory array.
Source: docs
So the result is possibly going to look like this
function listMyPromises() public returns(uint256[] memory ){ //lists all my past promises
uint256 count = getCount();
uint256[] memory List = new uint256[](count);
uint256 j;
for (uint i = 0; i < table.length; i++) {
if(table[i].userAddress==msg.sender){
List[j] = uint256(table[i].friendAddress);
j++;
}
}
return List;
}
function getCount() internal view returns (uint) {
uint count;
for (uint i = 0; i < table.length; i++) {
if (table[i].userAddress == msg.sender) {
count++;
}
}
return count;
}
Depending on the datatypes wrapped in the table[i] struct, you might also run into another error. The friendAddress suggests that it's a type address, but it cannot be converted to uint256.
In Solidity, this sentence:
(bool sent, ) = msg.sender.call{value: _amount}("");
What is the sense of that "," after sent variable?
Any link to offcial documentation?
Many thanks.
It means you do not need to define both the variables to access the return values. You can access either of these variables as follows
(,uint256 alpha) = testFunction(); //access first returned variable
(uint256 beta,) = testFunction(); //access second returned variable
function testFunction() public pure returns(uint256,uint256){
return (1,2);
}
Solidity functions can return multiple variables of different types.
If you only want to keep one variable, then you can declare a variable and then use commas:
function multiValueFunction() public returns (bool, string memory, uint[] memory, uint {
//do something
return (true, "New String", [1,2], 21)
}
function differentFunction() public {
uint numberToKeep;
(,,,numberToKeep) = multiValueFunction();
}
Expected: numberToKeep = 21
Each comma represents the place of a returned variable (that is not kept)
It just means that the function will return two variables and you just want to store the first one.
This kind of syntax (variable type) is called Tuple In Python and other languages.
In Solidity,
they're not considered a proper type but can be used as a shorthand.
See the Official Docs: Destructuring Assignments and Returning Multiple Values
example:
uint256 amount = 10 ether;
require(
amount <= address(this).balance,
"Trying to withdraw more money than the contract has."
);
(bool success, ) = (msg.sender).call{value: amount}("");
require(success, "Failed to withdraw money from contract.");
above code, Roughly, Can be translated with basic if else statements like following:
uint256 amount = 10 ether;
bool success;
if(amount <= address(this).balance) {
success = true;
} else {
success = false;
return "Trying to withdraw more money than the contract has.";
}
if(success) {
(msg.sender).call{value: amount}("")
} else {
return "Failed to withdraw money from contract.";
}
here's another contract as example,
use this link https://remix.ethereum.org/#version=soljson-v0.6.9+commit.3e3065ac.js&optimize=false&gist=83bfbd85ef79387f760154999eb4f192&runs=200&evmVersion=null to play around in remix online
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.8.0;
contract myContract {
uint index;
function myFunction() public {
( , , uint256 standardDepositAmount, , ) = returnTuple();
require(standardDepositAmount == 3);
// do something...
}
function returnTuple() public pure returns (uint, uint, uint, uint, uint) {
return (1, 2, 3, 4, 5);
}
}