Skip to content

Commit

Permalink
Introduce Customizable Universal Resolver (#45)
Browse files Browse the repository at this point in the history
* Introduce Customizable Universal Resolver

Co-authored-by: Luc van Kampen <luc@lucemans.nl>

---------

Co-authored-by: Antonio F. Trstenjak <antoniostignjedec@gmail.com>
  • Loading branch information
lucemans and Antony1060 authored Jan 16, 2024
1 parent 3cb79a4 commit 0b6f266
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .github/.k8s/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ spec:
value: redis://redis.enstate.svc.cluster.local:6379
- name: RPC_URL
value: https://eth.llamarpc.com,https://rpc.payload.de,https://rpc.ankr.com/eth
- name: UNIVERSAL_RESOLVER
value: 0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
resources:
requests:
cpu: 100m
Expand Down
112 changes: 112 additions & 0 deletions .github/.k8s/deploy_goerli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-goerli
namespace: enstate
spec:
replicas: 1
selector:
matchLabels:
app: redis-goerli
template:
metadata:
labels:
app: redis-goerli
spec:
containers:
- name: redis-goerli
image: redis:6.0.9-alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-goerli
namespace: enstate
spec:
selector:
app: redis-goerli
ports:
- protocol: TCP
port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: enstate-goerli
namespace: enstate
spec:
replicas: 2
selector:
matchLabels:
app: enstate-goerli
template:
metadata:
labels:
app: enstate-goerli
spec:
containers:
- name: enstate-goerli
image: ghcr.io/v3xlabs/enstate:sha-749e1d2
imagePullPolicy: Always
ports:
- containerPort: 3000
env:
- name: OPENSEA_API_KEY
valueFrom:
secretKeyRef:
name: opensea-api-key
key: api-key
- name: REDIS_URL
value: redis://redis-goerli.enstate.svc.cluster.local:6379
- name: RPC_URL
value: https://rpc.ankr.com/eth_goerli,https://ethereum-goerli.publicnode.com,https://goerli.gateway.tenderly.co
- name: UNIVERSAL_RESOLVER
value: 0x3952Be0b2186f8B113193a84b69bD71ad3fc1ae3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: enstate-goerli
namespace: enstate
spec:
selector:
app: enstate-goerli
ports:
- protocol: TCP
port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: enstate-goerli
namespace: enstate
annotations:
cert-manager.io/issuer: le-http
spec:
ingressClassName: traefik
rules:
- host: goerli.enstate.rs
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: enstate-goerli
port:
number: 3000
tls:
- hosts:
- goerli.enstate.rs
secretName: tls-goerli-enstate-ingress-http
112 changes: 112 additions & 0 deletions .github/.k8s/deploy_sepolia.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-sepolia
namespace: enstate
spec:
replicas: 1
selector:
matchLabels:
app: redis-sepolia
template:
metadata:
labels:
app: redis-sepolia
spec:
containers:
- name: redis-sepolia
image: redis:6.0.9-alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-sepolia
namespace: enstate
spec:
selector:
app: redis-sepolia
ports:
- protocol: TCP
port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: enstate-sepolia
namespace: enstate
spec:
replicas: 2
selector:
matchLabels:
app: enstate-sepolia
template:
metadata:
labels:
app: enstate-sepolia
spec:
containers:
- name: enstate-sepolia
image: ghcr.io/v3xlabs/enstate:sha-749e1d2
imagePullPolicy: Always
ports:
- containerPort: 3000
env:
- name: OPENSEA_API_KEY
valueFrom:
secretKeyRef:
name: opensea-api-key
key: api-key
- name: REDIS_URL
value: redis://redis-sepolia.enstate.svc.cluster.local:6379
- name: RPC_URL
value: https://rpc.ankr.com/eth_sepolia,https://ethereum-sepolia.publicnode.com,https://sepolia.gateway.tenderly.co
- name: UNIVERSAL_RESOLVER
value: 0x21B000Fd62a880b2125A61e36a284BB757b76025
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: enstate-sepolia
namespace: enstate
spec:
selector:
app: enstate-sepolia
ports:
- protocol: TCP
port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: enstate-sepolia
namespace: enstate
annotations:
cert-manager.io/issuer: le-http
spec:
ingressClassName: traefik
rules:
- host: sepolia.enstate.rs
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: enstate-sepolia
port:
number: 3000
tls:
- hosts:
- sepolia.enstate.rs
secretName: tls-sepolia-enstate-ingress-http
2 changes: 2 additions & 0 deletions .github/workflows/pr_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ jobs:
- run: cargo check --target ${{ matrix.target }} --release
working-directory: ${{ matrix.path }}
test:
name: Test ENState 🧪
uses: ./.github/workflows/test.yml
secrets: inherit
needs: [check]
28 changes: 23 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ jobs:
strategy:
matrix:
suite: [server, worker]
include:
- suite: server
build: cargo build --release
env_file: .env
- suite: worker
build: bun install --global pnpm && pnpm install && pnpm build
env_file: .dev.vars
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -30,12 +37,23 @@ jobs:
- run: bun install
working-directory: test

- run: bun install --global wrangler
if: ${{ matrix.suite == 'worker' }}
- name: Set-up environment > ${{ matrix.env_file }}
shell: bash
env:
RPC_URL: ${{ secrets.RPC_URL }}
OPENSEA_API_KEY: ${{ secrets.OPENSEA_API_KEY }}
run: |
cat <<EOF > ${{ matrix.env_file }}
RPC_URL=$RPC_URL
OPENSEA_API_KEY=$OPENSEA_API_KEY
UNIVERSAL_RESOLVER=0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
EOF
working-directory: ${{ matrix.suite }}

- name: Build
run: ${{ matrix.build }}
working-directory: ${{ matrix.suite }}

- name: Test
run: bun test ${{ matrix.suite }}
working-directory: test
env:
RPC_URL: https://rpc.ankr.com/eth
OPENSEA_API_KEY: ${{ secrets.OPENSEA_API_KEY }}
1 change: 1 addition & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
REDIS_URL=redis://localhost:6379
RPC_URL=https://rpc.ankr.com/eth
OPENSEA_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
UNIVERSAL_RESOLVER=0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62

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

Expand Down Expand Up @@ -62,13 +63,19 @@ impl AppState {
let opensea_api_key =
env::var("OPENSEA_API_KEY").expect("OPENSEA_API_KEY should've been set");

let universal_resolver = env::var("UNIVERSAL_RESOLVER")
.expect("UNIVERSAL_RESOLVER should've been set")
.parse::<H160>()
.expect("UNIVERSAL_RESOLVER should be a valid address");

Self {
service: ProfileService {
cache,
rpc: Box::new(provider),
opensea_api_key,
profile_records: Arc::from(profile_records),
profile_chains: Arc::from(multicoin_chains),
universal_resolver,
},
}
}
Expand Down
11 changes: 7 additions & 4 deletions shared/src/models/eip155/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub async fn resolve_eip155(
// Example url: https://my.nft.metadata.test/1234/2257
// Content: json encoded {name: "", description: "", image: "", ...}
let mut token_metadata_url = result
.get(0)
.first()
// should never trigger
.ok_or_else(|| EIP155Error::ImplementationError("".to_string()))?
.to_string();
Expand Down Expand Up @@ -129,16 +129,19 @@ pub async fn resolve_eip155(
#[cfg(test)]
mod tests {
use std::env;
use std::sync::Arc;

use ethers::middleware::MiddlewareBuilder;
use ethers::providers::{Http, Provider};
use ethers_ccip_read::CCIPReadMiddleware;

use super::*;

#[tokio::test]
async fn test_calldata_avatar_erc721() {
let provider = Provider::<Http>::try_from("https://rpc.ankr.com/eth")
.unwrap()
.wrap_into(CCIPReadMiddleware::new);
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let data = resolve_eip155(
Expand All @@ -159,7 +162,7 @@ mod tests {
async fn test_calldata_avatar_erc1155() {
let provider = Provider::<Http>::try_from("https://rpc.ankr.com/eth")
.unwrap()
.wrap_into(CCIPReadMiddleware::new);
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let data = resolve_eip155(
Expand All @@ -184,7 +187,7 @@ mod tests {
async fn test_calldata_avatar_erc1155_opensea() {
let provider = Provider::<Http>::try_from("https://rpc.ankr.com/eth")
.unwrap()
.wrap_into(CCIPReadMiddleware::new);
.wrap_into(|it| CCIPReadMiddleware::new(Arc::from(it)));
let opensea_api_key = env::var("OPENSEA_API_KEY").unwrap().to_string();

let data = resolve_eip155(
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 @@ -4,6 +4,7 @@ use std::sync::Arc;
use ethers::prelude::Http;
use ethers::providers::Provider;
use ethers_ccip_read::CCIPReadMiddleware;
use ethers_core::types::H160;
use serde::{Deserialize, Serialize};

use crate::models::multicoin::cointype::coins::CoinType;
Expand Down Expand Up @@ -53,4 +54,5 @@ pub struct ProfileService {
pub opensea_api_key: String,
pub profile_records: Arc<[String]>,
pub profile_chains: Arc<[CoinType]>,
pub universal_resolver: H160,
}
4 changes: 2 additions & 2 deletions shared/src/models/profile/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ impl ProfileService {
let mut resolves = Vec::new();

for chunk in calldata.chunks(50) {
resolves.push(resolve_universal(name, chunk, &rpc).await?);
resolves.push(resolve_universal(name, chunk, &rpc, &self.universal_resolver).await?);
}

let Some((_, resolver, ccip_urls)) = resolves.get(0) else {
let Some((_, resolver, ccip_urls)) = resolves.first() else {
return Err(ProfileError::ImplementationError(String::new()));
};

Expand Down
Loading

0 comments on commit 0b6f266

Please sign in to comment.