Skip to content

Commit 0b6f266

Browse files
lucemansAntony1060
andauthored
Introduce Customizable Universal Resolver (#45)
* Introduce Customizable Universal Resolver Co-authored-by: Luc van Kampen <[email protected]> --------- Co-authored-by: Antonio F. Trstenjak <[email protected]>
1 parent 3cb79a4 commit 0b6f266

File tree

17 files changed

+290
-24
lines changed

17 files changed

+290
-24
lines changed

.github/.k8s/deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ spec:
6363
value: redis://redis.enstate.svc.cluster.local:6379
6464
- name: RPC_URL
6565
value: https://eth.llamarpc.com,https://rpc.payload.de,https://rpc.ankr.com/eth
66+
- name: UNIVERSAL_RESOLVER
67+
value: 0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
6668
resources:
6769
requests:
6870
cpu: 100m

.github/.k8s/deploy_goerli.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: redis-goerli
5+
namespace: enstate
6+
spec:
7+
replicas: 1
8+
selector:
9+
matchLabels:
10+
app: redis-goerli
11+
template:
12+
metadata:
13+
labels:
14+
app: redis-goerli
15+
spec:
16+
containers:
17+
- name: redis-goerli
18+
image: redis:6.0.9-alpine
19+
ports:
20+
- containerPort: 6379
21+
---
22+
apiVersion: v1
23+
kind: Service
24+
metadata:
25+
name: redis-goerli
26+
namespace: enstate
27+
spec:
28+
selector:
29+
app: redis-goerli
30+
ports:
31+
- protocol: TCP
32+
port: 6379
33+
targetPort: 6379
34+
---
35+
apiVersion: apps/v1
36+
kind: Deployment
37+
metadata:
38+
name: enstate-goerli
39+
namespace: enstate
40+
spec:
41+
replicas: 2
42+
selector:
43+
matchLabels:
44+
app: enstate-goerli
45+
template:
46+
metadata:
47+
labels:
48+
app: enstate-goerli
49+
spec:
50+
containers:
51+
- name: enstate-goerli
52+
image: ghcr.io/v3xlabs/enstate:sha-749e1d2
53+
imagePullPolicy: Always
54+
ports:
55+
- containerPort: 3000
56+
env:
57+
- name: OPENSEA_API_KEY
58+
valueFrom:
59+
secretKeyRef:
60+
name: opensea-api-key
61+
key: api-key
62+
- name: REDIS_URL
63+
value: redis://redis-goerli.enstate.svc.cluster.local:6379
64+
- name: RPC_URL
65+
value: https://rpc.ankr.com/eth_goerli,https://ethereum-goerli.publicnode.com,https://goerli.gateway.tenderly.co
66+
- name: UNIVERSAL_RESOLVER
67+
value: 0x3952Be0b2186f8B113193a84b69bD71ad3fc1ae3
68+
resources:
69+
requests:
70+
cpu: 100m
71+
memory: 128Mi
72+
limits:
73+
cpu: 100m
74+
memory: 128Mi
75+
---
76+
apiVersion: v1
77+
kind: Service
78+
metadata:
79+
name: enstate-goerli
80+
namespace: enstate
81+
spec:
82+
selector:
83+
app: enstate-goerli
84+
ports:
85+
- protocol: TCP
86+
port: 3000
87+
targetPort: 3000
88+
---
89+
apiVersion: networking.k8s.io/v1
90+
kind: Ingress
91+
metadata:
92+
name: enstate-goerli
93+
namespace: enstate
94+
annotations:
95+
cert-manager.io/issuer: le-http
96+
spec:
97+
ingressClassName: traefik
98+
rules:
99+
- host: goerli.enstate.rs
100+
http:
101+
paths:
102+
- path: /
103+
pathType: Prefix
104+
backend:
105+
service:
106+
name: enstate-goerli
107+
port:
108+
number: 3000
109+
tls:
110+
- hosts:
111+
- goerli.enstate.rs
112+
secretName: tls-goerli-enstate-ingress-http

.github/.k8s/deploy_sepolia.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: redis-sepolia
5+
namespace: enstate
6+
spec:
7+
replicas: 1
8+
selector:
9+
matchLabels:
10+
app: redis-sepolia
11+
template:
12+
metadata:
13+
labels:
14+
app: redis-sepolia
15+
spec:
16+
containers:
17+
- name: redis-sepolia
18+
image: redis:6.0.9-alpine
19+
ports:
20+
- containerPort: 6379
21+
---
22+
apiVersion: v1
23+
kind: Service
24+
metadata:
25+
name: redis-sepolia
26+
namespace: enstate
27+
spec:
28+
selector:
29+
app: redis-sepolia
30+
ports:
31+
- protocol: TCP
32+
port: 6379
33+
targetPort: 6379
34+
---
35+
apiVersion: apps/v1
36+
kind: Deployment
37+
metadata:
38+
name: enstate-sepolia
39+
namespace: enstate
40+
spec:
41+
replicas: 2
42+
selector:
43+
matchLabels:
44+
app: enstate-sepolia
45+
template:
46+
metadata:
47+
labels:
48+
app: enstate-sepolia
49+
spec:
50+
containers:
51+
- name: enstate-sepolia
52+
image: ghcr.io/v3xlabs/enstate:sha-749e1d2
53+
imagePullPolicy: Always
54+
ports:
55+
- containerPort: 3000
56+
env:
57+
- name: OPENSEA_API_KEY
58+
valueFrom:
59+
secretKeyRef:
60+
name: opensea-api-key
61+
key: api-key
62+
- name: REDIS_URL
63+
value: redis://redis-sepolia.enstate.svc.cluster.local:6379
64+
- name: RPC_URL
65+
value: https://rpc.ankr.com/eth_sepolia,https://ethereum-sepolia.publicnode.com,https://sepolia.gateway.tenderly.co
66+
- name: UNIVERSAL_RESOLVER
67+
value: 0x21B000Fd62a880b2125A61e36a284BB757b76025
68+
resources:
69+
requests:
70+
cpu: 100m
71+
memory: 128Mi
72+
limits:
73+
cpu: 100m
74+
memory: 128Mi
75+
---
76+
apiVersion: v1
77+
kind: Service
78+
metadata:
79+
name: enstate-sepolia
80+
namespace: enstate
81+
spec:
82+
selector:
83+
app: enstate-sepolia
84+
ports:
85+
- protocol: TCP
86+
port: 3000
87+
targetPort: 3000
88+
---
89+
apiVersion: networking.k8s.io/v1
90+
kind: Ingress
91+
metadata:
92+
name: enstate-sepolia
93+
namespace: enstate
94+
annotations:
95+
cert-manager.io/issuer: le-http
96+
spec:
97+
ingressClassName: traefik
98+
rules:
99+
- host: sepolia.enstate.rs
100+
http:
101+
paths:
102+
- path: /
103+
pathType: Prefix
104+
backend:
105+
service:
106+
name: enstate-sepolia
107+
port:
108+
number: 3000
109+
tls:
110+
- hosts:
111+
- sepolia.enstate.rs
112+
secretName: tls-sepolia-enstate-ingress-http

.github/workflows/pr_check.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,7 @@ jobs:
4040
- run: cargo check --target ${{ matrix.target }} --release
4141
working-directory: ${{ matrix.path }}
4242
test:
43+
name: Test ENState 🧪
4344
uses: ./.github/workflows/test.yml
45+
secrets: inherit
4446
needs: [check]

.github/workflows/test.yml

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ jobs:
1111
strategy:
1212
matrix:
1313
suite: [server, worker]
14+
include:
15+
- suite: server
16+
build: cargo build --release
17+
env_file: .env
18+
- suite: worker
19+
build: bun install --global pnpm && pnpm install && pnpm build
20+
env_file: .dev.vars
1421
steps:
1522
- uses: actions/checkout@v3
1623
with:
@@ -30,12 +37,23 @@ jobs:
3037
- run: bun install
3138
working-directory: test
3239

33-
- run: bun install --global wrangler
34-
if: ${{ matrix.suite == 'worker' }}
40+
- name: Set-up environment > ${{ matrix.env_file }}
41+
shell: bash
42+
env:
43+
RPC_URL: ${{ secrets.RPC_URL }}
44+
OPENSEA_API_KEY: ${{ secrets.OPENSEA_API_KEY }}
45+
run: |
46+
cat <<EOF > ${{ matrix.env_file }}
47+
RPC_URL=$RPC_URL
48+
OPENSEA_API_KEY=$OPENSEA_API_KEY
49+
UNIVERSAL_RESOLVER=0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
50+
EOF
51+
working-directory: ${{ matrix.suite }}
52+
53+
- name: Build
54+
run: ${{ matrix.build }}
55+
working-directory: ${{ matrix.suite }}
3556

3657
- name: Test
3758
run: bun test ${{ matrix.suite }}
3859
working-directory: test
39-
env:
40-
RPC_URL: https://rpc.ankr.com/eth
41-
OPENSEA_API_KEY: ${{ secrets.OPENSEA_API_KEY }}

server/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
REDIS_URL=redis://localhost:6379
22
RPC_URL=https://rpc.ankr.com/eth
33
OPENSEA_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
4+
UNIVERSAL_RESOLVER=0xc0497E381f536Be9ce14B0dD3817cBcAe57d2F62
45

56
# Optionally you can specify a comma-seperated list PROFILE_RECORDS, however if not provided there are sensible defaults
67
# PROFILE_RECORDS=com.discord,com.twitter

server/src/state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use enstate_shared::cache::{CacheLayer, PassthroughCacheLayer};
2+
use ethers_core::types::H160;
23
use std::env;
34
use std::sync::Arc;
45

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

66+
let universal_resolver = env::var("UNIVERSAL_RESOLVER")
67+
.expect("UNIVERSAL_RESOLVER should've been set")
68+
.parse::<H160>()
69+
.expect("UNIVERSAL_RESOLVER should be a valid address");
70+
6571
Self {
6672
service: ProfileService {
6773
cache,
6874
rpc: Box::new(provider),
6975
opensea_api_key,
7076
profile_records: Arc::from(profile_records),
7177
profile_chains: Arc::from(multicoin_chains),
78+
universal_resolver,
7279
},
7380
}
7481
}

shared/src/models/eip155/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub async fn resolve_eip155(
9797
// Example url: https://my.nft.metadata.test/1234/2257
9898
// Content: json encoded {name: "", description: "", image: "", ...}
9999
let mut token_metadata_url = result
100-
.get(0)
100+
.first()
101101
// should never trigger
102102
.ok_or_else(|| EIP155Error::ImplementationError("".to_string()))?
103103
.to_string();
@@ -129,16 +129,19 @@ pub async fn resolve_eip155(
129129
#[cfg(test)]
130130
mod tests {
131131
use std::env;
132+
use std::sync::Arc;
132133

133134
use ethers::middleware::MiddlewareBuilder;
135+
use ethers::providers::{Http, Provider};
136+
use ethers_ccip_read::CCIPReadMiddleware;
134137

135138
use super::*;
136139

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

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

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

190193
let data = resolve_eip155(

shared/src/models/profile/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::sync::Arc;
44
use ethers::prelude::Http;
55
use ethers::providers::Provider;
66
use ethers_ccip_read::CCIPReadMiddleware;
7+
use ethers_core::types::H160;
78
use serde::{Deserialize, Serialize};
89

910
use crate::models::multicoin::cointype::coins::CoinType;
@@ -53,4 +54,5 @@ pub struct ProfileService {
5354
pub opensea_api_key: String,
5455
pub profile_records: Arc<[String]>,
5556
pub profile_chains: Arc<[CoinType]>,
57+
pub universal_resolver: H160,
5658
}

shared/src/models/profile/name.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ impl ProfileService {
101101
let mut resolves = Vec::new();
102102

103103
for chunk in calldata.chunks(50) {
104-
resolves.push(resolve_universal(name, chunk, &rpc).await?);
104+
resolves.push(resolve_universal(name, chunk, &rpc, &self.universal_resolver).await?);
105105
}
106106

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

0 commit comments

Comments
 (0)