Skip to content

Commit

Permalink
Introduce IPFS_GATEWAY environment variable
Browse files Browse the repository at this point in the history
  • Loading branch information
Antony1060 committed Feb 21, 2024
1 parent 31551cd commit e556f59
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 39 deletions.
2 changes: 2 additions & 0 deletions .github/.k8s/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ spec:
value: redis://redis.enstate.svc.cluster.local:6379
- name: UNIVERSAL_RESOLVER
value: 0x8cab227b1162f03b8338331adaad7aadc83b895e
- name: IPFS_GATEWAY
value: https://cloudflare-ipfs.com/ipfs/
resources:
requests:
cpu: 100m
Expand Down
2 changes: 2 additions & 0 deletions .github/.k8s/deploy_goerli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ spec:
value: https://rpc.ankr.com/eth_goerli,https://ethereum-goerli.publicnode.com,https://goerli.gateway.tenderly.co
- name: UNIVERSAL_RESOLVER
value: 0xfc4AC75C46C914aF5892d6d3eFFcebD7917293F1
- name: IPFS_GATEWAY
value: https://cloudflare-ipfs.com/ipfs/
resources:
requests:
cpu: 100m
Expand Down
2 changes: 2 additions & 0 deletions .github/.k8s/deploy_sepolia.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ spec:
value: https://rpc.ankr.com/eth_sepolia,https://ethereum-sepolia.publicnode.com,https://sepolia.gateway.tenderly.co
- name: UNIVERSAL_RESOLVER
value: 0xBaBC7678D7A63104f1658c11D6AE9A21cdA09725
- name: IPFS_GATEWAY,
value: https://cloudflare-ipfs.com/ipfs/
resources:
requests:
cpu: 100m
Expand Down
1 change: 1 addition & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ REDIS_URL=redis://localhost:6379
RPC_URL=https://rpc.ankr.com/eth
OPENSEA_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
UNIVERSAL_RESOLVER=0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
IPFS_GATEWAY=https://ipfs.io/ipfs/

# Optionally you can specify a comma-seperated list PROFILE_RECORDS, however if not provided there are sensible defaults
# PROFILE_RECORDS=com.discord,com.twitter
8 changes: 6 additions & 2 deletions server/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use enstate_shared::cache::{CacheLayer, PassthroughCacheLayer};
use ethers_core::types::H160;
use std::env;
use std::sync::Arc;

use enstate_shared::cache::{CacheLayer, PassthroughCacheLayer};
use enstate_shared::core::ENSService;
use enstate_shared::models::{
multicoin::cointype::{coins::CoinType, Coins},
records::Records,
};
use ethers_core::types::H160;
use tracing::{info, warn};

use crate::provider::RoundRobin;
Expand Down Expand Up @@ -63,6 +63,9 @@ impl AppState {
let opensea_api_key =
env::var("OPENSEA_API_KEY").expect("OPENSEA_API_KEY should've been set");

let ipfs_gateway =
env::var("IPFS_GATEWAY").unwrap_or_else(|_| "https://ipfs.io/ipfs/".to_string());

let universal_resolver = env::var("UNIVERSAL_RESOLVER")
.expect("UNIVERSAL_RESOLVER should've been set")
.parse::<H160>()
Expand All @@ -73,6 +76,7 @@ impl AppState {
cache,
rpc: Box::new(provider),
opensea_api_key,
ipfs_gateway,
profile_records: Arc::from(profile_records),
profile_chains: Arc::from(multicoin_chains),
universal_resolver,
Expand Down
1 change: 1 addition & 0 deletions shared/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub struct ENSService {
pub cache: Box<dyn crate::cache::CacheLayer>,
pub rpc: Box<dyn Factory<Arc<Provider<Http>>>>,
pub opensea_api_key: String,
pub ipfs_gateway: String,
pub profile_records: Arc<[String]>,
pub profile_chains: Arc<[CoinType]>,
pub universal_resolver: H160,
Expand Down
1 change: 1 addition & 0 deletions shared/src/core/records.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl ENSService {
let lookup_state = LookupState {
rpc,
opensea_api_key: self.opensea_api_key.clone(),
ipfs_gateway: self.ipfs_gateway.clone()
};

// Assume results & calldata have the same length
Expand Down
38 changes: 26 additions & 12 deletions shared/src/models/eip155/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use thiserror::Error;
use tracing::info;

use crate::models::ipfs::{URLFetchError, OPENSEA_BASE_PREFIX};
use crate::models::lookup::LookupState;
use crate::models::multicoin::cointype::evm::ChainId;
use crate::core::CCIPProvider;

use super::ipfs::IPFSURLUnparsed;

Expand Down Expand Up @@ -56,8 +56,7 @@ pub async fn resolve_eip155(
contract_type: EIP155ContractType,
contract_address: &str,
token_id: U256,
provider: &CCIPProvider,
opensea_api_key: &str,
state: &LookupState,
) -> Result<String, EIP155Error> {
let chain_id: u64 = chain_id.into();

Expand Down Expand Up @@ -86,7 +85,7 @@ pub async fn resolve_eip155(
typed_transaction.set_to(contract_h160);
typed_transaction.set_data(Bytes::from(transaction_data));

let res = provider.provider().call_raw(&typed_transaction).await?;
let res = state.rpc.provider().call_raw(&typed_transaction).await?;

let res_data = res.to_vec();

Expand Down Expand Up @@ -115,13 +114,13 @@ pub async fn resolve_eip155(
// TODO: Validate URL here
let token_metadata_url = IPFSURLUnparsed::from_unparsed(token_metadata_url);

let token_metadata = token_metadata_url.fetch(opensea_api_key).await?;
let token_metadata = token_metadata_url.fetch(state).await?;

let image = token_metadata.image.ok_or(EIP155Error::Other)?;

info!("Image: {}", image);

let token_image_url = IPFSURLUnparsed::from_unparsed(image).to_url_or_gateway();
let token_image_url = IPFSURLUnparsed::from_unparsed(image).to_url_or_gateway(state);

Ok(token_image_url)
}
Expand All @@ -144,13 +143,18 @@ mod tests {
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let state = LookupState {
rpc: Arc::new(provider),
opensea_api_key,
ipfs_gateway: "https://ipfs.io/ipfs/".to_string(),
};

let data = resolve_eip155(
ChainId::Ethereum,
EIP155ContractType::ERC721,
"0xc92ceddfb8dd984a89fb494c376f9a48b999aafc",
U256::from_dec_str("2257").unwrap(),
&provider,
&opensea_api_key,
&state,
)
.await
.unwrap();
Expand All @@ -165,13 +169,18 @@ mod tests {
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let state = LookupState {
rpc: Arc::new(provider),
opensea_api_key,
ipfs_gateway: "https://ipfs.io/ipfs/".to_string(),
};

let data = resolve_eip155(
ChainId::Ethereum,
EIP155ContractType::ERC1155,
"0xb32979486938aa9694bfc898f35dbed459f44424",
U256::from_dec_str("10063").unwrap(),
&provider,
&opensea_api_key,
&state,
)
.await
.unwrap();
Expand All @@ -190,6 +199,12 @@ mod tests {
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let state = LookupState {
rpc: Arc::new(provider),
opensea_api_key,
ipfs_gateway: "https://ipfs.io/ipfs/".to_string(),
};

let data = resolve_eip155(
ChainId::Ethereum,
EIP155ContractType::ERC1155,
Expand All @@ -198,8 +213,7 @@ mod tests {
"8112316025873927737505937898915153732580103913704334048512380490797008551937",
)
.unwrap(),
&provider,
&opensea_api_key,
&state,
)
.await
.unwrap();
Expand Down
20 changes: 7 additions & 13 deletions shared/src/models/ipfs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::models::lookup::image::IPFS_REGEX;
use lazy_static::lazy_static;
use reqwest::header::HeaderValue;
use thiserror::Error;
use crate::models::lookup::LookupState;

use super::erc721::metadata::NFTMetadata;

Expand All @@ -26,10 +28,6 @@ lazy_static! {
static ref RAW_IPFS_REGEX: regex::Regex =
regex::Regex::new(r"^Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}$")
.expect("should be a valid regex");

static ref IPFS_REGEX: regex::Regex =
regex::Regex::new(r"^ipfs://(ip[fn]s/)?([0-9a-zA-Z]+(/.*)?)")
.expect("should be a valid regex");
}

impl IPFSURLUnparsed {
Expand All @@ -49,26 +47,22 @@ impl IPFSURLUnparsed {
IPFSURLUnparsed::URL(value)
}

pub fn from_ipfs(value: String) -> Self {
Self::from_unparsed(value)
}

// This function turns the unparsed
pub fn to_url_or_gateway(&self) -> String {
pub fn to_url_or_gateway(&self, state: &LookupState) -> String {
match self {
IPFSURLUnparsed::URL(url) => url.to_string(),
IPFSURLUnparsed::IPFS(hash) => format!("https://ipfs.io/ipfs/{}", hash),
IPFSURLUnparsed::IPFS(hash) => format!("{gateway}/{hash}", gateway=state.ipfs_gateway),
}
}

pub async fn fetch(&self, opensea_api_key: &str) -> Result<NFTMetadata, URLFetchError> {
let url = self.to_url_or_gateway();
pub async fn fetch(&self, state: &LookupState) -> Result<NFTMetadata, URLFetchError> {
let url = self.to_url_or_gateway(state);
let mut client_headers = reqwest::header::HeaderMap::new();

if url.starts_with(OPENSEA_BASE_PREFIX) {
client_headers.insert(
"X-API-KEY",
HeaderValue::from_str(opensea_api_key)
HeaderValue::from_str(&state.opensea_api_key)
.unwrap_or_else(|_| HeaderValue::from_static("")),
);
}
Expand Down
16 changes: 6 additions & 10 deletions shared/src/models/lookup/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ use crate::models::multicoin::cointype::evm::ChainId;
use super::{abi_decode_universal_ccip, ENSLookupError, LookupState};

lazy_static! {
static ref IPFS_REGEX: regex::Regex =
regex::Regex::new(r"ipfs://([0-9a-zA-Z]+)").expect("should be a valid regex");
pub static ref IPFS_REGEX: regex::Regex =
regex::Regex::new(r"^ipfs://(ip[fn]s/)?([0-9a-zA-Z]+(/.*)?)")
.expect("should be a valid regex");
static ref EIP155_REGEX: regex::Regex =
regex::Regex::new(r"eip155:([0-9]+)/(erc1155|erc721):0x([0-9a-fA-F]{40})/([0-9]+)")
.expect("should be a valid regex");
}
const IPFS_GATEWAY: &str = "https://ipfs.io/ipfs/";

#[derive(Error, Debug)]
enum ImageLookupError {
#[error("Format error: {0}")]
Expand Down Expand Up @@ -54,12 +53,10 @@ pub async fn decode(data: &[u8], state: &LookupState) -> Result<String, ENSLooku
return Err(ENSLookupError::AbiDecodeError);
};

let opensea_api_key = state.opensea_api_key.clone();

if let Some(captures) = IPFS_REGEX.captures(value) {
let hash = captures.get(1).unwrap().as_str();
let hash = captures.get(2).unwrap().as_str();

return Ok(format!("{}{hash}", IPFS_GATEWAY));
return Ok(format!("{gateway}{hash}", gateway = state.ipfs_gateway));
}

let Some(captures) = EIP155_REGEX.captures(value) else {
Expand Down Expand Up @@ -104,8 +101,7 @@ pub async fn decode(data: &[u8], state: &LookupState) -> Result<String, ENSLooku
contract_type,
contract_address,
token_id,
&state.rpc,
&opensea_api_key,
state,
)
.await?;

Expand Down
1 change: 1 addition & 0 deletions shared/src/models/lookup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ impl ENSLookup {
pub struct LookupState {
pub rpc: Arc<CCIPProvider>,
pub opensea_api_key: String,
pub ipfs_gateway: String,
}

lazy_static! {
Expand Down
10 changes: 8 additions & 2 deletions worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ethers::prelude::{Http, Provider};
use ethers::types::H160;
use http::StatusCode;
use lazy_static::lazy_static;
use worker::{event, Context, Cors, Env, Headers, Method, Request, Response, Router};
use worker::{event, Context, Cors, Env, Headers, Method, Request, Response, Router, Var};

use crate::http_util::http_simple_status_error;
use crate::kv_cache::CloudflareKVCache;
Expand All @@ -33,6 +33,11 @@ async fn main(req: Request, env: Env, _ctx: Context) -> worker::Result<Response>
.expect("OPENSEA_API_KEY should've been set")
.to_string();

let ipfs_gateway = env
.var("IPFS_GATEWAY")
.map(|it| it.to_string())
.unwrap_or_else(|_| "https://ipfs.io/ipfs/".to_string());

let cache: Box<dyn CacheLayer> = Box::new(CloudflareKVCache {
env: Env::from(env.clone()),
});
Expand All @@ -57,7 +62,8 @@ async fn main(req: Request, env: Env, _ctx: Context) -> worker::Result<Response>
let service = ENSService {
cache,
rpc: Box::new(SimpleFactory::from(Arc::new(rpc))),
opensea_api_key: opensea_api_key.to_string(),
opensea_api_key,
ipfs_gateway,
profile_records: Arc::from(profile_records),
profile_chains: Arc::from(profile_chains),
universal_resolver,
Expand Down

0 comments on commit e556f59

Please sign in to comment.