I made a new token on the Ropsten test network. Here's the contract address: 0x801fd9c17087ec868dc8540055b7ea3cb6dbbe34.
When I followed the instructions to add this custom token to MyEtherWallet (by specifying the contract address, symbol and correct number of decimals), I see that my ICICB token is added to the token list. However, the balance says 0, even though I have sent some tokens to my address. Also, when I try to select the ICICB token from the dropdown menu to send it, it doesn't show up (just Eth shows up).
When you look at https://ropsten.etherscan.io/address/0x411724F571e83D5fa74d42462F0cAFBddDfed5fc which is my MyEtherWallet address, you can see that is has 2,000,000 ICICB tokens.
Could you please explain to me what's going on? Maybe I'm missing something.
I also, looked at this thread, but it seems to me that my token is ERC20 compliant, as I have all of the necessary functions.
Here's my contract:
pragma solidity ^0.4.24;
// ----------------------------------------------------------------------------
// 'ICICB' token contract
//
// Deployed to : 0x9f7bb2e565F94C3FF3e365eb95cAF73b458b2149
// Symbol : ICICB
// Name : ICICB Token
// Total supply: 100000000
// Decimals : 18
//
// Enjoy.
// (c) by Moritz Neto with BokkyPooBah / Bok Consulting Pty Ltd Au 2017. The MIT Licence.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
contract SafeMath {
function safeAdd(uint a, uint b) public pure returns (uint c) {
c = a + b;
require(c >= a);
}
function safeSub(uint a, uint b) public pure returns (uint c) {
require(b <= a);
c = a - b;
}
function safeMul(uint a, uint b) public pure returns (uint c) {
c = a * b;
require(a == 0 || c / a == b);
}
function safeDiv(uint a, uint b) public pure returns (uint c) {
require(b > 0);
c = a / b;
}
}
// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
function totalSupply() public view returns (uint);
function balanceOf(address tokenOwner) public view returns (uint balance);
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
}
// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
address public owner;
address public newOwner;
event OwnershipTransferred(address indexed _from, address indexed _to);
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address _newOwner) public onlyOwner {
newOwner = _newOwner;
}
function acceptOwnership() public {
require(msg.sender == newOwner);
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and assisted
// token transfers
// ----------------------------------------------------------------------------
contract ICICBToken is ERC20Interface, Owned, SafeMath {
string public symbol;
string public name;
uint8 public decimals;
uint public _totalSupply;
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
constructor() public {
symbol = "ICICB";
name = "ICICB Token";
decimals = 18;
_totalSupply = 100000000000000000000000000;
balances[0x9f7bb2e565F94C3FF3e365eb95cAF73b458b2149] = _totalSupply;
emit Transfer(address(0), 0x9f7bb2e565F94C3FF3e365eb95cAF73b458b2149, _totalSupply);
}
// ------------------------------------------------------------------------
// Total supply
// ------------------------------------------------------------------------
function totalSupply() public view returns (uint) {
return _totalSupply - balances[address(0)];
}
// ------------------------------------------------------------------------
// Get the token balance for account tokenOwner
// ------------------------------------------------------------------------
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
// ------------------------------------------------------------------------
// Transfer the balance from token owner's account to to account
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = safeSub(balances[msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
// ------------------------------------------------------------------------
// Token owner can approve for spender to transferFrom(...) tokens
// from the token owner's account
//
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// recommends that there are no checks for the approval double-spend attack
// as this should be implemented in user interfaces
// ------------------------------------------------------------------------
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
// ------------------------------------------------------------------------
// Transfer tokens from the from account to the to account
//
// The calling account must already have sufficient tokens approve(...)-d
// for spending from the from account and
// - From account must have sufficient balance to transfer
// - Spender must have sufficient allowance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
balances[from] = safeSub(balances[from], tokens);
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
// ------------------------------------------------------------------------
// Returns the amount of tokens approved by the owner that can be
// transferred to the spender's account
// ------------------------------------------------------------------------
function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
return allowed[tokenOwner][spender];
}
// ------------------------------------------------------------------------
// Token owner can approve for spender to transferFrom(...) tokens
// from the token owner's account. The spender contract function
// receiveApproval(...) is then executed
// ------------------------------------------------------------------------
function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
return true;
}
// ------------------------------------------------------------------------
// Don't accept ETH
// ------------------------------------------------------------------------
function () public payable {
revert();
}
// ------------------------------------------------------------------------
// Owner can transfer out any accidentally sent ERC20 tokens
// ------------------------------------------------------------------------
function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
return ERC20Interface(tokenAddress).transfer(owner, tokens);
}
}
I looked at all the other relevant threads and I didn't find the answer
The problem was that I used MEW on desktop, and even though I selected the Ropsten testnet on my phone, I needed to select it on my desktop also. This is kinda confusing because the ETH address that was displayed on my desktop version was the Ropsten address (because I switched to it on my phone before scanning the QR code to connect), but for some reason I had to manually set the network on desktop too.
Having the same issue. Ethplorer says I have XYO tokens but it wont show in MEW. I have tried all the different nodes with no luck. I have tried to install the custom token but it says already there. This wallet is a new design from the old style which worked better. Where can I find these tokens which are there hiding in cyberspace.
OK just solved my issue. I am out of the UK at the moment. I used my VPN to connect to the uk. Opened my wallet and there they were. So try using VPN to connect to a different country.
Related
The deployment of InsuranceProvider is working fine and the calling of newContract() with the required parameters is successfully creating/deploying the InsuranceConsumer contract. Even, the payOutContract() is working correctly in terms of transferring the ETH balance from the InsuranceConsumer to the client's wallet.
The issue is with the refundToInsurer() function, as it's expected to transfer the ETH balance from the InsuranceConsumer to the insurer's wallet, but it's transaction is getting failed/reverted.
Here's the code:
SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer agreed amount to client
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer back the amount to insurer
i.refundToInsurer();
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer() public {
// Transfer back the amount to insurer
insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Can anyone please help by pointing out the logical mistake that I'm doing in the refundToInsurer() function ?
As, we're creating the InsuranceConsumer using the newContract() function of InsuranceProvider. Therefore, the msg.sender of the InsuranceConsumer is going to be the InsuranceProvider itself, not the insurer's wallet.
So, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the InsuranceProvider (not the insurer's wallet), and since InsuranceProvider is not expected to be a receiver, that's why it's reverting the transaction.
So, the corrected code will be:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public onlyOwner {
// Transfer agreed amount to client
InsuranceConsumer i = InsuranceConsumer(_contract);
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
// Transfer back the amount to insurer
InsuranceConsumer i = InsuranceConsumer(_contract);
i.refundToInsurer(insurer);
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer(address payable _insurer) public {
// Transfer back the amount to insurer
_insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Now, while calling the refundInsurer(), we're explicitly passing the insurer as the parameter, and it's taking the value of msg.sender from InsuranceProvider, so the msg.sender is going to be the insurer's wallet (with which the InsuranceProvider is being deployed) in this case.
And now, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
_insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the insurer's wallet. So, the transaction will be successful resulting in the withdrawal of the funds from the InsuranceConsumer to the insurer's wallet.
I am practising this tutorial in Remix IDE - https://www.youtube.com/watch?v=_aXumgdpnPU
I saw in the Chainlink documentation that their Randomness VRF code has been changed since the development of the video.
I started replacing the parts and trying to deploy the class via Remix but it gives an error which I am not sure how to fix.
Would you be able to check what I have as code and I'll send a screenshot of the error?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "#chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
import "#chainlink/contracts/src/v0.8/VRFV2WrapperConsumerBase.sol";
contract Lottery is
VRFV2WrapperConsumerBase,
ConfirmedOwner
{
address public owner;
address payable[] public players;
uint public lotteryId;
mapping (uint => address payable) public lotteryHistory;
event RequestSent(uint256 requestId, uint32 numWords);
event RequestFulfilled(
uint256 requestId,
uint256[] randomWords,
uint256 payment
);
struct RequestStatus {
uint256 paid; // amount paid in link
bool fulfilled; // whether the request has been successfully fulfilled
uint256[] randomWords;
}
mapping(uint256 => RequestStatus)
public s_requests; /* requestId --> requestStatus */
// past requests Id.
uint256[] public requestIds;
uint256 public lastRequestId;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 callbackGasLimit = 100000;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;
// For this example, retrieve 2 random values in one request.
// Cannot exceed VRFV2Wrapper.getConfig().maxNumWords.
uint32 numWords = 2;
// Address LINK - hardcoded for Goerli
address linkAddress = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
// address WRAPPER - hardcoded for Goerli
address wrapperAddress = 0x708701a1DfF4f478de54383E49a627eD4852C816;
constructor()
ConfirmedOwner(msg.sender)
VRFV2WrapperConsumerBase(linkAddress, wrapperAddress)
{
owner = msg.sender;
lotteryId = 1;
}
function requestRandomWords()
external
onlyOwner
returns (uint256 requestId)
{
requestId = requestRandomness(
callbackGasLimit,
requestConfirmations,
numWords
);
s_requests[requestId] = RequestStatus({
paid: VRF_V2_WRAPPER.calculateRequestPrice(callbackGasLimit),
randomWords: new uint256[](0),
fulfilled: false
});
requestIds.push(requestId);
lastRequestId = requestId;
emit RequestSent(requestId, numWords);
return requestId;
}
function fulfillRandomWords(
uint256 _requestId,
uint256[] memory _randomWords
) internal override {
require(s_requests[_requestId].paid > 0, "request not found");
s_requests[_requestId].fulfilled = true;
s_requests[_requestId].randomWords = _randomWords;
emit RequestFulfilled(
_requestId,
_randomWords,
s_requests[_requestId].paid
);
payWinner();
}
function getRequestStatus(
uint256 _requestId
)
external
view
returns (uint256 paid, bool fulfilled, uint256[] memory randomWords)
{
require(s_requests[_requestId].paid > 0, "request not found");
RequestStatus memory request = s_requests[_requestId];
return (request.paid, request.fulfilled, request.randomWords);
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(linkAddress);
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}
function getWinnerByLottery(uint lottery) public view returns (address payable) {
return lotteryHistory[lottery];
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
function enter() public payable {
require(msg.value > .01 ether);
// address of player entering lottery
players.push(payable(msg.sender));
}
//function getRandomNumber() public view returns (uint) {
//return uint(keccak256(abi.encodePacked(owner, block.timestamp)));
//}
function pickWinner() public onlyowner {
requestRandomWords;
}
function payWinner() public {
uint index = lastRequestId % players.length;
players[index].transfer(address(this).balance);
lotteryHistory[lotteryId] = players[index];
lotteryId++;
// reset the state of the contract
players = new address payable[](0);
}
modifier onlyowner() {
require(msg.sender == owner);
_;
}
}
enter image description here
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 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);
}
}
This is my solidity file for NFT marketplace.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract NFT is ERC721URIStorage,Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address payable public _owner;
mapping(address => uint[]) public addressToTokenArray;
mapping(uint256 => bool) public forSale;
mapping(uint256 => uint256) public tokenIdToPrice;
event Minting(address _owner, uint256 _tokenId, uint256 _price);
event Purchase(address _seller, address _buyer, uint256 _price);
event Remove(uint256 _tokenId, uint[] beforeBuy, uint[] afterBuy);
constructor() ERC721("TeddyBear", "TEDDY") {
}
function mint(string memory _tokenURI, uint256 _price) public onlyOwner returns (bool)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
tokenIdToPrice[newItemId] = _price;
if(addressToTokenArray[msg.sender].length !=1){
addressToTokenArray[msg.sender].push(newItemId);
}else{
addressToTokenArray[msg.sender] = [newItemId];
}
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, _tokenURI);
emit Minting(msg.sender, newItemId, _price);
return true;
}
// 토큰의 주인이 판매 하는 함수
function sell(uint256 _tokenId, uint256 _price) external {
require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
require(_price > 0, 'Price zero');
tokenIdToPrice[_tokenId] = _price;
forSale[_tokenId] = true;
}
// 토큰의 주인이 판매를 취하하는 함수
function stopSell(uint256 _tokenId) external {
require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
forSale[_tokenId] = false;
}
// function remove(uint[] memory array, uint index) public pure returns(uint[] memory) {
// if (index >= array.length) return array;
// for (uint i = index; i<array.length-1; i++){
// array[i] = array[i+1];
// }
// delete array[array.length-1];
// return array;
// }
function buy(uint256 _tokenId, uint256 sendAmount) external payable {
uint256 price = tokenIdToPrice[_tokenId];
bool isOnSale = forSale[_tokenId];
require(isOnSale, 'This token is not for sale');
require(sendAmount == price, 'Incorrect value');
address seller = ownerOf(_tokenId);
require(seller == ownerOf(_tokenId), 'Seller and Owner is not same');
// uint[] memory beforeBuy = addressToTokenArray[seller];
// // for(uint i=0;i<addressToTokenArray[seller].length;i++){
// // if(_tokenId == addressToTokenArray[seller][i]){
// // remove(addressToTokenArray[seller],i);
// // }
// // }
// uint[] memory afterBuy = addressToTokenArray[seller];
// emit Remove(_tokenId, beforeBuy, afterBuy);
addressToTokenArray[msg.sender] = [_tokenId];
safeTransferFrom(seller, msg.sender, _tokenId);
forSale[_tokenId] = true;
payable(seller).transfer(sendAmount); // send the ETH to the seller
emit Purchase(seller, msg.sender, sendAmount);
}
function getPrice(uint256 _tokenId) public view returns (uint256){
uint256 price = tokenIdToPrice[_tokenId];
return price;
}
function isSale(uint256 _tokenId) public view returns (bool){
bool isOnSale = forSale[_tokenId];
return isOnSale;
}
function getMyTokenId() public view returns (uint[] memory){
uint[] memory myTokens = addressToTokenArray[msg.sender];
return myTokens;
}
}
Among functions up there, the buy function does not emit an error when I compile the .sol file, but after I deploy this contract and send transaction for "buy" function it keeps making this error.
I just want to know where I should fix it and if there is any better idea for other functions, feel free to let me know... many thanks
Most likely it is failing here:
safeTransferFrom(seller, msg.sender, _tokenId);
If you check the ERC721 contract, safeTransferFrom eventually calls this:
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// ****** HERE IS THE ISSUE *****
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
If your contract is going to transfer a token on behalf of owner, owner has to approve first.
so from the seller's contract, this should be called:
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
tokenApprovals is a mapping that keeps track of which tokens can be transferred.
Debugging
in order to test which function call is causing error, place this requirement statement require(sendAmount == price, 'Incorrect value'); right before the function. and pass an incorrect value and you will get an error : 'Incorrect value'
Then put that require statement after the function, and pass a wrong value, if this require does send you error, you can be sure that function is causing the error