Skip to content

Commit

Permalink
Merge pull request #108 from reown-com/fix/smart-sessions-major-changes
Browse files Browse the repository at this point in the history
fix: smart sessions major changes
  • Loading branch information
chris13524 authored Jan 7, 2025
2 parents 3f098b2 + a3401f2 commit 1f82a83
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 68 deletions.
2 changes: 1 addition & 1 deletion crates/yttrium/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ dotenvy = { version = "0.15.7", default-features = false }
hex = { version = "0.4.3", features = ["std"], default-features = false }
async-trait = { version = "0.1.83", default-features = false }
tracing = { version = "0.1.40", default-features = false }
fastlz-rs = { version = "0.0.3", features = ["std"], default-features = false }
# fastlz-rs = { version = "0.0.3", features = ["std"], default-features = false }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

Expand Down
1 change: 1 addition & 0 deletions crates/yttrium/src/erc7579/ownable_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use {
},
};

// https://github.com/rhinestonewtf/module-sdk/blob/main/src/module/ownable-validator/constants.ts
pub const OWNABLE_VALIDATOR_ADDRESS: Address =
address!("2483DA3A338895199E5e538530213157e931Bf06");

Expand Down
3 changes: 2 additions & 1 deletion crates/yttrium/src/erc7579/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use {
alloy::primitives::{address, Address, Bytes},
};

// https://github.com/rhinestonewtf/module-sdk/blob/main/src/module/smart-sessions/policies/sudo-policy/constants.ts
pub const SUDO_POLICY_ADDRESS: Address =
address!("529Ad04F4D83aAb25144a90267D4a1443B84f5A6");
address!("0000003111cD8e92337C100F22B7A9dbf8DEE301");

// https://github.com/rhinestonewtf/module-sdk/blob/1f2f2c5380614ad07b6e1ccbb5a9ed55374c673c/src/module/smart-sessions/policies/sudo-policy/installation.ts#L4
pub fn get_sudo_policy() -> PolicyData {
Expand Down
47 changes: 31 additions & 16 deletions crates/yttrium/src/erc7579/smart_sessions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use {
},
};

// https://github.com/erc7579/smartsessions/blob/main/contracts/DataTypes.sol
sol! {
struct ChainDigest {
uint64 chainId;
Expand All @@ -18,8 +19,16 @@ sol! {
bytes initData;
}

struct ERC7739Context {
// we can not use a detailed EIP712Domain struct here.
// EIP712 specifies: Protocol designers only need to include the fields that make sense for their signing domain.
// Unused fields are left out of the struct type.
bytes32 appDomainSeparator;
string[] contentNames;
}

struct ERC7739Data {
string[] allowedERC7739Content;
ERC7739Context[] allowedERC7739Content;
PolicyData[] erc1271Policies;
}

Expand All @@ -36,13 +45,15 @@ sol! {
PolicyData[] userOpPolicies;
ERC7739Data erc7739Policies;
ActionData[] actions;
// when setting `permitERC4337Paymaster` to true, the length of `userOpPolicies` needs to be at least 1
bool permitERC4337Paymaster;
}

// https://github.com/erc7579/smartsessions/blob/b1624f851f56ec67cc677dce129e9caa12fcafd9/contracts/DataTypes.sol#L14
struct EnableSession {
uint8 chainDigestIndex;
ChainDigest[] hashesAndChainIds;
Session sessionToEnable;
// in order to enable a session, the smart account has to sign a digest. The signature for this is stored here.
bytes permissionEnableSig;
}

Expand All @@ -58,18 +69,32 @@ sol! {
}
}

// https://github.com/rhinestonewtf/module-sdk/blob/main/src/module/smart-sessions/constants.ts#L3
pub const SMART_SESSIONS_ADDRESS: Address =
address!("DDFF43A42726df11E34123f747bDce0f755F784d");
address!("00000000002B0eCfbD0496EE71e01257dA0E37DE");

// https://github.com/rhinestonewtf/module-sdk/blob/1f2f2c5380614ad07b6e1ccbb5a9ed55374c673c/src/module/smart-sessions/installation.ts#L12
pub fn get_smart_sessions_validator(
sessions: &[Session],
hook: Option<Address>,
) -> Module {
let use_registry = true;
Module {
address: SMART_SESSIONS_ADDRESS,
module: SMART_SESSIONS_ADDRESS,
init_data: sessions.abi_encode_params().into(),
init_data: (
FixedBytes::from(
if use_registry {
SmartSessionMode::Enable
} else {
SmartSessionMode::UnsafeEnable
}
.to_u8(),
),
sessions.abi_encode_params(),
)
.abi_encode_packed()
.into(),
de_init_data: Default::default(),
additional_context: Default::default(),
hook,
Expand All @@ -88,7 +113,7 @@ pub fn get_permission_id(session: &Session) -> B256 {
)
}

#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum SmartSessionMode {
Use,
Enable,
Expand Down Expand Up @@ -138,17 +163,7 @@ fn encode_smart_session_signature(
) -> Bytes {
match mode {
SmartSessionMode::Use => {
let signature = signature.abi_encode();
let mut compress_state = fastlz_rs::CompressState::new();
let compressed = Bytes::from(
compress_state
.compress_to_vec(
&signature,
fastlz_rs::CompressionLevel::Level1,
)
.expect("this shouldn't panic"),
);
(FixedBytes::from(mode.to_u8()), permission_id, compressed)
(FixedBytes::from(mode.to_u8()), permission_id, signature)
.abi_encode_packed()
.into()
}
Expand Down
158 changes: 108 additions & 50 deletions crates/yttrium/src/examples/eip7702.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use {
entry_point::ENTRYPOINT_ADDRESS_V07,
erc7579::{
accounts::safe::encode_validator_key,
addresses::{MOCK_ATTESTER_ADDRESS, RHINESTONE_ATTESTER_ADDRESS},
addresses::RHINESTONE_ATTESTER_ADDRESS,
ownable_validator::{
encode_owners, get_ownable_validator,
get_ownable_validator_mock_signature,
Expand Down Expand Up @@ -39,8 +39,9 @@ use {
primitives::{
address, eip191_hash_message, fixed_bytes, Address, B256, U256,
},
rlp::Encodable,
rpc::types::Authorization,
signers::{local::LocalSigner, SignerSync},
signers::{k256::ecdsa::SigningKey, local::LocalSigner, SignerSync},
sol,
sol_types::SolCall,
},
Expand All @@ -49,12 +50,57 @@ use {
};

#[tokio::test]
async fn test() {
#[ignore]
#[cfg(feature = "test_pimlico_api")]
async fn test_pimlico() {
use {
crate::{
config::{Endpoint, Endpoints},
test_helpers::private_faucet,
},
std::env,
};
let config = Config {
endpoints: {
let api_key = env::var("PIMLICO_API_KEY")
.expect("You've not set the PIMLICO_API_KEY");

let rpc = {
let base_url = "https://odyssey.ithaca.xyz".to_owned();
Endpoint { api_key: api_key.clone(), base_url }
};

let bundler = {
let chain_id = 911867; // Odyssey Testnet
let base_url = format!(
"https://api.pimlico.io/v2/{chain_id}/rpc?apikey={api_key}"
);
Endpoint { api_key: api_key.clone(), base_url }
};

Endpoints { rpc, paymaster: bundler.clone(), bundler }
},
};
let faucet = private_faucet();
test_impl(config, faucet).await
}

#[tokio::test]
async fn test_local() {
let config = Config::local();
let faucet =
anvil_faucet(config.endpoints.rpc.base_url.parse::<Url>().unwrap())
.await;
test_impl(config, faucet).await
}

async fn test_impl(config: Config, faucet: LocalSigner<SigningKey>) {
let rpc_url = config.endpoints.rpc.base_url.parse::<Url>().unwrap();
println!("rpc_url: {}", rpc_url);
let provider = ReqwestProvider::<Ethereum>::new_http(rpc_url.clone());

let chain_id = provider.get_chain_id().await.unwrap();
println!("chain_id: {:?}", chain_id);

let account = LocalSigner::random();
let safe_owner = LocalSigner::random();
Expand All @@ -68,13 +114,13 @@ async fn test() {
let session_owner = LocalSigner::random();

let session = Session {
sessionValidator: OWNABLE_VALIDATOR_ADDRESS, // todo is this wrong???
sessionValidator: OWNABLE_VALIDATOR_ADDRESS,
sessionValidatorInitData: encode_owners(&Owners {
threshold: 1,
owners: vec![session_owner.address()],
}),
salt: B256::default(),
userOpPolicies: vec![],
userOpPolicies: vec![get_sudo_policy()],
erc7739Policies: ERC7739Data {
allowedERC7739Content: vec![],
erc1271Policies: vec![],
Expand All @@ -84,6 +130,7 @@ async fn test() {
actionTargetSelector: fixed_bytes!("00000000"), /* function selector to be used in the execution, in this case no function selector is used */
actionPolicies: vec![get_sudo_policy()],
}],
permitERC4337Paymaster: true,
};

let smart_sessions = get_smart_sessions_validator(&[session.clone()], None);
Expand Down Expand Up @@ -118,56 +165,67 @@ async fn test() {
}
};

let faucet = anvil_faucet(rpc_url).await;
println!("using faucet: {}", faucet.address());
let wallet = EthereumWallet::new(faucet);
let wallet_provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.on_provider(provider.clone());
assert!(SetupContract::new(account.address(), wallet_provider.clone())
.setup(
owners.owners,
U256::from(owners.threshold),
SAFE_ERC_7579_LAUNCHPAD_ADDRESS,
AddSafe7579Contract::addSafe7579Call {
safe7579: SAFE_4337_MODULE_ADDRESS,
validators: vec![
AddSafe7579Contract::ModuleInit {
module: ownable_validator.address,
initData: ownable_validator.init_data,
},
AddSafe7579Contract::ModuleInit {
module: smart_sessions.address,
initData: smart_sessions.init_data,
},
],
executors: vec![],
fallbacks: vec![],
hooks: vec![],
attesters: vec![
RHINESTONE_ATTESTER_ADDRESS,
MOCK_ATTESTER_ADDRESS,
],
threshold: owners.threshold,
}
.abi_encode()
.into(),
SAFE_4337_MODULE_ADDRESS,
Address::ZERO,
U256::ZERO,
Address::ZERO,
)
.map(|mut t| {
t.set_authorization_list(vec![auth]);
t
})
.send()
.await
.unwrap()
.get_receipt()
.await
.unwrap()
.status());
let sent_txn =
SetupContract::new(account.address(), wallet_provider.clone())
.setup(
owners.owners,
U256::from(owners.threshold),
SAFE_ERC_7579_LAUNCHPAD_ADDRESS,
AddSafe7579Contract::addSafe7579Call {
safe7579: SAFE_4337_MODULE_ADDRESS,
validators: vec![
AddSafe7579Contract::ModuleInit {
module: ownable_validator.address,
initData: ownable_validator.init_data,
},
AddSafe7579Contract::ModuleInit {
module: smart_sessions.address,
initData: smart_sessions.init_data,
},
],
executors: vec![],
fallbacks: vec![],
hooks: vec![],
attesters: vec![
RHINESTONE_ATTESTER_ADDRESS,
// MOCK_ATTESTER_ADDRESS,
],
threshold: 1,
}
.abi_encode()
.into(),
SAFE_4337_MODULE_ADDRESS,
Address::ZERO,
U256::ZERO,
Address::ZERO,
)
.map(|mut t| {
println!("t: {:?}", t);
println!("t.chain_id: {:?}", t.chain_id);
let mut buf = Vec::new();
auth.encode(&mut buf);
println!("auth: {}", hex::encode(buf));
t.set_authorization_list(vec![auth]);
// t.set_nonce(1);
// t.set_gas_limit(1000000);
// t.set_max_fee_per_gas(252);
// t.set_max_priority_fee_per_gas(0);
// t.set_chain_id(chain_id);
t
})
.send()
.await
.unwrap();
println!("txn hash: {}", sent_txn.tx_hash());
let receipt = sent_txn.get_receipt().await.unwrap();
println!("receipt: {:?}", receipt);
assert!(receipt.status());

let nonce = get_nonce_with_key(
&provider,
Expand Down

0 comments on commit 1f82a83

Please sign in to comment.