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

Adds missing features #5

Merged
merged 14 commits into from
Nov 7, 2023
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI Tests

on: [push, pull_request, pull_request_target]

env:
SCARB_VERSION: 2.3.1

jobs:
scarb-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install scarb
run: |
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v $SCARB_VERSION

- name: Install project dependencies
run: scarb fetch

- name: Compile smart contracts
run: scarb build

- name: Run scarb tests
run: scarb test -p identity
3 changes: 2 additions & 1 deletion Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ repository = "https://github.com/starknet-id/identity"
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest

[dependencies]
starknet = "2.3.0"
starknet = "2.3.1"
openzeppelin = { git = "https://github.com/andrew-fleming/cairo-contracts.git", branch = "component-erc721" }
storage_read = { git = "https://github.com/starknet-id/storage_read_component", rev = "c6c69e15d34abfc39ac51dc21b96724e2e19ff31" }
custom_uri = { git = "https://github.com/starknet-id/custom_uri_component", rev = "abb2f3d43c7be56dd5cd9f93c33af40b272c2245" }

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
python-dotenv
starknet-py==0.17.1
starknet-py==0.18.2
case-converter==1.1.0
requests
cairo-lang
14 changes: 13 additions & 1 deletion scripts/deploy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# %% Imports
import logging
from asyncio import run
from dotenv import load_dotenv
import os

load_dotenv()
NETWORK = os.getenv("STARKNET_NETWORK", "devnet")

from utils.constants import COMPILED_CONTRACTS, ETH_TOKEN_ADDRESS
from utils.starknet import (
Expand All @@ -14,6 +19,13 @@
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# https://api.starknet.id/uri?id=
MAINNET_CONST = [0x68747470733A2F2F6170692E737461726B6E65742E69642F7572693F69643D]
# https://goerli.api.starknet.id/uri?id="
GOERLI_CONST = [
0x68747470733A2F2F676F65726C692E6170692E737461726B6E65742E69642F,
0x7572693F69643D,
]


# %% Main
Expand All @@ -30,7 +42,7 @@ async def main():

deployments = {}
deployments["identity_Identity"] = await deploy_v2(
"identity_Identity",
"identity_Identity", (MAINNET_CONST if NETWORK == "mainnet" else GOERLI_CONST)
)

dump_deployments(deployments)
Expand Down
6 changes: 2 additions & 4 deletions scripts/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@
}

VARS = NETWORKS[os.getenv("STARKNET_NETWORK", "devnet")]
VARS["account_address"] = os.environ.get(
f"{VARS['name'].upper()}_ACCOUNT_ADDRESS"
)
VARS["account_address"] = os.environ.get(f"{VARS['name'].upper()}_ACCOUNT_ADDRESS")
if VARS["account_address"] is None:
logger.warning(
f"⚠️ {VARS['name'].upper()}_ACCOUNT_ADDRESS not set, defaulting to ACCOUNT_ADDRESS"
Expand All @@ -63,7 +61,7 @@
)

ETH_TOKEN_ADDRESS = 0x49D36570D4E46F48E99674BD3FCC84644DDD6B96F7C741B1562B82F9E004DC7
ETH_CLASS_HASH = 0x6a22bf63c7bc07effa39a25dfbd21523d211db0100a0afd054d172b81840eaf
ETH_CLASS_HASH = 0x6A22BF63C7BC07EFFA39A25DFBD21523D211DB0100A0AFD054D172B81840EAF
SOURCE_DIR = Path("src")
CONTRACTS = {p.stem: p for p in list(SOURCE_DIR.glob("**/*.cairo"))}

Expand Down
34 changes: 22 additions & 12 deletions scripts/utils/starknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async def get_contract(contract_name) -> Contract:
await get_starknet_account(),
)


def dump_declarations(declarations):
json.dump(
{name: hex(class_hash) for name, class_hash in declarations.items()},
Expand Down Expand Up @@ -127,21 +128,27 @@ def get_alias(contract_name):
def get_tx_url(tx_hash: int) -> str:
return f"{VARS['explorer_url']}/tx/0x{tx_hash:064x}"


def get_sierra_artifact(contract_name):
return BUILD_DIR / f"{contract_name}.sierra.json"
return BUILD_DIR / f"{contract_name}.contract_class.json"


def get_casm_artifact(contract_name):
return BUILD_DIR / f"{contract_name}.casm.json"
return BUILD_DIR / f"{contract_name}.compiled_contract_class.json"


def get_abi(contract_name):
sierra_artifact = get_sierra_artifact(contract_name)
contract_compiled_sierra = Path(sierra_artifact).read_text()
return create_sierra_compiled_contract(compiled_contract = contract_compiled_sierra).abi
return create_sierra_compiled_contract(
compiled_contract=contract_compiled_sierra
).abi


async def declare_v2(contract_name):
logger.info(f"ℹ️ Declaring {contract_name}")

# contract_compiled_casm is a string containing the content of the starknet-sierra-compile (.casm file)
# contract_compiled_casm is a string containing the content of the starknet-sierra-compile (.casm file)
casm_artifact = get_casm_artifact(contract_name)
contract_compiled_casm = Path(casm_artifact).read_text()
casm_class = create_casm_class(contract_compiled_casm)
Expand All @@ -151,11 +158,11 @@ async def declare_v2(contract_name):
sierra_artifact = get_sierra_artifact(contract_name)
contract_compiled_sierra = Path(sierra_artifact).read_text()
sierra_class = create_sierra_compiled_contract(contract_compiled_sierra)
sierra_class_hash= compute_sierra_class_hash(sierra_class)
sierra_class_hash = compute_sierra_class_hash(sierra_class)
# Check has not been declared before
try:
await GATEWAY_CLIENT.get_class_by_hash(class_hash=sierra_class_hash)
logger.info(f"✅ Class already declared, skipping")
logger.info(f"✅ Class {hex(sierra_class_hash)} already declared, skipping")
return sierra_class_hash
except Exception:
pass
Expand All @@ -175,14 +182,15 @@ async def declare_v2(contract_name):
logger.info(f"✅ {contract_name} class hash: {hex(resp.class_hash)}")
return resp.class_hash


async def deploy_v2(contract_name, *args):
logger.info(f"ℹ️ Deploying {contract_name}")

account = await get_starknet_account()

sierra_class_hash = get_declarations()[contract_name]
abi = get_abi(contract_name)

deploy_result = await Contract.deploy_contract(
account=account,
class_hash=sierra_class_hash,
Expand All @@ -208,11 +216,12 @@ async def invoke(contract_name, function_name, inputs, address=None):
account = await get_starknet_account()
deployments = get_deployments()
call = Call(
to_addr=int(deployments[contract_name]["address"], 16) if address is None else address,
selector=get_selector_from_name(function_name),
calldata=inputs
to_addr=int(deployments[contract_name]["address"], 16)
if address is None
else address,
selector=get_selector_from_name(function_name),
calldata=inputs,
)
print("call", call)
logger.info(f"ℹ️ Invoking {contract_name}.{function_name}({json.dumps(inputs)})")
response = await account.execute(calls=call, max_fee=int(1e17))
await account.client.wait_for_tx(response.transaction_hash)
Expand All @@ -222,6 +231,7 @@ async def invoke(contract_name, function_name, inputs, address=None):
)
return response.transaction_hash


async def invoke_cairo0(contract_name, function_name, *inputs, address=None):
account = await get_starknet_account()
deployments = get_deployments()
Expand All @@ -237,4 +247,4 @@ async def invoke_cairo0(contract_name, function_name, *inputs, address=None):
f"✅ {contract_name}.{function_name} invoked at tx: %s",
hex(response.transaction_hash),
)
return response.transaction_hash
return response.transaction_hash
2 changes: 2 additions & 0 deletions src/identity.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
mod main;
mod internal;
mod erc721;
42 changes: 42 additions & 0 deletions src/identity/erc721.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use openzeppelin::{
token::erc721::{ERC721Component::{ERC721Metadata, HasComponent}},
introspection::src5::SRC5Component,
};
use custom_uri::{main::custom_uri_component::InternalImpl, main::custom_uri_component};


#[starknet::interface]
trait IERC721Metadata<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn token_uri(self: @TState, tokenId: u256) -> Array<felt252>;
fn tokenURI(self: @TState, tokenId: u256) -> Array<felt252>;
}

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

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

fn token_uri(self: @TContractState, tokenId: u256) -> Array<felt252> {
let component = custom_uri_component::HasComponent::get_component(self);
component.get_uri(tokenId)
}

fn tokenURI(self: @TContractState, tokenId: u256) -> Array<felt252> {
self.token_uri(tokenId)
}
}
Loading