pubkey.ts 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import BN from "bn.js";
  2. import { sha256 as sha256Sync } from "js-sha256";
  3. import { PublicKey } from "@solana/web3.js";
  4. import { Address, translateAddress } from "../program/common";
  5. // Sync version of web3.PublicKey.createWithSeed.
  6. export function createWithSeedSync(
  7. fromPublicKey: PublicKey,
  8. seed: string,
  9. programId: PublicKey
  10. ): PublicKey {
  11. const buffer = Buffer.concat([
  12. fromPublicKey.toBuffer(),
  13. Buffer.from(seed),
  14. programId.toBuffer(),
  15. ]);
  16. const hash = sha256Sync.digest(buffer);
  17. return new PublicKey(Buffer.from(hash));
  18. }
  19. // Sync version of web3.PublicKey.createProgramAddress.
  20. export function createProgramAddressSync(
  21. seeds: Array<Buffer | Uint8Array>,
  22. programId: PublicKey
  23. ): PublicKey {
  24. const MAX_SEED_LENGTH = 32;
  25. let buffer = Buffer.alloc(0);
  26. seeds.forEach(function (seed) {
  27. if (seed.length > MAX_SEED_LENGTH) {
  28. throw new TypeError(`Max seed length exceeded`);
  29. }
  30. buffer = Buffer.concat([buffer, toBuffer(seed)]);
  31. });
  32. buffer = Buffer.concat([
  33. buffer,
  34. programId.toBuffer(),
  35. Buffer.from("ProgramDerivedAddress"),
  36. ]);
  37. let hash = sha256Sync(new Uint8Array(buffer));
  38. let publicKeyBytes = new BN(hash, 16).toArray(undefined, 32);
  39. if (PublicKey.isOnCurve(new Uint8Array(publicKeyBytes))) {
  40. throw new Error(`Invalid seeds, address must fall off the curve`);
  41. }
  42. return new PublicKey(publicKeyBytes);
  43. }
  44. // Sync version of web3.PublicKey.findProgramAddress.
  45. export function findProgramAddressSync(
  46. seeds: Array<Buffer | Uint8Array>,
  47. programId: PublicKey
  48. ): [PublicKey, number] {
  49. let nonce = 255;
  50. let address: PublicKey | undefined;
  51. while (nonce != 0) {
  52. try {
  53. const seedsWithNonce = seeds.concat(Buffer.from([nonce]));
  54. address = createProgramAddressSync(seedsWithNonce, programId);
  55. } catch (err) {
  56. if (err instanceof TypeError) {
  57. throw err;
  58. }
  59. nonce--;
  60. continue;
  61. }
  62. return [address, nonce];
  63. }
  64. throw new Error(`Unable to find a viable program address nonce`);
  65. }
  66. const toBuffer = (arr: Buffer | Uint8Array | Array<number>): Buffer => {
  67. if (arr instanceof Buffer) {
  68. return arr;
  69. } else if (arr instanceof Uint8Array) {
  70. return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
  71. } else {
  72. return Buffer.from(arr);
  73. }
  74. };
  75. export async function associated(
  76. programId: Address,
  77. ...args: Array<PublicKey | Buffer>
  78. ): Promise<PublicKey> {
  79. let seeds = [Buffer.from([97, 110, 99, 104, 111, 114])]; // b"anchor".
  80. args.forEach((arg) => {
  81. seeds.push(
  82. // @ts-ignore
  83. arg.buffer !== undefined ? arg : translateAddress(arg).toBuffer()
  84. );
  85. });
  86. const [assoc] = await PublicKey.findProgramAddress(
  87. seeds,
  88. translateAddress(programId)
  89. );
  90. return assoc;
  91. }