I'm calling a withdrawal method from a contract written in solidity from a react.js app using metamask. The transaction is failing and I don't know why. I think is something related to the gas fee because when I change it I get different errors. This is the react code:
contract.methods
.withdrawDividends()
.send({
from: userAddress,
value: availableToWithdraw,
})
.on("transactionHash", function (hash: string) {
console.log(hash);
})
.on(
"confirmation",
function (confirmationNumber: number, receipt: unknown) {
console.log(confirmationNumber);
console.log(receipt);
}
)
.on("receipt", function (receipt: unknown) {
// receipt example
console.log(receipt);
})
.on("error", function (error: unknown, receipt: unknown) {
// If the transaction was rejected by the network with a receipt, the second parameter will be the receipt.
console.log(error);
console.log(receipt);
});
This is my solidity method:
function withdrawDividends() public {
User storage user = users[_msgSender()];
uint256 totalAmount = getUserDividends(_msgSender());
require(totalAmount > 0, "User has no dividends");
user.checkpoint = block.timestamp;
(bool success, ) = _msgSender().call.value(totalAmount)("");
require(success, "Transfer failed.");
emit Withdrawn(_msgSender(), totalAmount);
}
The method is not crashing but I see the following error in metamask:
What I'm doing wrong? Is something related to the gas?
If you want your function to accept ETH value, it needs to have the payable modifier.
In your case:
function withdrawDividends() public payable {
You can read more about the payable modifier in the docs. It links to the receive function, which is a slightly different topic. But it also covers the payable modifier.
Related
Hello and thank you in advance!
const comprarCapsula = () => {
const compraCapsula = async () => {
console.log("Iniciando transacción...");
// ------------------------
const pago = web3.utils.toWei(precioFinal.toString(), 'ether');
// Mensaje de información
infoAlert();
// Petición al SC
const transaction = await contract.myFunction(cantidad, {
from: props.currentAccount,
value: pago.toString()}
).then((result) => {
console.log("RESULT:", result);
successAlert(result.tx);
}).catch((error) => {
console.error("TESTING: ", error.message);
errorAlert(error.message);
});
console.log("TRANS: ", transaction);
// ------------------------
}
contract && compraCapsula()
}
My application detects when I cancel the operation with MetaMask (error) but if the Smart Contract throws an error it is not picked up by the catch.
MetaMask - RPC Error: Internal JSON-RPC error.
Object { code: -32603, message: "Internal JSON-RPC error.", data: {…} }
Data: Object { code: 3, message: "execution reverted: Exception: must have minter role to mint"
Error "must have minter role to mint" its in my Smart Contract.
Why? I'm trying several ways to collect the RPC errors that Metamask throws but I can't find the way.
Could you check calling your contract function as such:
contract.myFunction.call
rather than
contract.myFunction
I had a similar problem when developing a contract. call can be used to see whether the function will throw an error - especially structural, modifier checking wise - but only using call will not invoke the full behaviour of the function. After checking for errors with call, you can call the function again.
Function calls with call enabled us to catch those kind of errors. I used such a structure then:
await contract.myFunction.call(`parameters...`)
.then(
contract.myFunction(`parameters...`)
)
I wrote a contract in Solidity with the following task in mind:
The user approves the smart contract to transfer a certain amount of tokens from their wallet.
The smart contract uses this amount to transfer to an address given as a parameter. But it also takes 1 token from this amount to transfer to the developer of the contract.
If everything succeeds, the user receives a "Payment successful!" message.
The first step (the approval) was made using React and Web3:
const derc20contract = '0x36850b80ad73fe66216609B9796ed6ceae8BE29F';
const handleClick = async (e) => {
e.preventDefault();
const prtmp = await detectEthereumProvider();
// -------------------- Approve Part ------------------------------//
const web3 = new Web3(prtmp);
const erc20contract = new web3.eth.Contract(
erc20abi,
derc20token,
{ from: '0xFromAddress' }
);
await erc20contract.methods.approve(derc20contract, web3.utils.toHex(3e18)).send();
// ---------------------------------------------------------------//
const contract = new web3.eth.Contract(derc20abi, derc20contract);
const response = await contract.methods.send_usdt(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress'});
console.log(response);
};
Once the approval succeeds the second part of the function resolves. The contract I deployed has a function called send_usdt. Through this function is my smart contract able to transfer the amount approved.
/ SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
interface IERC20 {
function transfer(address _to, uint256 _value) external returns(bool);
function transferFrom(address _from, address _to, uint _amount) external returns (bool);
function allowance(address _owner, address _contract) external returns (uint256);
function balanceOf(address _buyer) external view returns (uint256);
function approve(address _contract, uint tokens) external returns (bool);
}
contract DPortalSubscription {
address private owner;
mapping(address => uint32) subscription_fees;
constructor()
{
owner = msg.sender;
}
function check_balance() external view returns (uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 balance = usdt.balanceOf(msg.sender);
return balance;
}
function check_sender_address() external view returns (address)
{
return msg.sender;
}
function check_allowance()external returns(uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 allowance = usdt.allowance(msg.sender, address(this));
return allowance;
}
function send_usdt(address _to, uint256 _amount) external returns (string memory)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
require(_amount > 1, "Purchases must be higher than 1 usdt");
require(usdt.balanceOf(msg.sender) >= _amount, "The buyer doesn't have enough funds");
require(usdt.allowance(msg.sender, address(this)) >= _amount, "Permissions to transfer tokens denied");
require(usdt.transferFrom(msg.sender, _to, _amount-1) == true, "Couldn't transfer tokens to seller");
require(usdt.transferFrom(msg.sender, owner, 1) == true, "Couldn't transfer tokens to support");
return "Payment successful!";
}
}
Once the second part of the function in React resolves, I receive the confirmation "Payment successful!" But the tokens weren't transferred. I keep the same amount in my "From Wallet", "To Wallet" and "Deploy Wallet" as before.
The problem was inside the react snippet. By changing the method call to sell the money could be successfully transferred.
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress' });
was changed to:
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18),
{ from: '0xFromAddress' }
)
.send();
which worked but raised another question. When I use the previous call method, the function returns "Payment Successful!" and with the sell method I receive an Object.
Since "Payment Successful" isn't true, I was wondering if it could be possible to throw an Exception when someone interacts with my contract using the call method.
Is that possible?
Following #Kuly14's answer and in order to make it clearer, you may want to create the following function instead:
function send_usdt(address _to, uint256 _amount) external returns (string memory) {
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
require(_amount > 1, "Purchases must be higher than 1 usdt");
usdt.transferFrom(msg.sender, owner, 1);
usdt.transferFrom(msg.sender, _to, _amount-1);
return "Payment successful!";
}
Notes:
By just calling the transferFrom method, it will jump its corresponding error if something goes wrong. You do not need to handle them.
I have changed the order in which you transfer the tokens. First, I send them to the owner and then to the desired recipient to avoid fees payments problems, but if you prefer the other way round, it is possible.
I need to implement in the code below "value" the cost in ETH because in Solidity I require msg.value and in order to be able to lie I have to put a parameter "value" in the code in js, but I don't know how, you can it helps? I also attached the Smart Contract part with mint.
React JS file
async function handleMint() {
if (mintFinish === true) {
setMintFinish(false);
} else {
setMintFinish(true);
}
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(
mintExampleAddress,
mintExampleABI.abi,
signer
);
console.log(signer)
try {
// console.log(contract)
const response = await contract.mint(mint);
console.log(response);
} catch (err) {
console.log(err);
}
}
}
Solidity file
function mint(uint256 _mintAmount) public payable mintCompliance(_mintAmount) {
require(!paused, "The contract is paused!");
require(msg.value >= cost * _mintAmount, "Insufficient funds!");
_mintLoop(msg.sender, _mintAmount);
}
how you are using etherjs and seeing the smart contract code inside the mint function, i suppose that cost is a public variable and can be read from outside the contract, you get the cost and multiply the value by the mint amount parameter, something like this
const cost = await contract.cost();
const response = await contract.mint(mint,{value:cost.mul(mint)});
you have to remember to use bignumbers and that all return values that are numbers will be returned as one, what i'm doing here is getting the cost from the contract and multiply that for mint and pass that to value as the last parameter in the function call
twitchClient.on('timeout', async (channel, username, user, reason, duration) => {
discordClient.on('message', async (message, messages) => {
async function deleteMessage() {
await discordClient.channels.cache.get("901568598538063932")
.messages.fetch({limit: null})
.then(message.delete(messages.first(user["display-name"]).author.name))
}
await deleteMessage()
})
async function sendMessage() {
const request = new XMLHttpRequest();
request.open("POST", "API url");
request.setRequestHeader('Content-type', 'application/json');
const users = {
username: "User Timed Out",
avatar_url: 'https://i.imgur.com/GUrbNsB.jpg',
content: `**${username} has been timed out for ${duration} seconds.**`
}
request.send(JSON.stringify(users));
}
await sendMessage()
});
I have this code for twitch chat to sync in discord and I want to do on event timeout on twitch
I want it to delete the messages of a certain name on the channel is it possible without ID
I am lost on how to do it like I can delete the last message but not from a specific user and I
only have one webhook so the id of all usernames will be the same
TypeError: Cannot read properties of undefined (reading 'first')
Note: This code is for Discord.js v13.3.0
As stated by the error, you're trying to access an undefined variable called messages. This is because you did not define it in the then() arguments, you instantly went to a callback.
then() is a function that allows for you to provide parameters to add. You can simply put the collection of messages as one variable called messages and pass it to the callback accordingly.
// DON'T do this
messages.fetch({limit: null})
.then(message.delete(messages.first(user["display-name"]).author.name))
// DO this
messages.fetch({limit: null})
.then((messages) => message.delete(messages.first(user["display-name"]).author.name))
I have the following function in an ERC20 solidity smart contract:
function getSummary() public view returns (string, string, address, uint, uint){
return(
symbol,
name,
creator,
balances[msg.sender],
_totalSupply
);
}
When I call this function in remix I get a non zero balance for the account I'm on in metamask. That value is correct.
But when I call this function in a react next.js app the the balance returns a zero. Here is that code:
const accounts = await web3.eth.getAccounts();
const account = accounts[0];
let tokenContract = new web3.eth.Contract(abi, props.query.address);
let tokenSummary = await tokenContract.methods.getSummary().call();
let balance = await tokenContract.methods.balanceOf(account).call();
console.log(tokenSummary);
When I console.log tokenSummary, the balance is 0. But then if I call balanceOf I get a non-zero value (which is correct). What could be causing this problem ?