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

Implement wildcard sessions #1261

Merged
merged 1 commit into from
Jan 9, 2025
Merged
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

Large diffs are not rendered by default.

36,834 changes: 18,422 additions & 18,412 deletions packages/account_sdk/artifacts/classes/controller.latest.contract_class.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/account_sdk/artifacts/metadata.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"controllers": {
"latest": {
"casm_hash": "0x2f2386cd9bea7724f79d8c392b6b99228721d1e8769b1b482287520dfc4d3eb",
"class_hash": "0x511dd75da368f5311134dee2356356ac4da1538d2ad18aa66d57c47e3757d59"
"casm_hash": "0x2fcd4b347622fd2dbe973ad873666f8925b3f244120793014248b4fd9670bd9",
"class_hash": "0x743c83c41ce99ad470aa308823f417b2141e02e04571f5c0004e743556e7faf"
},
"v1.0.4": {
"casm_hash": "0x6b22de13b878ab346fa53442adaa8a40a6bd25732aa1aeb2a26375987f0be00",
Expand Down
14 changes: 12 additions & 2 deletions packages/account_sdk/src/account/session/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ impl SessionAccount {
.await
}

async fn sign(&self, hash: Felt, policies: &[Policy]) -> Result<SessionToken, SignError> {
let hash = self.message_hash(hash)?;
fn generate_proofs(&self, policies: &[Policy]) -> Result<Vec<Vec<Felt>>, SignError> {
let mut proofs = Vec::new();

for policy in policies {
Expand All @@ -113,6 +112,17 @@ impl SessionAccount {
proofs.push(proof);
}

Ok(proofs)
}

async fn sign(&self, hash: Felt, policies: &[Policy]) -> Result<SessionToken, SignError> {
let hash = self.message_hash(hash)?;
let proofs = if self.session.is_wildcard() {
vec![]
} else {
self.generate_proofs(policies)?
};

Ok(SessionToken {
session: self.session.clone().into(),
cache_authorization: true,
Expand Down
35 changes: 34 additions & 1 deletion packages/account_sdk/src/account/session/hash.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use cainome_cairo_serde::NonZero;
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use starknet::core::types::Felt;
use starknet::core::utils::NonAsciiNameError;
Expand Down Expand Up @@ -78,6 +79,34 @@ impl Session {
})
}

pub fn new_wildcard(
policies: Vec<Policy>,
expires_at: u64,
session_signer: &Signer,
guardian_guid: Felt,
) -> Result<Self, SignError> {
let metadata = json!({ "metadata": "metadata", "max_fee": 0 });

Ok(Self {
inner: crate::abigen::controller::Session {
expires_at,
allowed_policies_root: short_string!("wildcard-policy"),
session_key_guid: session_signer.clone().into(),
guardian_key_guid: guardian_guid,
metadata_hash: Felt::ZERO,
},
requested_policies: policies.clone(),
proved_policies: policies
.into_iter()
.map(|policy| ProvedPolicy {
policy: policy.clone(),
proof: vec![],
})
.collect(),
metadata: serde_json::to_string(&metadata).unwrap(),
})
}

pub fn message_hash(
&self,
tx_hash: Felt,
Expand All @@ -94,6 +123,10 @@ impl Session {
.map(|ProvedPolicy { proof, .. }| proof.clone())
}

pub fn is_wildcard(&self) -> bool {
self.inner.allowed_policies_root == short_string!("wildcard-policy")
}

pub fn is_authorized(&self, policy: &Policy) -> bool {
self.proved_policies.iter().any(|proved_policy| {
proved_policy.policy == *policy && proved_policy.policy.is_authorized()
Expand Down
4 changes: 2 additions & 2 deletions packages/account_sdk/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ lazy_static! {
Version::LATEST,
ContractClass {
content: include_str!("../artifacts/classes/controller.latest.contract_class.json"),
hash: felt!("0x511dd75da368f5311134dee2356356ac4da1538d2ad18aa66d57c47e3757d59"),
hash: felt!("0x743c83c41ce99ad470aa308823f417b2141e02e04571f5c0004e743556e7faf"),
casm_hash: felt!(
"0x2f2386cd9bea7724f79d8c392b6b99228721d1e8769b1b482287520dfc4d3eb"
"0x2fcd4b347622fd2dbe973ad873666f8925b3f244120793014248b4fd9670bd9"
),
},
);
Expand Down
31 changes: 29 additions & 2 deletions packages/account_sdk/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,33 @@ impl Controller {
&session_signer.clone().into(),
guardian,
)?;

self.create_with_session(signer, session).await
}

pub async fn create_wildcard_session(
&mut self,
methods: Vec<Policy>,
expires_at: u64,
) -> Result<SessionAccount, ControllerError> {
let signer = SigningKey::from_random();
let session_signer = Signer::Starknet(signer.clone());

let session = Session::new_wildcard(
methods,
expires_at,
&session_signer.clone().into(),
Felt::ZERO,
)?;

self.create_with_session(signer, session).await
}

pub async fn create_with_session(
&mut self,
session_signer: SigningKey,
session: Session,
) -> Result<SessionAccount, ControllerError> {
let hash = session
.inner
.get_message_hash_rev_1(self.chain_id, self.address);
Expand All @@ -55,15 +82,15 @@ impl Controller {
max_fee: None,
credentials: Some(Credentials {
authorization: authorization.clone(),
private_key: signer.secret_scalar(),
private_key: session_signer.secret_scalar(),
}),
is_registered: false,
},
)?;

let session_account = SessionAccount::new(
self.provider().clone(),
session_signer,
Signer::Starknet(session_signer),
self.address,
self.chain_id,
authorization,
Expand Down
50 changes: 50 additions & 0 deletions packages/account_sdk/src/session_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,3 +386,53 @@ pub async fn test_verify_execute_with_invalid_guardian() {
"Should return error"
);
}

#[tokio::test]
async fn test_verify_execute_session_wildcard() {
let signer = Signer::new_starknet_random();
let runner = KatanaRunner::load();
let mut controller = runner
.deploy_controller(
"username".to_owned(),
Owner::Signer(signer),
Version::LATEST,
)
.await;

let signer = SigningKey::from_random();
let session_signer = Signer::Starknet(signer.clone());
let session =
Session::new_wildcard(vec![], u64::MAX, &session_signer.into(), Felt::ZERO).unwrap();

let session_account = controller
.create_with_session(signer, session)
.await
.unwrap();

let recipient = ContractAddress(felt!("0x18301129"));
let contract_erc20 = Erc20::new(*FEE_TOKEN_ADDRESS, &session_account);

contract_erc20
.balanceOf(&recipient)
.block_id(BlockId::Tag(BlockTag::Latest))
.call()
.await
.expect("failed to call contract");

let tx = contract_erc20
.transfer(
&recipient,
&U256 {
low: 0x1_u128,
high: 0,
},
)
.send()
.await
.unwrap();

TransactionWaiter::new(tx.transaction_hash, runner.client())
.wait()
.await
.unwrap();
}
8 changes: 7 additions & 1 deletion packages/contracts/controller/src/session/session.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod session_component {
use controller::account::IAssertOwner;

const SESSION_MAGIC: felt252 = 'session-token';
const WILDCARD_MAGIC: felt252 = 'wildcard-policy';
const AUTHORIZATION_BY_REGISTERED: felt252 = 'authorization-by-registered';

#[storage]
Expand Down Expand Up @@ -184,7 +185,6 @@ mod session_component {
transaction_hash: felt252,
) -> Option<(felt252, felt252)> {
let contract = self.get_contract();
assert(signature.proofs.len() == calls.len(), 'session/length-mismatch');

let now = get_block_timestamp();
assert(signature.session.expires_at > now, 'session/expired');
Expand Down Expand Up @@ -254,6 +254,12 @@ mod session_component {
);
}

if (signature.session.allowed_policies_root == WILDCARD_MAGIC) {
return to_be_cached;
}

assert(signature.proofs.len() == calls.len(), 'session/length-mismatch');

assert(
check_policy(calls, signature.session.allowed_policies_root, signature.proofs),
'session/policy-check-failed'
Expand Down
Loading