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

feat: POC for Starknet #1490

Open
wants to merge 17 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
Expand Up @@ -112,3 +112,7 @@ cypress/screenshots
# multi-app
/app-selector.js
/app.config.js

# starknet / cairo
cairo/keystore.json
.cairo
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ GO?=go
GOFMT?=$(shell $(GO) env GOROOT)/bin/gofmt
CAT := $(if $(filter $(OS),Windows_NT),type,cat)

PROJECT_ROOT=$(shell pwd)

COSMWASM_CONTRACTS_DIR=rust/cw-contracts
INTERNAL_COSMWASM_CONTRACTS=$(wildcard $(COSMWASM_CONTRACTS_DIR)/*)

STARKNET_CONTRACTS=$(wildcard cairo/contracts/*)
STARKNET_CONTRACT_CLIENTS=packages/starknet-contract-clients

TOKEN_REPO=teritori-nfts
TOKEN_PACKAGE=teritori-nft
SQUAD_STAKING_PACKAGE=teritori-squad-staking
Expand Down Expand Up @@ -385,6 +390,38 @@ init-weshd-go:
bump-app-build-number:
npx tsx packages/scripts/app-build/bumpBuildNumber.ts $(shell echo $$(($$(git rev-list HEAD --count) + 10)))

.PHONY: test.starknet
test.starknet:
set -e ; \
for file in $(STARKNET_CONTRACTS); do \
echo "> Testing $${file}" ; \
cd $${file} ; \
snforge test ; \
cd - ; \
done

.PHONY: build.starknet
build.starknet:
set -e ; \
for file in $(STARKNET_CONTRACTS); do \
echo "> Building $${file}" ; \
cd $${file} ; \
scarb build ; \
cd - ; \
done

.PHONY: gen.starknet-clients
gen.starknet-clients:
set -e ; \
for file in $(STARKNET_CONTRACTS); do \
echo "> Generating client for $${file}" ; \
cd $${file} ; \
output=$(PROJECT_ROOT)/$(STARKNET_CONTRACT_CLIENTS)/$$(basename $${file}) ; \
mkdir -p $${output} ; \
starknet-compile --single-file src/lib.cairo $${output}/abi.json ; \
cd - ; \
done

.PHONY: test.rust
test.rust:
set -e ; \
Expand Down
1 change: 1 addition & 0 deletions assets/icons/argent-x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/icons/networks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import solana from "./solana.svg";
import teritoriCircle from "./teritori-circle.svg";
import teritori from "./teritori.svg";
import polygon from "./polygon.svg";
import starknet from "./starknet.svg";
import starknetCircle from "./starknet-circle.svg";

export const networks = {
teritori,
Expand All @@ -30,4 +32,6 @@ export const networks = {
solanaCircle,
gno,
polygon,
starknet,
starknetCircle,
};
30 changes: 30 additions & 0 deletions assets/icons/networks/starknet-circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions assets/icons/networks/starknet.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions cairo/account.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": 1,
"variant": {
"type": "open_zeppelin",
"version": 1,
"public_key": "0x5865f50c819ded17adf5e75af231419c458987526583d0e7d03fa22b577bd3f",
"legacy": false
},
"deployment": {
"status": "deployed",
"class_hash": "0x4a444ef8caf8fa0db05da60bf0ad9bae264c73fa7e32c61d245406f5523174b",
"address": "0x5592f41259100b2e67112545aa55f1c93007ea2a7fab02132d75fa69f268b5d"
}
}
2 changes: 2 additions & 0 deletions cairo/contracts/todo_list/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
.snfoundry_cache/
24 changes: 24 additions & 0 deletions cairo/contracts/todo_list/Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "snforge_scarb_plugin"
version = "0.35.1"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:1b6d50abc7f306a06abf90649bcd60a3bc1cdf6d0dc21a9725c71b014a334bab"

[[package]]
name = "snforge_std"
version = "0.35.1"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:e25cbeb9cbed6da8e14ab19ad0e7c1d888055dfee62978a845ce669cfaba5d93"
dependencies = [
"snforge_scarb_plugin",
]

[[package]]
name = "todo_list"
version = "0.1.0"
dependencies = [
"snforge_std",
]
49 changes: 49 additions & 0 deletions cairo/contracts/todo_list/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
name = "todo_list"
version = "0.1.0"
edition = "2024_07"

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

[dependencies]
starknet = "2.9.2"

[dev-dependencies]
snforge_std = "0.35.1"
assert_macros = "2.9.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
11 changes: 11 additions & 0 deletions cairo/contracts/todo_list/snfoundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Visit https://foundry-rs.github.io/starknet-foundry/appendix/snfoundry-toml.html
# and https://foundry-rs.github.io/starknet-foundry/projects/configuration.html for more information

# [sncast.default] # Define a profile name
# url = "https://free-rpc.nethermind.io/sepolia-juno/v0_7" # Url of the RPC provider
# accounts-file = "../account-file" # Path to the file with the account data
# account = "mainuser" # Account from `accounts_file` or default account file that will be used for the transactions
# keystore = "~/keystore" # Path to the keystore file
# wait-params = { timeout = 300, retry-interval = 10 } # Wait for submitted transaction parameters
# block-explorer = "StarkScan" # Block explorer service used to display links to transaction details
# show-explorer-links = true # Print links pointing to pages with transaction details in the chosen block explorer
53 changes: 53 additions & 0 deletions cairo/contracts/todo_list/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#[derive(Drop, Serde, Copy)]
pub struct Todo {
pub title: felt252,
pub done: bool,
}

#[starknet::interface]
pub trait ITodoList<TContractState> {
fn add_todo(ref self: TContractState, title: felt252);
fn set_todo_done(ref self: TContractState, index: u64);
fn get_todos(self: @TContractState) -> Array<Todo>;
}

#[starknet::contract]
mod TodoList {
use core::starknet::storage::{
StoragePointerWriteAccess, StoragePointerReadAccess, VecTrait, MutableVecTrait, Vec,
};
use super::Todo;

#[storage]
struct Storage {
todos_title: Vec<felt252>,
}

#[abi(embed_v0)]
impl TodoListImpl of super::ITodoList<ContractState> {
fn add_todo(ref self: ContractState, title: felt252) {
assert(title != '', 'Title cannot be empty');

self.todos_title.append().write(title);
self.todos_done.append().write(false);
}

fn set_todo_done(ref self: ContractState, index: u64) {
// assert(index < self.todos_title.len(), 'Index out of bounds');

self.todos_done.at(index).write(true);
}

fn get_todos(self: @ContractState) -> Array<Todo> {
let mut result = ArrayTrait::new();

for i in 0..self.todos_title.len() {
let title = self.todos_title.at(i).read();
let done = self.todos_done.at(i).read();
result.append(Todo { title, done });
};

result
}
}
}
59 changes: 59 additions & 0 deletions cairo/contracts/todo_list/tests/test_contract.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use starknet::ContractAddress;

use snforge_std::{declare, ContractClassTrait, DeclareResultTrait};

use todo_list::ITodoListSafeDispatcher;
use todo_list::ITodoListSafeDispatcherTrait;
use todo_list::ITodoListDispatcher;
use todo_list::ITodoListDispatcherTrait;

fn deploy_contract(name: ByteArray) -> ContractAddress {
let contract = declare(name).unwrap().contract_class();
let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap();
contract_address
}

#[test]
fn test_add_todo() {
let contract_address = deploy_contract("TodoList");

let dispatcher = ITodoListDispatcher { contract_address };

dispatcher.add_todo('Do Teritori task');

let todo = dispatcher.get_todos().at(0);
assert(todo.title.clone() == 'Do Teritori task', 'Invalid todo title');
assert(todo.done.clone() == false, 'Todo is not done');
}

#[test]
fn test_set_todo_done() {
let contract_address = deploy_contract("TodoList");

let dispatcher = ITodoListDispatcher { contract_address };

dispatcher.add_todo('Do Teritori task');
dispatcher.set_todo_done(0);

let todo = dispatcher.get_todos().at(0);
assert(todo.title.clone() == 'Do Teritori task', 'Invalid todo title');
assert(todo.done.clone() == true, 'Todo must be done');
}

#[test]
#[feature("safe_dispatcher")]
fn test_cannot_set_todo_done_with_invalid_index() {
let contract_address = deploy_contract("TodoList");

let safe_dispatcher = ITodoListSafeDispatcher { contract_address };

safe_dispatcher.add_todo('Do Teritori task').unwrap();

// TODO: Fix this test
// match safe_dispatcher.set_todo_done(2) {
// Result::Ok(_) => core::panic_with_felt252('Should have panicked'),
// Result::Err(panic_data) => {
// assert(*panic_data.at(0) == 'Index out of bounds', *panic_data.at(0));
// },
// };
}
Loading
Loading