Skip to content

Commit 58d51d4

Browse files
Merge pull request #324 from originalworks/introduce-owen-wallet
Introduce OWEN wallet module
2 parents 4dc0b93 + d5f6cfc commit 58d51d4

5 files changed

Lines changed: 154 additions & 129 deletions

File tree

owen/src/contracts.rs

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::blob::BlobTransactionData;
2+
use crate::wallet::OwenWallet;
23
use crate::{is_local, Config};
3-
use alloy::primitives::{Address, FixedBytes};
4+
use alloy::primitives::FixedBytes;
45
use alloy::providers::{Provider, ProviderBuilder};
5-
use alloy::signers::local::PrivateKeySigner;
66
use alloy::sol_types::private::Bytes;
77
use alloy::{
88
network::EthereumWallet,
@@ -15,10 +15,7 @@ use alloy::{
1515
},
1616
sol,
1717
};
18-
use alloy_signer_aws::AwsSigner;
19-
use anyhow::Context;
20-
use aws_config::meta::region::RegionProviderChain;
21-
use aws_config::BehaviorVersion;
18+
2219
use log_macros::{format_error, log_info, log_warn};
2320
use serde_json::json;
2421
use DdexEmitter::getSupportedBlobImageIdsReturn;
@@ -55,8 +52,8 @@ pub struct ContractsManager {
5552
}
5653

5754
impl ContractsManager {
58-
pub async fn build(config: &Config) -> anyhow::Result<Self> {
59-
let wallet = Self::build_wallet(config).await?;
55+
pub async fn build(config: &Config, owen_wallet: &OwenWallet) -> anyhow::Result<Self> {
56+
let wallet = owen_wallet.wallet.clone();
6057

6158
let provider = ProviderBuilder::new()
6259
.wallet(wallet)
@@ -76,42 +73,6 @@ impl ContractsManager {
7673
})
7774
}
7875

79-
async fn build_wallet(config: &Config) -> anyhow::Result<EthereumWallet> {
80-
let wallet: EthereumWallet;
81-
if config.use_kms {
82-
let rpc_provider = ProviderBuilder::new().connect_http(config.rpc_url.parse()?);
83-
let chain_id = rpc_provider.get_chain_id().await?;
84-
85-
let region_provider = RegionProviderChain::default_provider().or_else("us-east-1");
86-
let aws_main_config = aws_config::defaults(BehaviorVersion::latest())
87-
.region(region_provider)
88-
.load()
89-
.await;
90-
91-
let client = aws_sdk_kms::Client::new(&aws_main_config);
92-
93-
let key_id = config
94-
.signer_kms_id
95-
.clone()
96-
.expect("'use_kms' is set to true but 'signer_kms_id' is missing");
97-
98-
let chain_id = Some(chain_id);
99-
let signer = AwsSigner::new(client, key_id, chain_id).await.unwrap();
100-
101-
let pubkey = signer.get_pubkey().await?;
102-
let address = Address::from_public_key(&pubkey);
103-
log_info!("Using KMS with address: {}", address);
104-
wallet = EthereumWallet::from(signer);
105-
} else {
106-
let private_key_signer: PrivateKeySigner = config
107-
.private_key
108-
.parse()
109-
.with_context(|| "Failed to parse PRIVATE_KEY")?;
110-
wallet = EthereumWallet::from(private_key_signer);
111-
}
112-
Ok(wallet)
113-
}
114-
11576
pub async fn check_image_compatibility(&self) -> anyhow::Result<()> {
11677
let getSupportedBlobImageIdsReturn {
11778
_0: current_image_id,

owen/src/ipfs.rs

Lines changed: 9 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
use crate::{
22
constants::{self, IPFS_API_ADD_FILE, REQWEST_CLIENT},
3+
wallet::OwenWallet,
34
Config,
45
};
5-
use alloy::{
6-
hex,
7-
providers::{Provider, ProviderBuilder},
8-
signers::{local::PrivateKeySigner, Signer},
9-
};
10-
use alloy_signer_aws::AwsSigner;
6+
use alloy::hex;
117
use anyhow::Context;
12-
use aws_config::{meta::region::RegionProviderChain, BehaviorVersion};
138
use log_macros::{format_error, log_info};
149
use reqwest::{multipart, Body};
1510
use serde::{Deserialize, Serialize};
@@ -27,56 +22,20 @@ struct StorachaBridgeResponse {
2722
url: String,
2823
}
2924

30-
pub struct IpfsManager {
25+
pub struct IpfsManager<'a> {
3126
local_ipfs: bool,
3227
ipfs_api_base_url: String,
3328
storacha_bridge_url: String,
34-
private_key_signer: Option<PrivateKeySigner>,
35-
use_kms: bool,
36-
kms_signer: Option<AwsSigner>,
29+
owen_wallet: &'a OwenWallet,
3730
}
3831

39-
impl IpfsManager {
40-
pub async fn build(config: &Config) -> anyhow::Result<Self> {
41-
let rpc_provider = ProviderBuilder::new().connect_http(config.rpc_url.parse()?);
42-
let chain_id = rpc_provider.get_chain_id().await?;
43-
let mut kms_signer: Option<AwsSigner> = None;
44-
let mut private_key_signer: Option<PrivateKeySigner> = None;
45-
46-
if config.use_kms {
47-
let region_provider = RegionProviderChain::default_provider().or_else("us-east-1");
48-
let aws_main_config = aws_config::defaults(BehaviorVersion::latest())
49-
.region(region_provider)
50-
.load()
51-
.await;
52-
53-
let client = aws_sdk_kms::Client::new(&aws_main_config);
54-
55-
let key_id = config
56-
.signer_kms_id
57-
.clone()
58-
.expect("'use_kms' is set to true but 'signer_kms_id' is missing");
59-
60-
kms_signer = Some(
61-
AwsSigner::new(client, key_id, Some(chain_id))
62-
.await
63-
.unwrap(),
64-
);
65-
} else {
66-
let private_key_signer_parsed: PrivateKeySigner = config
67-
.private_key
68-
.parse()
69-
.with_context(|| "Failed to parse PRIVATE_KEY")?;
70-
private_key_signer = Some(private_key_signer_parsed);
71-
}
72-
32+
impl<'a> IpfsManager<'a> {
33+
pub async fn build(config: &Config, owen_wallet: &'a OwenWallet) -> anyhow::Result<Self> {
7334
Ok(Self {
7435
local_ipfs: config.local_ipfs.clone(),
7536
ipfs_api_base_url: config.ipfs_api_base_url.clone(),
7637
storacha_bridge_url: config.storacha_bridge_url.clone(),
77-
use_kms: config.use_kms,
78-
kms_signer,
79-
private_key_signer,
38+
owen_wallet,
8039
})
8140
}
8241

@@ -121,20 +80,8 @@ impl IpfsManager {
12180
}
12281

12382
async fn sign_authorization_header(&self) -> anyhow::Result<String> {
124-
let signature;
125-
if self.use_kms {
126-
let kms_signer = self
127-
.kms_signer
128-
.clone()
129-
.expect("IpfsManager: Failed to get kms_signer");
130-
signature = kms_signer.sign_message(constants::CLIENT).await?;
131-
} else {
132-
let private_key_signer = self
133-
.private_key_signer
134-
.clone()
135-
.expect("IpfsManager: Failed to get private_key_signer");
136-
signature = private_key_signer.sign_message(constants::CLIENT).await?;
137-
}
83+
let signature = self.owen_wallet.sign_message(constants::CLIENT).await?;
84+
13885
let authorization = format!("{}::0x{}", "OWEN", hex::encode(signature.as_bytes()));
13986
Ok(authorization)
14087
}

owen/src/lib.rs

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ mod image_processor;
88
mod ipfs;
99
pub mod logger;
1010
pub mod output_generator;
11+
mod wallet;
1112
use alloy::primitives::Address;
1213
use blob::BlobTransactionData;
1314
use contracts::ContractsManager;
1415
use ddex_parser::ParserError;
1516
pub use log;
16-
use log_macros::log_error;
17+
use log_macros::{format_error, log_error};
1718
use output_generator::MessageDirProcessingContext;
1819
use sentry::User;
1920
use serde_json::json;
2021
use std::env;
2122
use std::str::FromStr;
2223

24+
use crate::wallet::OwenWallet;
25+
2326
#[cfg(any(feature = "aws-integration", feature = "local-s3"))]
2427
pub mod s3_message_storage;
2528

@@ -41,7 +44,7 @@ pub enum IpfsInterface {
4144
#[derive(Debug, serde::Serialize, Clone)]
4245
pub struct Config {
4346
pub rpc_url: String,
44-
pub private_key: String,
47+
pub private_key: Option<String>,
4548
pub folder_path: String,
4649
pub local_ipfs: bool,
4750
pub output_files_dir: String,
@@ -77,7 +80,6 @@ impl Config {
7780
.unwrap_or_else(|| Config::get_env_var("INPUT_FILES_DIR").to_string());
7881

7982
let rpc_url = Config::get_env_var("RPC_URL");
80-
let private_key = Config::get_env_var("PRIVATE_KEY");
8183
let local_ipfs = matches!(
8284
std::env::var("LOCAL_IPFS")
8385
.unwrap_or_else(|_| "false".to_string())
@@ -110,26 +112,28 @@ impl Config {
110112
let ipfs_api_base_url = env::var("IPFS_API_BASE_URL")
111113
.unwrap_or_else(|_| constants::IPFS_API_BASE_URL.to_string());
112114

115+
let mut signer_kms_id = None;
116+
let mut private_key = None;
113117
let use_kms = matches!(
114118
std::env::var("USE_KMS")
115119
.unwrap_or_else(|_| "false".to_string())
116120
.as_str(),
117121
"1" | "true"
118122
);
119123

124+
if use_kms {
125+
signer_kms_id = Some(Config::get_env_var("SIGNER_KMS_ID"));
126+
} else {
127+
private_key = Some(Config::get_env_var("PRIVATE_KEY"));
128+
}
129+
120130
let use_batch_sender = matches!(
121131
std::env::var("USE_BATCH_SENDER")
122132
.unwrap_or_else(|_| "false".to_string())
123133
.as_str(),
124134
"1" | "true"
125135
);
126136

127-
let mut signer_kms_id: Option<String> = None;
128-
129-
if use_kms {
130-
signer_kms_id = Some(Config::get_env_var("SIGNER_KMS_ID"));
131-
}
132-
133137
let config = Config {
134138
rpc_url,
135139
private_key,
@@ -149,13 +153,39 @@ impl Config {
149153

150154
config
151155
}
156+
157+
fn try_private_key(&self) -> anyhow::Result<&String> {
158+
if self.use_kms == false {
159+
self.private_key
160+
.as_ref()
161+
.ok_or_else(|| format_error!("Missing private_key"))
162+
} else {
163+
return Err(format_error!(
164+
"private_key not available with USE_KMS=true flag"
165+
));
166+
}
167+
}
168+
169+
fn try_signer_kms_id(&self) -> anyhow::Result<&String> {
170+
if self.use_kms == true {
171+
self.signer_kms_id
172+
.as_ref()
173+
.ok_or_else(|| format_error!("Missing signer_kms_id"))
174+
} else {
175+
return Err(format_error!(
176+
"signer_kms_id not available without USE_KMS=true flag"
177+
));
178+
}
179+
}
152180
}
153181

154182
pub async fn run(config: &Config) -> anyhow::Result<Vec<MessageDirProcessingContext>> {
155-
let contracts_manager = ContractsManager::build(&config).await?;
183+
let owen_wallet = OwenWallet::build(&config).await?;
184+
let contracts_manager = ContractsManager::build(&config, &owen_wallet).await?;
156185
contracts_manager.check_image_compatibility().await?;
157186

158-
let message_dir_processing_log = output_generator::create_output_files(&config).await?;
187+
let message_dir_processing_log =
188+
output_generator::create_output_files(&config, &owen_wallet).await?;
159189

160190
let blob_transaction_data = BlobTransactionData::build(&config.output_files_dir)?;
161191

@@ -185,10 +215,6 @@ pub async fn run_with_sentry(config: &Config) -> anyhow::Result<Vec<MessageDirPr
185215
username: Some(config.username.to_owned()),
186216
..Default::default()
187217
}));
188-
189-
let mut cloned_config = config.clone();
190-
cloned_config.private_key = "***".to_string();
191-
scope.set_extra("config", json!(cloned_config));
192218
});
193219

194220
let message_dir_processing_context = run(&config).await.map_err(|e| {

owen/src/output_generator.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::image_processor::optimize_image;
22
use crate::ipfs::IpfsManager;
33
use crate::logger::report_validation_error;
4+
use crate::wallet::OwenWallet;
45
use crate::Config;
56
use anyhow::Context;
67
use blob_codec::BlobEstimator;
@@ -25,7 +26,7 @@ pub struct MessageDirProcessingContext {
2526
async fn pin_and_write_cid(
2627
message_dir_processing_context: &mut MessageDirProcessingContext,
2728
new_release_message: &mut NewReleaseMessage,
28-
ipfs_manager: &IpfsManager,
29+
ipfs_manager: &IpfsManager<'_>,
2930
) -> anyhow::Result<()> {
3031
for image_resource in &mut new_release_message.resource_list.images {
3132
if let Some(technical_details) = image_resource.technical_details.get_mut(0) {
@@ -57,7 +58,7 @@ fn is_xml_file_empty(file_path: &Path) -> anyhow::Result<bool> {
5758

5859
async fn process_message_folder(
5960
message_folder_path: PathBuf,
60-
ipfs_manager: &IpfsManager,
61+
ipfs_manager: &IpfsManager<'_>,
6162
config: &Config,
6263
) -> anyhow::Result<MessageDirProcessingContext> {
6364
let mut message_dir_processing_context = MessageDirProcessingContext {
@@ -197,6 +198,7 @@ async fn process_message_folder(
197198

198199
pub async fn create_output_files(
199200
config: &Config,
201+
owen_wallet: &OwenWallet,
200202
) -> anyhow::Result<Vec<MessageDirProcessingContext>> {
201203
log_info!("Creating output files");
202204
let mut result: Vec<MessageDirProcessingContext> = Vec::new();
@@ -225,7 +227,7 @@ pub async fn create_output_files(
225227
)
226228
})?;
227229

228-
let ipfs_manager = IpfsManager::build(config).await?;
230+
let ipfs_manager = IpfsManager::build(config, owen_wallet).await?;
229231

230232
for message_folder in message_folders {
231233
empty_root_folder = false;
@@ -308,7 +310,7 @@ mod tests {
308310
async fn create_output_files_with_cids() -> anyhow::Result<()> {
309311
let config = Config {
310312
rpc_url: String::new(),
311-
private_key: String::new(),
313+
private_key: None,
312314
folder_path: String::from_str("./tests").unwrap(),
313315
local_ipfs: true,
314316
output_files_dir: "./output_files".to_string(),
@@ -322,7 +324,8 @@ mod tests {
322324
signer_kms_id: None,
323325
use_batch_sender: false,
324326
};
325-
let processing_context_vec = create_output_files(&config).await?;
327+
let owen_wallet = OwenWallet::build(&config).await?;
328+
let processing_context_vec = create_output_files(&config, &owen_wallet).await?;
326329

327330
let processed_count = processing_context_vec.len();
328331

@@ -344,7 +347,7 @@ mod tests {
344347
async fn error_when_empty_directory() {
345348
let config = Config {
346349
rpc_url: String::new(),
347-
private_key: String::new(),
350+
private_key: None,
348351
folder_path: String::from_str("./tests/empty_dir").unwrap(),
349352
local_ipfs: true,
350353
output_files_dir: "./output_files".to_string(),
@@ -359,8 +362,8 @@ mod tests {
359362
use_batch_sender: false,
360363
};
361364
fs::create_dir_all(&config.folder_path).unwrap();
362-
363-
create_output_files(&config).await.unwrap();
365+
let owen_wallet = OwenWallet::build(&config).await.unwrap();
366+
create_output_files(&config, &owen_wallet).await.unwrap();
364367
fs::remove_dir_all(&config.folder_path).unwrap();
365368
()
366369
}

0 commit comments

Comments
 (0)