A platform for reliable customer reviews and ratings on any business that accepts payment in SNIP-20 tokens. Powered by Secret Network, privacy is preserved for reviewers.
❗ RENAME: Cashmaps have been deprecated in favor of Keymaps
This example demonstrates how to query different contracts, and how to use a CashMap - a key-value data structure for secret that can be iterated through (other key-value data structures cannot, because keys are not known in advance).
- Customers who rate/review must prove they transacted with the business, by providing a snip-20 receipt.
- Ratings and reviews are weighted by price of the transaction.
-
⚠️ Receipt Privacy: although Secret Network makes it possible for us to keep the content of the receipt private, the volume of the transaction can still be deduced by a replay attack. The attacker can know the business' total weight by querying the change done to its average rating by his own transaction, which he knows the weight of. Then he can replay the transaction that he wants to discover the weight of, and see how did it change the average.⚠️ -
Incentive to rate and review: customers have to pay the network fee and gas fees for rating. This price could be mitigated by an option to let the business being reviewed refund the fees. This could further improve the business' reputation
A Business must be registered to be able to review it. Anyone can register an address as a business. (Functionality to edit business or to claim it by the owner is not implemented). Every review on this business must provide a receipt for a transfer from the reviewer to that business
message='{
"register_business": {
"name": "Crypto Bicycles",
"description": "renting bicycles privately",
"address": "secret1examplebicycles"
}
}'
secretcli tx compute execute <contract-address> "$message" --from <keyname> --gas 150000
# then query the result of the tx
secretcli query compute tx <tx_hash>
# {
# ...
# "output_data_as_string": {
# "register_business": {
# "status": "successfully called register business"
# }
# }
# }
After a Business is registered, anyone who transacted with it can review and rate it. Ratings are
integers between 0 and 5 (stars).
A "receipt" is a transfer that is fetched from the SNIP-20 contract that was used for payment to the
business. This example uses SSCRT as the paying token. The
reviewer must provide the tx_id
of the payment, the tx_page
where the tx occurs in the contract
(pages are of size 10), and the viewing_key
, which is never saved in the contract.
The rating provided by this message will have the same weight as the amount of coins in the transfer.
message='{
"review_business": {
"address": "secret1examplebicycles",
"content": "excellent service",
"rating": 5,
"title": "Best crypto bicycles I have every ridden",
"tx_id": 8,
"tx_page": 0,
"viewing_key": "vk"
}
}'
secretcli tx compute execute <contract-address> "$message" --from <keyname> --gas 150000
The result of this transaction may be:
# ...
# "output_data_as_string": {
# "review_business": {
# "status": "Successfully added a new review on business, receipt was accounted for"
# }
# }
# ...
To Edit a review, simply provide the same tx_id
(note that pagination in SSCRT is from newest
to oldest so the page number might change), with the new content/rating. The result of the
transaction will then be:
"status": "Successfully updated a previous review on business"
You can provide more receipts to enlarge the weight of the review, every tx is accounted for. Note
that there is only one review and rating that a single account may have on each business. Previous
transactions are considered to have given the last rating that was given by the account.
For example, these two txs:
tx1(weight=1, rating=4)
, and then
tx2(weight=2, rating=0)
are the same as
tx3(weight=3, rating=0)
"status": "Successfully updated a previous review on business, receipt was accounted for"
All Queries that return an array accept a page_size
and an optional page
for pagination purposes.
The average_rating
field should be considered a value with 3 decimal places, e.g. 4428 ->
4.428
stars.
You can query all businesses:
message='{
"get_businesses": {
"page_size": 8,
"page": 0
}
}'
secretcli q compute query <contract-address> "$message"
# {
# "businesses": {
# "businesses": [
# {
# "name": "Starbucks",
# "description": "a place to eat",
# "address": "secret1example",
# "average_rating": "4428",
# "reviews_count": 3
# }
# ],
# "total": 1
# }
# }
# }
All reviews on a specific business:
message='{
"get_reviews_on_business": {
"business_address": "secret1example",
"page_size": 8
}
}'
secretcli q compute query <contract-address> "$message"
# {
# "reviews": {
# "reviews": [
# {
# "title": "amazing restaurant",
# "content": "great stuff!",
# "rating": 5,
# "last_update_timestamp": 1651679560
# },
# {
# "title": "2nd time is the charm",
# "content": "second time was amazing",
# "rating": 5,
# "last_update_timestamp": 1651679566
# },
# ...
# ],
# "total": 3
# }
# }
Or you can query a single business.
We use secret-toolkit's CashMap
(incubator feature) to save our businesses and reviews.
We need this data structure becuase we want key-value mapping
- fetch businesses by their address and reviews by the reviewer's address,
But also need to iterate through all our keys, as want to list all reviews on a business and all businesses in our platform.
We have:
- A CashMap that contains all businesses' metadata.
KEY_BUSINESSES -> CashMap(business_address -> Business)
- A CashMap for each business that contains all its reviews, mapping each reviewer's address to its review. This is a double mapping that is done by prefixing the key to retrieve the data with the business' address
KEY_REVIEWS|BUSINESS_ADDRESS -> CashMap(reviewer_address -> Review)
We also have DisplayedReview
and DisplayedBusiness
that we return in queries that omit the private
data.