Skip to content

Commit

Permalink
Introduce CCIP urls in response (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
Antony1060 authored Dec 6, 2023
1 parent e7e9fc1 commit b293ccb
Show file tree
Hide file tree
Showing 21 changed files with 84 additions and 44 deletions.
12 changes: 6 additions & 6 deletions server/Cargo.lock

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

2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ utoipa = { version = "4.1.0", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "4.0.0", features = ["axum"] }
redis = { version = "0.23.0", features = ["connection-manager", "tokio-comp"] }
ethers-ccip-read = { git = "https://github.com/ensdomains/ethers-ccip-read", branch = "main" }
tower-http = { version = "0.4.1", features = ["cors", "tracing", "trace"] }
tower-http = { version = "0.4.4", features = ["cors", "tracing", "trace"] }
rand = "0.8.5"
chrono = "0.4.31"
ethers-contract = "2.0.9"
Expand Down
2 changes: 1 addition & 1 deletion shared/Cargo.lock

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

2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/binance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@ impl MulticoinDecoder for BinanceDecoder {
})
}
}

// TODO: tests
4 changes: 1 addition & 3 deletions shared/src/models/multicoin/decoding/bitcoin_cash.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{MulticoinDecoder, MulticoinDecoderError, p2pkh::P2PKHDecoder, p2sh::P2SHDecoder};
use super::{p2pkh::P2PKHDecoder, p2sh::P2SHDecoder, MulticoinDecoder, MulticoinDecoderError};

pub struct BitcoinCashDecoder {}

Expand All @@ -15,5 +15,3 @@ impl MulticoinDecoder for BitcoinCashDecoder {
Err(MulticoinDecoderError::InvalidStructure(String::new()))
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/dogecoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ impl MulticoinDecoder for DogecoinDecoder {
}
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/hedera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ impl MulticoinDecoder for HederaDecoder {
Ok(format!("{shard}.{realm}.{account}"))
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/litecoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,3 @@ impl MulticoinDecoder for LitecoinDecoder {
Err(MulticoinDecoderError::InvalidStructure(String::new()))
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/monacoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ impl MulticoinDecoder for MonacoinDecoder {
}
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/monero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@ impl MulticoinDecoder for MoneroDecoder {
Err(MulticoinDecoderError::NotSupported)
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/polkadot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,3 @@ impl MulticoinDecoder for PolkadotDecoder {
.into_string())
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/ripple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,3 @@ impl MulticoinDecoder for RippleDecoder {
.into_string())
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ impl MulticoinDecoder for SolanaDecoder {
Ok(bs58::encode(data).into_string())
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/stellar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,3 @@ impl MulticoinDecoder for StellarDecoder {
Ok(base32::encode(Alphabet::RFC4648 { padding: false }, full.as_slice()))
}
}

// TODO: tests
2 changes: 0 additions & 2 deletions shared/src/models/multicoin/decoding/tezos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,3 @@ impl MulticoinDecoder for TezosDecoder {
)
}
}

// TODO: tests
4 changes: 3 additions & 1 deletion shared/src/models/profile/from_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ impl Profile {
// ens CCIP unwrapper is limited to 50 sub-requests, i.e. per request
let calldata_chunks = calldata.chunks(50).collect::<Vec<_>>();

let (mut data, resolver) = resolve_universal(name, calldata_chunks[0], &rpc).await?;
let (mut data, resolver, ccip_urls) =
resolve_universal(name, calldata_chunks[0], &rpc).await?;

for &chunk in &calldata_chunks[1..] {
data = [data, resolve_universal(name, chunk, &rpc).await?.0].concat();
Expand Down Expand Up @@ -183,6 +184,7 @@ impl Profile {
chains,
fresh: chrono::offset::Utc::now().timestamp_millis(),
resolver: EIP55Address(resolver),
ccip_urls,
errors,
};

Expand Down
2 changes: 2 additions & 0 deletions shared/src/models/profile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct Profile {
pub fresh: i64,
// Resolver the information was fetched from
pub resolver: EIP55Address,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub ccip_urls: Vec<String>,
// Errors encountered while fetching & decoding
pub errors: BTreeMap<String, String>,
}
63 changes: 56 additions & 7 deletions shared/src/models/universal_resolver/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use std::vec;

use ethers::prelude::ProviderError::JsonRpcClientError;
use ethers::{
providers::{namehash, Http, Middleware, Provider},
providers::{namehash, Http, Provider},
types::{transaction::eip2718::TypedTransaction, Address, Bytes},
};
use ethers_ccip_read::{CCIPReadMiddleware, CCIPReadMiddlewareError};
use ethers_ccip_read::{CCIPReadMiddleware, CCIPReadMiddlewareError, CCIPRequest};
use ethers_contract::abigen;
use ethers_core::abi;
use ethers_core::abi::{ParamType, Token};
use lazy_static::lazy_static;

use crate::models::lookup::ENSLookup;
use crate::utils::dns::dns_encode;
use crate::utils::vec::dedup_ord;

use super::profile::error::ProfileError;

Expand All @@ -34,7 +38,7 @@ pub async fn resolve_universal(
name: &str,
data: &[Box<dyn ENSLookup + Send + Sync>],
provider: &CCIPReadMiddleware<Provider<Http>>,
) -> Result<(Vec<Vec<u8>>, Address), ProfileError> {
) -> Result<(Vec<Vec<u8>>, Address, Vec<String>), ProfileError> {
let name_hash = namehash(name);

// Prepare the variables
Expand All @@ -46,8 +50,7 @@ pub async fn resolve_universal(
.map(Token::Bytes)
.collect();

let encoded_data =
ethers_core::abi::encode(&[Token::Bytes(dns_encoded_node), Token::Array(wildcard_data)]);
let encoded_data = abi::encode(&[Token::Bytes(dns_encoded_node), Token::Array(wildcard_data)]);

// resolve(bytes node, bytes[] data)
let resolve_selector = hex_literal::hex!("206c74c9").to_vec();
Expand All @@ -63,8 +66,8 @@ pub async fn resolve_universal(
typed_transaction.set_data(Bytes::from(transaction_data));

// Call the transaction
let res = provider
.call(&typed_transaction, None)
let (res, ccip_requests) = provider
.call_ccip(&typed_transaction, None)
.await
.map_err(|err| {
let CCIPReadMiddlewareError::MiddlewareError(provider_error) = err else {
Expand Down Expand Up @@ -116,9 +119,55 @@ pub async fn resolve_universal(
.map(|t| t.into_bytes().expect("result[0] elements should be bytes"))
.collect(),
resolver,
dedup_ord(
&ccip_requests
.iter()
.flat_map(urls_from_request)
.collect::<Vec<_>>(),
),
))
}

fn urls_from_request(request: &CCIPRequest) -> Vec<String> {
if request.calldata.len() < 4 {
return Vec::new();
}

let decoded = abi::decode(
&[ParamType::Array(Box::new(ParamType::Tuple(vec![
ParamType::Address,
ParamType::Array(Box::new(ParamType::String)),
ParamType::Bytes,
])))],
&request.calldata[4..],
)
.unwrap_or_default();

let Some(Token::Array(requests)) = decoded.get(0) else {
return Vec::new();
};

requests
.iter()
.flat_map(|request| {
let Token::Tuple(request) = request else {
return Vec::new();
};

let Some(Token::Array(urls)) = request.get(1) else {
return Vec::new();
};

urls.iter()
.filter_map(|url| match url {
Token::String(url) => Some(url.clone()),
_ => None,
})
.collect::<Vec<_>>()
})
.collect()
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
5 changes: 3 additions & 2 deletions shared/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod sha256;
pub mod eip55;
pub mod dns;
pub mod eip55;
pub mod sha256;
pub mod vec;
11 changes: 11 additions & 0 deletions shared/src/utils/vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::collections::HashSet;
use std::hash::Hash;

pub fn dedup_ord<T: Clone + Hash + Eq>(src: &[T]) -> Vec<T> {
let mut set = HashSet::new();

let mut copy = src.to_vec();
copy.retain(|item| set.insert(item.clone()));

copy
}
1 change: 0 additions & 1 deletion worker/Cargo.lock

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

0 comments on commit b293ccb

Please sign in to comment.