I’m encountering an error while trying to send Ether using Ethers.js in my decentralised Application. I have a Solidity function sendMoneyToCustomer
that is marked as payable
, but when I call it using Ethers.js, I get the following error:
Error: contract runner does not support sending transactions (operation=”sendTransaction”, code=UNSUPPORTED_OPERATION, version=6.13.3)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
contract LoyaltyPoints {
struct UserProfile {
string username;
string role;
}
mapping(address => UserProfile) private profiles;
mapping(address => uint256) private balances;
mapping(bytes32 => PurchaseRequest) private purchaseRequests;
struct PurchaseRequest {
address supermarket;
uint256 amount;
}
modifier onlyRegisteredSupermarket() {
UserProfile memory userProfile = profiles[msg.sender];
require(bytes(userProfile.username).length > 0, "Supermarket does not exist");
require(keccak256(bytes(userProfile.role)) == keccak256(bytes("supermarket")), "Not a Supermarket");
_;
}
modifier onlyRegisteredCustomer() {
UserProfile memory userProfile = profiles[msg.sender];
require(bytes(userProfile.username).length > 0, "Customer does not exist");
require(keccak256(bytes(userProfile.role)) == keccak256(bytes("customer")), "Not a Customer");
_;
}
error InsufficientBalance(uint requested, uint available);
function setProfile(string memory _username, string memory _role) public {
profiles[msg.sender] = UserProfile(_username, _role);
}
function getProfile(address userAddress) public view returns (UserProfile memory) {
return profiles[userAddress];
}
// Function to generate a QR code (purchase request) for a customer to scan and pay
function generatePurchaseRequest(uint256 amount) public onlyRegisteredSupermarket returns (bytes32) {
require(amount > 0, "Amount must be greater than zero");
bytes32 qrCode = keccak256(abi.encodePacked(msg.sender, amount, block.timestamp));
purchaseRequests[qrCode] = PurchaseRequest(msg.sender, amount);
return qrCode;
}
// Function for customer to scan the QR code and pay
function payWithQRCode(bytes32 qrCode) public payable onlyRegisteredCustomer {
PurchaseRequest memory request = purchaseRequests[qrCode];
require(request.supermarket != address(0), "Invalid QR code"); // Ensure valid request
require(msg.value >= request.amount, "Insufficient amount sent");
// Transfer ETH from customer to supermarket
payable(request.supermarket).transfer(request.amount);
// Remove the purchase request after payment is made
delete purchaseRequests[qrCode];
}
function sendMoneyToCustomer(address payable customer) public payable onlyRegisteredSupermarket {
require(customer != address(0), "Invalid customer address");
balances[customer] += msg.value;
customer.transfer(msg.value);
}
}
import { defineStore } from "pinia";
import axios from "axios";
import { ethers } from 'ethers';
import { SHOPIFY_URL} from "~~/services/global.variables";
export const useShopBrandsStore = defineStore('shopBrands', {
state: () => ({
name: "",
full_name: "",
my_profile : null,
contractAddress: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
abi : [
{
"inputs": [
{
"internalType": "uint256",
"name": "requested",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "available",
"type": "uint256"
}
],
"name": "InsufficientBalance",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "generatePurchaseRequest",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "userAddress",
"type": "address"
}
],
"name": "getProfile",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "username",
"type": "string"
},
{
"internalType": "string",
"name": "role",
"type": "string"
}
],
"internalType": "struct LoyaltyPoints.UserProfile",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "qrCode",
"type": "bytes32"
}
],
"name": "payWithQRCode",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "customer",
"type": "address"
}
],
"name": "sendMoneyToCustomer",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_username",
"type": "string"
},
{
"internalType": "string",
"name": "_role",
"type": "string"
}
],
"name": "setProfile",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
}),
actions: {
async connectWallet () {
console.log("Ethers:", ethers);
const provider = new ethers.BrowserProvider(window.ethereum)
console.log("Ethers:", ethers);
console.log("Provider:", provider);
await provider.send("eth_requestAccounts", []);
const signer = await provider.getSigner();
console.log('s',signer)
const walletAddress = await signer;
// Save wallet address and provider in localStorage
localStorage.setItem("signer", JSON.stringify(signer));
return provider.getSigner();
},
async setProfile(signer, username, role) {
const contract = new ethers.Contract(this.contractAddress, this.abi, signer);
const tx = await contract.setProfile(username, role);
await tx.wait();
},
async getProfile (signer) {
const contract = new ethers.Contract(this.contractAddress, this.abi, signer);
console.log('signer',signer)
const userAddress = await signer; // Get the user's wallet address
const profile = await contract.getProfile(userAddress);
this.my_profile = profile
return profile;
},
async generatePurchaseRequest (signer, amount) {
const contract = new ethers.Contract(contractAddress, abi, signer);
const qrCode = await contract.generatePurchaseRequest(amount);
return qrCode;
},
async payWithQRCode (signer, qrCode, amount) {
const contract = new ethers.Contract(contractAddress, abi, signer);
const tx = await contract.payWithQRCode(qrCode, { value: ethers.utils.parseEther(amount) });
await tx.wait();
},
async sendMoneyToCustomer (signer, customerAddress, amount) {
const contract = new ethers.Contract(this.contractAddress, this.abi, signer);
console.log('aaa',amount)
const ethValue = ethers.parseEther(amount)
console.log('eth',ethValue)
const tx = await contract.sendMoneyToCustomer(customerAddress, {value: ethValue}, // Convert the amount from ETH to Wei
);
await tx.wait(); // Wait for the transaction to be mined
},
}
});
Here's what I've checked so far:
The signer is correct, and I can call other non-payable functions like setProfile with the same signer.and its qorking when call setProfile