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
Show file tree
Hide file tree
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
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions api-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ type AppConfig {
authLinkProviders: [IdentityProvider!]
authLoginProviders: [IdentityProvider!]
features: [AppFeature!]!
pubkeyProtocolCommunity: String
pubkeyProtocolEndpoint: String
pubkeyProtocolSigner: String
resolvers: [NetworkResolver!]!
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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() {
Expand Down
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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
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
Expand Up @@ -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[]
}
Expand Down
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],
Expand Down
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() {
Expand All @@ -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
Expand Up @@ -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'

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

@Module({
controllers: [ApiCoreController, ApiCoreProtocolController],
controllers: [ApiCoreController],
imports: [...imports],
providers: [ApiCoreResolver],
})
Expand Down
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
Expand Up @@ -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 {
Expand Down
Loading
Loading