Skip to content

Commit

Permalink
arbitrum-client: fetch_public_shares_from_tx
Browse files Browse the repository at this point in the history
  • Loading branch information
akirillo committed Nov 21, 2023
1 parent ca25681 commit 7e6e503
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 9 deletions.
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions arbitrum-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ark-bn254 = "0.4.0"
ark-ec = "0.4.0"
ark-ff = "0.4.0"
alloy-primitives = "0.3.1"
alloy-sol-types = "0.3.1"
num-bigint = { workspace = true }
lazy_static = "1.4.0"

Expand Down
7 changes: 7 additions & 0 deletions arbitrum-client/src/abi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Solidity ABI definitions of smart contracts, events, and other on-chain
//! data structures used by the Arbitrum client.
use alloy_sol_types::sol;
use ethers::contract::abigen;

abigen!(
Expand All @@ -23,3 +24,9 @@ abigen!(
event NodeChanged(uint8 indexed height, uint128 indexed index, bytes indexed new_value_hash, bytes new_value)
]"#
);

sol! {
function newWallet(bytes memory wallet_blinder_share, bytes memory proof, bytes memory valid_wallet_create_statement_bytes) external;
function updateWallet(bytes memory wallet_blinder_share, bytes memory proof, bytes memory valid_wallet_update_statement_bytes, bytes memory public_inputs_signature) external;
function processMatchSettle(bytes memory party_0_match_payload, bytes memory party_0_valid_commitments_proof, bytes memory party_0_valid_reblind_proof, bytes memory party_1_match_payload, bytes memory party_1_valid_commitments_proof, bytes memory party_1_valid_reblind_proof, bytes memory valid_match_settle_proof, bytes memory valid_match_settle_statement_bytes,) external;
}
4 changes: 2 additions & 2 deletions arbitrum-client/src/client/contract_interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use constants::Scalar;

use crate::{
errors::ArbitrumClientError,
helpers::{deserialize_retdata, serialize_calldata},
helpers::{deserialize_calldata, serialize_calldata},
serde_def_types::SerdeScalarField,
types::{
MatchPayload, Proof, ValidMatchSettleStatement, ValidWalletCreateStatement,
Expand All @@ -33,7 +33,7 @@ impl ArbitrumClient {
.await
.map_err(|e| ArbitrumClientError::ContractInteraction(e.to_string()))?;

let merkle_root = deserialize_retdata::<SerdeScalarField>(&merkle_root_bytes)?.0;
let merkle_root = deserialize_calldata::<SerdeScalarField>(&merkle_root_bytes)?.0;

Ok(Scalar::new(merkle_root))
}
Expand Down
49 changes: 46 additions & 3 deletions arbitrum-client/src/client/event_indexing.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
//! Defines `ArbitrumClient` helpers that allow for indexing events
//! emitted by the darkpool contract
use alloy_sol_types::SolCall;
use circuit_types::{traits::BaseType, SizedWalletShare};
use common::types::merkle::{MerkleAuthenticationPath, MerkleTreeCoords};
use constants::{Scalar, MERKLE_HEIGHT};
use ethers::types::TxHash;
use num_bigint::BigUint;

use crate::{
abi::{NodeChangedFilter, WalletUpdatedFilter},
constants::DEFAULT_AUTHENTICATION_PATH,
abi::{
newWalletCall, processMatchSettleCall, updateWalletCall, NodeChangedFilter,
WalletUpdatedFilter,
},
constants::{DEFAULT_AUTHENTICATION_PATH, SELECTOR_LEN},
errors::ArbitrumClientError,
helpers::keccak_hash_scalar,
helpers::{
deserialize_calldata, keccak_hash_scalar, parse_shares_from_new_wallet,
parse_shares_from_process_match_settle, parse_shares_from_update_wallet,
},
serde_def_types::SerdeScalarField,
types::{
MatchPayload, ValidMatchSettleStatement, ValidWalletCreateStatement,
ValidWalletUpdateStatement,
},
};

use super::ArbitrumClient;
Expand Down Expand Up @@ -101,4 +113,35 @@ impl ArbitrumClient {
.map(|event| event.index)
.ok_or(ArbitrumClientError::CommitmentNotFound)
}

/// Fetch and parse the public secret shares from the calldata of the given
/// transaction
///
/// In the case that the referenced transaction is a `process_match_settle`,
/// we disambiguate between the two parties by adding the public blinder of
/// the party's shares the caller intends to fetch
// TODO: Add support for nested calls
pub async fn fetch_public_shares_from_tx(
&self,
public_blinder_share: Scalar,
tx_hash: TxHash,
) -> Result<SizedWalletShare, ArbitrumClientError> {
let tx = self
.darkpool_contract
.client()
.get_transaction(tx_hash)
.await
.map_err(|e| ArbitrumClientError::TxNotFound(e.to_string()))?;

let calldata: Vec<u8> = tx.input.into();
let selector = &calldata[..SELECTOR_LEN];
match selector {
&<newWalletCall as SolCall>::SELECTOR => parse_shares_from_new_wallet(&calldata),
&<updateWalletCall as SolCall>::SELECTOR => parse_shares_from_update_wallet(&calldata),
&<processMatchSettleCall as SolCall>::SELECTOR => {
parse_shares_from_process_match_settle(&calldata)
},
_ => return Err(ArbitrumClientError::InvalidSelector),
}
}
}
3 changes: 3 additions & 0 deletions arbitrum-client/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub const EMPTY_LEAF_VALUE: Scalar = Scalar(Fp(
PhantomData,
));

/// The number of bytes in a Solidity function selector
pub const SELECTOR_LEN: usize = 4;

lazy_static! {
// ------------------------
// | Merkle Tree Metadata |
Expand Down
9 changes: 9 additions & 0 deletions arbitrum-client/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ pub enum ArbitrumClientError {
EventQuerying(String),
/// Error thrown when a commitment can't be found in the Merkle tree
CommitmentNotFound,
/// Error thrown when a transaction can't be found
TxNotFound(String),
/// Error thrown when a transaction's selector doesn't match
/// one of the supported ones
/// (`newWallet`, `updateWallet`, `processMatchSettle`)
InvalidSelector,
/// Error thrown when a target public blinder share was not found
/// in a given transaction
BlinderNotFound,
}

impl Display for ArbitrumClientError {
Expand Down
77 changes: 73 additions & 4 deletions arbitrum-client/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
//! Various helpers for Arbitrum client execution
use alloy_sol_types::SolCall;
use circuit_types::{traits::BaseType, SizedWalletShare};
use constants::Scalar;
use ethers::{
types::{Bytes, H256},
utils::keccak256,
};
use serde::{Deserialize, Serialize};

use crate::{errors::ArbitrumClientError, serde_def_types::SerdeScalarField};
use crate::{
abi::{newWalletCall, processMatchSettleCall, updateWalletCall},
errors::ArbitrumClientError,
serde_def_types::SerdeScalarField,
types::{
MatchPayload, ValidMatchSettleStatement, ValidWalletCreateStatement,
ValidWalletUpdateStatement,
},
};

/// Serializes a calldata element for a contract call
pub fn serialize_calldata<T: Serialize>(data: &T) -> Result<Bytes, ArbitrumClientError> {
Expand All @@ -17,10 +27,10 @@ pub fn serialize_calldata<T: Serialize>(data: &T) -> Result<Bytes, ArbitrumClien
}

/// Deserializes a return value from a contract call
pub fn deserialize_retdata<'de, T: Deserialize<'de>>(
retdata: &'de Bytes,
pub fn deserialize_calldata<'de, T: Deserialize<'de>>(
calldata: &'de Bytes,
) -> Result<T, ArbitrumClientError> {
postcard::from_bytes(retdata).map_err(|e| ArbitrumClientError::Serde(e.to_string()))
postcard::from_bytes(calldata).map_err(|e| ArbitrumClientError::Serde(e.to_string()))
}

/// Computes the Keccak-256 hash of the serialization of a scalar,
Expand All @@ -29,3 +39,62 @@ pub fn keccak_hash_scalar(scalar: Scalar) -> Result<H256, ArbitrumClientError> {
let scalar_bytes = serialize_calldata(&SerdeScalarField(scalar.inner()))?;
Ok(keccak256(scalar_bytes).into())
}

pub fn parse_shares_from_new_wallet(
calldata: &[u8],
) -> Result<SizedWalletShare, ArbitrumClientError> {
let call = newWalletCall::decode(&calldata, true /* validate */)
.map_err(|e| ArbitrumClientError::Serde(e.to_string()))?;

let mut statement = deserialize_calldata::<ValidWalletCreateStatement>(
&call.valid_wallet_create_statement_bytes.into(),
)?;

Ok(SizedWalletShare::from_scalars(
&mut statement.public_wallet_shares,
))
}

pub fn parse_shares_from_update_wallet(
calldata: &[u8],
) -> Result<SizedWalletShare, ArbitrumClientError> {
let call = updateWalletCall::decode(&calldata, true /* validate */)
.map_err(|e| ArbitrumClientError::Serde(e.to_string()))?;

let mut statement = deserialize_calldata::<ValidWalletUpdateStatement>(
&call.valid_wallet_update_statement_bytes.into(),
)?;

Ok(SizedWalletShare::from_scalars(
&mut statement.new_public_shares,
))
}

pub fn parse_shares_from_process_match_settle(
calldata: &[u8],
) -> Result<SizedWalletShare, ArbitrumClientError> {
let call = processMatchSettleCall::decode(&calldata, true /* validate */)
.map_err(|e| ArbitrumClientError::Serde(e.to_string()))?;

let party_0_match_payload =
deserialize_calldata::<MatchPayload>(&call.party_0_match_payload.into())?;
let party_1_match_payload =
deserialize_calldata::<MatchPayload>(&call.party_1_match_payload.into())?;

let mut valid_match_settle_statement = deserialize_calldata::<ValidMatchSettleStatement>(
&call.valid_match_settle_statement_bytes.into(),
)?;

let target_share = public_blinder_share.inner();
if party_0_match_payload.wallet_blinder_share == target_share {
Ok(SizedWalletShare::from_scalars(
&mut valid_match_settle_statement.party0_modified_shares,
))
} else if party_1_match_payload.wallet_blinder_share == target_share {
Ok(SizedWalletShare::from_scalars(
&mut valid_match_settle_statement.party1_modified_shares,
))
} else {
Err(ArbitrumClientError::BlinderNotFound)
}
}

0 comments on commit 7e6e503

Please sign in to comment.