diff --git a/js/package-lock.json b/js/package-lock.json index f3974df..a8ee77f 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bonfida/spl-name-service", - "version": "2.0.2", + "version": "2.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@bonfida/spl-name-service", - "version": "2.0.2", + "version": "2.0.4", "license": "MIT", "dependencies": { "@bonfida/sns-records": "0.0.1-alpha.8", diff --git a/js/package.json b/js/package.json index 65d76d3..466df5f 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "@bonfida/spl-name-service", - "version": "2.0.3", + "version": "2.0.4", "license": "MIT", "files": [ "dist" diff --git a/js/src/record_v2.ts b/js/src/record_v2.ts index 064122d..0977b0a 100644 --- a/js/src/record_v2.ts +++ b/js/src/record_v2.ts @@ -47,7 +47,7 @@ export const ETH_ROA_RECORDS = new Set([ export const verifyStaleness = async ( connection: Connection, record: Record, - domain: string + domain: string, ) => { const recordKey = getRecordV2Key(domain, record); const owner = await resolve(connection, domain); @@ -76,7 +76,7 @@ export const verifyRightOfAssociation = async ( connection: Connection, record: Record, domain: string, - verifier?: Buffer + verifier?: Buffer, ) => { const recordKey = getRecordV2Key(domain, record); const recordObj = await SnsRecord.retrieve(connection, recordKey); @@ -139,7 +139,7 @@ export const SELF_SIGNED = new Set([ */ export const deserializeRecordV2Content = ( content: Buffer, - record: Record + record: Record, ): string => { const utf8Encoded = UTF8_ENCODED.has(record); @@ -171,7 +171,7 @@ export const deserializeRecordV2Content = ( */ export const serializeRecordV2Content = ( content: string, - record: Record + record: Record, ): Buffer => { const utf8Encoded = UTF8_ENCODED.has(record); if (utf8Encoded) { @@ -213,3 +213,83 @@ export const getRecordV2Key = (domain: string, record: Record): PublicKey => { const hashed = getHashedNameSync(`\x02`.concat(record as string)); return getNameAccountKeySync(hashed, CENTRAL_STATE_SNS_RECORDS, pubkey); }; + +export interface GetRecordV2Options { + deserialize?: boolean; +} + +export interface RecordResult { + retrievedRecord: SnsRecord; + record: Record; + deserializedContent?: string; +} + +export type SingleRecordResult = Omit; + +/** + * This function can be used to retrieve a specified record V2 for the given domain name + * @param connection The Solana RPC connection object + * @param domain The .sol domain name + * @param record The record to search for + * @returns + */ +export async function getRecordV2( + connection: Connection, + domain: string, + record: Record, + options: GetRecordV2Options = {}, +): Promise { + const pubkey = getRecordV2Key(domain, record); + const retrievedRecord = await SnsRecord.retrieve(connection, pubkey); + + if (options.deserialize) { + return { + retrievedRecord, + deserializedContent: deserializeRecordV2Content( + retrievedRecord.getContent(), + record, + ), + }; + } + + return { retrievedRecord }; +} + +/** + * This function can be used to retrieve multiple records V2 for a given domain + * @param connection The Solana RPC connection object + * @param domain The .sol domain name + * @param record The record to search for + * @returns + */ +export async function getMultipleRecordsV2( + connection: Connection, + domain: string, + records: Record[], + options: GetRecordV2Options = {}, +): Promise<(RecordResult | undefined)[]> { + const pubkeys = records.map((record) => getRecordV2Key(domain, record)); + const retrievedRecords = await SnsRecord.retrieveBatch(connection, pubkeys); + + if (options.deserialize) { + return retrievedRecords.map((e, idx) => { + if (!e) return undefined; + return { + retrievedRecord: e, + record: records[idx], + deserializedContent: deserializeRecordV2Content( + e.getContent(), + records[idx], + ), + }; + }); + } + + return retrievedRecords.map((e, idx) => { + if (!e) return undefined; + return { + retrievedRecord: e, + record: records[idx], + }; + }); +} diff --git a/js/tests/records-v2.test.ts b/js/tests/records-v2.test.ts index 373fb26..56c8d94 100644 --- a/js/tests/records-v2.test.ts +++ b/js/tests/records-v2.test.ts @@ -2,6 +2,8 @@ require("dotenv").config(); import { test, expect } from "@jest/globals"; import { deserializeRecordV2Content, + getMultipleRecordsV2, + getRecordV2, serializeRecordV2Content, } from "../src/record_v2"; import { Record } from "../src/types/record"; @@ -263,3 +265,39 @@ test("Create record for sub & update & verify staleness & delete", async () => { const { value } = await connection.simulateTransaction(tx); expect(value.err).toBe(null); }); + +test("getRecordV2", async () => { + const domain = "wallet-guide-9.sol"; + const items = [ + { record: Record.IPFS, value: "ipfs://test" }, + { record: Record.Email, value: "test@gmail.com" }, + { record: Record.Url, value: "https://google.com" }, + ]; + for (let item of items) { + const res = await getRecordV2(connection, domain, item.record, { + deserialize: true, + }); + expect(res.deserializedContent).toBe(item.value); + } +}); + +test("getMultipleRecordsV2", async () => { + const domain = "wallet-guide-9.sol"; + const items = [ + { record: Record.IPFS, value: "ipfs://test" }, + { record: Record.Email, value: "test@gmail.com" }, + { record: Record.Url, value: "https://google.com" }, + ]; + const res = await getMultipleRecordsV2( + connection, + domain, + items.map((e) => e.record), + { + deserialize: true, + }, + ); + for (let i = 0; i < items.length; i++) { + expect(items[i].value).toBe(res[i]?.deserializedContent); + expect(items[i].record).toBe(res[i]?.record); + } +});