use alloy_sol_types::sol;
sol!(
#[derive(Debug)]
#[allow(missing_docs)]
#[sol(rpc)]
MidribFactory,
"artifacts/MidribFactory.json"
);
pub mod config_pb {
pub use crate::commands::config::config_pb::*;
}
use config_pb::config_service_client::ConfigServiceClient;
use config_pb::{
DeleteChainRequest, DeleteChainResponse, DeleteMarketRequest, DeleteMarketResponse,
DeleteTokenRequest, DeleteTokenResponse, DeleteTradeContractRequest,
DeleteTradeContractResponse, DeployContractRequest, DeployContractResponse, Empty,
GetDeployCalldataRequest, GetDeployCalldataResponse, SetChainRequest, SetChainResponse,
SetMarketRequest, SetMarketResponse, SetTokenRequest, SetTokenResponse,
SetTradeContractRequest, SetTradeContractResponse, UpdateAdminRequest, UpdateAdminResponse,
VersionInfo,
};
use eyre::Result;
use tonic::metadata::MetadataValue;
use tonic::Request;
use crate::grpc::create_channel;
fn authenticated_request<T>(jwt: &str, payload: T) -> Request<T> {
let mut request = Request::new(payload);
let bearer = format!("Bearer {}", jwt);
if let Ok(value) = bearer.parse::<MetadataValue<_>>() {
request.metadata_mut().insert("authorization", value);
}
request
}
pub async fn update_admin(
url: String,
jwt: String,
admin_address: String,
) -> Result<UpdateAdminResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(&jwt, UpdateAdminRequest { admin_address });
let response = client.update_admin(request).await?;
Ok(response.into_inner())
}
pub async fn get_deploy_calldata(
url: String,
jwt: String,
chain_network: String,
fee_bps: u32,
) -> Result<GetDeployCalldataResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
GetDeployCalldataRequest {
chain_network,
fee_bps,
},
);
let response = client.get_deploy_calldata(request).await?;
Ok(response.into_inner())
}
pub async fn deploy_contract(
url: String,
jwt: String,
chain_network: String,
tx_hash: String,
) -> Result<DeployContractResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
DeployContractRequest {
chain_network,
tx_hash,
},
);
let response = client.deploy_contract(request).await?;
Ok(response.into_inner())
}
#[derive(Debug, Clone)]
pub struct CreateInstanceParams {
pub factory_address: String,
pub calldata: Vec<u8>,
pub rpc_url: String,
pub chain_id: u64,
pub privkey: String,
}
pub async fn build_create_instance_tx(params: CreateInstanceParams) -> Result<Vec<u8>> {
use alloy::consensus::{SignableTransaction, TxEip1559, TxEnvelope};
use alloy::network::{EthereumWallet, TransactionBuilder, TxSigner};
use alloy::primitives::{Address, Bytes, TxKind, U256};
use alloy::providers::{Provider, ProviderBuilder};
use alloy::rpc::types::TransactionRequest;
use alloy::signers::local::PrivateKeySigner;
use url::Url;
let factory_addr: Address = params.factory_address.parse()?;
let signer: PrivateKeySigner = params.privkey.parse()?;
let wallet = EthereumWallet::new(signer.clone());
let from_address = signer.address();
let rpc_url = Url::parse(¶ms.rpc_url)?;
let provider = ProviderBuilder::new()
.with_chain_id(params.chain_id)
.wallet(wallet)
.connect_http(rpc_url);
let nonce = provider.get_transaction_count(from_address).await?;
let calldata_bytes = Bytes::from(params.calldata.clone());
let tx_request = TransactionRequest::default()
.with_from(from_address)
.with_to(factory_addr)
.with_input(calldata_bytes.clone());
let gas_estimate = provider.estimate_gas(tx_request).await?;
let fee_estimate = provider.estimate_eip1559_fees().await?;
let mut tx = TxEip1559 {
chain_id: params.chain_id,
nonce,
gas_limit: gas_estimate + (gas_estimate / 10), max_fee_per_gas: fee_estimate.max_fee_per_gas,
max_priority_fee_per_gas: fee_estimate.max_priority_fee_per_gas,
to: TxKind::Call(factory_addr),
value: U256::ZERO,
access_list: Default::default(),
input: calldata_bytes,
};
let signature = signer.sign_transaction(&mut tx).await?;
let signed_tx = TxEnvelope::Eip1559(tx.into_signed(signature));
use alloy::eips::eip2718::Encodable2718;
let mut encoded = Vec::new();
signed_tx.encode_2718(&mut encoded);
Ok(encoded)
}
pub async fn broadcast_transaction(rpc_url: String, signed_tx: Vec<u8>) -> Result<String> {
use alloy::providers::{Provider, ProviderBuilder};
use url::Url;
let rpc_url_parsed = Url::parse(&rpc_url)?;
let provider = ProviderBuilder::new().connect_http(rpc_url_parsed);
let pending_tx = provider
.send_raw_transaction(&signed_tx)
.await
.map_err(|e| eyre::eyre!("Failed to broadcast transaction: {}", e))?;
let tx_hash = pending_tx.tx_hash();
Ok(format!("{:?}", tx_hash))
}
pub async fn set_trade_contract(
url: String,
jwt: String,
address: String,
chain_network: String,
) -> Result<SetTradeContractResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
SetTradeContractRequest {
address,
chain_network,
},
);
let response = client.set_trade_contract(request).await?;
Ok(response.into_inner())
}
pub async fn delete_trade_contract(
url: String,
jwt: String,
chain_network: String,
) -> Result<DeleteTradeContractResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(&jwt, DeleteTradeContractRequest { chain_network });
let response = client.delete_trade_contract(request).await?;
Ok(response.into_inner())
}
pub async fn set_chain(url: String, jwt: String, chain: Chain) -> Result<SetChainResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(&jwt, SetChainRequest { chain: Some(chain) });
let response = client.set_chain(request).await?;
Ok(response.into_inner())
}
pub async fn delete_chain(
url: String,
jwt: String,
chain_network: String,
) -> Result<DeleteChainResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(&jwt, DeleteChainRequest { chain_network });
let response = client.delete_chain(request).await?;
Ok(response.into_inner())
}
pub async fn set_token(
url: String,
jwt: String,
chain_network: String,
token: Token,
) -> Result<SetTokenResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
SetTokenRequest {
chain_network,
token: Some(token),
},
);
let response = client.set_token(request).await?;
Ok(response.into_inner())
}
pub async fn delete_token(
url: String,
jwt: String,
chain_network: String,
token_symbol: String,
) -> Result<DeleteTokenResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
DeleteTokenRequest {
chain_network,
token_symbol,
},
);
let response = client.delete_token(request).await?;
Ok(response.into_inner())
}
#[derive(Debug, Clone)]
pub struct SetMarketParams {
pub base_chain_network: String,
pub quote_chain_network: String,
pub base_chain_token_symbol: String,
pub quote_chain_token_symbol: String,
pub base_chain_token_address: String,
pub quote_chain_token_address: String,
pub base_chain_token_decimals: i32,
pub quote_chain_token_decimals: i32,
pub pair_decimals: i32,
}
pub async fn set_market(
url: String,
jwt: String,
params: SetMarketParams,
) -> Result<SetMarketResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(
&jwt,
SetMarketRequest {
base_chain_network: params.base_chain_network,
quote_chain_network: params.quote_chain_network,
base_chain_token_symbol: params.base_chain_token_symbol,
quote_chain_token_symbol: params.quote_chain_token_symbol,
base_chain_token_address: params.base_chain_token_address,
quote_chain_token_address: params.quote_chain_token_address,
base_chain_token_decimals: params.base_chain_token_decimals,
quote_chain_token_decimals: params.quote_chain_token_decimals,
pair_decimals: params.pair_decimals,
},
);
let response = client.set_market(request).await?;
Ok(response.into_inner())
}
pub async fn delete_market(
url: String,
jwt: String,
market_id: String,
) -> Result<DeleteMarketResponse> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = authenticated_request(&jwt, DeleteMarketRequest { market_id });
let response = client.delete_market(request).await?;
Ok(response.into_inner())
}
pub async fn get_version(url: String) -> Result<VersionInfo> {
let channel = create_channel(&url).await?;
let mut client = ConfigServiceClient::new(channel);
let request = Request::new(Empty {});
let response = client.get_version(request).await?;
Ok(response.into_inner())
}
pub use config_pb::Chain;
pub use config_pb::Token;
pub use config_pb::TradeContract;