Skip to content

Commit

Permalink
feat(sessions): updating the cosign signing and the bundler
Browse files Browse the repository at this point in the history
  • Loading branch information
geekbrother committed Jul 22, 2024
1 parent 4193843 commit eb01bed
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 129 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export RPC_PROXY_PROVIDER_COINBASE_APP_ID=""
export RPC_PROXY_PROVIDER_ZERION_API_KEY=""
export RPC_PROXY_PROVIDER_ONE_INCH_API_KEY=""
export RPC_PROXY_PROVIDER_GETBLOCK_ACCESS_TOKENS='{}'
export RPC_PROXY_PROVIDER_BICONOMY_BUNDLER_TOKEN=""
export RPC_PROXY_PROVIDER_BUNDLER_TOKEN=""

# PostgreSQL URI connection string
export RPC_PROXY_POSTGRES_URI="postgres://postgres@localhost/postgres"
Expand Down
2 changes: 1 addition & 1 deletion .env.terraform.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export TF_VAR_coinbase_app_id=""
export TF_VAR_zerion_api_key=""
export TF_VAR_one_inch_api_key=""
export TF_VAR_getblock_access_tokens='{}'
export TF_VAR_biconomy_bundler_token=""
export TF_VAR_bundler_token=""
export TF_VAR_grafana_endpoint=$(aws grafana list-workspaces | jq -r '.workspaces[] | select( .tags.Env == "prod") | select( .tags.Name == "grafana-9") | .endpoint')
export TF_VAR_registry_api_auth_token=""
export TF_VAR_debug_secret=""
Expand Down
7 changes: 2 additions & 5 deletions src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,7 @@ mod test {
("RPC_PROXY_PROVIDER_ONE_INCH_API_KEY", "ONE_INCH_API_KEY"),
("RPC_PROXY_PROVIDER_ONE_INCH_REFERRER", "ONE_INCH_REFERRER"),
("RPC_PROXY_PROVIDER_GETBLOCK_ACCESS_TOKENS", "{}"),
(
"RPC_PROXY_PROVIDER_BICONOMY_BUNDLER_TOKEN",
"BICONOMY_TOKEN",
),
("RPC_PROXY_PROVIDER_BUNDLER_TOKEN", "BUNDLER_TOKEN"),
(
"RPC_PROXY_PROVIDER_PROMETHEUS_QUERY_URL",
"PROMETHEUS_QUERY_URL",
Expand Down Expand Up @@ -249,7 +246,7 @@ mod test {
one_inch_api_key: Some("ONE_INCH_API_KEY".to_owned()),
one_inch_referrer: Some("ONE_INCH_REFERRER".to_owned()),
getblock_access_tokens: Some("{}".to_owned()),
biconomy_bundler_token: Some("BICONOMY_TOKEN".to_owned()),
bundler_token: Some("BUNDLER_TOKEN".to_owned()),
},
rate_limiting: RateLimitingConfig {
max_tokens: Some(100),
Expand Down
13 changes: 12 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub enum RpcError {
#[error("Requested chain provider is temporarily unavailable: {0}")]
ChainTemporarilyUnavailable(String),

#[error("Invalid chainId format for the requested namespace: {0}")]
InvalidChainIdFormat(String),

#[error("Specified provider is not supported: {0}")]
UnsupportedProvider(String),

Expand Down Expand Up @@ -215,7 +218,7 @@ impl IntoResponse for RpcError {
StatusCode::BAD_REQUEST,
Json(new_error_response(
"".to_string(),
format!("Crypto utils invalid argument: {}", e),
format!("Crypto utils error: {}", e),
)),
)
.into_response(),
Expand All @@ -227,6 +230,14 @@ impl IntoResponse for RpcError {
)),
)
.into_response(),
Self::InvalidChainIdFormat(chain_id) => (
StatusCode::BAD_REQUEST,
Json(new_error_response(
"chainId".to_string(),
format!("Requested {chain_id} has invalid format for the requested namespace"),
)),
)
.into_response(),
Self::UnsupportedProvider(provider) => (
StatusCode::BAD_REQUEST,
Json(new_error_response(
Expand Down
3 changes: 1 addition & 2 deletions src/handlers/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,7 @@ impl JsonRpcClient for SelfProvider {
let id = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time should't go backwards")
.as_millis()
.to_string();
.as_secs();

let response = rpc_call(
self.state.clone(),
Expand Down
93 changes: 57 additions & 36 deletions src/handlers/sessions/cosign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use {
storage::irn::OperationType,
utils::crypto::{
abi_encode_two_bytes_arrays, call_get_signature, call_get_user_op_hash,
disassemble_caip10, send_user_operation_to_bundler, CaipNamespaces,
disassemble_caip10, pack_signature, send_user_operation_to_bundler, to_eip191_message,
CaipNamespaces, ChainId,
},
},
axum::{
Expand All @@ -16,14 +17,14 @@ use {
},
base64::prelude::*,
ethers::{
core::k256::{
ecdsa::{signature::Signer, Signature, SigningKey},
pkcs8::DecodePrivateKey,
},
types::{Bytes, H160},
core::k256::ecdsa::SigningKey,
signers::LocalWallet,
types::{H160, H256},
utils::keccak256,
},
serde::{Deserialize, Serialize},
std::{sync::Arc, time::SystemTime},
tracing::info,
wc::future::FutureExt,
};

Expand All @@ -48,14 +49,23 @@ pub async fn handler(
#[tracing::instrument(skip(state), level = "debug")]
async fn handler_internal(
state: State<Arc<AppState>>,
Path(address): Path<String>,
Path(caip10_address): Path<String>,
request_payload: CoSignRequest,
) -> Result<Response, RpcError> {
// Checking the CAIP-10 address format
let (namespace, chain_id, address) = disassemble_caip10(&address)?;
let (namespace, chain_id, address) = disassemble_caip10(&caip10_address)?;
if namespace != CaipNamespaces::Eip155 {
return Err(RpcError::UnsupportedNamespace(namespace));
}

// ChainID validation
let chain_id_uint = chain_id
.parse::<u64>()
.map_err(|_| RpcError::InvalidChainIdFormat(chain_id.clone()))?;
if !ChainId::is_supported(chain_id_uint) {
return Err(RpcError::UnsupportedChain(chain_id.clone()));
}

let h160_address = address
.parse::<H160>()
.map_err(|_| RpcError::InvalidAddress)?;
Expand Down Expand Up @@ -86,12 +96,13 @@ async fn handler_internal(
user_op.clone(),
)
.await?;
let eip191_user_op_hash = to_eip191_message(&user_op_hash);

// Get the PCI object from the IRN
let irn_client = state.irn.as_ref().ok_or(RpcError::IrnNotConfigured)?;
let irn_call_start = SystemTime::now();
let storage_permissions_item = irn_client
.hget(address.clone(), request_payload.pci.clone())
.hget(caip10_address.clone(), request_payload.pci.clone())
.await?
.ok_or_else(|| RpcError::PermissionNotFound(request_payload.pci.clone()))?;
state
Expand All @@ -105,27 +116,42 @@ async fn handler_internal(
.context
.clone()
.ok_or_else(|| RpcError::PermissionContextNotUpdated(request_payload.pci.clone()))?;
let permission_context = hex::decode(permission_context_item.context.permissions_context)
.map_err(|e| RpcError::WrongHexFormat(e.to_string()))?;
let permission_context = hex::decode(
permission_context_item
.context
.permissions_context
.clone()
.trim_start_matches("0x"),
)
.map_err(|e| {
RpcError::WrongHexFormat(format!(
"error:{:?} permission_context:{}",
e.to_string(),
permission_context_item.context.permissions_context
))
})?;

// Sign the userOp hash with the permission signing key
let signing_key_bytes = BASE64_STANDARD
.decode(storage_permissions_item.signing_key)
.map_err(|e| RpcError::WrongBase64Format(e.to_string()))?;
let signer = SigningKey::from_pkcs8_der(&signing_key_bytes)?;
let signature: Signature = signer.sign(&user_op_hash);
let signer = SigningKey::from_bytes(signing_key_bytes.as_slice().into())
.map_err(|e| RpcError::KeyFormatError(e.to_string()))?;

// Create a LocalWallet for signing and signing the hashed message
let wallet = LocalWallet::from(signer);
let signature = wallet
.sign_hash(H256::from(&keccak256(eip191_user_op_hash.clone())))
.unwrap();
let packed_signature = pack_signature(&signature);

// ABI encode the signatures
let concatenated_signature = abi_encode_two_bytes_arrays(
&Bytes::from(signature.to_der().as_bytes().to_vec()),
&user_op.signature,
);
let concatenated_signature = abi_encode_two_bytes_arrays(&packed_signature, &user_op.signature);

// Update the userOp with the signature
user_op.signature = concatenated_signature;

// Get the Signature
// UserOpBuilder contract address
// Get the Signature from the UserOpBuilder
let user_op_builder_contract_address = permission_context_item
.context
.signer_data
Expand All @@ -142,31 +168,26 @@ async fn handler_internal(
)
.await?;

// Update the userOp with the signature
user_op.signature = get_signature_result;
// Todo: remove this debug line before production stage
info!("UserOpPacked final JSON: {:?}", serde_json::json!(user_op));

// Using the Biconomy bundler to send the userOperation
let entry_point = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789";
let simulation_type = "validation_and_execution";
let bundler_url = format!(
"https://bundler.biconomy.io/api/v2/{}/{}",
chain_id,
// Update the userOp with the signature,
// send the userOperation to the bundler and get the receipt
user_op.signature = get_signature_result;
let bundler_api_token =
state
.config
.providers
.biconomy_bundler_token
.bundler_token
.clone()
.ok_or(RpcError::InvalidConfiguration(
"Missing biconomy bundler token".to_string()
))?
);

// Send the userOperation to the bundler and get the receipt
"Missing bundler API token".to_string(),
))?;
let receipt = send_user_operation_to_bundler(
&user_op,
&bundler_url,
entry_point,
simulation_type,
&chain_id,
&bundler_api_token,
ENTRY_POINT_V07_CONTRACT_ADDRESS,
&state.http_client,
)
.await?;
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/sessions/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async fn handler_internal(
// Generate a secp256k1 keys and export to DER Base64 format
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = VerifyingKey::from(&signing_key);
let private_key_der = signing_key.to_bytes();
let private_key_der = signing_key.to_bytes().to_vec();
let private_key_der_base64 = BASE64_STANDARD.encode(private_key_der);
let public_key_der = verifying_key.to_encoded_point(false).as_bytes().to_vec();
let public_key_der_base64 = BASE64_STANDARD.encode(&public_key_der);
Expand Down
4 changes: 2 additions & 2 deletions src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ pub struct ProvidersConfig {
pub one_inch_referrer: Option<String>,
/// GetBlock provider access tokens in JSON format
pub getblock_access_tokens: Option<String>,
/// Biconomy bundler API key
pub biconomy_bundler_token: Option<String>,
/// Bundler API token
pub bundler_token: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
Expand Down
Loading

0 comments on commit eb01bed

Please sign in to comment.