Openzepplin crowdsale contract got: VM Exception while processing transaction: revert error - blockchain

I am developing smart contract based on openzeppelin-solidity and I want to write an easy Crowdsale contract, only I did is inherit Contract.sol:
// FloatFlowerTokenCrowdsale.sol
pragma solidity 0.4.23;
import "openzeppelin-solidity/contracts/crowdsale/Crowdsale.sol";
contract FloatFlowerTokenCrowdsale is Crowdsale{
constructor(ERC20 _token) public Crowdsale(1000, msg.sender, _token)
{
}
}
Here is my FloatFlowerToken.sol
// FloatFlowerToken.sol
pragma solidity 0.4.23;
import "openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
contract FloatFlowerToken is StandardToken {
string public name = "FLOATFLOWER TOKEN";
string public symbol = "FFT";
uint8 public decimals = 18;
constructor() public {
totalSupply_ = 36000000;
balances[msg.sender] = totalSupply_;
}
}
And this is my 2_deploy_contract.js
const FloatFlowerToken = artifacts.require('./FloatFlowerToken.sol');
const FloatFlowerTokenCrowdsale =
artifacts.require('./FloatFlowerTokenCrowdsale.sol');
module.exports = function(deployer, network, accounts) {
return deployer
.then(() => {
return deployer.deploy(FloatFlowerToken);
})
.then(() => {
return deployer.deploy(FloatFlowerTokenCrowdsale, FloatFlowerToken.address);
})
};
After I execute the truffle test and I got the error Error: VM Exception while processing transaction: revert
And here is my test code:
it('one ETH should buy 1000 FLOATFLOWER TOKEN in Crowdsale', function(done) {
FloatFlowerTokenCrowdsale.deployed().then(async function(instance) {
const data = await instance.sendTransaction({from: accounts[7], value: web3.toWei(1, "ether")}, function(error, txhash) {
console.log(error);
});
const tokenAddress = await instance.token.call();
const FloatFlowerToken = FloatFlowerToken.at(tokenAddress);
const tokenAmount = await FloatFlowerToken.balanceOf(accounts[7]);
assert.equal(tokenAmount.toNumber(), 1000000000000000000000, 'The sender didn\'t receive the tokens as crowdsale rate.');
})
})
I don't know how to check the error log and to know which line cause this problem.

You have 2 issues:
First, the units you're working with aren't correct. You've initialized your crowdsale to sell 1000 tokens for every Wei sent. From the documentation in the Zeppelin contract:
#param _rate Number of token units a buyer gets per wei
#param _wallet Address where collected funds will be forwarded to
#param _token Address of the token being sold
You're passing in 1 ether in your transaction, which means you're attempting to buy 1000 * (10^18) token units, but you've only allocated 36000000 total supply. You need to increase your total supply and/or lower your rate.
Second, only token owners can do a transfer unless an approve has been done first. When you deploy the token contract, all of the tokens are owned by msg.sender. However, when someone makes a purchase through your crowdsale contract, the request to do the transfer is coming from the address of the crowdsale contract, not the token owner when your token contract was deployed. The simplest way around this is after deploying your contracts, transfer enough tokens for the crowdsale from the address you used to create the token contract over to the address of the crowdsale contract.

Related

Paying with ERC20 token

I want to build an NFT that I can paid with an ERC-20 token to mint it. I'm using currently the Mumbai testnet on polygon, and I'm using the Dummy ERC20 token to test it out.
This is currently my constructor:
ERC20 token;
constructor() ERC721("Token", "TKN") {
token = ERC20(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1);
}
And this is my mint function:
function mint() public returns (uint256) {
uint256 tokenId = _tokenIds.current();
require(tokenId <= MAX_TOKEN_ID);
token.approve(address(this), NFT_PRICE);
token.transfer(address(this), NFT_PRICE);
_mint(msg.sender, tokenId);
_setTokenURI(tokenId, TOKEN_URI);
_tokenIds.increment();
return tokenId;
}
If I remove those 2 lines the code works fine, it mints the NFT:
token.approve(address(this), NFT_PRICE);
token.transfer(address(this), NFT_PRICE);
But as soon as I add it, the code breaks, it gives me the following gas estimation error:
The transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": 3, "message": "execution reverted: ERC20: transfer amount exceeds balance", "data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002645524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63650000000000000000000000000000000000000000000000000000" }
As a troubleshooting step I've also added this inside my mint function to make sure I'm calling from my own wallet:
sender = msg.sender;
And created this function:
function tokenBalance(address addr) public view returns (uint256) {
return token.balanceOf(addr);
}
And if I grab the token balance of the sender address it gives me the value:
0: uint256: 2000000000000000000
It's because the logic is wrong. That approve function you call inside your mint function is useless: the spender needs to call the approve function from the the contract of your dummy ERC20.
And then you can call the transferFrom(msg.sender, address(this), NFT_PRICE) from your mint function.

Gas estimation error with Chainlink and Remix

I am working on a project that will need to use ChainLink to make external API calls from the Ethereum blockchain. I was testing out the demo code like so:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
/**
* Request testnet LINK and ETH here: https://faucets.chain.link/
* Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/
*/
/**
* THIS IS AN EXAMPLE CONTRACT WHICH USES HARDCODED VALUES FOR CLARITY.
* PLEASE DO NOT USE THIS CODE IN PRODUCTION.
*/
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256 public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: d5270d1c311941d0b08bead21fea7747
* Fee: 0.1 LINK
*/
constructor() {
setPublicChainlinkToken();
oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
jobId = "d5270d1c311941d0b08bead21fea7747";
fee = 0.1 * 10 ** 18; // (Varies by network and job)
}
/**
* Create a Chainlink request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*/
function requestVolumeData() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
// Set the path to find the desired data in the API response, where the response format is:
// {"RAW":
// {"ETH":
// {"USD":
// {
// "VOLUME24HOUR": xxx.xxx,
// }
// }
// }
// }
request.add("path", "RAW.ETH.USD.VOLUME24HOUR");
// Multiply the result by 1000000000000000000 to remove decimals
int timesAmount = 10**18;
request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
{
volume = _volume;
}
However, I am consistently running into a Gas estimation error after deploying and trying to call requestVolumeData.
What am I doing wrong?
Video
Gas estimation error is a common error meaning that you don't have enough of "something" to send your transaction, maybe it's layer 1 (ETH) gas, or an ERC20 token like LINK (technically, erc677, but I digress...)
Whenever you work with a Chainlink feature that uses the request and receive method of using chainlink, you need to fund the consumer contract with LINK token.
The issue here is you sent LINK to the oracle address and not the address of your deployed contract.
If you copy the address of your deployed contract and send the LINK there, it should work for you.

How to transfer eth from an account to a contract?

I'm fresh on solidity, when I use remix to test my contract, I want to transfer some eth from my account to the smart contract. I have tried this code, but it seems to transfer the eth from the contract but not my account.
function addStaker (uint _stakeAmount) public membership(master, msg.sender) returns(bool) {
if(!members[msg.sender].alreadyExist) {
Member memory newMember = Member(msg.sender, true);
members[msg.sender] = newMember;
bool sent = payable(address(this)).send(_stakeAmount);
require(sent, "invalid balance");
return true;
} else {
return false;
}
}
How could I transfer eth from my account to the smart contract?
A smart contract is not able to pull a contract-specified amount of ETH from an address. The amount needs to always be specified and signed by the sender.
The contract can only validate the sent amount:
function addStaker() public payable {
require(msg.value == 1 ether);
}
How to chose the amount depends on the wallet software you're using. In case of Remix, there's the "Value" input in the "Deploy & Run Transactions" tab, where you specify the amount of ETH sent with the transaction.
If you want to implement a defi contract (since your function name is addStaker) that accepts staked coins from ERC20 tokens, the implementation is different. But if you just want to send money to contract from your metamask account, you have to mark the function payable.
function pay() public payable {
// msg.value is the amount of wei sent with the message to the contract.
// with this you are setting a minimum amount
require(msg.value > .01 ether);
// add your logic
}

Unable to call safeTransferFrom method from a JS api file

I have deployed my ERC721 contract on polygon testnet from owner(ox43b....81). I have created a small node server to interact with my contract through web3. I m using truffle config
//truffle-config.js
polygon-testnet: {
provider: new HDWalletProvider(privateKey, https://rpc-mumbai.maticvigil.com),
network_id: 80001,
gas: 6000000,
gasPrice: 10000000000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
}
//index.js file
function test(){
const owner = await myContract.methods.owner().call()
console.log('contract owner', owner) //ox43b....81
//miniting token
const mint = await myContract.methods
.safeMint(owner,1001, 'google.com')
.send({ from: owner, gas: 100000 }) // is this the write way of calling ??
//token transfer
const transfer = await myContract.methods
.safeTransferFrom(acc1, acc2, 1003)
.send({ from: acc1, gas: 1000000 }) // is this the write way of calling ??
}
bcz i m getting err in both function calling: Error: Returned error: unknown account.
NOTE: I am not calling my contract func from truffle console. I m calling through a JS api file index.js
I know there is another way by using web3.eth.accounts.signTransaction() to mint & transfer the token.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
Q.2 By using web3.eth.accounts.signTransaction() method i can able to mint the tokens successfully but i am facing issue in token transfer (using safeTransferFrom()). There are two cases:
case 1: i am transferring the token which is created/minted by contract owner(ox43b....81) to any other individual user address.
const fromAddress = 'ox43b....81' //owner of the contract
const toAddress = '0x26....7D'
const tokenId = 10001 // created by owner(ox43b....81)
const tx = {
from: ownerAddress, // ox43b....81 --> owner who created contract
to: contractAddress,// 0xfe.....24
nonce: nonce, // nonce with the no of transactions from our owner address
gas: 1000000, // fee estimate to complete the transaction
data: await myContract.methods
.safeTransferFrom(fromAddress, toAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m able to transfer the token successfully.
case 2: i am transferring the token which is created/minted by another(not contract owner) user(0x26....7D) to any other individual user address / or to owner.
const fromAddress = '0x26....7D' (not the owner of contract)
const toAnyAddress = '0x5e....5a' // any other user
const tokenId = 10002 // created by user '0x26....7D' (not the owner of contract)
const nonce = await web3.eth.getTransactionCount(fromAddress, 'latest')
const tx = {
from: fromAddress, // 0x26....7D -> is this right? or i put contract owner adr?
to: contractAddress,// 0xfe.....24
nonce: nonce,
gas: 1000000, // fee estimate to complete the transaction
data: await this.myContract.methods
.safeTransferFrom(fromAddress, toAnyAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m getting err - Fail with error 'ERC721: transfer caller is not owner nor approved'.
I need solution for my case 2. Is there something related with locked/unlocked accounts? How can i fix it?
Please help! Thanks in advance.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
The .send() method of the web3 Contract instance performs/requests the signature in the background. So it's always signed - just not with an explicit "sign" keyword in the code in this case.
Q.2 There are two cases:
This is not related to the way you sign the transaction.
The second case fails because the token holder has not approved the spender (i.e. the transaction sender) to spend their tokens.
You need to invoke the approve(<spender>, <tokenId>) function from the token holder address first, to be able to successfully use the transferFrom().
// assuming `acc1` is holder of the token ID `1003`
// approve the `owner` to spend the `acc1`'s token
await myContract.methods.approve(owner, 1003).send({from: acc1});
// transfer token `1003` held by `acc1` ... and send the transaction from the `owner` address
await myContract.methods.transferFrom(acc1, recipient, 1003).send({from: owner});

Calling a Smart Contract method using Web3 1.0

Presently, I have a smart contract successfully deployed to the Rinkeby testnet, I'm having trouble accessing the method in question using web3 version 1.0.
Here's my web3 code, which instantiates a contract instance and calls a contract method:
const contractInstance = new web3.eth.Contract(abiDefinition, contractAddress);
var value = web3.utils.toWei('1', 'ether')
var sentTransaction = contractInstance.methods.initiateScoreRetrieval().send({value: value, from: fromAddress})
console.log('event sent, now set listeners')
sentTransaction.on('confirmation', function(confirmationNumber, receipt){
console.log('method confirmation', confirmationNumber, receipt)
})
sentTransaction.on('error', console.error);
And here is my smart contract, or rather a version of it stripped down to the relevant bits:
contract myContract {
address private txInitiator;
uint256 private amount;
function initiateScoreRetrieval() public payable returns(bool) {
require(msg.value >= coralFeeInEth);
amount = msg.value;
txInitiator = msg.sender;
return true;
}
}
I am not able to get to the console.log that is setting the event listeners on the web3 side, and I am not getting an error of any kind thrown. I'm certainly not getting the consoles from the actual event listeners. I am guessing something is wrong with the way I'm sending the transaction, but I think I am correctly following the pattern documented below: https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-send
Does anyone have any insight on how to use web3 1.0 to make contract method calls correctly? Am I doing something wrong with how I'm passing options, etc.?
Thanks!
I believe you forgot to specify your HttpProvider for your web3, thus you're not connecting to live Rinkeby network, and by default web3 is running on you local host, which is why even if you provide the right contract address, there's nothing there.
To connect to live network, I would strongly encourage you to use Infura Node by ConsenSys.
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://rinkeby.infura.io"));
Then by now, everything should work perfectly fine.
First, you need to generate your transaction ABI using encodeABI(), here is an example:
let tx_builder = contractInstance.methods.myMethod(arg1, arg2, ...);
let encoded_tx = tx_builder.encodeABI();
let transactionObject = {
gas: amountOfGas,
data: encoded_tx,
from: from_address,
to: contract_address
};
Then you have to sign the transaction using signTransaction() using private key of sender. Later you can sendSignedTransaction()
web3.eth.accounts.signTransaction(transactionObject, private_key, function (error, signedTx) {
if (error) {
console.log(error);
// handle error
} else {
web3.eth.sendSignedTransaction(signedTx.rawTransaction)
.on('receipt', function (receipt) {
//do something
});
}