Solidity - How to set to null or empty a payable address - ethereum

I am quite new to solidity and I have the following situation:
I have this struct
struct Item {
uint sku;
uint upc;
address ownerID;
address originProducerID;
string originProducerName;
string originProducerInformation;
uint productId;
string productNotes;
uint productPrice;
State itemState;
address payable consumerID;
}
In the last one (consumerID) I had to make it payable for this (I need to use transfer):
modifier checkValue(uint _upc) {
_;
uint _price = items[_upc].productPrice;
uint amountToReturn = msg.value - _price;
items[_upc].consumerID.transfer(amountToReturn);
}
The problem is when I try to create an item, I need to set that value to what it would be null or empty.
function collectMaterials(address _originProducerId, string memory _originProducerName, string memory _originProducerInformation, uint _productId, string memory _productNotes, uint _productPrice) public
{
items[sku] = Item(
{
sku: sku,
upc: upc,
ownerID: msg.sender,
originProducerID: msg.sender,
originProducerName: _originProducerName,
originProducerInformation: _originProducerInformation,
productId: sku + upc,
productNotes: _productNotes,
productPrice: _productPrice,
itemState: State.MaterialSelection,
consumerID: address(0)
});
But I get this error
Invalid type for argument in function call. Invalid implicit
conversion from address to address payable requested
How can I initialise that value to empty or null? Or is there a way to make it optional to add?
Thanks!

consumerID is of type address payable (an extension of the type address).
However, in the collectMaterials() function, you're passing type address as the value of consumerID.
Solution: Typecast the value 0 to address payable
consumerID: payable(address(0))

Related

Ordinal Number Function in Remix Solidity

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.

ERC721 Invalid token id

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 am unable to transfer funds to the owner of my NFT

//SPDX-License-Identifier: MIT
import "#openzeppelin/contracts/token/ERC721/IERC721.sol";
import "#openzeppelin/contracts/security/ReentrancyGuard.sol";
pragma solidity ^0.8.0;
contract Shop is ReentrancyGuard {
uint itemCount;
struct Item {
uint itemId;
address payable owner;
address nft;
uint tokenId;
uint price;
uint sale;
uint ownerNumber;
uint256 warrantyPeriod;
uint256 dateOfPurcahse;
}
mapping(uint => Item) items;
function listItem(address _nft, uint _tokenId, uint _price, uint256 _warrantyPeriod) external nonReentrant {
require(_price > 0,"Price must be greate than zero");
uint itemId = itemCount;
_warrantyPeriod = _warrantyPeriod * 1 days;
items[itemId] = Item(itemId,payable(msg.sender),_nft,_tokenId,_price,1,1,_warrantyPeriod,0);
itemCount++;
}
function purchaseItem(uint _itemId) external payable nonReentrant {
Item storage item = items[_itemId];
address payable buyer = payable(msg.sender);
item.owner.transfer(item.price);
IERC721(item.nft).approve(buyer,item.tokenId);
IERC721(item.nft).transferFrom(item.owner, buyer, item.tokenId);
item.owner = buyer;
item.sale += 1;
item.ownerNumber += 1;
item.dateOfPurcahse = block.timestamp;
}
}
I am storing my nft address and tokenId in the Item struct along with address of the owner. On purchasing the item, the caller of the function transfers price of the item to the owner, the nft is transfered to the buyer and the owner of the item is updated to the buyer. I was running this code on remix and it is throwing this error -
transact to Shop.purchaseItem errored: VM error: revert.
revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
I made sure that the function and address of the owner were payable and the price of the nft was lower than the balance. Where am I going wrong?
item.owner.transfer(item.price);
You have this line in your code. As far as I know, it should be msg.value, not item.price. Since your function is payable, there should be a value. msg.sender is the buyer; msg.value is the price. And you should check it like require (msg.value==item.price).

Solidity: How to type cast string memory to address and uint type?

I get the following errors when trying to type cast string memory to address and uint type.
TypeError: Explicit type conversion not allowed from "string memory" to "address".
TypeError: Explicit type conversion not allowed from "string memory" to "uint256".
Below is the solidity code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
struct allowedTokenDetails {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
uint256 timestampAdded;
uint256 timestampLastUpdated;
}
mapping(address => allowedTokenDetails) public allowedTokensData;
function setAllowedTokensData(address _token, string[][] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
string memory dataKey = _data[dataIndex][0];
string memory dataValue = _data[dataIndex][1];
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("admin"))) allowedTokensData[_token].admin = address(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("price"))) allowedTokensData[_token].price = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("balance"))) allowedTokensData[_token].balance = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("rewardToken"))) allowedTokensData[_token].rewardToken = address(dataValue);
allowedTokensData[_token].timestampLastUpdated = block.timestamp;
}
}
}
Is there a solution to this?
Instead of validating the input with a set of if statements and typecasting each value based on the function logic, you can already pass the input data in expected types in a prepared struct:
struct inputData {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
}
function setAllowedTokensData(address _token, inputData[] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
allowedTokensData[_token] = allowedTokenDetails(
_data[dataIndex].admin,
_data[dataIndex].price,
_data[dataIndex].balance,
_data[dataIndex].rewardToken,
0, // `timestampAdded` not set in your snippet
block.timestamp
);
}
}

How to encode tuple as input parameter to function using web3j

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.