Skip to content

Commit

Permalink
im truly the honored one
Browse files Browse the repository at this point in the history
  • Loading branch information
kariy committed Aug 15, 2024
1 parent a9b0bc5 commit 10ec335
Show file tree
Hide file tree
Showing 20 changed files with 320 additions and 281 deletions.
347 changes: 174 additions & 173 deletions Cargo.lock

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [
"bin/scheduler",
"bin/sozo",
"bin/torii",
# "crates/benches",
# "crates/benches",
"crates/common",
"crates/dojo-bindgen",
"crates/dojo-core",
Expand Down Expand Up @@ -60,7 +60,8 @@ inherits = "release"
lto = "fat"

[workspace.dependencies]
cainome = { git = "/~https://github.com/cartridge-gg/cainome", tag = "v0.3.2", features = [ "abigen-rs" ] }
# cainome = { git = "/~https://github.com/cartridge-gg/cainome", tag = "v0.3.2", features = [ "abigen-rs" ] }
cainome = { git = "/~https://github.com/cartridge-gg/cainome", branch = "main", features = [ "abigen-rs" ] }
common = { path = "crates/common" }

# metrics
Expand Down Expand Up @@ -172,7 +173,7 @@ pretty_assertions = "1.2.1"
rand = "0.8.5"
rayon = "1.8.0"
regex = "1.10.3"
reqwest = { version = "0.12", features = [ "blocking", "rustls-tls", "json" ], default-features = false }
reqwest = { version = "0.12", features = [ "blocking", "json", "rustls-tls" ], default-features = false }
rpassword = "7.2.0"
rstest = "0.18.2"
rstest_reuse = "0.6.0"
Expand All @@ -182,17 +183,10 @@ scarb-ui = { git = "/~https://github.com/software-mansion/scarb", tag = "v2.7.0" }
semver = "1.0.5"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { version = "1.0", features = [ "arbitrary_precision" ] }
serde_with = "2.3"
serde_with = "3.9.0"
similar-asserts = "1.5.0"
smol_str = { version = "0.2.0", features = [ "serde" ] }
sqlx = { version = "0.7.2", features = [ "chrono", "macros", "regexp", "runtime-async-std", "runtime-tokio", "sqlite", "uuid" ] }
starknet = "0.11.0"
starknet-crypto = "0.7.0"
# `starknet-rs` is using `starknet-types-core` 0.1.3, but we need >=0.1.4 because
# we need this </~https://github.com/starknet-io/types-rs/pull/75>. So we put strict
# requirement here to prevent from being downgraded.
# We can remove this requirement once `starknet-rs` is using >=0.1.4
starknet-types-core = "~0.1.4"
starknet_api = "0.11.0"
strum = "0.25"
strum_macros = "0.25"
Expand Down Expand Up @@ -230,8 +224,10 @@ alloy-sol-types = { version = "0.7.6", default-features = false }
criterion = "0.5.1"

# Controller integration
account_sdk = { git = "/~https://github.com/cartridge-gg/controller", rev = "512ff89" }
slot = { git = "/~https://github.com/cartridge-gg/slot", rev = "4c1165d" }
# account_sdk = { git = "/~https://github.com/cartridge-gg/controller", rev = "512ff89" }
# slot = { git = "/~https://github.com/cartridge-gg/slot", rev = "4c1165d" }
account_sdk = { path = "../../cartridge/controller/packages/account_sdk" }
slot = { path = "../../cartridge/slot/slot" }

alloy-contract = { version = "0.2", default-features = false }
alloy-json-rpc = { version = "0.2", default-features = false }
Expand All @@ -241,10 +237,14 @@ alloy-rpc-types-eth = { version = "0.2", default-features = false }
alloy-signer = { version = "0.2", default-features = false }
alloy-transport = { version = "0.2", default-features = false }

starknet = "0.11.0"
starknet-crypto = "0.7.1"
# `starknet-rs` is using `starknet-types-core` 0.1.3, but we need >=0.1.4 because
# we need this </~https://github.com/starknet-io/types-rs/pull/75>. So we put strict
# requirement here to prevent from being downgraded.
# We can remove this requirement once `starknet-rs` is using >=0.1.4
starknet-types-core = "~0.1.4"

[patch.crates-io]
# Remove this patch once the following PR is merged: </~https://github.com/xJonathanLEI/starknet-rs/pull/615>
#
# To enable std feature on `starknet-types-core`.
# To re-export the entire `felt` module from `starknet-types-core`.
starknet-core = { git = "/~https://github.com/kariy/starknet-rs", branch = "dojo-patch" }
starknet-types-core = { git = "/~https://github.com/dojoengine/types-rs", rev = "289e2f0" }
starknet = { git = "/~https://github.com/xJonathanLEI/starknet-rs", rev = "2ddc694" }
starknet-types-core = { git = "/~https://github.com/starknet-io/types-rs", rev = "f98f048" }
79 changes: 52 additions & 27 deletions bin/sozo/src/commands/options/account/controller.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::str::FromStr;
use std::sync::Arc;

use account_sdk::account::session::hash::{AllowedMethod, Session};
use account_sdk::account::session::hash::{AllowedMethod, ProvedMethod};
use account_sdk::account::session::merkle::MerkleTree;
use account_sdk::account::session::SessionAccount;
use account_sdk::signers::HashSigner;
use account_sdk::storage::SessionMetadata;
use anyhow::{bail, Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use dojo_world::contracts::naming::get_name_from_tag;
Expand All @@ -14,7 +16,9 @@ use slot::session::Policy;
use starknet::core::types::contract::{AbiEntry, StateMutability};
use starknet::core::types::StarknetError::ContractNotFound;
use starknet::core::types::{BlockId, BlockTag, Felt};
use starknet::core::utils::{cairo_short_string_to_felt, get_contract_address};
use starknet::core::utils::{
cairo_short_string_to_felt, get_contract_address, get_selector_from_name,
};
use starknet::macros::{felt, short_string};
use starknet::providers::Provider;
use starknet::providers::ProviderError::StarknetError;
Expand All @@ -25,9 +29,14 @@ use url::Url;

use super::WorldAddressOrName;

// Why the Arc? becaues the Controller account implementation over on `account_sdk` crate is
// riddled with `+ Clone` bounds on its Provider generic. So we explicitly specify that the Provider
// impl here is wrapped in an Arc to satisfy the Clone bound. Otherwise, you would get a 'trait
// bound not satisfied' error.
//
// This type comes from account_sdk, which doesn't derive Debug.
#[allow(missing_debug_implementations)]
pub type ControllerSessionAccount<P> = SessionAccount<P, SigningKey, SigningKey>;
pub type ControllerSessionAccount<P> = SessionAccount<Arc<P>, SigningKey, SigningKey>;

/// Create a new Catridge Controller account based on session key.
#[tracing::instrument(
Expand Down Expand Up @@ -62,28 +71,24 @@ where
// Check if the session exists, if not create a new one
let session_details = match slot::session::get(chain_id)? {
Some(session) => {
trace!(expires_at = %session.expires_at, policies = session.policies.len(), "Found existing session.");
trace!(expires_at = %session.session.expires_at, policies = session.session.allowed_methods.len(), "Found existing session.");

// Perform policies diff check. For security reasons, we will always create a new
// session here if the current policies are different from the existing
// session.
//
// TODO(kariy): maybe don't need to update if current policies is a
// subset of the existing policies.
let policies = collect_policies(world_addr_or_name, contract_address, config)?;
// check if the policies have changed
let is_equal = is_equal_to_existing(&policies, rpc_url.clone(), chain_id, session);

if policies != session.policies {
if is_equal {
session
} else {
trace!(
new_policies = policies.len(),
existing_policies = session.policies.len(),
existing_policies = session.session.allowed_methods.len(),
"Policies have changed. Creating new session."
);

let session = slot::session::create(rpc_url.clone(), &policies).await?;
let session = slot::session::create(rpc_url, &policies).await?;
slot::session::store(chain_id, &session)?;
session
} else {
session
}
}

Expand All @@ -97,37 +102,57 @@ where
}
};

let methods = session_details
.policies
.into_iter()
.map(|p| AllowedMethod::new(p.target, &p.method))
.collect::<Result<Vec<AllowedMethod>, _>>()?;

// Copied from `account-wasm` </~https://github.com/cartridge-gg/controller/blob/0dd4dd6cbc5fcd3b9a1fd8d63dc127f6312b733f/packages/account-wasm/src/lib.rs#L78-L88>
let guardian = SigningKey::from_secret_scalar(short_string!("CARTRIDGE_GUARDIAN"));
let signer = SigningKey::from_secret_scalar(session_details.credentials.private_key);
// TODO(kariy): make `expires_at` a `u64` type in the session struct
let expires_at = session_details.expires_at.parse::<u64>()?;
let session = Session::new(methods, expires_at, &signer.signer())?;

// make sure account exist on the provided chain, if not, we deploy it first before proceeding
deploy_account_if_not_exist(rpc_url, &provider, chain_id, contract_address, &username)
.await
.with_context(|| format!("Deploying Controller account on chain {chain_id}"))?;

let session_account = SessionAccount::new(
provider,
Arc::new(provider),
signer,
guardian,
contract_address,
chain_id,
session_details.credentials.authorization,
session,
session_details.session,
);

Ok(session_account)
}

// Check if the new policies are equal to the ones in the existing session
async fn is_equal_to_existing(
new_policies: &[Policy],
rpc_url: Url,
chain_id: Felt,
session: SessionMetadata,
) -> bool {
let allowed_methods = new_policies
.iter()
.map(|p| AllowedMethod::new(p.target, get_selector_from_name(&p.method).unwrap()))
.collect::<Vec<AllowedMethod>>();

// Copied from somewhere
let hashes = allowed_methods.iter().map(AllowedMethod::as_merkle_leaf).collect::<Vec<Felt>>();

let allowed_methods = allowed_methods
.into_iter()
.enumerate()
.map(|(i, method)| ProvedMethod {
method,
proof: MerkleTree::compute_proof(hashes.clone(), i),
})
.collect::<Vec<ProvedMethod>>();

let root = MerkleTree::compute_root(hashes[0], allowed_methods[0].proof.clone());

root != session.session.allowed_methods_root
}

/// Policies are the building block of a session key. It's what defines what methods are allowed for
/// an external signer to execute using the session key.
///
Expand Down
7 changes: 4 additions & 3 deletions bin/sozo/src/commands/options/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ impl AccountOptions {
if self.controller {
let url = starknet.url(env_metadata)?;
let account = self.controller(url, provider, world_address_or_name, config).await?;
return Ok(SozoAccount::from(account));
return Ok(SozoAccount::Controller(account));
}

let account = self.std_account(provider, env_metadata).await?;
Ok(SozoAccount::from(account))
Ok(SozoAccount::Standard(account))
}

pub async fn std_account<P>(
Expand Down Expand Up @@ -151,7 +151,8 @@ impl AccountOptions {
#[cfg(test)]
mod tests {
use clap::Parser;
use starknet::accounts::{Call, ExecutionEncoder};
use starknet::accounts::ExecutionEncoder;
use starknet::core::types::Call;
use starknet_crypto::Felt;

use super::{AccountOptions, DOJO_ACCOUNT_ADDRESS_ENV_VAR};
Expand Down
19 changes: 13 additions & 6 deletions bin/sozo/src/commands/options/account/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use std::sync::Arc;

use async_trait::async_trait;
use starknet::accounts::{
single_owner, Account, Call, ConnectedAccount, DeclarationV2, DeclarationV3, ExecutionEncoder,
single_owner, Account, ConnectedAccount, DeclarationV2, DeclarationV3, ExecutionEncoder,
ExecutionV1, ExecutionV3, LegacyDeclaration, RawDeclarationV2, RawDeclarationV3,
RawExecutionV1, RawExecutionV3, RawLegacyDeclaration, SingleOwnerAccount,
};
use starknet::core::types::contract::legacy::LegacyContractClass;
use starknet::core::types::{BlockId, Felt, FlattenedSierraClass};
use starknet::core::types::{BlockId, Call, Felt, FlattenedSierraClass};
use starknet::providers::Provider;
use starknet::signers::{local_wallet, LocalWallet};
use starknet::signers::{local_wallet, LocalWallet, SignerInteractivityContext};

#[cfg(feature = "controller")]
use super::controller::ControllerSessionAccount;
Expand All @@ -30,12 +30,11 @@ pub enum SozoAccountSignError {
/// This is the account type that should be used by the CLI.
#[must_use]
#[non_exhaustive]
#[derive(derive_more::From)]
#[allow(missing_debug_implementations)]
pub enum SozoAccount<P>
where
P: Send,
P: Provider,
P: Send + Sync,
{
Standard(SingleOwnerAccount<P, LocalWallet>),

Expand All @@ -52,6 +51,14 @@ where
{
type SignError = SozoAccountSignError;

fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool {
match self {
Self::Standard(account) => account.is_signer_interactive(context),
#[cfg(feature = "controller")]
Self::Controller(account) => account.is_signer_interactive(context),
}
}

fn address(&self) -> Felt {
match self {
Self::Standard(account) => account.address(),
Expand All @@ -64,7 +71,7 @@ where
match self {
Self::Standard(account) => account.chain_id(),
#[cfg(feature = "controller")]
Self::Controller(account) => account.chain_id(),
Self::Controller(account) => Account::chain_id(account),
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/dojo-world/src/contracts/abi/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,5 +325,6 @@ abigen!(
]"#,
type_aliases {
dojo::world::config::Config::Event as DojoConfigEvent;
}
},
derives(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone)
);
4 changes: 2 additions & 2 deletions crates/dojo-world/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use anyhow::{anyhow, Result};
use async_trait::async_trait;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass;
use starknet::accounts::{Account, AccountError, Call, ConnectedAccount};
use starknet::accounts::{Account, AccountError, ConnectedAccount};
use starknet::core::types::contract::{CompiledClass, SierraClass};
use starknet::core::types::{
BlockId, BlockTag, DeclareTransactionResult, Felt, FlattenedSierraClass,
BlockId, BlockTag, Call, DeclareTransactionResult, Felt, FlattenedSierraClass,
InvokeTransactionResult, ReceiptBlock, StarknetError, TransactionReceiptWithBlockInfo,
};
use starknet::core::utils::{get_contract_address, CairoShortStringToFeltError};
Expand Down
28 changes: 14 additions & 14 deletions crates/katana/controller/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::collections::HashMap;

use account_sdk::abigen::controller::Signer;
use account_sdk::signers::webauthn::{DeviceSigner, WebauthnAccountSigner};
use account_sdk::signers::webauthn::{CredentialID, WebauthnSigner};
// use account_sdk::signers::webauthn::{DeviceSigner, WebauthnAccountSigner};
use account_sdk::signers::SignerTrait;
use account_sdk::wasm_webauthn::CredentialID;
// use account_sdk::wasm_webauthn::CredentialID;
use alloy_primitives::U256;
use anyhow::Result;
use coset::CoseKey;
Expand Down Expand Up @@ -134,21 +135,20 @@ fn get_contract_storage(
credential_id: CredentialID,
public_key: CoseKey,
) -> Result<HashMap<StorageKey, StorageValue>> {
let signer = DeviceSigner::new(
WEBAUTHN_RP_ID.to_string(),
WEBAUTHN_ORIGIN.to_string(),
credential_id,
public_key,
);
// let signer =
// WebauthnSigner::new(WEBAUTHN_RP_ID.to_string(), credential_id, public_key,
// BrowserBackend);

// let signer = Signer::Webauthn(signer.signer_pub_data());
// let guid = signer.guid();

let signer = Signer::Webauthn(signer.signer_pub_data());
let guid = signer.guid();
// // the storage variable name for webauthn signer
// const MULTIPLE_OWNERS_COMPONENT_SUB_STORAGE: &str = "owners";
// let storage = get_storage_var_address(MULTIPLE_OWNERS_COMPONENT_SUB_STORAGE, &[guid])?;

// the storage variable name for webauthn signer
const MULTIPLE_OWNERS_COMPONENT_SUB_STORAGE: &str = "owners";
let storage = get_storage_var_address(MULTIPLE_OWNERS_COMPONENT_SUB_STORAGE, &[guid])?;
// Ok(HashMap::from([(storage, FieldElement::ONE)]))

Ok(HashMap::from([(storage, FieldElement::ONE)]))
todo!()
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions crates/katana/controller/src/webauthn.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub mod credential {
use account_sdk::wasm_webauthn::CredentialID;
use account_sdk::signers::webauthn::CredentialID;
use base64::engine::general_purpose;
use base64::{DecodeError, Engine};

pub fn from_base64(base64: &str) -> Result<CredentialID, DecodeError> {
let bytes = general_purpose::URL_SAFE_NO_PAD.decode(base64)?;
Ok(CredentialID(bytes))
Ok(CredentialID::from(bytes))
}
}

Expand Down
Loading

0 comments on commit 10ec335

Please sign in to comment.