Below is my code.`
pragma solidity ^0.8.0;
contract Auction {
// Data
//Structure to hold details of the item
struct Item {
uint itemId; // id of the item
uint[] itemTokens; //tokens bid in favor of the item
}
//Structure to hold the details of a persons
struct Person {
uint remainingTokens; // tokens remaining with bidder
uint personId; // it serves as tokenId as well
address addr;//address of the bidder
}
mapping(address => Person) tokenDetails; //address to person
Person [4] bidders;//Array containing 4 person objects
Item [3] public items;//Array containing 3 item objects
address[3] public winners;//Array for address of winners
address public beneficiary;//owner of the smart contract
uint bidderCount=0;//counter
//functions
function Auction() public payable{ //constructor
//Part 1 Task 1. Initialize beneficiary with address of smart contract’s owner
//Hint. In the constructor,"msg.sender" is the address of the owner.
// ** Start code here. 1 line approximately. **/
beneficiary = msg.sender;
//** End code here. **/
uint[] memory emptyArray;
items[0] = Item({itemId:0,itemTokens:emptyArray});
//Part 1 Task 2. Initialize two items with at index 1 and 2.
// ** Start code here. 2 lines approximately. **/
uint[] memory emptyArray1;
items[1] = Item({itemId:1,itemTokens:emptyArray1});
uint[] memory emptyArray2;
items[2] = Item({itemId:2,itemTokens:emptyArray2});
//** End code here**/
}
function register() public payable{
bidders[bidderCount].personId = bidderCount;
//Part 1 Task 3. Initialize the address of the bidder
/*Hint. Here the bidders[bidderCount].addr should be initialized with address of the registrant.*/
// ** Start code here. 1 line approximately. **/
bidders[bidderCount].addr = msg.sender;
//** End code here. **
bidders[bidderCount].remainingTokens = 5; // only 5 tokens
tokenDetails[msg.sender]=bidders[bidderCount];
bidderCount++;
}
function bid(uint _itemId, uint _count) public payable{
/*
Bids tokens to a particular item.
Arguments:
_itemId -- uint, id of the item
_count -- uint, count of tokens to bid for the item
*/
/*
Part 1 Task 4. Implement the three conditions below.
4.1 If the number of tokens remaining with the bidder is < count of tokens bidded, revert.
4.2 If there are no tokens remaining with the bidder, revert.
4.3 If the id of the item for which bid is placed, is greater than 2, revert.
Hint: "tokenDetails[msg.sender].remainingTokens" gives the details of the number of tokens remaining with the bidder.
*/
// ** Start code here. 2 lines approximately. **/
if ( (tokenDetails[msg.sender].remainingTokens < _count) ||
(tokenDetails[msg.sender].remainingTokens <= 0)
) { revert(); }
if (_itemId > items.length - 1) { revert(); }
//** End code here. **
/*Part 1 Task 5. Decrement the remainingTokens by the number of tokens bid and store the value in balance variable.
Hint. "tokenDetails[msg.sender].remainingTokens" should be decremented by "_count". */
// ** Start code here. 1 line approximately. **
uint balance = tokenDetails[msg.sender].remainingTokens - _count;
//** End code here. **
tokenDetails[msg.sender].remainingTokens=balance;
bidders[tokenDetails[msg.sender].personId].remainingTokens=balance;//updating the same balance in bidders map.
Item storage bidItem = items[_itemId];
for(uint i=0; i<_count;i++) {
bidItem.itemTokens.push(tokenDetails[msg.sender].personId);
}
}
// Part 2 Task 1. Create a modifier named "onlyOwner" to ensure that only owner is allowed to reveal winners
//Hint : Use require to validate if "msg.sender" is equal to the "beneficiary".
modifier onlyOwner {
// ** Start code here. 2 lines approximately. **
require (msg.sender == beneficiary);
_;
//** End code here. **
}
function revealWinners() public onlyOwner{
/*
Iterate over all the items present in the auction.
If at least on person has placed a bid, randomly select the winner */
for (uint id = 0; id < 3; id++) {
Item storage currentItem=items[id];
if(currentItem.itemTokens.length != 0){
// generate random# from block number
uint randomIndex = (block.number / currentItem.itemTokens.length)% currentItem.itemTokens.length;
// Obtain the winning tokenId
uint winnerId = currentItem.itemTokens[randomIndex];
/* Part 1 Task 6. Assign the winners.
Hint." bidders[winnerId] " will give you the person object with the winnerId.
you need to assign the address of the person obtained above to winners[id] */
// ** Start coding here *** 1 line approximately.
winners[id] = bidders[winnerId].addr;
//** end code here*
}
}
}
//Miscellaneous methods: Below methods are used to assist Grading. Please DONOT CHANGE THEM.
function getPersonDetails(uint id) public constant returns(uint,uint,address){
return (bidders[id].remainingTokens,bidders[id].personId,bidders[id].addr);
}
}`
I am trying to compile it but I am unable to do it.
please help in this regard
thanks
Related
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.
I am newbie to this field, and just learning some courses online about solidity and creating a simple contract, I would like to ask about a simple project that I try but not successful yet.
I want to create a swap function that can swap between 2 tokens that I created from ERC20, WITHOUT using uniswap or something like that, just dev a new function that swap between token A and token B, for example with the rate of 1 token A = 3 token B, the rate was ask to save in a mapping and got config at first, but I dont really know how to setting up the rate for swapping.
Could anyone help me out with this, many thanks guys.
Existed Code of Swap contract, just temporary :
// SPDX-License-Identifier: MIT
pragma solidity >= 0.7.0 <0.9.0;
import "./Token.sol";
import "./safemath.sol";
contract SwapToken {
using SafeMath for uint;
Token public token1;
address public owner1;
Token public token2;
address public owner2;
uint public amount1;
uint public amount2;
uint public swapRate;
constructor(
address _token1,
address _owner1,
address _token2,
address _owner2,
uint _amount1
) {
token1 = Token(_token1);
owner1 = _owner1;
token2 = Token(_token2);
owner2 = _owner2;
swapRate = 3;
amount1 = _amount1;
amount2 = _amount1.mul(swapRate);
}
function swap() public {
require(msg.sender == owner1 || msg.sender == owner2, "Not authorized from owners");
require(
token1.allowance(owner1, address(this)) >= amount1,
"Token 1 allowance too low"
);
require(
token2.allowance(owner2, address(this)) >= amount2,
"Token 2 allowance too low"
);
_safeTransferFrom(token1, owner1, owner2, amount1);
_safeTransferFrom(token2, owner2, owner1, amount2);
}
function _safeTransferFrom(
Token token,
address sender,
address recipient,
uint amount
) private {
bool sent = token.transferFrom(sender, recipient, amount);
require(sent, "Token transfer failed");
}
}
Let's start with a general answer and we'll build on it as we understand the question better.
I think you are not trying to create a swapping solution with a liquidity pool, but instead, want to match 2 people(?) that want to swap tokens.
A very simplistic approach to it could be
// have a mapping, as your tutor said. This will store information about how a token (token's contract address) and another token (again, contract address) rate against each other.
mapping(address => mapping (address => uint256)) rates;
function setRating(address memory token1, address memory token2, uint256 rate) public {
rates[token1][token2] = rate;
}
Then, while swapping, check the rate and calculate accordingly.
// you need to pass which token to swap and how much swap
function swap(address tokenIn, uint amountIn) public {
// you want only either of two owners call
require(
msg.sender == owner1 || msg.sender == owner2,
"Not authorized from owners"
);
require(
token1.allowance(owner1, address(this)) >= amount1,
"Token 1 allowance too low"
);
require(
token2.allowance(owner2, address(this)) >= amount2,
"Token 2 allowance too low"
);
// you need to require tokenIn is only token1 or token2 that you store in storage
require(
tokenIn == address(token1) || tokenIn == address(token2),
"Invalid token"
);
// make sure you pass positive amount
require(_amountIn > 0, "invalid amount");
// define token1 and token2 based on function arg tokenIn
bool isToken1 = tokenIn == address(token1);
( // you are using Token as type instead of IERC20
Token tokenIn,
Token tokenOut,
// reserve1 and reserve2 how many each tokens holds. you should be setting in state
uint reserve1,
uint reserve2
) = isToken1
? (token1, token2, reserve1, reserve2)
: (token2, token1, reserve2, reserve1);
// instead token1, tokenIn should be transferred
// I believe this is what it does
_safeTransferFrom(tokenIn, owner1, owner2, amount1);
// calculate the tokenOut including the fee=0.3%. user who wants to swap has to pay for fee
uint amountInAfterFee = (_amountIn * 997) / 1000;
// here you need to calculate how much y token will be taken out
// this is the formula dy=(y*dx)/(x+dx) y and x are reserves, dx is amountInAfterFee
amountOut =
(reserve2 * amountInAfterFee) /
(reserve1 + amountInAfterFee);
// now you need to send this amountOut to tokenOut or token2 in your contract
token2.transfer(msg.sender,amountOut)
// here update the reserves
// I dont think that you need this
// _safeTransferFrom(token2, owner2, owner1, amount2);
}
I need a time constant to calculate timestamps for deposit, withdrawal, and reward sub-pools. this time constant called T will start from contract deployment and will not be specific to one address/user. I.e rewards(R) are divided into 3 sub-pools: R1 = 20% available after 2T has passed since contract deployment, R2 = 30% available after 3T has passed since contract deployment, R3= 50% available after 4T has passed since contract deployment. I need this variable to be in minutes, for example, sender inputs 3 I want the time between each timestamp to be 3, like deposit in the first T, withdrawal after 3T. How to set it in minutes?
Here is the state variable
uint256 public T;
Here is the constructor
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
My full code
error TransferFailed();
error NeedsMoreThanZero();
contract Staking is ReentrancyGuard {
IERC20 public s_rewardsToken;
IERC20 public s_stakingToken;
// This is the reward token per seco
nd
// Which will be multiplied by the tokens the user staked divided by the total
// This ensures a steady reward rate of the platform
// So the more users stake, the less for everyone who is staking.
uint256 public constant REWARD_RATE = 100;
uint256 public s_lastUpdateTime;
uint256 public s_rewardPerTokenStored;
//uint256 public constant T = 3;
uint256 public initialTime;
uint256 public T;
mapping(address => uint256) public s_userRewardPerTokenPaid;
mapping(address => uint256) public s_rewards;
uint256 private s_totalSupply;
mapping(address => uint256) public s_balances; // someones address => how much he staked
event Staked(address indexed user, uint256 indexed amount);
event WithdrewStake(address indexed user, uint256 indexed amount);
event RewardsClaimed(address indexed user, uint256 indexed amount);
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
/**
* #notice How much reward a token gets based on how long it's been in and during which "snapshots"
*/
function rewardPerToken() public view returns (uint256) {
if (s_totalSupply == 0) {
return s_rewardPerTokenStored;
}
return
s_rewardPerTokenStored +
(((block.timestamp - s_lastUpdateTime) * REWARD_RATE * 1e18) / s_totalSupply);
}
/**
* #notice How much reward a user has earned
*/
function earned(address account) public view returns (uint256) {
uint256 nowTime = block.timestamp-initialTime;
require(nowTime > 2*T);
if (nowTime > 2*T && nowTime <= 3*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 5 );
} else if
(nowTime > 3*T && nowTime <= 4*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 2 );
} else {
return
(((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]);
}
}
/**
* #notice Deposit tokens into this contract
* #param amount | How much to stake
*/
function stake(uint256 amount)
external
updateReward(msg.sender)
nonReentrant
moreThanZero(amount)
{
//from T0 to T deposit is available
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime < T);
s_totalSupply += amount;
// increasing how much they are staking for how much they staked each time.
s_balances[msg.sender] += amount;
emit Staked(msg.sender, amount);
// sending an amount of token from an address to this contract
bool success = s_stakingToken.transferFrom(msg.sender, address(this), amount);
// if not successfully sent, return an error.
// using the below code instead of "require(success, "Failed")" reduces gas fees, since it doesn't output a string.
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* #notice Withdraw tokens from this contract
* #param amount | How much to withdraw
*/
function withdraw(uint256 amount) external updateReward(msg.sender) nonReentrant {
// from 2T the user can reward his tokens
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime > 2* T);
s_totalSupply -= amount;
s_balances[msg.sender] -= amount;
emit WithdrewStake(msg.sender, amount);
// transfer: send tokens from contract back to msg.sender.
bool success = s_stakingToken.transfer(msg.sender, amount);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* #notice User claims their tokens
*/
function claimReward() external updateReward(msg.sender) nonReentrant {
uint256 reward = s_rewards[msg.sender];
s_rewards[msg.sender] = 0;
emit RewardsClaimed(msg.sender, reward);
bool success = s_rewardsToken.transfer(msg.sender, reward);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/********************/
/* Modifiers Functions */
/********************/
modifier updateReward(address account) {
s_rewardPerTokenStored = rewardPerToken();
s_lastUpdateTime = block.timestamp;
s_rewards[account] = earned(account);
s_userRewardPerTokenPaid[account] = s_rewardPerTokenStored;
_;
}
modifier moreThanZero(uint256 amount) {
if (amount == 0) {
revert NeedsMoreThanZero();
}
_;
}
/********************/
/* Getter Functions */
/********************/
// Ideally, we'd have getter functions for all our s_ variables we want exposed, and set them all to private.
// But, for the purpose of this demo, we've left them public for simplicity.
function getStaked(address account) public view returns (uint256) {
return s_balances[account];
}
}
Firstly maintain a map for storing the time for each user. Then make functions like depositTimeSet , withdrawalTimeSet for storing different time for different user. While despositing update the variable and while withdraw check the time has exceed or not.
struct Users {
uint dipositTime;
uint withDrawTime;
uint lastDepositTime;
}
mapping(address => Users ) users;
function depositeTimeSet(uint t) {
users[msg.sender].dipositTime = t minutes;
withdrawalTimeSet(t);
}
function withdrawalTimeSet(uint t) {
users[msg.sender].withDrawTime = 3 * t minutes
}
function deposite() {
transferFrom(msg.sender,address(this));
depositeTimeSet(3); // considering sender send 3
users[msg.sender].lastDepositTime = now;
}
function withdraw() {
if(
now > users[msg.sender].lastDepositTime +
users[msg.sender].withDrawTime,"too early for withdraw
request"
)
transferFrom(address(this),msg.sender);
}
You can see THIS one might be helpful
You can see THIS resource for time unit in solidity
I have a Smart Contract that I'd like to build a web based marketplace app for. How can I list all available "Items" in the contract. Seeing as there is no upper limit to the number of minted Items, how can I implement pagination and search?
What is a best practice and scalable solution:
to simply return the Items[] array
sync the array with my database on Transfer and other events
other suggestions?
pragma solidity ^0.4.24;
contract Item is ERC721{
struct Item{
string name; // Name of the Item
uint level; // Item Level
uint rarityLevel; // 1 = normal, 2 = rare, 3 = epic, 4 = legendary
}
Item[] public items; // First Item has Index 0
address public owner;
function Item() public {
owner = msg.sender; // The Sender is the Owner; Ethereum Address of the Owner
}
function createItem(string _name, address _to) public{
require(owner == msg.sender); // Only the Owner can create Items
uint id = items.length; // Item ID = Length of the Array Items
items.push(Item(_name,5,1)) // Item ("Sword",5,1)
_mint(_to,id); // Assigns the Token to the Ethereum Address that is specified
}
}
You can create an itemsCount public property that holds the current amount of existing items, and increment it after each items.push().
Without pagination and search:
Off-chain systems that want to read your data, can simply loop from items[0] to items[itemsCount] and since it's just a read operation, it doesn't require a transaction (i.e. it's free).
With pagination and search:
You can to create a view function that:
Takes page and query as arguments
Loops through existing items and if the item fits the criteria (name contains query), add it to the results array
Returns the results array
Note: Step 2 is actually going to be a bit more complicated in Solidity, because you can't push into an in-memory dynamic array. So you need to:
Loop through the items and find an amount that fit the criteria (up to the page limit)
Create a fix-length in-memory array results
Now you can loop through the items again and fill the fix-length results array with values
mapping are more efficient than arrays in solidity. You could have a uint in the smart contract that keeps the count of every Item and use a getter function to get each item from whatever number you want to paginate subtracted from the item count.
contract Item is ERC721{
struct Item{
string name; // Name of the Item
uint level; // Item Level
uint rarityLevel; // 1 = normal, 2 = rare, 3 = epic, 4 = legendary
uint id;
}
mapping(uint => Item) items; // First Item has Index 0
uint count;
address public owner;
function Item() public {
owner = msg.sender; // The Sender is the Owner; Ethereum Address of the Owner
}
function createItem(string memory _name, address _to, uint level, uint rarityLevel
uint id) public{
require(owner == msg.sender); // Only the Owner can create Items
uint num = count++;
items[num].name = _name;
items[num].level = level;
items[num].rarityLevel = rarityLevel;
items[num].id = num;
count++;
}
function getItem(uint item) public view returns(string memory _name, uint level,
uint rarityLevel, uint id){
uint level = items[item].level;
uint rarityLevel = items[item].rarityLevel;
uint id = items[item].id;
string memory _name = items[item].name
return(level, rarityLevel, id, _name)
}
This contract appears to be a game offering 1/16 odds at the balance of the contract. However, when running the code in a debugger it appears as if the 'secretNumber' variable is being overwritten before it is used.
pragma solidity ^0.4.19;
contract CryptoRoulette {
uint256 private secretNumber;
uint256 public lastPlayed;
uint256 public betPrice = 0.1 ether;
address public ownerAddr;
struct Game {
address player;
uint256 number;
}
Game[] public gamesPlayed;
function CryptoRoulette() public {
ownerAddr = msg.sender;
shuffle();
}
function shuffle() internal {
// initialize secretNumber with a value between 0 and 15
secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 16;
}
function play(uint256 number) payable public {
require(msg.value >= betPrice && number < 16);
Game game;
game.player = msg.sender;
game.number = number;
gamesPlayed.push(game);
if (number == secretNumber) {
// win!
msg.sender.transfer(this.balance);
}
shuffle();
lastPlayed = now;
}
function kill() public {
if (msg.sender == ownerAddr && now > lastPlayed + 1 days) {
suicide(msg.sender);
}
}
function() public payable { }
}
The way secretNumber is updated, it should always be less than 16
secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 16;
This debugger output shows that during execution of if (number == secretNumber) { the value of secretNumber has been updated to, oddly enough, the callers address (msg.sender).
`
(243) PUSH1 0x00
000000000000000000000000000000000000000000000000000000006898f82b
0000000000000000000000000000000000000000000000000000000000000143
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000000 (top)
40: if (number == secretNumber) {
^^^^^^^^^^^^
debug(develop:0x98cacf83...)> i
CryptoRoulette.sol | 0xbd2c938b9f6bfc1a66368d08cb44dc3eb2ae27be:
40: if (number == secretNumber) {
^^^^^^
debug(develop:0x98cacf83...)> p
CryptoRoulette.sol | 0xbd2c938b9f6bfc1a66368d08cb44dc3eb2ae27be:
(245) DUP3
000000000000000000000000000000000000000000000000000000006898f82b
0000000000000000000000000000000000000000000000000000000000000143
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000627306090abab3a6e1400e9345bc60c78a8bef57 (top)
40: if (number == secretNumber) {
^^^^^^
My guess is that the storage access before the condition is causing the stack to be corrupted somehow.
Is this a known vulnerability? Can someone please explain what is going on?
This is a common issue when attempting to create a local reference without specifying the correct storage location.
From the Solidity docs:
There are defaults for the storage location depending on which type of variable it concerns:
state variables are always in storage
function arguments are in memory by default
local variables of struct, array or mapping type reference storage by default
local variables of value type (i.e. neither array, nor struct nor mapping) are stored in the stack
The bolded comment indicates that the line Game game; defaults to storage. If you don't initialize a storage variable, it will point to storage slot 0 by default. The end result is when you make a change to game (with game.player = msg.sender;), it will write the value out to the first slot, which will be whatever the first variable is in your contract (in this case, secretNumber).
The correct way to write this is to use Game memory game;. The compiler will give you a warning if you omit the memory keyword for this exact reason.