Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scarb 2.11.4
starknet-foundry 0.40.0
starknet-foundry 0.43.1
21 changes: 21 additions & 0 deletions src/base/types.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,24 @@ pub struct Purchase {
pub transaction_hash: felt252,
pub timeout_expiry: u64,
}


#[derive(Drop, Serde, starknet::Store, Debug)]
pub enum ReceiptStatus {
#[default]
Invalid,
Valid,
}

#[derive(Drop, Serde, starknet::Store, Debug)]
pub struct Receipt {
pub id: u256,
pub purchase_id: u256,
pub content_id: felt252,
pub buyer: ContractAddress,
pub creator: ContractAddress,
pub price: u256,
pub status: ReceiptStatus,
pub issued_at: u64,
pub transaction_hash: felt252,
}
89 changes: 86 additions & 3 deletions src/chainlib/ChainLib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ pub mod ChainLib {
};
use crate::base::errors::payment_errors;
use crate::base::types::{
AccessRule, AccessType, Permissions, Purchase, PurchaseStatus, Rank, Role, Status,
TokenBoundAccount, User, VerificationRequirement, VerificationType, permission_flags,
AccessRule, AccessType, Permissions, Purchase, PurchaseStatus, Rank, Receipt, ReceiptStatus,
Role, Status, TokenBoundAccount, User, VerificationRequirement, VerificationType,
permission_flags,
};
use crate::interfaces::IChainLib::IChainLib;

Expand Down Expand Up @@ -215,7 +216,12 @@ pub mod ChainLib {
subscription_count: Map<
u256, u256,
>, // subscriber count to number of times the subscription record has been updated
token_address: ContractAddress // Address of the token contract used for payments
// RECEIPTS
receipt_counter: u256,
receipt: Map<u256, Receipt>,
creator_sales: Map<ContractAddress, u256>,
total_sales_for_content: Map<felt252, u256>,
token_address: ContractAddress,
}


Expand Down Expand Up @@ -259,6 +265,7 @@ pub mod ChainLib {
PurchaseStatusUpdated: PurchaseStatusUpdated,
SubscriptionCancelled: SubscriptionCancelled,
SubscriptionRenewed: SubscriptionRenewed,
ReceiptGenerated: ReceiptGenerated,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -285,6 +292,11 @@ pub mod ChainLib {
new_end_time: u64,
}

#[derive(Drop, starknet::Event)]
struct ReceiptGenerated {
receipt_id: u256,
}

#[derive(Drop, starknet::Event)]
struct SubscriptionCancelled {
user: ContractAddress,
Expand Down Expand Up @@ -1853,7 +1865,23 @@ pub mod ChainLib {
fn verify_purchase(ref self: ContractState, purchase_id: u256) -> bool {
// Get the purchase details
let purchase = self.purchases.read(purchase_id);
let content = self.content.read(purchase.content_id);
let total_content_sales = self.total_sales_for_content.read(purchase.content_id)
+ purchase.price;

let total_creator_sales = self.creator_sales.read(content.creator) + purchase.price;
self.creator_sales.write(content.creator, total_creator_sales);

self.total_sales_for_content.write(purchase.content_id, total_content_sales);
self
.issue_receipt(
purchase_id,
purchase.content_id,
purchase.buyer,
content.creator,
purchase.price,
purchase.transaction_hash,
);
// A purchase is valid if its status is Completed
if purchase.status == PurchaseStatus::Completed {
return true;
Expand Down Expand Up @@ -1984,6 +2012,61 @@ pub mod ChainLib {

true
}

fn issue_receipt(
ref self: ContractState,
purchase_id: u256,
content_id: felt252,
buyer: ContractAddress,
creator: ContractAddress,
price: u256,
transaction_hash: felt252,
) -> u256 {
let receipt_id = self.receipt_counter.read() + 1;
let issued_at = starknet::get_block_timestamp();

let receipt = Receipt {
id: receipt_id,
purchase_id,
content_id,
buyer,
creator,
price,
status: ReceiptStatus::Valid,
issued_at,
transaction_hash,
};
self.receipt_counter.write(receipt_id);
self.receipt.write(receipt_id, receipt);

self.emit(ReceiptGenerated { receipt_id });

receipt_id
}

fn get_receipt(self: @ContractState, receipt_id: u256) -> Receipt {
let receipt = self.receipt.read(receipt_id);
receipt
}

fn is_receipt_valid(self: @ContractState, receipt_id: u256) -> bool {
let receipt = self.receipt.read(receipt_id);

match receipt.status {
ReceiptStatus::Valid => true,
ReceiptStatus::Invalid => false,
}
}

fn get_total_sales_by_creator(self: @ContractState, creator: ContractAddress) -> u256 {
let total_sales = self.creator_sales.read(creator);
total_sales
}

fn get_total_sales_for_content(self: @ContractState, content_id: felt252) -> u256 {
let total_content_sales = self.total_sales_for_content.read(content_id);
total_content_sales
}
}

#[generate_trait]
Expand Down
18 changes: 17 additions & 1 deletion src/interfaces/IChainLib.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::array::Array;
use starknet::ContractAddress;
use crate::base::types::{
AccessRule, Permissions, Purchase, PurchaseStatus, Rank, Role, TokenBoundAccount, User,
AccessRule, Permissions, Purchase, PurchaseStatus, Rank, Receipt, Role, TokenBoundAccount, User,
VerificationRequirement, VerificationType,
};
use crate::chainlib::ChainLib::ChainLib::{
Expand Down Expand Up @@ -213,4 +213,20 @@ pub trait IChainLib<TContractState> {
fn get_user_subscription_record(ref self: TContractState, user_id: u256) -> Array<Subscription>;
fn cancel_subscription(ref self: TContractState, user_id: u256) -> bool;
fn renew_subscription(ref self: TContractState, user_id: u256) -> bool;
fn issue_receipt(
ref self: TContractState,
purchase_id: u256,
content_id: felt252,
buyer: ContractAddress,
creator: ContractAddress,
price: u256,
transaction_hash: felt252,
) -> u256;

fn get_receipt(self: @TContractState, receipt_id: u256) -> Receipt;
fn is_receipt_valid(self: @TContractState, receipt_id: u256) -> bool;
fn get_total_sales_by_creator(self: @TContractState, creator: ContractAddress) -> u256;
fn get_total_sales_for_content(self: @TContractState, content_id: felt252) -> u256;
// fn get_daily_sales(self: @TContractState, day: u64) -> u256;
// fn get_unique_buyers_count(self: @TContractState) -> u256;
}
4 changes: 4 additions & 0 deletions tests/test_ChainLib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,10 @@ fn test_verify_purchase() {
// Now the purchase should be verified
let is_now_verified = dispatcher.verify_purchase(purchase_id);
assert(is_now_verified, 'Purchase should be verified');

let receipt = dispatcher.get_receipt(1);

assert(receipt.purchase_id == purchase_id, 'receipt error');
}

#[test]
Expand Down
Loading