I'm creating a raffle website. The user connects his wallet and pays for a raffle ticket. After the blockchain transaction confirmation, I add his raffle ticket in a collection in firestore.
It causes a security issue because if I allow the user to write to the raffle ticket collection in my firebase security rules, he could create his own tickets without paying.
I need tickets to be added to the database only if payment has been successfully made.
I don't know how websites that have means of payment do it. Maybe firebase isn't a good solution ?
My project is in react/typescript.
CodePudding user response:
You say you do the payment over the blockchain and I assume you use solidity as your smart contract language?
- Why don't you emit an event in your smart contract?
- You then listen for these events on a (seperate) server.
- That updates your (firebase) database whenever an event was emitted.
(Untested) Sample Code:
How do you emit events in solidity? (raffle.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Raffle {
event PaymentCompletion(address buyer, uint256 amountOfTickets);
function buyTickets() external payable {
emit PaymentCompletion(msg.sender, msg.value)
}
}
How do you listen to these events? when using web3js:
const contract = new web3.eth.Contract(CONTRACT_ABI, CONTRACT_ADDRESS);
const lastBlock = await web3.eth.getBlockNumber()
// paymentEvents is an array containing the payments of the last 500 blocks.
const paymentEvents = await contract.getPastEvents(
'PaymentCompletion', // change if your looking for a different event
{ fromBlock: latestBlock - 500, toBlock: 'latest' }
);
now iterate through these events and put them into your database. You can also set up a subscription which notifies you whenever a new block was created, so you can check if new events were inside of the current block.
This is what it would look like if you add the first blockchain event to the firebase realtime database
.
var db = admin.database();
var ref = db.ref("/payments");
// ...
ref.child("path/to/transaction").set({
buyer: paymentEvents[0].buyer,
amountOfTickets: paymentEvents[0].amountOfTickets,
// put the rest of your data here
}, (err) => {
if (err) {
console.error(err)
}
})
Alternatively (if you don't want to handle the payment on the blockchain) you could also take a look at stripe, it also has a firebase plugin for easy integration. (but I've never tried it out). However, imo using the blockchain for handling the payment would be the cleanest solution. ( you don't have the handling fees stripe uses).
I hope I could give you some good clues! Firebase should be definitely suitable for this.