Skip to content

Commit 7053ea6

Browse files
committed
feat: support creating roles based on Realms governance power
1 parent 6b81970 commit 7053ea6

28 files changed

+264
-12
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ FEATURE_PRIVATE_PROFILES=false
6666
#FEATURE_RESOLVER_SOLANA_FUNGIBLE=true
6767
# Enable resolver for Solana Non-Fungible Tokens
6868
#FEATURE_RESOLVER_SOLANA_NON_FUNGIBLE=true
69+
# Enable resolver for Solana Realms Voters
70+
#FEATURE_RESOLVER_SOLANA_REALMS=true
6971
# Enable resolver for Solana Validators
7072
#FEATURE_RESOLVER_SOLANA_VALIDATOR=false
7173
# Enable Network Asset Verification

api-schema.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ enum NetworkResolver {
629629
Anybodies
630630
SolanaFungible
631631
SolanaNonFungible
632+
SolanaRealms
632633
SolanaValidator
633634
}
634635

@@ -658,6 +659,7 @@ type NetworkTokenPaging {
658659
enum NetworkTokenType {
659660
Fungible
660661
NonFungible
662+
RealmsVoter
661663
Validator
662664
}
663665

libs/api/core/data-access/src/lib/config/api-core-config.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export class ApiCoreConfigService {
3939
if (this.featureResolverSolanaNonFungible) {
4040
resolvers.push(NetworkResolver.SolanaNonFungible)
4141
}
42+
if (this.featureResolverSolanaRealms) {
43+
resolvers.push(NetworkResolver.SolanaRealms)
44+
}
4245
if (this.featureResolverSolanaValidator) {
4346
resolvers.push(NetworkResolver.SolanaValidator)
4447
}
@@ -252,6 +255,10 @@ export class ApiCoreConfigService {
252255
return this.service.get<boolean>('featureResolverSolanaNonFungible')
253256
}
254257

258+
get featureResolverSolanaRealms() {
259+
return this.service.get<boolean>('featureResolverSolanaRealms')
260+
}
261+
255262
get featureResolverSolanaValidator() {
256263
return this.service.get<boolean>('featureResolverSolanaValidator')
257264
}

libs/api/core/data-access/src/lib/config/configuration.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export interface ApiCoreConfig {
7070
featurePubkeyProtocol: boolean
7171
featureResolverSolanaFungible: boolean
7272
featureResolverSolanaNonFungible: boolean
73+
featureResolverSolanaRealms: boolean
7374
featureResolverSolanaValidator: boolean
7475
// Host
7576
host: string
@@ -140,6 +141,7 @@ export function configuration(): ApiCoreConfig {
140141
featurePubkeyProtocol: process.env['FEATURE_PUBKEY_PROTOCOL'] === 'true',
141142
featureResolverSolanaFungible: process.env['FEATURE_RESOLVER_SOLANA_FUNGIBLE'] === 'true',
142143
featureResolverSolanaNonFungible: process.env['FEATURE_RESOLVER_SOLANA_NON_FUNGIBLE'] === 'true',
144+
featureResolverSolanaRealms: process.env['FEATURE_RESOLVER_SOLANA_REALMS'] === 'true',
143145
featureResolverSolanaValidator: process.env['FEATURE_RESOLVER_SOLANA_VALIDATOR'] === 'true',
144146
host: process.env['HOST'] as string,
145147
logColor: process.env['LOG_COLOR'] === 'true',

libs/api/core/data-access/src/lib/config/validation-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const validationSchema = Joi.object({
4646
FEATURE_PUBKEY_PROTOCOL: Joi.boolean().default(false),
4747
FEATURE_RESOLVER_SOLANA_FUNGIBLE: Joi.boolean().default(true),
4848
FEATURE_RESOLVER_SOLANA_NON_FUNGIBLE: Joi.boolean().default(true),
49+
FEATURE_RESOLVER_SOLANA_REALMS: Joi.boolean().default(true),
4950
FEATURE_RESOLVER_SOLANA_VALIDATOR: Joi.boolean().default(false),
5051
FEATURE_VERIFY_NETWORK_ASSETS: Joi.boolean().default(false),
5152
GRAPHQL_PLAYGROUND: Joi.boolean().default(false),

libs/api/network-asset/data-access/src/lib/api-network-asset-sync.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ export class ApiNetworkAssetSyncService {
190190
// Get the fungible and non-fungible tokens for the cluster
191191
const solanaFungibleTokens: NetworkToken[] = tokens.filter((t) => t.type === NetworkTokenType.Fungible)
192192
const solanaNonFungibleTokens: NetworkToken[] = tokens.filter((t) => t.type === NetworkTokenType.NonFungible)
193+
const solanaRealmsVoterTokens: NetworkToken[] = tokens.filter((t) => t.type === NetworkTokenType.RealmsVoter)
193194

194195
this.logger.verbose(
195-
`[${cluster}] syncIdentity: Syncing assets for ${owner} on ${cluster}, solanaFungibleTokens: ${solanaFungibleTokens.length}, solanaNonFungibleTokens: ${solanaNonFungibleTokens.length},`,
196+
`[${cluster}] syncIdentity: Syncing assets for ${owner} on ${cluster}, solanaFungibleTokens: ${solanaFungibleTokens.length}, solanaNonFungibleTokens: ${solanaNonFungibleTokens.length}, solanaRealmsVoterTokens: ${solanaRealmsVoterTokens.length},`,
196197
)
197198
// TODO: Move the resolveNetworkAssets function into a separate method
198199
let assets: NetworkAssetInput[] = []
@@ -202,6 +203,7 @@ export class ApiNetworkAssetSyncService {
202203
owner,
203204
solanaFungibleTokens,
204205
solanaNonFungibleTokens,
206+
solanaRealmsVoterTokens,
205207
})
206208
} catch (error) {
207209
this.logger.error(`[${cluster}] syncIdentity: Error syncing assets for ${owner} on ${cluster}: ${error}`)

libs/api/network-asset/data-access/src/lib/api-network-asset.service.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,23 @@ export class ApiNetworkAssetService {
5353
},
5454
})
5555
}
56+
57+
async getRealmsVoterAssetsForOwners({
58+
accounts,
59+
cluster,
60+
owners,
61+
}: {
62+
accounts: string[]
63+
cluster: NetworkCluster
64+
owners: string[]
65+
}) {
66+
return this.core.data.networkAsset.findMany({
67+
where: {
68+
cluster,
69+
group: { in: accounts },
70+
owner: { in: owners },
71+
type: NetworkTokenType.RealmsVoter,
72+
},
73+
})
74+
}
5675
}

libs/api/network-token/data-access/src/lib/api-network-token-data.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { OnEvent } from '@nestjs/event-emitter'
33
import { NetworkCluster, NetworkToken, NetworkTokenType, Prisma } from '@prisma/client'
44
import { ApiCoreService, EVENT_APP_STARTED, PagingInputFields } from '@pubkey-link/api-core-data-access'
55
import { ApiNetworkService, EVENT_NETWORKS_PROVISIONED } from '@pubkey-link/api-network-data-access'
6-
import { getNetworkTokenType } from '@pubkey-link/api-network-util'
6+
import { getNetworkTokenType, REALMS_PROGRAM_ID } from '@pubkey-link/api-network-util'
77
import { SystemProgram } from '@solana/web3.js'
88
import { AdminUpdateNetworkTokenInput } from './dto/admin-update-network-token.input'
99
import { NetworkTokenPaging } from './entity/network-token.entity'
@@ -89,6 +89,8 @@ export class ApiNetworkTokenDataService {
8989
const type =
9090
info.owner.toString() === 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d'
9191
? NetworkTokenType.NonFungible
92+
: info.owner.toString() === REALMS_PROGRAM_ID
93+
? NetworkTokenType.RealmsVoter
9294
: getNetworkTokenType(info?.data?.program)
9395

9496
const data: Prisma.NetworkTokenCreateInput = {

libs/api/network/data-access/src/lib/api-network.data-access.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ApiNetworkProvisionService } from './provision/api-network-provision.se
88
import { ApiNetworkResolverSolanaFungibleService } from './resolver/api-network-resolver-solana-fungible.service'
99
import { ApiNetworkResolverSolanaNonFungibleService } from './resolver/api-network-resolver-solana-non-fungible.service'
1010
import { ApiNetworkResolverService } from './resolver/api-network-resolver.service'
11+
import { ApiNetworkResolverRealmsVoterService } from './resolver/api-network-resolver-realms-voter.service'
1112

1213
@Module({
1314
imports: [ApiCoreDataAccessModule],
@@ -16,6 +17,7 @@ import { ApiNetworkResolverService } from './resolver/api-network-resolver.servi
1617
ApiNetworkDataAdminService,
1718
ApiNetworkDataService,
1819
ApiNetworkProvisionService,
20+
ApiNetworkResolverRealmsVoterService,
1921
ApiNetworkResolverService,
2022
ApiNetworkResolverSolanaFungibleService,
2123
ApiNetworkResolverSolanaNonFungibleService,

libs/api/network/data-access/src/lib/api-network.service.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { DasApiAsset } from '@metaplex-foundation/digital-asset-standard-api'
22
import { publicKey } from '@metaplex-foundation/umi'
33
import { Injectable, Logger } from '@nestjs/common'
4-
import { NetworkCluster, Prisma } from '@prisma/client'
4+
import { NetworkCluster, NetworkTokenType, Prisma } from '@prisma/client'
55
import { ApiCoreService } from '@pubkey-link/api-core-data-access'
6-
import { getMetadataProgram, getNetworkTokenType, WNS_PROGRAM_ID } from '@pubkey-link/api-network-util'
6+
import {
7+
getMetadataProgram,
8+
getNetworkTokenType,
9+
getRealm,
10+
REALMS_PROGRAM_ID,
11+
WNS_PROGRAM_ID,
12+
} from '@pubkey-link/api-network-util'
713
import { getTokenMetadata, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token'
814
import { TokenMetadata } from '@solana/spl-token-metadata'
915
import { AccountInfo, BlockhashWithExpiryBlockHeight, ParsedAccountData, PublicKey } from '@solana/web3.js'
@@ -47,6 +53,26 @@ export class ApiNetworkService {
4753
return res.blockhash
4854
}
4955

56+
async getRealmsMetadata({
57+
cluster,
58+
account,
59+
}: {
60+
cluster: NetworkCluster
61+
account: PublicKey | string
62+
}): Promise<Prisma.NetworkTokenCreateInput> {
63+
const found = await getRealm({ realm: account.toString() })
64+
if (!found) {
65+
throw new Error(`Realm not found`)
66+
}
67+
return {
68+
account: account.toString(),
69+
type: NetworkTokenType.RealmsVoter,
70+
name: found.name,
71+
program: found.program,
72+
network: { connect: { cluster } },
73+
raw: found,
74+
}
75+
}
5076
async getAccountInfo({ cluster, account }: { cluster: NetworkCluster; account: PublicKey | string }) {
5177
return this.cluster
5278
.getConnection(cluster)
@@ -70,6 +96,11 @@ export class ApiNetworkService {
7096
}
7197

7298
async getAllTokenMetadata({ cluster, account }: { cluster: NetworkCluster; account: string }) {
99+
const info = await this.getAccountInfo({ account, cluster })
100+
if (info.owner.toString() === REALMS_PROGRAM_ID) {
101+
return this.getRealmsMetadata({ account, cluster })
102+
}
103+
73104
const asset = await this.getAsset({ cluster: cluster, account: account })
74105

75106
// If we have the group pointer, we can fetch the members of the group to create a list of mints

0 commit comments

Comments
 (0)