Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update to PubKey Protocol v1 sdk #87

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: update to PubKey Protocol v1 sdk
  • Loading branch information
beeman committed Dec 6, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 512fa1f7bc84d15b77d4c2ff3ef2f705de325d77
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -77,10 +77,14 @@ LOG_LEVEL=ALL
PORT=3000
# PubKey Protocol Cluster
#PUBKEY_PROTOCOL_CLUSTER=devnet
# PubKey Protocol Community
#PUBKEY_PROTOCOL_COMMUNITY=pubkey
# PubKey Protocol Endpoint
#PUBKEY_PROTOCOL_ENDPOINT=https://api.devnet.solana.com
# PubKey Protocol Endpoint (Public)
#PUBKEY_PROTOCOL_ENDPOINT_PUBLIC=https://api.devnet.solana.com
# PubKey Protocol Fee Payer
#PUBKEY_PROTOCOL_FEE_PAYER=[70,56,165,176,206,28,236,12,82,10,157,230,111,245,20,153,78,236,236,175,139,94,74,166,234,105,243,29,7,128,180,102,5,188,6,222,199,100,106,167,167,226,149,117,130,48,84,46,158,67,159,201,180,76,27,163,29,203,181,210,8,28,97,48]
#PUBKEY_PROTOCOL_SIGNER=[70,56,165,176,206,28,236,12,82,10,157,230,111,245,20,153,78,236,236,175,139,94,74,166,234,105,243,29,7,128,180,102,5,188,6,222,199,100,106,167,167,226,149,117,130,48,84,46,158,67,159,201,180,76,27,163,29,203,181,210,8,28,97,48]
# Redis configuration
REDIS_URL=redis://localhost:6379
# Solana Cluster endpoints.
3 changes: 3 additions & 0 deletions api-schema.graphql
Original file line number Diff line number Diff line change
@@ -195,6 +195,9 @@ type AppConfig {
authLinkProviders: [IdentityProvider!]
authLoginProviders: [IdentityProvider!]
features: [AppFeature!]!
pubkeyProtocolCommunity: String
pubkeyProtocolEndpoint: String
pubkeyProtocolSigner: String
resolvers: [NetworkResolver!]!
}

Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { LogLevel } from '@ogma/common'
import { IdentityProvider } from '@prisma/client'
import { Keypair } from '@solana/web3.js'
import { RedisOptions } from 'bullmq'
import { CookieOptions } from 'express-serve-static-core'
import { AppConfig, AppFeature } from '../entity/app-config.entity'
@@ -48,6 +49,9 @@ export class ApiCoreConfigService {
authLinkProviders: link,
authLoginProviders: login,
features: this.featureFlags,
pubkeyProtocolCommunity: this.pubkeyProtocolCommunity,
pubkeyProtocolEndpoint: this.pubkeyProtocolEndpointPublic ?? this.pubkeyProtocolEndpoint,
pubkeyProtocolSigner: this.pubkeyProtocolSigner?.publicKey.toString(),
resolvers,
}
}
@@ -265,12 +269,20 @@ export class ApiCoreConfigService {
return this.service.get<string>('pubkeyProtocolCluster')
}

get pubkeyProtocolCommunity() {
return this.service.get<string>('pubkeyProtocolCommunity')
}

get pubkeyProtocolEndpoint() {
return this.service.get<string>('pubkeyProtocolEndpoint')
}

get pubkeyProtocolFeePayer() {
return this.service.get<string>('pubkeyProtocolFeePayer')
get pubkeyProtocolEndpointPublic() {
return this.service.get<string>('pubkeyProtocolEndpointPublic')
}

get pubkeyProtocolSigner() {
return this.service.get<Keypair | undefined>('pubkeyProtocolSigner')
}

get prefix() {
12 changes: 10 additions & 2 deletions libs/api/core/data-access/src/lib/config/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Remove trailing slashes from the URLs to avoid double slashes
import { LogLevel } from '@ogma/common'
import { getKeypairFromByteArray } from '@pubkey-protocol/sdk'
import { Keypair } from '@solana/web3.js'

const API_URL = getUrl('API_URL') as string

@@ -76,8 +78,10 @@ export interface ApiCoreConfig {
port: number
// PubKey Protocol
pubkeyProtocolCluster?: string
pubkeyProtocolCommunity?: string
pubkeyProtocolEndpoint?: string
pubkeyProtocolFeePayer?: string
pubkeyProtocolEndpointPublic?: string
pubkeyProtocolSigner?: Keypair | undefined
// Redis
redisUrl: string
// Solana Endpoints
@@ -135,8 +139,12 @@ export function configuration(): ApiCoreConfig {
jwtSecret: process.env['JWT_SECRET'] as string,
port: parseInt(process.env['PORT'] as string, 10) || 3000,
pubkeyProtocolCluster: process.env['PUBKEY_PROTOCOL_CLUSTER'] as string,
pubkeyProtocolCommunity: process.env['PUBKEY_PROTOCOL_COMMUNITY'] as string,
pubkeyProtocolEndpoint: process.env['PUBKEY_PROTOCOL_ENDPOINT'] as string,
pubkeyProtocolFeePayer: process.env['PUBKEY_PROTOCOL_FEE_PAYER'] as string,
pubkeyProtocolEndpointPublic: process.env['PUBKEY_PROTOCOL_ENDPOINT_PUBLIC'] as string,
pubkeyProtocolSigner: process.env['PUBKEY_PROTOCOL_SIGNER']?.length
? getKeypairFromByteArray(JSON.parse(process.env['PUBKEY_PROTOCOL_SIGNER']))
: undefined,
redisUrl: process.env['REDIS_URL'] as string,
solanaCustomEndpoint: process.env['SOLANA_CUSTOM_ENDPOINT'] as string,
solanaDevnetEndpoint: process.env['SOLANA_DEVNET_ENDPOINT'] as string,
6 changes: 6 additions & 0 deletions libs/api/core/data-access/src/lib/entity/app-config.entity.ts
Original file line number Diff line number Diff line change
@@ -18,6 +18,12 @@ export class AppConfig {
authLinkProviders!: IdentityProvider[]
@Field(() => [AppFeature])
features!: AppFeature[]
@Field({ nullable: true })
pubkeyProtocolCommunity?: string
@Field({ nullable: true })
pubkeyProtocolEndpoint?: string
@Field({ nullable: true })
pubkeyProtocolSigner?: string
@Field(() => [NetworkResolver])
resolvers!: NetworkResolver[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Controller, Get, NotFoundException, Param } from '@nestjs/common'
import { IdentityProvider } from '@pubkey-protocol/sdk'
import { ApiCoreProtocolService } from './api-core-protocol.service'

@Controller('protocol')
export class ApiCoreProtocolController {
constructor(private readonly service: ApiCoreProtocolService) {}

@Get('communities')
communities() {
return this.service.getCommunities()
}

@Get('community/:community')
async community(@Param('community') community: string) {
const found = await this.service.getCommunity({ community })
if (found) {
return found
}
throw new NotFoundException('Profile not found')
}

@Get('pointers')
pointers() {
return this.service.getPointers()
}

@Get('profiles')
profiles() {
return this.service.getProfiles()
}

@Get('providers')
providers() {
return this.service.getProviders()
}

@Get('provider/:provider/:providerId')
async profileByProvider(@Param('provider') provider: IdentityProvider, @Param('providerId') providerId: string) {
const found = await this.service.getProfileByProvider({ providerId, provider })
if (found) {
return found
}
throw new NotFoundException('Profile not found')
}

@Get('profile/:username')
async profileByUsername(@Param('username') username: string) {
const found = await this.service.getProfileByUsername({ username })
if (found) {
return found
}
throw new NotFoundException('Profile not found')
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Module } from '@nestjs/common'
import { ApiCoreConfigModule } from '../config/api-core-config.module'
import { ApiCoreProtocolController } from './api-core-protocol.controller'
import { ApiCoreProtocolService } from './api-core-protocol.service'

@Module({
controllers: [ApiCoreProtocolController],
imports: [ApiCoreConfigModule],
providers: [ApiCoreProtocolService],
exports: [ApiCoreProtocolService],
Original file line number Diff line number Diff line change
@@ -1,54 +1,61 @@
import { AnchorProvider } from '@coral-xyz/anchor'
import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
import {
PUBKEY_PROFILE_PROGRAM_ID,
PubKeyIdentityProvider,
AnchorKeypairWallet,
IdentityProvider,
ProfileGetByProvider,
ProfileGetByUsername,
PUBKEY_PROTOCOL_PROGRAM_ID,
PubKeyCommunity,
PubKeyPointer,
PubKeyProfile,
} from '@pubkey-program-library/anchor'
import { AnchorKeypairWallet, GetProfileByUsername, PubKeyProfileSdk } from '@pubkey-program-library/sdk'
import { GetProfileByProvider } from '@pubkey-program-library/sdk/src/lib/pubkey-profile-sdk'
PubkeyProtocolSdk,
} from '@pubkey-protocol/sdk'
import { Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'
import { ApiCoreConfigService } from '../config/api-core-config.service'

function isValidProvider(provider: string): boolean {
return Object.values(PubKeyIdentityProvider).includes(provider as PubKeyIdentityProvider)
return Object.values(IdentityProvider).includes(provider as IdentityProvider)
}

@Injectable()
export class ApiCoreProtocolService implements OnModuleInit {
private readonly logger = new Logger(ApiCoreProtocolService.name)
private feePayer: Keypair | undefined
private signer: Keypair | undefined
private connection: Connection | undefined
private sdk: PubKeyProfileSdk | undefined
private sdk: PubkeyProtocolSdk | undefined

constructor(private readonly config: ApiCoreConfigService) {}

async onModuleInit() {
if (
!this.config.featurePubkeyProtocol ||
!this.config.pubkeyProtocolCluster ||
!this.config.pubkeyProtocolCommunity ||
!this.config.pubkeyProtocolEndpoint ||
!this.config.pubkeyProtocolFeePayer
!this.config.pubkeyProtocolSigner
) {
this.logger.warn(`PubKey Protocol is disabled`)
return
}

this.feePayer = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(this.config.pubkeyProtocolFeePayer)))
this.signer = this.config.pubkeyProtocolSigner
this.connection = new Connection(this.config.pubkeyProtocolEndpoint, 'confirmed')
this.logger.verbose(`PubKey Protocol: Endpoint: ${this.config.pubkeyProtocolEndpoint}`)
const balance = await this.connection.getBalance(this.feePayer.publicKey)
this.logger.verbose(
`PubKey Protocol: Fee payer: ${this.feePayer.publicKey}, balance: ${balance / LAMPORTS_PER_SOL}`,
)
this.sdk = new PubKeyProfileSdk({
const balance = await this.connection.getBalance(this.signer.publicKey)
this.logger.verbose(`PubKey Protocol: Signer: ${this.signer.publicKey}, balance: ${balance / LAMPORTS_PER_SOL}`)
this.sdk = new PubkeyProtocolSdk({
connection: this.connection,
programId: PUBKEY_PROFILE_PROGRAM_ID,
provider: new AnchorProvider(this.connection, new AnchorKeypairWallet(this.feePayer), {
programId: PUBKEY_PROTOCOL_PROGRAM_ID,
provider: new AnchorProvider(this.connection, new AnchorKeypairWallet(this.signer), {
commitment: this.connection.commitment,
}),
})
this.logger.verbose(`PubKey Protocol: SDK Initialized`)
const community = await this.ensureSdk().communityGet({ community: this.config.pubkeyProtocolCommunity })
this.logger.verbose(`PubKey Protocol: SDK Initialized. Community: ${community.name} (${community.slug})`)
if (!community?.signers.includes(this.signer.publicKey.toString())) {
throw new Error(`Signer is not a signer for the community ${community.name} (${community.slug})`)
}
}

private ensureSdk() {
@@ -59,26 +66,34 @@ export class ApiCoreProtocolService implements OnModuleInit {
return this.sdk
}

async getProfileByProvider(options: GetProfileByProvider): Promise<PubKeyProfile | null> {
async getCommunity(options: { community: string }): Promise<PubKeyCommunity> {
return this.ensureSdk().communityGet(options)
}

async getCommunities(): Promise<PubKeyCommunity[]> {
return this.ensureSdk().communityGetAll()
}

async getProfileByProvider(options: ProfileGetByProvider): Promise<PubKeyProfile | null> {
if (!isValidProvider(options.provider)) {
throw new Error(`Invalid provider: ${options.provider}`)
}
return this.ensureSdk().getProfileByProviderNullable(options)
return this.ensureSdk().profileGetByProviderNullable(options)
}

async getProfileByUsername(options: GetProfileByUsername): Promise<PubKeyProfile | null> {
return this.ensureSdk().getProfileByUsernameNullable(options)
async getProfileByUsername(options: ProfileGetByUsername): Promise<PubKeyProfile | null> {
return this.ensureSdk().profileGetByUsernameNullable(options)
}

async getProfiles(): Promise<PubKeyProfile[]> {
return this.ensureSdk().getProfiles()
return this.ensureSdk().profileGetAll()
}

getProviders() {
return Object.values(PubKeyIdentityProvider)
return Object.values(IdentityProvider)
}

async getPointers(): Promise<PubKeyPointer[]> {
return this.ensureSdk().getPointers()
return this.ensureSdk().pointerGetAll()
}
}
3 changes: 1 addition & 2 deletions libs/api/core/feature/src/lib/api-core-feature.module.ts
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@ import { ApiNetworkTokenFeatureModule } from '@pubkey-link/api-network-token-fea
import { ApiRoleFeatureModule } from '@pubkey-link/api-role-feature'
import { ApiSnapshotFeatureModule } from '@pubkey-link/api-snapshot-feature'
import { ApiUserFeatureModule } from '@pubkey-link/api-user-feature'
import { ApiCoreProtocolController } from './api-core-protocol.controller'
import { ApiCoreController } from './api-core.controller'
import { ApiCoreResolver } from './api-core.resolver'

@@ -36,7 +35,7 @@ const imports = [
]

@Module({
controllers: [ApiCoreController, ApiCoreProtocolController],
controllers: [ApiCoreController],
imports: [...imports],
providers: [ApiCoreResolver],
})
33 changes: 0 additions & 33 deletions libs/api/core/feature/src/lib/api-core-protocol.controller.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import { Injectable, Logger } from '@nestjs/common'
import { OnEvent } from '@nestjs/event-emitter'
import { Network, NetworkCluster } from '@prisma/client'
import { ApiCoreService } from '@pubkey-link/api-core-data-access'
import { AnchorKeypairWallet } from '@pubkey-program-library/sdk'
import { AnchorKeypairWallet } from '@pubkey-protocol/sdk'
import { Connection, Keypair } from '@solana/web3.js'
import { ChainId, Client } from '@solflare-wallet/utl-sdk'
import {
Loading