I'm having a problem figuring out where to store donations in a donations platform I'm creating. And then later, the campaign owners can withdraw their donations minus a platform fee that is deducted automatically.
Case 1
At first, I was sending the donations directly to the owner of the campaign and it was working fine. The problem with this is that a person can spend/withdraw the ether without paying the platform fee since the ether is already in their wallets.
(bool sent,) = payable(campaign.owner).call{value: amount}("");
Case 2
I changed the address that was to receive the donations to the manager. That is the owner of the platform.
constructor(uint256 _platformFee) payable {
manager == msg.sender;
}
// Sending donations
(bool sent, ) = payable(manager).call{value: amount}("");
require(sent, "donation failed");
When I donate everything is okay. The problem comes when I want to withdraw. How can a campaign owner trigger a withdrawal from the manager's address? And they only have to withdraw what was donated to them. Assuming there are several campaigns, and each campaign has several donations, we don't want one campaign owner to withdraw other people's money.
Withdraw Function
// platform fee
function calculatePlatformFee(
uint256 _id
) public view returns (uint, uint) {
require(campaigns[_id].amountCollected > 0, "no donations collected");
uint raisedAmount = campaigns[_id].amountCollected;
uint fee = (raisedAmount * platformFee) / 100;
return (raisedAmount, fee);
}
// withdraw donations
function withdrawDonations(
uint256 _id
) public authorisedPerson(_id) returns (bool) {
(uint raisedAmount, uint256 fee) = calculatePlatformFee(_id);
address platformAddress = 0x13A19933267ec307c96f3dE8Ff8A2392C39263EB;
//balances[msg.sender] = 0; // updating adress balance before atually withdrawing
//send to campaign owner
require(
(raisedAmount - fee) <= (manager.balance),
"amount in excess of balance"
);
_payTo(campaigns[_id].owner, (raisedAmount - fee));
//send to platform
require(fee <= (manager.balance), "fee in excess of balance");
_payTo(platformAddress, fee);
emit Action(_id, "Funds Withdrawn", msg.sender, block.timestamp);
return true;
}
function _payTo(address to, uint256 amount) internal {
require(amount > 0, "Can't send 0");
(bool success, ) = payable(to).call{value: amount}("");
require(success, "transfer failed");
}
The Error after calling withdraw
Error occurred while withdrawing funds Error:
╔═══════════════════╗
║ TRANSACTION ERROR ║
╚═══════════════════╝
Reason: transfer failed
╔═════════════════════════╗
║ TRANSACTION INFORMATION ║
╚═════════════════════════╝
from: 0x13A19933267ec307c96f3dE8Ff8A2392C39263EB
to: 0x39f93Ef4E7a02fBAC7BCACa9174A83B4C54cf4ab
chain: sepolia (11155111)
rpc: sepolia.rpc.thirdweb.com
data: 0x388a7ec10000000000000000000000000000000000000000000000000000000000000000
method: withdrawDonations(0)
Here is the repo for more info.