I'm using ether.js to create a dapp.I want to input something in my database when something modifies on a blockchain.So I am using this for the check const receipt = await transaction.wait(1); Once the transaction receipt is received it means it has been mined successfully. But the problem is when I am speeding up the transaction I get an error saying "TRANSACTION REPLACED" because I tried to send transaction again using the same nonce.The block is mined on the network but on frontend I'm getting this error. How to handle this error? This is the explanation of this error on docs.
This error is thrown when waiting for a transaction which has been replaced by another, by the sender submitting a second transaction with the same nonce, while the transaction was pending in the transaction pool.
Just found out what the core problem is -
https://medium.com/the-capital/ethereum-speed-up-transactions-how-they-work-and-what-they-mean-for-dapps-6d4ba1068580
But their service is paid.
error from console log-
index.ts:261
Uncaught (in promise) Error: transaction was replaced [ See: https://links.ethers.org/v5-errors-TRANSACTION_REPLACED ] (cancelled=false, reason="repriced", replacement={"hash":"0x6fb9737ee9449817cb797104e64e023641e480f01b9a76721fbbd5d4bd8a25a5","type":2,"accessList":[],"blockHash":"0x95b11ed6cb7329fd9b475d324a6eb5de54cfb3ca79eac0c2ecdb0952a0021ad6","blockNumber":27034014,"transactionIndex":4,"confirmations":1,"from":"0xB157e57e493167491c8EE69681D89873a9D68B1C","gasPrice":{"type":"BigNumber","hex":"0x08896c4c12"},"maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x08896c4c0b"},"maxFeePerGas":{"type":"BigNumber","hex":"0x08896c4c16"},"gasLimit":{"type":"BigNumber","hex":"0x6e80"},"to":"0x92265B57f08EF2F30dDd6d9CdCac1BD62C1A004b","value":{"type":"BigNumber","hex":"0x038d7ea4c68000"},"nonce":38,"data":"0xf340fa01000000000000000000000000b157e57e493167491c8ee69681d89873a9d68b1c","r":"0x96346c519bd65bbe2550a1396757e92f89c4d87246bf0bd4c3a8c8d315a6e78c","s":"0x332b38044b3efcd7bbe8e7b7e860024fb13306ce47c37a7b2168765c6e82f7e1","v":0,"creates":null,"chainId":80001}, hash="0x1a7442367d14df07d598aeb0ac9479926bee663637e11d535fa698cd9fd8f113", receipt={"to":"0x92265B57f08EF2F30dDd6d9CdCac1BD62C1A004b","from":"0xB157e57e493167491c8EE69681D89873a9D68B1C","contractAddress":null,"transactionIndex":4,"gasUsed":{"type":"BigNumber","hex":"0x6e80"},"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000008000100000000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100048000004000000000000000080000000010000000000000000000000080000000000000000000000000000000000000000000000000080001000080000000000000000000200000000000000000000000000000004000000400000100000000000000004000000000000000020001000000000000000000000000800000108040000000000000000000000000000000000000000000000000000000400000000000100000","blockHash":"0x95b11ed6cb7329fd9b475d324a6eb5de54cfb3ca79eac0c2ecdb0952a0021ad6","transactionHash":"0x6fb9737ee9449817cb797104e64e023641e480f01b9a76721fbbd5d4bd8a25a5","logs":[{"transactionIndex":4,"blockNumber":27034014,"transactionHash":"0x6fb9737ee9449817cb797104e64e023641e480f01b9a76721fbbd5d4bd8a25a5","address":"0x0000000000000000000000000000000000001010","topics":["0xe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c4","0x0000000000000000000000000000000000000000000000000000000000001010","0x000000000000000000000000b157e57e493167491c8ee69681d89873a9d68b1c","0x00000000000000000000000092265b57f08ef2f30ddd6d9cdcac1bd62c1a004b"],"data":"0x00000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000004a10eca800d2aa93000000000000000000000000000000000000000000000000035801792bb0d0000000000000000000000000000000000000000000000000004a0d5f295c0c2a93000000000000000000000000000000000000000000000000035b8ef7d0775000","logIndex":10,"blockHash":"0x95b11ed6cb7329fd9b475d324a6eb5de54cfb3ca79eac0c2ecdb0952a0021ad6"},{"transactionIndex":4,"blockNumber":27034014,"transactionHash":"0x6fb9737ee9449817cb797104e64e023641e480f01b9a76721fbbd5d4bd8a25a5","address":"0x92265B57f08EF2F30dDd6d9CdCac1BD62C1A004b","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],"data":"0x000000000000000000000000b157e57e493167491c8ee69681d89873a9d68b1c00000000000000000000000000000000000000000000000000038d7ea4c68000","logIndex":11,"blockHash":"0x95b11ed6cb7329fd9b475d324a6eb5de54cfb3ca79eac0c2ecdb0952a0021ad6"},{"transactionIndex":4,"blockNumber":27034014,"transactionHash":"0x6fb9737ee9449817cb797104e64e023641e480f01b9a76721fbbd5d4bd8a25a5","address":"0x0000000000000000000000000000000000001010","topics":["0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63","0x0000000000000000000000000000000000000000000000000000000000001010","0x000000000000000000000000b157e57e493167491c8ee69681d89873a9d68b1c","0x000000000000000000000000be188d6641e8b680743a4815dfa0f6208038960f"],"data":"0x0000000000000000000000000000000000000000000000000003af513ed2bf800000000000000000000000000000000000000000000000004a149bf93fa86f93000000000000000000000000000000000000000000001d2f81f5cd2c083658f80000000000000000000000000000000000000000000000004a10eca800d5b013000000000000000000000000000000000000000000001d2f81f97c7d47091878","logIndex":12,"blockHash":"0x95b11ed6cb7329fd9b475d324a6eb5de54cfb3ca79eac0c2ecdb0952a0021ad6"}],"blockNumber":27034014,"confirmations":1,"cumulativeGasUsed":{"type":"BigNumber","hex":"0x06733e"},"effectiveGasPrice":{"type":"BigNumber","hex":"0x08896c4c12"},"status":1,"type":2,"byzantium":true}, code=TRANSACTION_REPLACED, version=providers/5.6.8)
at Logger.makeError (index.ts:261:1)
at Web3Provider.<anonymous> (base-provider.ts:1372:1)
at Generator.next (<anonymous>)
at fulfilled (base-provider.ts:1:1)
if (typeof window.ethereum !== "undefined" && logInState === true) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(gambleAddress, Gamble.abi, signer);
const transaction = await contract.deposit(acc, {
value: ethers.utils.parseEther(matic.toString()),
});
const receipt = await transaction.wait(1);
console.log(receipt);
if (receipt) {
updateDepositInDb();
} else {
alert("transaction failed");
}
You should surround your code with try catch to handle exceptions.
You may refer to the link below to find out how to detect replacement transactions in your scenarios.
https://blog.ricmoo.com/highlights-ethers-js-may-2021-2826e858277d
I've been trying to get a transaction to execute on Polygon but it's been failing with the following error:
reason: 'processing response error',
code: 'SERVER_ERROR',
body: '{"jsonrpc":"2.0","id":89,"error":{"code":-32000,"message":"transaction underpriced"}}',
This error only occurs on Polygon and it only occurs when using the Gnosis SDK. I've tested it using the Gnosis UI and it executes successfully. I've also tested it using the Gnosis SDK on rinkeby and that works as well.
Here is the code that fails:
const infuraProvider = new ethers.providers.JsonRpcProvider(RPC_PROVIDER);
const wallet = new ethers.Wallet(`0x${PRIVATE_KEY}`, infuraProvider);
const owner1 = wallet.connect(infuraProvider);
const ethAdapterOwner1 = new EthersAdapter({ ethers, signer: owner1 });
const safeSdkInstance = await Safe.create({
ethAdapter: ethAdapterOwner1,
safeAddress: GNOSIS_SAFE_ADDR,
});
const contract = new ethers.Contract(contractJson.address, contractJson.abi, owner1);
const tx = {
to: contract.address,
value: '0',
data: contract.interface.encodeFunctionData('mint', ['[wallet address here]', '[token id here]']),
};
const safeTransaction = await safeSdkInstance.createTransaction(tx);
const executeTxResponse = await safeSdkInstance.executeTransaction(safeTransaction);
Other things I've tried:
Adding a gasPrice - making that gas price incredibly large
Adding a gasLimit
Changing RPC_PROVIDER from an infura provider to a public one
Calling a different function - I tried calling my contracts burn function and it came back with the exact same error
I did notice that even when providing a gasPrice the error I get back says that the transaction provided had a gasPrice of null. But when logging the safeTransaction object it shows a gasPrice is generated by the createTransaction function. So something must be going wrong in the executeTransaction function
I'm creating a logging system for my Discord server of over 12k members. What I would like to achieve is that whenever a moderator uses the .lock command, the bot sends a message to the logs channel and DM's me. Both work, but I can't figure out how to attach the message url so that I can click on that and immediately jump to the .lock command itself so I can review what happened.
This is the code that I have thus far:
// Message url to be used in logging later.
const msgURL = 'empty';
// Send lock message
const embed = new Discord.MessageEmbed()
.setTitle("LOCKDOWN")
.setColor('#ff0000')
.setDescription("There have been a large number of infringements in this channel. Please be patient as we review the sent messages and take appropriate action.")
.setFooter("Please do not DM staff asking when the lockdown will be over. ");
message.channel.send({embed}).then(msgURL => {
msgURL = embed.url;
})
// Send unlock notification to #staff-logs.
// async method to get the channel id (in case of delay.)
function getStaffLogChannel(){
return message.guild.channels.cache.get('ID');
}
// Staff logs channel
let staffLogs = await getStaffLogChannel();
// User who issued the command
let commandIssuer = message.member.user.tag;
// message published in staff-logs
staffLogs.send(commandIssuer + " has used the **.lock** command in: " + message.channel.name)
// send notification in DM
client.users.cache.get('ID').send(commandIssuer + " has used the **.lock** command in: " + message.channel.name + " ( " + msgURL + " )");
I have also tried to change the
message.channel.send({embed}).then(msgURL => {
msgURL = embed.url;
})
to:
message.channel.send({embed}).then(msgURL => {
msgURL = embed.url.get;
})
But that unfortunately doesn't work either. Here you get this error:
TypeError: Cannot read property 'get' of null`
You can just use Message#url. There is no need for the .get().
You are trying to get the URL of the embed, not the message.
The HTML file where form is in doesn't have any client side javascript code. That I cannot change directly because my task is nodejs and express.
app.post('/',function(request,response){
const htmlCode = fs.readFileSync(__dirname + '/loggain.html');
const loggaInDom = new jsDOM.JSDOM(htmlCode);
const input = request.body.nickname;
try{
if(input.length<3){
throw new Error("nickname must be at least 3 characters");
}
else{
response.cookie('nickName',input);
response.redirect('index.html');
console.log(request.cookies.nickName);
}
}
catch(error){
console.log(error);
}
});
This is part of my nodejs code.
I would like to block form submit when input.length is smaller than 3. Like event.preventDefault() in client javascript code.
Now it throws error in console, which is correct, but browser keeps loading page permanently.
I cannot directly change HTML file but probably can insert client javascript file to HTML with nodejs, but I would like to know if it is possible to do with only nodeJS
Instead of throwing the error you need to send a response to the client with an error status:
if(input.length<3){
response.status(400).send("nickname must be at least 3 characters");
}
Choose the appropriate error code depending on your error: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
You can also send json instead of text if you want some structure that your frontend can use:
if(input.length<3){
response.status(400).json({
type: "validation error",
message: "nickname must be at least 3 characters"
});
}
Centralized error handling
Alternatively you may not want standardize error handling and do the response.status() thing at one location. Express has a way to catch errors but you cannot use the throw keyword. Instead you pass your error to the next function:
app.post('/',function(request, response, next){ // NOTE: next
const htmlCode = fs.readFileSync(__dirname + '/loggain.html');
const loggaInDom = new jsDOM.JSDOM(htmlCode);
const input = request.body.nickname;
try{
if(input.length<3){
throw new Error("nickname must be at least 3 characters");
}
else{
response.cookie('nickName',input);
response.redirect('index.html');
console.log(request.cookies.nickName);
}
}
catch(error){
next(error); // This is how errors are handled in Express
}
});
Now all you need to do is write a default error handler which is a special middleware that accepts four arguments instead of three or two. Make sure this middleware is loaded last after all your routes:
app.use((error, request, response, next) => {
response.status(500).send(error.message);
});
When used with error types you can send different responses to the browser depending on types of error:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError"; // (2)
}
}
Then you can throw:
next(new ValidationError("nickname must be at least 3 characters"))
Which you can handle with:
app.use((error, request, response, next) => {
switch(error.name) {
case "ValidationError":
response.status(400);
break;
default:
response.status(500);
}
response.send(error.message);
});
I'm trying to create a channel I can join using Flask socketio and Javascript.
All of my debug statements are firing, indicating that everything is initializing, but when I try to capture the message emitted from my Flask/socket-io route, which I assume executes the actual room change, I get Uncaught ReferenceError: Invalid left-hand side in assignment in my console referring to the line in my JS file let message = data.msg; in the section:
socket.on('status', data => {
let message = data.msg;
document.querySelectorAll('#messages') += message;
});
I tried writing data.msg various ways (e.g., with backticks, like this ${data.msg} surrounded by backticks as if part of a formatted string, etc), but nothing worked. I've read the docs, and they were sparse on details. There appear to be zero examples of how to do this effectively on the web. Most people seem to favor node.js, but I'm a Flask guy.
How can I join my room, and chat only in that room? I'll need to allow users to create as many as they want.
Here's the route in Flask:
#socketio.on('join')
def on_join(data):
username = data['username']
room = data['room']
join_room(room)
emit("status", {'msg': username + 'has joined the room'}, room=room)
Here's the accompanying JS:
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
if (!socket) console.log("Socket not connected!");
socket.on('connect', () => {
console.log("socket connected");
// after socket connect, configure channel button
document.querySelectorAll('button').forEach(button => {
button.onclick = () => {
console.log("button click fired!");
let username = localStorage["login"]
let room = button.dataset.room;
console.log("ChannelName" + room);
socket.emit("join", {'username':username, "room":room});
};
});
socket.on('status', data => {
console.log("JOINED!")
let message = data.msg;
document.querySelectorAll('#messages') += message;
});
Note, the error occurs right before assignment to the #message div.
EDIT
Unpacking the error reveals multiple references to the minified JS file flask socket-io requires. It is in the <head> section of layout.html. Placement in the <body> caused serious errors impeded development of all socket-related functionality.
messages:134 Uncaught ReferenceError: Invalid left-hand side in assignment
at r.socket.on.data (messages:134)
at r.n.emit (socket.io.min.js:1)
at r.onevent (socket.io.min.js:1)
at r.onpacket (socket.io.min.js:1)
at n.<anonymous> (socket.io.min.js:1)
at n.emit (socket.io.min.js:1)
at n.ondecoded (socket.io.min.js:1)
at s.<anonymous> (socket.io.min.js:1)
at s.n.emit (socket.io.min.js:1)
at s.add (socket.io.min.js:2)
This is not valid: document.querySelectorAll('#messages') += message;
document.querySelectorAll('#messages') Would give you a list of DOM elements.
Also, element id's are supposed to be unique, so you should probably be using document.querySelector('#messages') so retrieve just one element, and not a list.
You can not add/concat text to an element directly this way. You probably are looking for something like document.querySelector('#messages').innerHTML += message;