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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: 2.8.4
scarb-version: 2.11.2
- name: Check cairo format
run: scarb fmt --check
- name: Build cairo programs
Expand All @@ -22,9 +22,9 @@ jobs:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: 2.9.2
scarb-version: 2.11.2
- uses: foundry-rs/setup-snfoundry@v3
with:
starknet-foundry-version: 0.32.0
starknet-foundry-version: 0.40.0
- name: Run cairo tests
run: snforge test
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scarb 2.9.2
starknet-foundry 0.39.0
scarb 2.11.4
starknet-foundry 0.40.0
8 changes: 4 additions & 4 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ dependencies = [

[[package]]
name = "snforge_scarb_plugin"
version = "0.32.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.32.0#3817c903b640201c72e743b9bbe70a97149828a2"
version = "0.40.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.40.0#c20f7692c1a2936327d86b7e2c89c5462f8afdcd"

[[package]]
name = "snforge_std"
version = "0.32.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.32.0#3817c903b640201c72e743b9bbe70a97149828a2"
version = "0.40.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.40.0#c20f7692c1a2936327d86b7e2c89c5462f8afdcd"
dependencies = [
"snforge_scarb_plugin",
]
38 changes: 3 additions & 35 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,15 @@ name = "chain_lib"
version = "0.1.0"
edition = "2023_11"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[dependencies]
starknet = "2.8.4"
starknet = "2.11.2"

[dev-dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.32.0" }
assert_macros = "2.8.4"
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.40.0" }
assert_macros = "2.11.2"

[[target.starknet-contract]]
sierra = true

[scripts]
test = "snforge test"

# Visit https://foundry-rs.github.io/starknet-foundry/appendix/scarb-toml.html for more information

# [tool.snforge] # Define `snforge` tool section
# exit_first = true # Stop tests execution immediately upon the first failure
# fuzzer_runs = 1234 # Number of runs of the random fuzzer
# fuzzer_seed = 1111 # Seed for the random fuzzer

# [[tool.snforge.fork]] # Used for fork testing
# name = "SOME_NAME" # Fork name
# url = "http://your.rpc.url" # Url of the RPC provider
# block_id.tag = "latest" # Block to fork from (block tag)

# [[tool.snforge.fork]]
# name = "SOME_SECOND_NAME"
# url = "http://your.second.rpc.url"
# block_id.number = "123" # Block to fork from (block number)

# [[tool.snforge.fork]]
# name = "SOME_THIRD_NAME"
# url = "http://your.third.rpc.url"
# block_id.hash = "0x123" # Block to fork from (block hash)

# [profile.dev.cairo] # Configure Cairo compiler
# unstable-add-statements-code-locations-debug-info = true # Should be used if you want to use coverage
# unstable-add-statements-functions-debug-info = true # Should be used if you want to use coverage/profiler
# inlining-strategy = "avoid" # Should be used if you want to use coverage

# [features] # Used for conditional compilation
# enable_for_tests = [] # Feature name and list of other features that should be enabled with it
110 changes: 87 additions & 23 deletions src/chainlib/ChainLib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pub mod ChainLib {
use core::option::OptionTrait;
use core::traits::Into;
use starknet::storage::{
Map, MutableVecTrait, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess,
StoragePointerWriteAccess, Vec, VecTrait,
Map, MutableVecTrait, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry,
StoragePointerReadAccess, StoragePointerWriteAccess, Vec, VecTrait,
};
use starknet::{
ContractAddress, contract_address_const, get_block_timestamp, get_caller_address,
Expand Down Expand Up @@ -68,7 +68,7 @@ pub mod ChainLib {
pub category: Category,
}

#[derive(Copy, Drop, Serde, starknet::Store, Debug)]
#[derive(Drop, Serde, starknet::Store, Clone)]
pub struct Subscription {
pub id: u256,
pub subscriber: ContractAddress,
Expand All @@ -78,6 +78,15 @@ pub mod ChainLib {
pub end_date: u64,
pub is_active: bool,
pub last_payment_date: u64,
pub subscription_type: PlanType,
}

#[derive(Drop, Serde, starknet::Store, Clone, PartialEq)]
pub enum PlanType {
#[default]
MONTHLY,
YEARLY,
TRIAL,
}

#[derive(Copy, Drop, Serde, starknet::Store, Debug)]
Expand Down Expand Up @@ -190,6 +199,10 @@ pub mod ChainLib {
next_purchase_id: u256, // Counter for purchase IDs
purchases: Map<u256, Purchase>, // Maps purchase ID to Purchase
purchase_timeout_duration: u64,
subscription_record: Map<u256, Vec<Subscription>>, // subcription id to subscription record
subscription_count: Map<
u256, u256,
> // subscriber count to number of times the subscription record has been updated
}


Expand Down Expand Up @@ -710,6 +723,7 @@ pub mod ChainLib {
content_metadata
}


/// @notice Processes the initial payment for a new subscription
/// @param amount The amount to be charged for the initial payment
/// @param subscriber The address of the subscriber
Expand All @@ -725,6 +739,8 @@ pub mod ChainLib {

// Create a new subscription
let subscription_id = self.subscription_id.read();
let subscription_plan: Subscription = self.subscriptions.read(subscription_id);

let current_time = get_block_timestamp();

// Default subscription period is 30 days (in seconds)
Expand All @@ -739,10 +755,16 @@ pub mod ChainLib {
end_date: current_time + subscription_period,
is_active: true,
last_payment_date: current_time,
subscription_type: subscription_plan.subscription_type,
};

// Store the subscription
self.subscriptions.write(subscription_id, new_subscription);
self.subscriptions.write(subscription_id, new_subscription.clone());

self.subscription_record.entry(subscription_id).append().write(new_subscription);

let current_count = self.subscription_count.read(subscription_id);
self.subscription_count.write(subscription_id, current_count + 1);

// Create and store the payment record
let payment_id = self.payment_id.read();
Expand Down Expand Up @@ -805,7 +827,7 @@ pub mod ChainLib {
let mut subscription = self.subscriptions.read(subscription_id);

// Verify subscription exists and is active
assert(subscription.id == subscription_id, 'Subscription not found');
assert(subscription.id.clone() == subscription_id, 'Subscription not found');
assert(subscription.is_active, 'Subscription not active');

// Check if it's time for a recurring payment
Expand All @@ -819,19 +841,20 @@ pub mod ChainLib {
// Default subscription period is 30 days (in seconds)
let subscription_period: u64 = 30 * 24 * 60 * 60;

// Save required fields before mutating subscription
let subscription_amount = subscription.amount;
let subscription_subscriber = subscription.subscriber;

// Update subscription details
subscription.last_payment_date = current_time;
subscription.end_date = current_time + subscription_period;

// Store updated subscription
self.subscriptions.write(subscription_id, subscription);

// Create and store the payment record
let payment_id = self.payment_id.read();
let new_payment = Payment {
id: payment_id,
subscription_id: subscription_id,
amount: subscription.amount,
amount: subscription_amount,
timestamp: current_time,
is_verified: true, // Auto-verify for simplicity
is_refunded: false,
Expand All @@ -852,15 +875,14 @@ pub mod ChainLib {

// Increment payment ID for next use
self.payment_id.write(payment_id + 1);

// Emit recurring payment processed event
self
.emit(
RecurringPaymentProcessed {
payment_id: payment_id,
subscription_id: subscription_id,
subscriber: subscription.subscriber,
amount: subscription.amount,
subscriber: subscription_subscriber,
amount: subscription_amount,
timestamp: current_time,
},
);
Expand Down Expand Up @@ -977,7 +999,7 @@ pub mod ChainLib {
};
self.content_verification_requirements.write((content_id, i), default_req);
i += 1;
};
}

// Store new requirements
let new_count = requirements.len();
Expand All @@ -986,7 +1008,7 @@ pub mod ChainLib {
let req = requirements.at(i);
self.content_verification_requirements.write((content_id, i), *req);
i += 1;
};
}

self.content_verification_requirements_count.write(content_id, new_count);
true
Expand All @@ -1004,7 +1026,7 @@ pub mod ChainLib {
let req = self.content_verification_requirements.read((content_id, i));
requirements.append(req);
i += 1;
};
}

requirements
}
Expand All @@ -1031,7 +1053,7 @@ pub mod ChainLib {
};
self.content_access_rules.write((content_id, i), empty_rule);
i += 1;
};
}

// Store new rules
let new_count = rules.len();
Expand All @@ -1040,7 +1062,7 @@ pub mod ChainLib {
let rule = *rules.at(i);
self.content_access_rules.write((content_id, i), rule);
i += 1;
};
}

self.content_access_rules_count.write(content_id, new_count);
true
Expand All @@ -1058,7 +1080,7 @@ pub mod ChainLib {
let rule = self.content_access_rules.read((content_id, i));
rules.append(rule);
i += 1;
};
}

rules
}
Expand Down Expand Up @@ -1109,7 +1131,7 @@ pub mod ChainLib {
break;
}
i += 1;
};
}
status
}

Expand Down Expand Up @@ -1363,7 +1385,9 @@ pub mod ChainLib {
}


fn create_subscription(ref self: ContractState, user_id: u256, amount: u256) -> bool {
fn create_subscription(
ref self: ContractState, user_id: u256, amount: u256, plan_type: u32,
) -> bool {
let caller = get_caller_address();

// Verify the user exists
Expand All @@ -1380,6 +1404,21 @@ pub mod ChainLib {
let subscription_period: u64 = 30 * 24 * 60 * 60;
let end_date = current_time + subscription_period;

let planTypeResult: Result<PlanType, felt252> = match plan_type {
0 => Ok(PlanType::MONTHLY),
1 => Ok(PlanType::YEARLY),
2 => Ok(PlanType::TRIAL),
_ => Err('Invalid plan option'),
};
let subscription_type = match planTypeResult {
Result::Ok(pt) => pt,
Result::Err(_) => {
assert(false, 'Invalid plan option');
// This line will never be reached, but is required for type checking
PlanType::MONTHLY
},
};

let new_subscription = Subscription {
id: subscription_id,
subscriber: caller,
Expand All @@ -1389,9 +1428,16 @@ pub mod ChainLib {
end_date: end_date,
is_active: true,
last_payment_date: current_time,
subscription_type: subscription_type,
};

self.subscriptions.write(user_id, new_subscription);
self.subscriptions.write(user_id, new_subscription.clone());

// read from the subscription
self.subscription_record.entry(user_id).append().write(new_subscription);

let current_count = self.subscription_count.read(user_id);
self.subscription_count.write(user_id, current_count + 1);

// Emit event
self.emit(SubscriptionCreated { user_id: user_id, end_date: end_date, amount: amount });
Expand Down Expand Up @@ -1439,6 +1485,24 @@ pub mod ChainLib {

true
}

fn get_user_subscription_record(
ref self: ContractState, user_id: u256,
) -> Array<Subscription> {
let count = self.subscription_count.entry(user_id).read();
let mut subscriptions = ArrayTrait::new();

let mut i = 0;
while i < count.try_into().unwrap() {
let subscription = self.subscription_record.entry(user_id).at(i).read();
subscriptions.append(subscription);
i += 1;
}

subscriptions
}


fn is_in_blacklist(self: @ContractState, user_id: u256, content_id: felt252) -> bool {
self.access_blacklist.read((user_id, content_id))
}
Expand Down Expand Up @@ -1707,7 +1771,7 @@ pub mod ChainLib {
purchases.append(purchase);
}
i += 1;
};
}

// Return the array of purchases
purchases
Expand All @@ -1732,7 +1796,7 @@ pub mod ChainLib {
purchases.append(purchase);
}
i += 1;
};
}

// Return the array of purchases
purchases
Expand Down
Loading
Loading