-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat/publication
- Loading branch information
Showing
8 changed files
with
269 additions
and
43 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"> | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ pub mod IRegistry; | |
pub mod IProfile; | ||
pub mod IFollowNFT; | ||
pub mod IPublication; | ||
pub mod IHandle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,5 @@ pub mod follownft; | |
pub mod mocks; | ||
pub mod publication; | ||
|
||
|
||
pub mod namespaces; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mod handles; | ||
mod handle_registry; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |