Skip to content

Commit

Permalink
Merge branch 'main' into feat/publication
Browse files Browse the repository at this point in the history
  • Loading branch information
codeWhizperer authored May 31, 2024
2 parents f25da19 + 82b38b4 commit 924ab4e
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 43 deletions.
Binary file added img/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 38 additions & 43 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
# Karst

Karst is a web3 social graph on Starknet. it aims to build a social infrastructure for the starknet ecosystem.

## TODOS

- [ ] Implement `create profiles contract` functionality using `erc6551`
- [x] Implement `create profile` functionality
- [x] Implement `setProfileMetadataURI` functionality
- [x] Write test for `createProfile` and related `profile` functions
- [ ] implement `Publications` contract
- [ ] Make contract upgradable, preferably uups.
- [ ] implement `post` functionality
- [ ] Implement `like` functionality
- [ ] Implement `comment` functionality
- [ ] Implement `mirror` functionality
- [ ] Implement `quote` functionality
- [ ] implement `tipPost` functionality
- [ ] implement `follow` functionality from followNFT
- [ ] Implement `FollowNFT` contract
- [ ] implement `unwrap` functionality
- [ ] Implement `approveFollow` functionality
- [ ] Implement `removeFollower` functionality
- [ ] Implement `wrap` functionality
- [ ] Implement `follow` functionality
- [ ] Implement `unfollow` functionality
- [ ] Implement `getOriginalFollowTimestamp` functionality
- [ ] Implement `getFollowTimestamp` functionality
- [ ] Implement `getProfileIdAllowedToRecover` functionality
- [ ] Implement `getFollowData` functionality
- [ ] Implement `getFollowApproved` functionality
- [ ] Implement `getFollowerCount` functionality
- Implement `addDelegate` functionality
- [ ] Implement indexing of publish contract
- [ ] indexing shall be done with [arweave](https://www.arweave.org/)
- [ ] index all events emitted by the publications contract
- [ ] set up api endpoints to query the indexer
- [ ] not important at the moment
- [ ] create a custom explorer for querying the content layer

## Remarks

our implementation may defer from lens by they both achieve the same goal
link to [Lens protocol](https://polygonscan.com/address/0x176c2a1c54e8b028eeec14bf0a059e354408ff47#code) contracts
Karst is a permissionless and composable social graph built on Starknet, empowering creators to own every part of their social experience.

With Karst, creators no longer need to worry about losing their content, audience, and livelihood based on the whims of an individual platform's algorithms and policies.

## Development Setup
You will need to have Scarb and Starknet Foundry installed on your system. Refer to the documentations below:

- [Starknet Foundry](https://foundry-rs.github.io/starknet-foundry/index.html)
- [Scarb](https://docs.swmansion.com/scarb/download.html)

To use this repository, first clone it:
```
git clone [email protected]:horuslabsio/karst-core.git
cd karst-core
```

### Building contracts
To build the contracts, run the command:
```
scarb build
```

### Running Tests
To run the tests contained within the `tests` folder, run the command:
```
snforge test
```

### Formatting contracts
We use the in-built formatter that comes with Scarb. To format your contracts, simply run the command:
```
scarb fmt
```

For more information on writing and running tests, refer to the [Starknet-Foundry documentation](https://foundry-rs.github.io/starknet-foundry/index.html)

## Architecture

Check out the architecture below, and also reference [lens protocol](https://github.com/lens-protocol/core/tree/master) to understand more.

*Architecture Preview.*
![Local Image](./img/karst%20archieture.png)
<img width="100%" alt="Screenshot 2024-05-24 at 00 11 16" src="https://github.com/horuslabsio/karst-core/blob/main/img/architecture.png?raw=true">


1 change: 1 addition & 0 deletions src/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub mod IRegistry;
pub mod IProfile;
pub mod IFollowNFT;
pub mod IPublication;
pub mod IHandle;
24 changes: 24 additions & 0 deletions src/interfaces/IHandle.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use starknet::ContractAddress;

// *************************************************************************
// INTERFACE of FollowNFT
// *************************************************************************
#[starknet::interface]
pub trait IHandle<TState> {
// *************************************************************************
// EXTERNALS
// *************************************************************************
fn mint_handle(ref self: TState, address: ContractAddress, local_name: felt252) -> u256;
fn burn_handle(ref self: TState, token_id: u256);
fn set_handle_token_uri(ref self: TState, token_id: u256, local_name: felt252);
fn migrate_handle(ref self: TState, address: ContractAddress, local_name: felt252) -> u256;
// *************************************************************************
// GETTERS
// *************************************************************************
fn get_namespace(self: @TState) -> felt252;
fn get_local_name(self: @TState, token_id: u256) -> felt252;
fn get_handle(self: @TState, token_id: u256) -> ByteArray;
fn exists(self: @TState, token_id: u256) -> bool;
fn total_supply(self: @TState) -> u256;
fn get_handle_token_uri(self: @TState, token_id: u256, local_name: felt252) -> ByteArray;
}
2 changes: 2 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ pub mod follownft;
pub mod mocks;
pub mod publication;


pub mod namespaces;
2 changes: 2 additions & 0 deletions src/namespaces.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod handles;
mod handle_registry;
1 change: 1 addition & 0 deletions src/namespaces/handle_registry.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

201 changes: 201 additions & 0 deletions src/namespaces/handles.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// *************************************************************************
// OZ ERC721
// *************************************************************************
use openzeppelin::{
token::erc721::{ERC721Component::{ERC721Metadata, HasComponent}},
introspection::src5::SRC5Component,
};

#[starknet::interface]
trait IERC721Metadata<TState> {
fn name(self: @TState) -> ByteArray;
fn symbol(self: @TState) -> ByteArray;
}

#[starknet::embeddable]
impl IERC721MetadataImpl<
TContractState,
+HasComponent<TContractState>,
+SRC5Component::HasComponent<TContractState>,
+Drop<TContractState>
> of IERC721Metadata<TContractState> {
fn name(self: @TContractState) -> ByteArray {
let component = HasComponent::get_component(self);
ERC721Metadata::name(component)
}

fn symbol(self: @TContractState) -> ByteArray {
let component = HasComponent::get_component(self);
ERC721Metadata::symbol(component)
}
}


#[starknet::contract]
mod Handles {
// *************************************************************************
// IMPORT
// *************************************************************************
use core::traits::TryInto;
use starknet::{ContractAddress, get_caller_address};
use openzeppelin::{
account, access::ownable::OwnableComponent,
token::erc721::{
ERC721Component, erc721::ERC721Component::InternalTrait as ERC721InternalTrait
},
introspection::{src5::SRC5Component}
};
use karst::interfaces::IHandle::IHandle;

component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
component!(path: SRC5Component, storage: src5, event: SRC5Event);
component!(path: ERC721Component, storage: erc721, event: ERC721Event);

// allow to check what interface is supported
#[abi(embed_v0)]
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>;

#[abi(embed_v0)]
impl ERC721Impl = ERC721Component::ERC721Impl<ContractState>;
#[abi(embed_v0)]
impl ERC721CamelOnlyImpl = ERC721Component::ERC721CamelOnlyImpl<ContractState>;
#[abi(embed_v0)]
impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl<ContractState>;

// add an owner
#[abi(embed_v0)]
impl OwnableImpl = OwnableComponent::OwnableImpl<ContractState>;
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

// *************************************************************************
// STORAGE
// *************************************************************************
#[storage]
struct Storage {
#[substorage(v0)]
erc721: ERC721Component::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
admin: ContractAddress,
total_supply: u256,
local_names: LegacyMap::<u256, felt252>,
karst_hub: ContractAddress,
}

// *************************************************************************
// CONSTANTS
// *************************************************************************
const MAX_LOCAL_NAME_LENGTH: u256 = 26;
const NAMESPACE: felt252 = 'karst';

// *************************************************************************
// EVENTS
// *************************************************************************
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC721Event: ERC721Component::Event,
#[flat]
SRC5Event: SRC5Component::Event,
#[flat]
OwnableEvent: OwnableComponent::Event,
}

// *************************************************************************
// CONSTRUCTOR
// *************************************************************************
#[constructor]
fn constructor(
ref self: ContractState,
admin: ContractAddress, // to perform upgrade
name: ByteArray,
symbol: ByteArray,
hub_address: ContractAddress
) {
self.admin.write(admin);
self.karst_hub.write(hub_address);
self.erc721.initializer("KARST HANDLES", "KARST", "");
}

// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
#[abi(embed_v0)]
impl HandlesImpl of IHandle<ContractState> {
fn mint_handle(
ref self: ContractState, address: ContractAddress, local_name: felt252
) -> u256 {
// TODO
return 123;
}

fn burn_handle(ref self: ContractState, token_id: u256) { // TODO
}

fn set_handle_token_uri(
ref self: ContractState, token_id: u256, local_name: felt252
) { // TODO
}

fn migrate_handle(
ref self: ContractState, address: ContractAddress, local_name: felt252
) -> u256 {
// TODO
return 123;
}

// *************************************************************************
// GETTERS
// *************************************************************************
fn get_namespace(self: @ContractState) -> felt252 {
return NAMESPACE;
}

fn get_local_name(self: @ContractState, token_id: u256) -> felt252 {
self.local_names.read(token_id)
}

fn get_handle(self: @ContractState, token_id: u256) -> ByteArray {
// TODO
return "TODO";
}

fn exists(self: @ContractState, token_id: u256) -> bool {
self.erc721._exists(token_id)
}

fn total_supply(self: @ContractState) -> u256 {
self.total_supply.read()
}

fn get_handle_token_uri(
self: @ContractState, token_id: u256, local_name: felt252
) -> ByteArray {
// TODO
return "TODO";
}
}

// *************************************************************************
// PRIVATE FUNCTIONS
// *************************************************************************
#[generate_trait]
impl Private of PrivateTrait {
fn _mint_handle(address: ContractAddress, local_name: felt252) -> u256 {
// TODO
return 123;
}

fn _validate_local_name(local_name: felt252) { // TODO
}

fn _is_alpha_numeric(char: felt252) -> bool {
// TODO
return false;
}
}
}

0 comments on commit 924ab4e

Please sign in to comment.