Creating and writing to new registries

We’re working on a registry of content for our new project and I was hoping to embed program-level triggers to use for content indexing and so on.

Is there an example that shows how to create a new name-service registration?

So far, I’ve been able to hack together some calls with the createInstruction and getHashedName functions listed here: https://github.com/solana-labs/solana-program-library/blob/482a9281f6afcf149870cd60d9c2742a1cdda9bc/name-service/js/src/instructions.ts#L5

I’m missing a few key points though, like how to predict the Lamports and Space values, and how to connect a sub-registry for subdomains

Any help would be really appreciated :slight_smile:

  • To create a new registry use the create instruction. To get the name account key use getHashedName followed by getNameAccountKey

  • For the size you need to understand how the NameRegistry works https://github.com/Bonfida/solana-name-service-guide#name-registry. It’s made of a fixed length header of 96 bytes and an arbitrary size data. So the size is NameRegistry::LEN + size_of(data) = 96 + size_of(data). You deduce the required lamports from this.

  • A sub registry is simply a registry created with a parent. So the only thing that changes is that you pass a parent key in the create instruction

Thanks, this helped a lot.

Here’s what I have right now:

(async () => {

  // Connect to cluster
  var connection = new web3.Connection(
    "https://api.devnet.solana.com", // change this to use a different network
    'confirmed',
  );

  // Generate a new wallet keypair and airdrop SOL
  // var fromWallet = web3.Keypair.fromSecretKey(Uint8Array.from(json));
   
  var fromWallet = await web3.Keypair.generate()

  var fromAirdropSignature = await connection.requestAirdrop(
    fromWallet.publicKey,
    web3.LAMPORTS_PER_SOL,
  );

  // wait for airdrop confirmation
  await connection.confirmTransaction(fromAirdropSignature);


  console.log('got wallet ', fromWallet.publicKey.toString())

  // * optional airdrop
  const nameToRegister = "@alex";
  const hash =  await nameService.getHashedName(nameToRegister);
  const name = await nameService.getNameAccountKey(hash);
  const lamports = new nameService.Numberu32 (10);
  const space = new nameService.Numberu32 (96 + nameToRegister.length);

  //create new token mint
  let newInstruction = {
    nameProgramId: nameService.NAME_PROGRAM_ID,
    systemProgramId: web3.SYSTEM_PROGRAM_ID,
    nameKey: name,
    nameOwnerKey: fromWallet.publicKey,
    payerKey: fromWallet.publicKey._keypair,
    hashed_name: hash,
    lamports: lamports,
    space: space,
    nameClassKey: null,
    nameParent: null,
    nameParentOwner: null
  };
  let argumentArray = []
  Object.keys(newInstruction).forEach(key => {
      argumentArray.push(newInstruction[key])
  })

  let registerInstruction = await nameService.createInstruction.apply(null, argumentArray);

  // Add token transfer instructions to transaction
  var transaction = new web3.Transaction().add( registerInstruction );
  transaction.feePayer = fromWallet.publicKey;
  console.log("*** transaction ***", transaction)
  try {
    // Sign transaction, broadcast, and confirm
    var signature = await web3.sendAndConfirmTransaction(
      connection,
      transaction,
      [fromWallet]
    );
    console.log('SIGNATURE', signature);
  } catch (err) {
    console.error(err)
  }

  

})();

The issue is, when I run this, I get an error in the tx signature step, saying TypeError: Cannot read property 'toBase58' of undefined which seems to indicate an issue with the underlying createInstruction call - am I missing a step here?

The printout of the starred ‘transaction’ is this:

Transaction {
  signatures: [],
  feePayer: PublicKey {
    _bn: <BN: b34a511c3d5521922e10b24cffb4e355f38028f9df622db0af446fa41522bd24>
  },
  instructions: [
    TransactionInstruction {
      keys: [Array],
      programId: [PublicKey],
      data: <Buffer 00 20 00 00 00 4d 7e d3 5c 2e 45 12 91 b1 46 ce 4f db 50 9b 47 16 92 bc c2 02 92 d8 23 54 fa 55 51 fe 78 00 8d 0a 00 00 00 6c 00 00 00>
    }
  ],
  recentBlockhash: undefined,
  nonceInfo: undefined
}

Just to clarify, I’m trying to implement a call to CreateInstruction, which looks like this:

import { PublicKey, TransactionInstruction } from '@solana/web3.js';

import { Numberu32, Numberu64 } from './utils';

export function createInstruction(
  nameProgramId: PublicKey,
  systemProgramId: PublicKey,
  nameKey: PublicKey,
  nameOwnerKey: PublicKey,
  payerKey: PublicKey,
  hashed_name: Buffer,
  lamports: Numberu64,
  space: Numberu32,
  nameClassKey?: PublicKey,
  nameParent?: PublicKey,
  nameParentOwner?: PublicKey
): TransactionInstruction {
  const buffers = [
    Buffer.from(Int8Array.from([0])),
    new Numberu32(hashed_name.length).toBuffer(),
    hashed_name,
    lamports.toBuffer(),
    space.toBuffer(),
  ];

  const data = Buffer.concat(buffers);

  const keys = [
    {
      pubkey: systemProgramId,
      isSigner: false,
      isWritable: false,
    },
    {
      pubkey: payerKey,
      isSigner: true,
      isWritable: true,
    },
    {
      pubkey: nameKey,
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: nameOwnerKey,
      isSigner: false,
      isWritable: false,
    },
  ];

  if (nameClassKey) {
    keys.push({
      pubkey: nameClassKey,
      isSigner: true,
      isWritable: false,
    });
  } else {
    keys.push({
      pubkey: new PublicKey(Buffer.alloc(32)),
      isSigner: false,
      isWritable: false,
    });
  }
  if (nameParent) {
    keys.push({
      pubkey: nameParent,
      isSigner: false,
      isWritable: false,
    });
  } else {
    keys.push({
      pubkey: new PublicKey(Buffer.alloc(32)),
      isSigner: false,
      isWritable: false,
    });
  }
  if (nameParentOwner) {
    keys.push({
      pubkey: nameParentOwner,
      isSigner: true,
      isWritable: false,
    });
  }

  return new TransactionInstruction({
    keys,
    programId: nameProgramId,
    data,
  });
}

export function updateInstruction(
  nameProgramId: PublicKey,
  nameAccountKey: PublicKey,
  offset: Numberu32,
  input_data: Buffer,
  nameUpdateSigner: PublicKey
): TransactionInstruction {
  const buffers = [
    Buffer.from(Int8Array.from([1])),
    offset.toBuffer(),
    new Numberu32(input_data.length).toBuffer(),
    input_data,
  ];

  const data = Buffer.concat(buffers);
  const keys = [
    {
      pubkey: nameAccountKey,
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: nameUpdateSigner,
      isSigner: true,
      isWritable: false,
    },
  ];

  return new TransactionInstruction({
    keys,
    programId: nameProgramId,
    data,
  });
}

export function transferInstruction(
  nameProgramId: PublicKey,
  nameAccountKey: PublicKey,
  newOwnerKey: PublicKey,
  currentNameOwnerKey: PublicKey,
  nameClassKey?: PublicKey
): TransactionInstruction {
  const buffers = [Buffer.from(Int8Array.from([2])), newOwnerKey.toBuffer()];

  const data = Buffer.concat(buffers);

  const keys = [
    {
      pubkey: nameAccountKey,
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: currentNameOwnerKey,
      isSigner: true,
      isWritable: false,
    },
  ];

  if (nameClassKey) {
    keys.push({
      pubkey: nameClassKey,
      isSigner: true,
      isWritable: false,
    });
  }

  return new TransactionInstruction({
    keys,
    programId: nameProgramId,
    data,
  });
}

export function deleteInstruction(
  nameProgramId: PublicKey,
  nameAccountKey: PublicKey,
  refundTargetKey: PublicKey,
  nameOwnerKey: PublicKey
): TransactionInstruction {
  const buffers = [Buffer.from(Int8Array.from([3]))];

  const data = Buffer.concat(buffers);
  const keys = [
    {
      pubkey: nameAccountKey,
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: nameOwnerKey,
      isSigner: true,
      isWritable: false,
    },
    {
      pubkey: refundTargetKey,
      isSigner: false,
      isWritable: true,
    },
  ];

  return new TransactionInstruction({
    keys,
    programId: nameProgramId,
    data,
  });
}

Ah… Duh sorry. I just found the example in the twitter.ts file in the repo: https://github.com/solana-labs/solana-program-library/blob/master/name-service/js/src/twitter.ts

All set now, thanks!

Let me know if you have any other question!

1 Like