Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ensdomains/offchain-resolver
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: likecoin/offchain-resolver
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 1 commit
  • 10 files changed
  • 1 contributor

Commits on Nov 13, 2024

  1. ✨ Add Liker ID resolver (#1)

    * ✨ Add likerid resolver
    
    * ✏️ Fix typo
    
    * 🔨 Add Dockerfile
    williamchong authored Nov 13, 2024

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    ca6a170 View commit details
2 changes: 1 addition & 1 deletion packages/contracts/hardhat.config.js
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ if (process.env.DEPLOYER_KEY && process.env.OWNER_KEY) {
real_accounts = [process.env.OWNER_KEY, process.env.DEPLOYER_KEY];
}
const gatewayurl =
'https://offchain-resolver-example.uc.r.appspot.com/{sender}/{data}.json';
'https://ens.like.co/{sender}/{data}.json';

let devgatewayurl = 'http://localhost:8080/{sender}/{data}.json';
if (process.env.REMOTE_GATEWAY) {
34 changes: 34 additions & 0 deletions packages/gateway/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/

**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
**/build
**/dist
LICENSE
README.md
72 changes: 72 additions & 0 deletions packages/gateway/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# syntax=docker/dockerfile:1

# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/

# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7

ARG NODE_VERSION=18

################################################################################
# Use node image for base image for all stages.
FROM node:${NODE_VERSION}-alpine as base

# Set working directory for all build stages.
WORKDIR /usr/src/app


################################################################################
# Create a stage for installing production dependecies.
FROM base as deps

# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.yarn to speed up subsequent builds.
# Leverage bind mounts to package.json and yarn.lock to avoid having to copy them
# into this layer.
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=yarn.lock,target=yarn.lock \
--mount=type=cache,target=/root/.yarn \
yarn install --production --frozen-lockfile

################################################################################
# Create a stage for building the application.
FROM deps as build

# Download additional development dependencies before building, as some projects require
# "devDependencies" to be installed to build. If you don't need this, remove this step.
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=yarn.lock,target=yarn.lock \
--mount=type=cache,target=/root/.yarn \
yarn install --frozen-lockfile

# Copy the rest of the source files into the image.
COPY . .
# Run the build script.
RUN yarn run build

################################################################################
# Create a new stage to run the application with minimal runtime dependencies
# where the necessary files are copied from the build stage.
FROM base as final

# Use production node environment by default.
ENV NODE_ENV production

# Run the application as a non-root user.
USER node

# Copy package.json so that package manager commands can be used.
COPY package.json .

# Copy the production dependencies from the deps stage and also
# the built application from the build stage into the image.
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist


# Expose the port that the application listens on.
EXPOSE 8080

# Run the application.
CMD yarn start
3 changes: 3 additions & 0 deletions packages/gateway/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
docker buildx build -t ens-resolver --platform linux/amd64 .
docker tag ens-resolver us.gcr.io/likecoin-foundation/ens-resolver:latest
docker push us.gcr.io/likecoin-foundation/ens-resolver:latest
1 change: 1 addition & 0 deletions packages/gateway/package.json
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@
"@chainlink/ethers-ccip-read-provider": "^0.2.3",
"@ensdomains/ens-contracts": "^0.0.8",
"@ensdomains/offchain-resolver-contracts": "^0.2.1",
"axios": "^1.7.7",
"commander": "^8.3.0",
"dotenv": "^15.0.0",
"ethers": "^5.7.2"
6 changes: 3 additions & 3 deletions packages/gateway/src/index.ts
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@ import { makeApp } from './server';
import { Command } from 'commander';
import { readFileSync } from 'fs';
import { ethers } from 'ethers';
import { JSONDatabase } from './json';
import { LikerIdDatabase } from './likerid';
const program = new Command();
program
.requiredOption(
'-k --private-key <key>',
'Private key to sign responses with. Prefix with @ to read from a file'
)
.requiredOption('-d --data <file>', 'JSON file to read data from')
.option('-D --development', 'Use development mode')
.option('-t --ttl <number>', 'TTL for signatures', '300')
.option('-p --port <number>', 'Port number to serve on', '8080');
program.parse(process.argv);
@@ -22,7 +22,7 @@ if (privateKey.startsWith('@')) {
}
const address = ethers.utils.computeAddress(privateKey);
const signer = new ethers.utils.SigningKey(privateKey);
const db = JSONDatabase.fromFilename(options.data, parseInt(options.ttl));
const db = new LikerIdDatabase(parseInt(options.ttl), options.development);
const app = makeApp(signer, '/', db);
console.log(`Serving on port ${options.port} with signing address ${address}`);
app.listen(parseInt(options.port));
100 changes: 100 additions & 0 deletions packages/gateway/src/likerid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import axios, { AxiosError } from 'axios';
import { Database } from './server';
import { ETH_COIN_TYPE, COSMOS_COIN_TYPE, EVM_COIN_TYPE_THRESHOLD } from './utils';

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
const EMPTY_CONTENT_HASH = '0x';

const TEXT_KEY_TO_FIELD_NAME: { [key: string]: string } = {
display: 'displayName',
avatar: 'avatar',
email: 'email',
description: 'description',
'addr.likecoin': 'likecoinWallet',
url: 'url',
};

function coinTypeToFieldName(coinType: number): string | null {
if (coinType === ETH_COIN_TYPE || coinType > EVM_COIN_TYPE_THRESHOLD) {
return 'evmWallet';
}
if (coinType === COSMOS_COIN_TYPE) {
return 'cosmosWallet';
}
return null;
}

function isLikeCoEns(name: string): boolean {
return name.split('.').length === 4 && name.endsWith('id.like.co');
}

function isLikerLandEns(name: string): boolean {
return name.split('.').length === 4 && name.endsWith('id.liker.land');
}

export class LikerIdDatabase implements Database {
ttl: number;
isTestnet: boolean;

constructor(ttl: number, isTestnet: boolean) {
this.ttl = ttl;
this.isTestnet = isTestnet;
}

async addr(name: string, coinType: number) {
const fieldName = coinTypeToFieldName(coinType);
if (!fieldName) {
return { addr: ZERO_ADDRESS, ttl: this.ttl };
}
const user = await this.findLikerId(name);
if (!user || !user[fieldName]) {
return { addr: ZERO_ADDRESS, ttl: this.ttl };
}
return { addr: user[fieldName], ttl: this.ttl };
}

async text(name: string, key: string) {
const fieldName = TEXT_KEY_TO_FIELD_NAME[key];
if (!fieldName) {
return { value: '', ttl: this.ttl };
}
const likerId = await this.findLikerId(name);
if (key === 'url') {

}
if (!likerId || !likerId[fieldName]) {
return { value: '', ttl: this.ttl };
}
return { value: likerId[fieldName], ttl: this.ttl };
}

contenthash(_: string) {
return { contenthash: EMPTY_CONTENT_HASH, ttl: this.ttl };
}

private async findLikerId(name: string): Promise<any> {
try {
const isLikeCo = isLikeCoEns(name);
const isLikerLand = isLikerLandEns(name);
if (!isLikeCo && !isLikerLand) {
return null;
}
const likerId = name.split('.')[0];
const { data = {} } = await axios.get(`https://api.${this.isTestnet ? 'rinkeby.' : ''}like.co/users/id/${likerId}/min`);
let hostAndPath = isLikerLand ? 'liker.land' : 'like.co/in';
if (this.isTestnet) {
hostAndPath = `rinkeby.${hostAndPath}`;
}
const url = `https://${hostAndPath}/${likerId}`;
return {
url,
...data,
};
} catch (e) {
if ((e as AxiosError).response?.status !== 404) {
console.error(`Failed to resolve liker id for ${name}: ${(e as Error).message}`);
}
return null;
}
}
}
2 changes: 2 additions & 0 deletions packages/gateway/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export const ETH_COIN_TYPE = 60;
export const COSMOS_COIN_TYPE = 118;
export const EVM_COIN_TYPE_THRESHOLD = 0x80000000;
Loading