I want to create a new function based on these codes below, that it can just fill in the ordinal number (first student is started by 1) to track out the struct student info in this case.
That's mean after I give the data of this first student to the struct by addInfo function:["Simon", 20, "CA USA", 10] Then my expected new function is that I just fill in this unit: 1, then it will appear this student detail
\`
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ReferenceTypes {
address public owner;
struct student {
string Name;
uint Age;
string BirthPlace;
uint8 Marks;
}
constructor() {
owner = msg.sender;
}
mapping (address => student) public Info;
address[] public student_Info;
function addInfo(student memory _student, address _address) public {
require(owner == msg.sender, "Only admin can add Info!!!");
Info[_address] = _student;
student_Info.push(_address);
}
function count() public view returns(uint) {
return student_Info.length;
}
}
\`
Thanks so much guys
I tried a new mapping but failed
You can make another mapping that leads to your mapping Info.
uint public studentsCounter;
mapping (uint => mapping (address => student)) public Info;
function addInfo(student memory _student, address _address) public returns(uint){
require(owner == msg.sender, "Only admin can add Info!!!");
Info[studentsCounter][_address] = _student;
studentsCounter++;
student_Info.push(_address);
return studentsCounter-1;
}
Thus you can reach your struct by passing studentId(studentCounter) which addInfo returns and students address.
Another approach is to remake you array of addresses.
student[] public student_Info;
And push struct in this array.
function addInfo(student memory _student, address _address) public {
require(owner == msg.sender, "Only admin can add Info!!!");
Info[_address] = _student;
student_Info.push(_student);
}
So now you can display studentsInfo buy passing index in student_Info array.
Related
I have created a smart contract which return to each user the amount deposited + a certain amount if the price of ETH decreases during the lock period. I have two problems with the last part of the code.
The first one concerns mapping the price of ethereum at the moment the user makes the deposit. I have tried several solutions but none of them seem to work. The problem arises on line 64 mapping(uint => uint) ethPrice;. Console returns:
DeclarationError: Identifier already declared.
--> oracle.sol:65:5:
|
65 | mapping(uint => uint) ethPrice;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note: The previous declaration is here:
--> oracle.sol:63:5:
|
63 | uint public ethPrice = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
The second is found on line no. 91. msg.sender.transfer(amountToWithdraw); with the transfer function. The console continues to return the following error despite the fact that the address of each user is defined as payable in the previous functions. Console returns:
TypeError: "send" and "transfer" are only available for objects of type "address payable", not "address".
--> oracle.sol:97:9:
|
97 | msg.sender.transfer(amountToWithdraw);
| ^^^^^^^^^^^^^^^^^^^
These two problems severely invalidate the smart contract and are holding up the completion of coding the latest functions. I have contacted several people and looked in forums concerning programming on solidity but no one seems to have an answer to my problem.
I hope that my question can be answered by the community and can help any other person trying to use ChainLink with Solidity in the future. I am happy to listen to any advice on the matter.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// EACAggregatorProxy is used for chainlink oracle
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
// Address dev
address public dev;
// Dev's public deposit amount
uint public devDeposit;
// Array dev's public amount
uint[] public devDeposits;
// List each user and amount
address[] public users;
uint[] public totalDeposited;
// Mapping user's deposit
mapping(address => uint) balances;
// Deployer = dev & Dev deposit function
function deployerIsDeveloper() public payable {
dev = msg.sender;
devDeposit = msg.value;
devDeposits.push(devDeposit);
}
// User's address
address user;
// Amount's address
uint amountDeposit;
// Deadline time
uint256 deadline;
// Amount's each user
uint256 lockAmount = lockAmounts[msg.sender];
// Mapping of deposit for each user
mapping(address => uint) lockAmounts;
// Timestamp for each user
uint256 startTime = startTimes[block.timestamp];
// Mapping timestamp for each user
mapping(uint => uint) startTimes;
// Kovan ETH/USD oracle address
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
// ethPrice
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) ethPrice;
// Deposit function for each user
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
amountDeposit = msg.value;
users.push(user);
totalDeposited.push(amountDeposit);
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
//return ethPrice = price;
//price.push(ethPrice);
}
// Withdraw function for each user
function withdraw() public payable {
require(block.timestamp >= deadline);
uint amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
msg.sender.transfer(amountToWithdraw);
}
}
For the first issue, Solidity compiler said that you declared two variables with the identifier. In details in your case, you give ethPrice for mapping and uint variable. To solve this issue, try to change one of these names in this way:
uint256 price = ethPrice;
mapping(uint => uint) mappingEthPrice;
Second issue refers that msg.sender keyword doesn't cast automatically with address payable and to solve it you can use payable() function that allows you convert an address to address payable.
In your smart contract you must to change in this way:
payable(msg.sender).transfer(amountToWithdraw);
This should be your smart contract fixed:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// EACAggregatorProxy is used for chainlink oracle
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
// Address dev
address public dev;
// Dev's public deposit amount
uint public devDeposit;
// Array dev's public amount
uint[] public devDeposits;
// List each user and amount
address[] public users;
uint[] public totalDeposited;
// Mapping user's deposit
mapping(address => uint) balances;
// Deployer = dev & Dev deposit function
function deployerIsDeveloper() public payable {
dev = msg.sender;
devDeposit = msg.value;
devDeposits.push(devDeposit);
}
// User's address
address user;
// Amount's address
uint amountDeposit;
// Deadline time
uint256 deadline;
// Amount's each user
uint256 lockAmount = lockAmounts[msg.sender];
// Mapping of deposit for each user
mapping(address => uint) lockAmounts;
// Timestamp for each user
uint256 startTime = startTimes[block.timestamp];
// Mapping timestamp for each user
mapping(uint => uint) startTimes;
// Kovan ETH/USD oracle address
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
// ethPrice
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) mappingEthPrice;
// Deposit function for each user
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
amountDeposit = msg.value;
users.push(user);
totalDeposited.push(amountDeposit);
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
//return ethPrice = price;
//price.push(ethPrice);
}
// Withdraw function for each user
function withdraw() public payable {
require(block.timestamp >= deadline);
uint amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
payable(msg.sender).transfer(amountToWithdraw);
}
}
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.
I've created a function in solidity smart contract that add players in a game, the players should be stored as an "user" or a "hero" as a role in the game. The user send a transaction request while the hero send a reward. I've created a modifier to allow only the user to request and the hero to send a reward, but to define the role of each one of them in the registration phase I'm confused about it. Thanks in advance.
function AddPlayer(string _name, string _role) public returns (bool){
players[msg.sender].name=_name;
players[msg.sender].Paddress=msg.sender;
players[msg.sender].role = _role;
return true;
}
modifier onlyuser() {
require(msg.sender == user, "Only user can call this method");
_;}
modifier onlyheros() {
require(msg.sender == hero, "Only hero can call this method");
_;}
function Request() onlyuser external payable returns(bool) {
balances[msg.sender] += msg.value;
}
function Reward() onlyhero external payable returns (bool) {
balances[msg.sender] += msg.value;
user.transfer(msg.value);
}
Try to declare them as an enum. enum name {variable1, variable2}
You can create a mapping and functions to check user roles like that:
pragma solidity >=0.4.22 <0.6.0;
pragma experimental ABIEncoderV2;
// User address => Role of user
mapping(address => string) UserAuth;
// Set user role to a User Address
function setUser(address _userAddress, string memory _role) public {
UserAuth[_userAddress] = _role;
}
//Check user role
modifier checkAuth(string memory _role){
require(keccak256(abi.encode(UserAuth[msg.sender])) == keccak256(abi.encode(_role)));
_;
}
//get user role
function getUserAuth(address _userAddress) public view returns ( string memory){
return UserAuth[_userAddress];
}
and also you can set an ADMIN user as a constructor to control of the functions like that:
pragma solidity >=0.4.22 <0.6.0;
pragma experimental ABIEncoderV2;
// User address => Role of user
mapping(address => string) UserAuth;
constructor() public{
UserAuth[msg.sender] = "ADMIN";
}
//Check user role
modifier checkAuth(string memory _role){
require(keccak256(abi.encode(UserAuth[msg.sender])) == keccak256(abi.encode(_role)));
_;
}
// Set User Role to a User Address
function setUser(address _userAddress, string memory _role) public checkAuth("ADMIN"){
UserAuth[_userAddress] = _role;
}
// get user role
function getUserAuth(address _userAddress) public view checkAuth("ADMIN") returns ( string memory){
return UserAuth[_userAddress];
}
I have this solidity mapping
mapping (string => Ticket) public myMapping;
I want to check if myMapping[key] exists or not. How can I check?
The entire storage space is virtually initialized to 0 (there is no undefined).
So you have to compare the value to the 0 value for your type.
For example, mapping[key] == address(0x0) or mapping[key] = bytes4(0x0).
There is no direct method to check whether the mapping has particular key. But you can check if mapping property has value or not. The following example considered that the Ticket is the struct with some property.
pragma solidity >=0.4.21 <0.6.0;
contract Test {
struct Ticket {
uint seatNumber;
}
mapping (string => Ticket) myMapping;
function isExists(string memory key) public view returns (bool) {
if(myMapping[key].seatNumber != 0){
return true;
}
return false;
}
function add(string memory key, uint seatNumber) public returns (bool){
myMapping[key].seatNumber = seatNumber;
return true;
}
}
pragma solidity ^0.8.0;
contract BookLibNew{
address public owner;
constructor() public{
owner = msg.sender;
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
struct bookDet{
uint bookId;
string bookTitle;
string bookAuthor;
}
mapping (uint8 => bookDet) public bookLib;
function addBookLib(uint8 _bookId, string memory _bookTitle, string memory _bookAuthor)
public onlyOwner {
require(bookLib(_bookId) == false, "Error: Book already exists");
bookLib[_bookId].bookTitle = _bookTitle;
bookLib[_bookId].bookAuthor = _bookAuthor;
}
function readBookDetails(uint8 _bookId) public view returns(string memory, string memory){
return(bookLib[_bookId].bookTitle, bookLib[_bookId].bookAuthor);
}
}
I am attempting to call a solidity function that looks something like the following:
function fillOrder(
Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
Using web3j I would create the function similar to below, however I'm not quite sure how to represent the order which is represented as a struct in Solidity.
List<Type> inputParams = Arrays.asList(???, new
Uint256(takerAssetFillAmount), new Bytes32(signture));
new Function("fillOrder", inputParams, Collections.emptyList());
Any pointers on how I should represent the struct?
Thanks.
You can wrap parameters with square brackets.
For example, let's say I have a contract:
contract Test {
struct Foo {
uint a;
string b;
address c;
}
function bar (Foo memory foo) public {
c = foo.c;
}
}
I can call bar function with web3.js like this:
contract.methods.foo([123, "123", "0xABC...."]).send({ from: '0x...' })
here is the contract address https://goerli.etherscan.io/address/0xd5999bf0ce31a1d9d6a6de2bf03feaff1913cee5#writeContract
in the write function , createSwapOrder is asking nested Tuple . here is the solidity code to show the structure of tuple :
struct Side {
address user;
bytes signedRequiredOutput;
ERC20Component[] erc20s;
ERC721Component[] erc721s;
ERC1155Component[] erc1155s;
}
struct ERC20Component {
uint256 amount;
address underlying;
// A signed approval transaction giving `amount` transfer rights
// of token `underlying` to address(this).
// bytes signedApproval;
}
struct ERC721Component {
uint256 tokenId;
address collection;
// A signed approval transaction giving `tokenId` tranfer rights
// of token `collection` to address(this).
// bytes signedApproval;
}
struct ERC1155Component {
uint256 tokenId;
uint256 amount;
address collection;
// A signed approval transaction giving `tokenId` tranfer rights
// of token `collection` to address(this).
// bytes signedApproval;
}
struct Order {
Side side0;
Side side1;
uint256 expiry;
bytes32 hashlock;
bytes32 preimage;
bool completed;
}
event OrderCreated(address indexed user, bytes32 orderId);
uint256 public totalOrders;
mapping(bytes32 => Order) public orders;
function createSwapOrder(
Side calldata side0,
bytes32 hashlock,
uint256 timelock
) public {
...
}
and in first args side0 is asking a nested tuple and this tuple formet should be like this
["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0x00",[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]]],
i hope you can understand the structure how its provided !! and sure it working
Web3j offers such classes as StaticStruct and DynamicStruct where you define your struct object via primitives. Here is the sample from my project:
class Value: DynamicStruct {
private lateinit var offer: String
private lateinit var availableSince: BigInteger
private lateinit var availabilityEnd: BigInteger
private var isConsumed: Boolean = false
private lateinit var lockedUntil: BigInteger
constructor(
offer: String,
availableSince: BigInteger,
availabilityEnd: BigInteger,
isConsumed: Boolean,
lockedUntil: BigInteger
) : super(
Utf8String(offer), Uint256(availableSince),
Uint256(availabilityEnd), Bool(isConsumed),
Uint256(lockedUntil)
) {
this.offer = offer
this.availableSince = availableSince
this.availabilityEnd = availabilityEnd
this.isConsumed = isConsumed
this.lockedUntil = lockedUntil
}
constructor(
offer: Utf8String,
availableSince: Uint256,
availabilityEnd: Uint256,
isConsumed: Bool,
lockedUntil: Uint256
) : super(offer, availableSince, availabilityEnd, isConsumed, lockedUntil) {
this.offer = offer.value
this.availableSince = availableSince.value
this.availabilityEnd = availabilityEnd.value
this.isConsumed = isConsumed.value
this.lockedUntil = lockedUntil.value
}
}
Ideally you just need to pass this struct instance to you contract method as a parameter where contract is autogenerated over $web3j solidity generate -b /path/to/<smart-contract>.bin -a /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name command.
However personally I faced with issue to make this console command working and have to implement required logic by my own. This is in the progress now.