Skip to content

Commit

Permalink
chore: use GRPC hub client
Browse files Browse the repository at this point in the history
  • Loading branch information
horsefacts committed Aug 16, 2024
1 parent 1fab840 commit a213661
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-llamas-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@farcaster/auth-relay": patch
---

chore: use GRPC hub client
4 changes: 2 additions & 2 deletions apps/relay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
"node": ">=18"
},
"dependencies": {
"@farcaster/core": "^0.14.8",
"@farcaster/hub-nodejs": "^0.11.24",
"@fastify/cors": "^8.4.2",
"@fastify/rate-limit": "^9.0.1",
"axios": "^1.7.4",
"dd-trace": "^5.21.0",
"dotenv": "^16.3.1",
"ethers": "^6.0.8",
Expand All @@ -30,6 +29,7 @@
"viem": "^2.5.0"
},
"devDependencies": {
"axios": "^1.7.4",
"jest": "^29.7.0"
}
}
85 changes: 29 additions & 56 deletions apps/relay/src/addresses.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,45 @@
import axios, { AxiosInstance } from "axios";
import { ResultAsync, err, ok } from "neverthrow";
import { createPublicClient, http } from "viem";
import type { PublicClient, HttpTransport, Hex } from "viem";
import { PublicClient, HttpTransport, Hex, bytesToHex } from "viem";
import { optimism } from "viem/chains";
import { ID_REGISTRY_ADDRESS, idRegistryABI } from "@farcaster/core";

import { RelayAsyncResult, RelayError } from "./errors";
import { HUB_URL, HUB_FALLBACK_URL, OPTIMISM_RPC_URL } from "./env";

interface VerificationAddAddressBody {
address: Hex;
}

interface ArbitraryVerificationMessageData {
verificationAddEthAddressBody: never;
verificationAddAddressBody: VerificationAddAddressBody;
}

interface EthVerificationMessageData {
verificationAddEthAddressBody: VerificationAddAddressBody;
verificationAddAddressBody: never;
}

type VerificationMessageData = ArbitraryVerificationMessageData | EthVerificationMessageData;

interface VerificationMessage {
data: VerificationMessageData;
}

interface VerificationsAPIResponse {
messages: VerificationMessage[];
}
import { HubService } from "./hubs";

export class AddressService {
private http: AxiosInstance;
private publicClient: PublicClient<HttpTransport, typeof optimism>;

constructor() {
this.http = axios.create();
this.publicClient = createPublicClient({
chain: optimism,
transport: http(OPTIMISM_RPC_URL),
});
}

async getAddresses(fid?: number): RelayAsyncResult<{ custody: Hex; verifications: Hex[] }> {
async getAddresses(fid: number): RelayAsyncResult<{ custody: Hex; verifications: Hex[] }> {
const custody = await this.custody(fid);
if (custody.isErr()) {
return err(custody.error);
}
const verifications = await this.verifications(fid);

let verifications = await this.tryVerifications(fid, HUB_URL);
if (verifications.isErr()) {
verifications = await this.tryVerifications(fid, HUB_FALLBACK_URL);
}

if (verifications.isErr()) {
return err(verifications.error);
}

return ok({
custody: custody.value,
verifications: verifications.value,
});
}

async custody(fid?: number): RelayAsyncResult<Hex> {
async custody(fid: number): RelayAsyncResult<Hex> {
return ResultAsync.fromPromise(
this.publicClient.readContract({
address: ID_REGISTRY_ADDRESS,
Expand All @@ -73,31 +53,24 @@ export class AddressService {
);
}

async verifications(fid?: number): RelayAsyncResult<Hex[]> {
const url = `${HUB_URL}/v1/verificationsByFid?fid=${fid}`;
const fallbackUrl = `${HUB_FALLBACK_URL}/v1/verificationsByFid?fid=${fid}`;
async tryVerifications(fid: number, hubEndpoint: string): RelayAsyncResult<Hex[]> {
const hub = await HubService.getReadyClient(hubEndpoint);
if (hub.isErr()) return err(hub.error);

return ResultAsync.fromPromise(this.http.get<VerificationsAPIResponse>(url, { timeout: 1500 }), (error) => {
return new RelayError("unknown", error as Error);
})
.orElse(() => {
return ResultAsync.fromPromise(
this.http.get<VerificationsAPIResponse>(fallbackUrl, {
timeout: 3500,
}),
(error) => {
return new RelayError("unknown", error as Error);
},
);
})
.andThen((res) => {
return ok(
res.data.messages.map((message) => {
return (
message.data?.verificationAddAddressBody?.address || message.data?.verificationAddEthAddressBody?.address
);
}),
);
});
const { client } = hub.value;
const verificationsResult = await client.getVerificationsByFid({
fid,
});
if (verificationsResult.isErr()) {
return err(new RelayError("unavailable", verificationsResult.error));
}
const verifications: Hex[] = [];
for (const message of verificationsResult.value.messages) {
const verification = message.data?.verificationAddAddressBody?.address;
if (verification) {
verifications.push(bytesToHex(verification));
}
}
return ok(verifications);
}
}
4 changes: 2 additions & 2 deletions apps/relay/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export const RELAY_SERVER_HOST = process.env["RELAY_SERVER_HOST"] || "localhost"
export const URL_BASE =
process.env["URL_BASE"] || process.env["CONNECT_URI_BASE"] || "https://warpcast.com/~/sign-in-with-farcaster";

export const HUB_URL = process.env["HUB_URL"] || "https://nemes.farcaster.xyz:2281";
export const HUB_FALLBACK_URL = process.env["HUB_FALLBACK_URL"] || "https://hoyt.farcaster.xyz:2281";
export const HUB_URL = process.env["HUB_URL"] || "hoyt.farcaster.xyz:2283";
export const HUB_FALLBACK_URL = process.env["HUB_FALLBACK_URL"] || "lamia.farcaster.xyz:2283";

export const OPTIMISM_RPC_URL =
process.env["OPTIMISM_RPC_URL"] || process.env["OP_MAINNET_RPC_URL"] || "https://mainnet.optimism.io";
Expand Down
35 changes: 35 additions & 0 deletions apps/relay/src/hubs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getSSLHubRpcClient, HubRpcClient } from "@farcaster/hub-nodejs";
import { RelayAsyncResult, RelayError } from "./errors";
import { err, ok } from "neverthrow";

export type HubClient = {
host: string;
client: HubRpcClient;
};

const MAX_RECEIVE_MESSAGE_LENGTH = 10 * 1024 * 1024; // 10mb

const clientOptions = {
"grpc.max_receive_message_length": MAX_RECEIVE_MESSAGE_LENGTH,
};

export class HubService {
public static async getReadyClient(host: string): RelayAsyncResult<HubClient> {
const client = getSSLHubRpcClient(host, clientOptions);
const res = await this.waitForReadyHubClient(client);
if (res.isErr()) return err(res.error);

return ok({
host,
client,
});
}

public static waitForReadyHubClient(hubClient: HubRpcClient): RelayAsyncResult<void> {
return new Promise((resolve) => {
hubClient?.$.waitForReady(Date.now() + 500, (e) => {
return e ? resolve(err(new RelayError("unknown", e))) : resolve(ok(undefined));
});
});
}
}
42 changes: 40 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2920,7 +2920,7 @@
find-up "^5.0.0"
js-yaml "^4.1.0"

"@farcaster/core@^0.14.8":
"@farcaster/core@0.14.20":
version "0.14.20"
resolved "https://registry.npmjs.org/@farcaster/core/-/core-0.14.20.tgz#b912ead5a3fedfb943d217593d1e5e10f1a97353"
integrity sha512-VHnvt78fITnztYwRrrLAI0MTxgUelGw8ieync4yLxDx/BA2wSr9gNNeLxnQupLXD6qf8k7JsxqLJrFAuVDzt5A==
Expand All @@ -2931,6 +2931,16 @@
neverthrow "^6.0.0"
viem "^2.17.4"

"@farcaster/hub-nodejs@^0.11.24":
version "0.11.24"
resolved "https://registry.npmjs.org/@farcaster/hub-nodejs/-/hub-nodejs-0.11.24.tgz#f4f8d125afd856221a3278c7bb9b0361baf6f028"
integrity sha512-MK6qmmKRVtQbJ53J48ZyzL/j63M2z3n/QPTSZVzer2VtO7cwn4oovKfDwjYZ1C87fEgnxYYtZnxOosHbd75rXA==
dependencies:
"@farcaster/core" "0.14.20"
"@grpc/grpc-js" "~1.11.1"
"@noble/hashes" "^1.3.0"
neverthrow "^6.0.0"

"@fastify/ajv-compiler@^3.5.0":
version "3.6.0"
resolved "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz#907497a0e62a42b106ce16e279cf5788848e8e79"
Expand Down Expand Up @@ -2986,6 +2996,24 @@
resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==

"@grpc/grpc-js@~1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70"
integrity sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw==
dependencies:
"@grpc/proto-loader" "^0.7.13"
"@js-sdsl/ordered-map" "^4.4.2"

"@grpc/proto-loader@^0.7.13":
version "0.7.13"
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf"
integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==
dependencies:
lodash.camelcase "^4.3.0"
long "^5.0.0"
protobufjs "^7.2.5"
yargs "^17.7.2"

"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
Expand Down Expand Up @@ -3353,6 +3381,11 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"

"@js-sdsl/ordered-map@^4.4.2":
version "4.4.2"
resolved "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c"
integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==

"@lukeed/ms@^2.0.1":
version "2.0.2"
resolved "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz#07f09e59a74c52f4d88c6db5c1054e819538e2a8"
Expand Down Expand Up @@ -10216,6 +10249,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"

lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==

lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
Expand Down Expand Up @@ -14783,7 +14821,7 @@ yargs@^15.1.0, yargs@^15.3.1:
y18n "^4.0.0"
yargs-parser "^18.1.2"

yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.1:
yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
Expand Down

0 comments on commit a213661

Please sign in to comment.