Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add referral contracts #1

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store

.snfoundry_cache/
target/
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,38 @@
# gmx-referral-fork-cairo
# JediSwap Referral Contracts

This repository consists of the referral contracts of JediSwap protocol, a cairo fork of Uniswap V3. CLAMM for Starknet.

## Testing and Development

Prerequisites:

- [Scarb](https://github.com/software-mansion/scarb) for managing the project.
- [starknet-foundry](https://github.com/foundry-rs/starknet-foundry) for testing and writing scripts.

### Compile Contracts

```
scarb build
```

### Run Tests

```
snforge test
```

### Run Scripts

#### Run a local devnet

We use [starknet-devnet-rs](https://github.com/0xSpaceShard/starknet-devnet-rs)

Run the devnet and add one of the predeployed accounts with your preferred name <test_account_local>. See the instructions [here](https://foundry-rs.github.io/starknet-foundry/starknet/account.html#importing-an-account).

#### Run Scripts

Run sncast in the parent folder by specifying the path to the script file. Example:

```
sncast --url http://127.0.0.1:5050 --account <test_account_local> --path-to-scarb-toml scripts/Scarb.toml script deploy_factory_and_pool
```
20 changes: 20 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "jediswap_referral"
version = "0.1.0"
dependencies = [
"openzeppelin",
"snforge_std",
]

[[package]]
name = "openzeppelin"
version = "0.11.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.11.0#a83f36b23f1af6e160288962be4a2701c3ecbcda"

[[package]]
name = "snforge_std"
version = "0.20.1"
source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.20.1#fea2db8f2b20148cc15ee34b08de12028eb42942"
17 changes: 17 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "jediswap_referral"
version = "0.1.0"

[lib]


[[target.starknet-contract]]
sierra = true
casm = true
casm-add-pythonic-hints = true
allowed-libfuncs-list.name = "all"

[dependencies]
starknet = "2.4.3"
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.11.0" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.20.1" }
4 changes: 4 additions & 0 deletions snfoundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[sncast.default]
account = "my_imported_account"
accounts-file = "~/my_accounts.json"
url = "https://api-starknet-sepolia.dwellir.com/dd28e566-3260-4d8d-8180-6ef1a161e41c"
7 changes: 7 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod referral_storage;

mod test_contracts {
mod referral_storage_v2;
}


109 changes: 109 additions & 0 deletions src/referral_storage.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use starknet::{ContractAddress,ClassHash};
use zeroable::Zeroable;


#[starknet::interface]
trait IReferralStorage<TContractState> {
fn get_referrer(
self: @TContractState,
account: ContractAddress,
) -> ContractAddress;

fn set_referrer(
ref self: TContractState,
address: ContractAddress,
);

fn upgrade(ref self: TContractState, new_class_hash: ClassHash);
}


#[starknet::contract]
mod ReferralStorage {
use starknet::ContractAddress;
use starknet::get_caller_address;
use zeroable::Zeroable;
use starknet::ClassHash;
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;

component!(path: UpgradeableComponent, storage: upgradeable_storage, event: UpgradeableEvent);
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

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

/// Upgradeable
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
SetReferrer: SetReferrer,
#[flat]
OwnableEvent: OwnableComponent::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event
}


#[derive(Drop, starknet::Event)]
struct SetReferrer {
account: ContractAddress,
referrer: ContractAddress,
}

#[storage]
struct Storage {
// @notice Maps the referee to the referrer
referrers: LegacyMap::<ContractAddress, ContractAddress>,

#[substorage(v0)]
ownable: OwnableComponent::Storage,
#[substorage(v0)]
upgradeable_storage: UpgradeableComponent::Storage,
}

#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

#[abi(embed_v0)]
impl ReferralStorage of super::IReferralStorage<ContractState> {

fn get_referrer(
self: @ContractState,
account: ContractAddress,
) -> ContractAddress {
self.referrers.read(account)
}

// @notice Sets the referrer to be referred by the caller
// @param address The referrer to set
// @dev An address can set the referrer only once
// @dev referrer cannot set refer themselves
fn set_referrer(
ref self: ContractState,
address: ContractAddress,
){
assert!(address != get_caller_address(), "ReferralStorage: referrer cannot refer themselves");

if(!self.referrers.read(get_caller_address()).is_non_zero()){
let account = get_caller_address();
self.referrers.write(account, address);
self.emit(SetReferrer{account:account, referrer: address});
}
}

fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();

self.upgradeable_storage._upgrade(new_class_hash);
}
}
}

159 changes: 159 additions & 0 deletions src/test_contracts/referral_storage_v2.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use starknet::{ContractAddress,ClassHash};
use zeroable::Zeroable;


#[starknet::interface]
trait IReferralStorageV2<TContractState> {
fn get_referrer(
ref self: TContractState,
_account: ContractAddress,
) -> felt252;

fn get_code_owner(
ref self: TContractState,
_code: felt252,
) -> ContractAddress;

fn get_code_from_owner(
ref self: TContractState,
_account: ContractAddress,
) -> felt252;

fn set_referrer(
ref self: TContractState,
_code: felt252,
);

fn register_code(
ref self: TContractState,
_code: felt252,
);

fn upgrade(ref self: TContractState, new_class_hash: ClassHash);

}


#[starknet::contract]
mod ReferralStorageV2 {
use starknet::ContractAddress;
use starknet::get_caller_address;
use zeroable::Zeroable;
use starknet::ClassHash;
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;


component!(path: UpgradeableComponent, storage: upgradeable_storage, event: UpgradeableEvent);
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
SetReferrer: SetReferrer,
RegisterCode: RegisterCode,
#[flat]
OwnableEvent: OwnableComponent::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event
}


#[derive(Drop, starknet::Event)]
struct SetReferrer {
account: ContractAddress,
code: felt252,
}

#[derive(Drop, starknet::Event)]
struct RegisterCode {
code: felt252,
account: ContractAddress,
}

#[storage]
struct Storage {
code_owner: LegacyMap::<felt252, ContractAddress>,
owner_to_code: LegacyMap::<ContractAddress, felt252>,
referrers: LegacyMap::<ContractAddress, felt252>,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
#[substorage(v0)]
upgradeable_storage: UpgradeableComponent::Storage,
}

#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

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

/// Upgradeable
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

#[abi(embed_v0)]
impl ReferralStorageV2 of super::IReferralStorageV2<ContractState> {

fn get_referrer(
ref self: ContractState,
_account: ContractAddress,
) -> felt252 {
self.referrers.read(_account)
}

fn get_code_owner(
ref self: ContractState,
_code: felt252,
) -> ContractAddress {
self.code_owner.read(_code)
}

fn get_code_from_owner(
ref self: ContractState,
_account: ContractAddress,
) -> felt252 {
self.owner_to_code.read(_account)
}

fn set_referrer(
ref self: ContractState,
_code: felt252,
){
assert!(self.code_owner.read(_code).is_non_zero(), "ReferralStorage: code not found");
assert!(self.code_owner.read(_code) != get_caller_address(), "ReferralStorage: referrer cannot refer themselves");

let _account = get_caller_address();
self.referrers.write(_account, _code);
self.emit(SetReferrer{account:_account, code: _code});
}

fn register_code(
ref self: ContractState,
_code: felt252,
){
assert!(self.owner_to_code.read(get_caller_address()).is_non_zero(), "ReferralStorage: user already has a code");

assert!(!self.code_owner.read(_code).is_non_zero(), "ReferralStorage: code already registered");

self.code_owner.write(_code, get_caller_address());
self.owner_to_code.write(get_caller_address(), _code);

self.emit(RegisterCode{code:_code, account: get_caller_address()});
}

fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();

self.upgradeable_storage._upgrade(new_class_hash);
}
}



}

1 change: 1 addition & 0 deletions tests/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod referral_storage_test;
Loading