Skip to content

Commit

Permalink
fix: fixing nonce for the initial tx and gas price
Browse files Browse the repository at this point in the history
  • Loading branch information
geekbrother committed Oct 31, 2024
1 parent 0541f4b commit d7979da
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 44 deletions.
9 changes: 8 additions & 1 deletion integration/chain_orchestrator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ describe('Chain abstraction orchestrator', () => {
const amount_to_send = 3_000_000
// How much needs to be topped up
const amount_to_topup = amount_to_send - usdc_funds_on_optimism
// Default gas esimation is default with 4x increase
const gas_estimate = "0xa69ac";

const receiver_address = "0x739ff389c8eBd9339E69611d46Eec6212179BB67";
const chain_id_optimism = "eip155:10";
Expand Down Expand Up @@ -188,14 +190,19 @@ describe('Chain abstraction orchestrator', () => {
// First transaction expected to be the approval transaction
const approvalTransaction = data.transactions[0]
expect(approvalTransaction.chainId).toBe(chain_id_base)
expect(approvalTransaction.nonce).not.toBe("0x00")
expect(approvalTransaction.gas).toBe(gas_estimate)
const decodedData = erc20Interface.decodeFunctionData('approve', approvalTransaction.data);
expect(decodedData.amount.toString()).toBe(amount_to_topup.toString())


// Second transaction expected to be the bridging to the Base
expect(data.transactions[1].chainId).toBe(chain_id_base)
expect(data.transactions[1].nonce).not.toBe("0x00")
expect(data.transactions[1].gas).toBe(gas_estimate)

// Last transaction expected to be the initial one
expect(data.transactions[2]).toStrictEqual(transactionObj.transaction)
expect(data.transactions[2].data).toBe(transactionObj.transaction.data)

// Set the Orchestration ID for the next test
orchestration_id = data.orchestrationId;
Expand Down
52 changes: 40 additions & 12 deletions src/handlers/chain_agnostic/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use {
storage::irn::OperationType,
utils::crypto::{
convert_alloy_address_to_h160, decode_erc20_function_type, decode_erc20_transfer_data,
get_balance, get_erc20_balance, Erc20FunctionType,
get_balance, get_erc20_balance, get_gas_price, get_nonce, Erc20FunctionType,
},
},
alloy::primitives::{Address, U256},
Expand Down Expand Up @@ -133,7 +133,7 @@ async fn handler_internal(
&request_payload.transaction.chain_id,
convert_alloy_address_to_h160(to_address),
convert_alloy_address_to_h160(from_address),
&query_params.project_id,
&query_params.project_id.clone(),
MessageSource::ChainAgnosticCheck,
)
.await?;
Expand All @@ -144,9 +144,12 @@ async fn handler_internal(
let erc20_topup_value = erc20_transfer_value - erc20_balance;

// Check for possible bridging by iterating over supported assets
if let Some((bridge_chain_id, bridge_contract)) =
check_bridging_for_erc20_transfer(query_params.project_id, erc20_topup_value, from_address)
.await?
if let Some((bridge_chain_id, bridge_contract)) = check_bridging_for_erc20_transfer(
query_params.project_id.clone(),
erc20_topup_value,
from_address,
)
.await?
{
// Skip bridging if that's the same chainId and contract address
if bridge_chain_id == request_payload.transaction.chain_id && bridge_contract == to_address
Expand All @@ -168,6 +171,26 @@ async fn handler_internal(
)
.await?;

// Getting the current nonce for the address
let mut current_nonce = get_nonce(
&request_payload.transaction.chain_id.clone(),
from_address,
&query_params.project_id.clone(),
MessageSource::ChainAgnosticCheck,
)
.await?;

// Getting the current gas price
let gas_price = get_gas_price(
&bridge_chain_id.clone(),
&query_params.project_id.clone(),
MessageSource::ChainAgnosticCheck,
)
.await?;
// Default gas estimate
// Using default with 4x increase: '0x029a6b * 4 = 0x52d9ac'
let gas = 0x029a6b * 0x4;

// Build bridging transaction
let mut routes = Vec::new();
let best_route = quotes.first().ok_or(RpcError::NoBridgingRoutesAvailable)?;
Expand Down Expand Up @@ -208,17 +231,18 @@ async fn handler_internal(
from: approval_tx.from,
to: approval_tx.to,
value: "0x00".to_string(),
gas_price: request_payload.transaction.gas_price.clone(),
gas: request_payload.transaction.gas.clone(),
gas_price: format!("0x{:x}", gas_price),
gas: format!("0x{:x}", gas),
data: approval_tx.data,
nonce: request_payload.transaction.nonce.clone(),
nonce: format!("0x{:x}", current_nonce),
max_fee_per_gas: request_payload.transaction.max_fee_per_gas.clone(),
max_priority_fee_per_gas: request_payload
.transaction
.max_priority_fee_per_gas
.clone(),
chain_id: bridge_chain_id.clone(),
});
current_nonce += 1;
}
}

Expand All @@ -227,17 +251,21 @@ async fn handler_internal(
from: from_address,
to: bridge_tx.tx_target,
value: bridge_tx.value,
gas_price: request_payload.transaction.gas_price.clone(),
gas: request_payload.transaction.gas.clone(),
gas_price: format!("0x{:x}", gas_price),
gas: format!("0x{:x}", gas),
data: bridge_tx.tx_data,
nonce: request_payload.transaction.nonce.clone(),
nonce: format!("0x{:x}", current_nonce),
max_fee_per_gas: request_payload.transaction.max_fee_per_gas.clone(),
max_priority_fee_per_gas: request_payload.transaction.max_priority_fee_per_gas.clone(),
chain_id: format!("eip155:{}", bridge_tx.chain_id),
});
current_nonce += 1;

// Push initial transaction last after all bridging transactions
routes.push(request_payload.transaction.clone());
routes.push(Transaction {
nonce: format!("0x{:x}", current_nonce),
..request_payload.transaction.clone()
});
let orchestration_id = Uuid::new_v4().to_string();

// Save the bridging transaction to the IRN
Expand Down
99 changes: 68 additions & 31 deletions src/utils/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use {
crate::{analytics::MessageSource, error::RpcError},
alloy::{
network::Ethereum,
primitives::{Address, U256 as AlloyU256},
providers::{Provider as AlloyProvider, ReqwestProvider},
rpc::json_rpc::Id,
sol,
sol_types::SolCall,
Expand Down Expand Up @@ -336,6 +338,25 @@ pub async fn verify_message_signature(
.await
}

/// Construct RPC calls url
fn get_rpc_url(
chain_id: &str,
rpc_project_id: &str,
source: MessageSource,
) -> Result<Url, CryptoUitlsError> {
let mut provider = Url::parse("https://rpc.walletconnect.com/v1").map_err(|e| {
CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e))
})?;
provider.query_pairs_mut().append_pair("chainId", chain_id);
provider
.query_pairs_mut()
.append_pair("projectId", rpc_project_id);
provider
.query_pairs_mut()
.append_pair("source", &source.to_string());
Ok(provider)
}

/// Veryfy message signature for eip6492 contract
#[tracing::instrument(level = "debug")]
pub async fn verify_eip6492_message_signature(
Expand All @@ -350,23 +371,7 @@ pub async fn verify_eip6492_message_signature(
let address = Address::parse_checksummed(address, None)
.map_err(|_| CryptoUitlsError::AddressChecksum(address.into()))?;

let mut provider = Url::parse("https://rpc.walletconnect.com/v1")
.map_err(|e| {
CryptoUitlsError::RpcUrlParseError(format!(
"Failed to parse RPC url:
{}",
e
))
})
.unwrap();
provider.query_pairs_mut().append_pair("chainId", chain_id);
provider
.query_pairs_mut()
.append_pair("projectId", rpc_project_id);
provider
.query_pairs_mut()
.append_pair("source", &source.to_string());

let provider = get_rpc_url(chain_id, rpc_project_id, source)?;
let hexed_signature = hex::decode(&signature[2..])
.map_err(|e| CryptoUitlsError::SignatureFormat(format!("Wrong signature format: {}", e)))?;

Expand Down Expand Up @@ -446,11 +451,11 @@ pub async fn get_erc20_contract_balance(
]"#,
);

let provider = Provider::<Http>::try_from(format!(
"https://rpc.walletconnect.com/v1?chainId={}&projectId={}&source={}",
chain_id, rpc_project_id, source
))
.map_err(|e| CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e)))?;
let provider =
Provider::<Http>::try_from(get_rpc_url(chain_id, rpc_project_id, source)?.as_str())
.map_err(|e| {
CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e))
})?;
let provider = Arc::new(provider);

let contract = ERC20Contract::new(contract, provider);
Expand All @@ -471,11 +476,11 @@ pub async fn get_balance(
rpc_project_id: &str,
source: MessageSource,
) -> Result<U256, CryptoUitlsError> {
let provider = Provider::<Http>::try_from(format!(
"https://rpc.walletconnect.com/v1?chainId={}&projectId={}&source={}",
chain_id, rpc_project_id, source
))
.map_err(|e| CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e)))?;
let provider =
Provider::<Http>::try_from(get_rpc_url(chain_id, rpc_project_id, source)?.as_str())
.map_err(|e| {
CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e))
})?;
let provider = Arc::new(provider);

let balance = provider
Expand All @@ -485,6 +490,39 @@ pub async fn get_balance(
Ok(balance)
}

/// Get the gas price
#[tracing::instrument(level = "debug")]
pub async fn get_gas_price(
chain_id: &str,
rpc_project_id: &str,
source: MessageSource,
) -> Result<u128, CryptoUitlsError> {
let provider =
ReqwestProvider::<Ethereum>::new_http(get_rpc_url(chain_id, rpc_project_id, source)?);
let gas_price = provider
.get_gas_price()
.await
.map_err(|e| CryptoUitlsError::ProviderError(format!("{}", e)))?;
Ok(gas_price)
}

/// Get the nonce
#[tracing::instrument(level = "debug")]
pub async fn get_nonce(
chain_id: &str,
wallet: Address,
rpc_project_id: &str,
source: MessageSource,
) -> Result<u64, CryptoUitlsError> {
let provider =
ReqwestProvider::<Ethereum>::new_http(get_rpc_url(chain_id, rpc_project_id, source)?);
let nonce = provider
.get_transaction_count(wallet)
.await
.map_err(|e| CryptoUitlsError::ProviderError(format!("{}", e)))?;
Ok(nonce)
}

/// Call entry point v07 getUserOpHash contract and get the userOperation hash
#[tracing::instrument(level = "debug")]
pub async fn call_get_user_op_hash(
Expand All @@ -501,10 +539,9 @@ pub async fn call_get_user_op_hash(
]"#,
);

let provider = Provider::<Http>::try_from(format!(
"https://rpc.walletconnect.com/v1?chainId={}&projectId={}",
chain_id, rpc_project_id
))
let provider = Provider::<Http>::try_from(
get_rpc_url(chain_id, rpc_project_id, MessageSource::ChainAgnosticCheck)?.as_str(),
)
.map_err(|e| CryptoUitlsError::RpcUrlParseError(format!("Failed to parse RPC url: {}", e)))?;
let provider = Arc::new(provider);

Expand Down

0 comments on commit d7979da

Please sign in to comment.