For example, let's say that every time a user successfully executes a contract function that calculates the sum of two numbers, I’d like to charge a 1% ETH fee that gets sent to an account separate from the contract. My current solution "works", but it is not a good solution as you can imagine. As it stands, the user has to sign two separate transactions, one after the other. First, to sign the fee amount, and second, to sign the contract function. How would I go about creating one transaction which includes both the fee and the contract function together? I'm using Ethers.js for the convenience library, but I'm open to other solutions.
Solidity Contract
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract Calculate {
uint private c = 123;
constructor() {
getC();
}
function getC() public view returns (uint) {
return c;
}
function add(uint _a, uint _b) public {
c = _a + _b;
}
}
React
async function add() {
await requestAccount();
await sendETH();
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(
calculateAddress,
Calculate.abi,
signer
);
const tx = await contract.add(a, b);
await tx.wait();
getC();
}
async function sendETH() {
await requestAccount();
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const tx = {
from: connectedAccount,
to: fundAcct,
value: ethers.utils.parseEther(fee.toString()),
};
signer.sendTransaction(tx).then((transaction) => {
console.dir(transaction);
alert("Send finished!");
});
}
In case if incoming transfer amount is any, and you charge 1%, you have to call add function with value*(1+fee) amount.
Considering fee is in range 0-1 and there is a total variable for a total transaction cost without fee.
const tx = await contract.add(a, b, {value: ethers.utils.parseEther(fee.toString()).mul(total)});
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract Calculate {
uint private c = 123;
address separateContract;
constructor(address _separateContract) {
getC();
separateContract = _separateContract;
}
function getC() public view returns (uint) {
return c;
}
function add(uint _a, uint _b) public payable {
separateContract.send(msg.value / 100); // send 1% to a separate contract
c = _a + _b;
}
}