accounts.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { AccountsCoder } from "../index.js";
  2. import { Idl, IdlTypeDef } from "../../idl.js";
  3. import * as BufferLayout from "buffer-layout";
  4. import { NONCE_ACCOUNT_LENGTH, PublicKey } from "@solana/web3.js";
  5. import { accountSize } from "../common.js";
  6. export class SystemAccountsCoder<A extends string = string>
  7. implements AccountsCoder
  8. {
  9. constructor(private idl: Idl) {}
  10. public async encode<T = any>(accountName: A, account: T): Promise<Buffer> {
  11. switch (accountName) {
  12. case "nonce": {
  13. const buffer = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
  14. const len = NONCE_ACCOUNT_LAYOUT.encode(account, buffer);
  15. return buffer.slice(0, len);
  16. }
  17. default: {
  18. throw new Error(`Invalid account name: ${accountName}`);
  19. }
  20. }
  21. }
  22. public decode<T = any>(accountName: A, ix: Buffer): T {
  23. return this.decodeUnchecked(accountName, ix);
  24. }
  25. public decodeUnchecked<T = any>(accountName: A, ix: Buffer): T {
  26. switch (accountName) {
  27. case "nonce": {
  28. return decodeNonceAccount(ix);
  29. }
  30. default: {
  31. throw new Error(`Invalid account name: ${accountName}`);
  32. }
  33. }
  34. }
  35. // TODO: this won't use the appendData.
  36. public memcmp(accountName: A, _appendData?: Buffer): any {
  37. switch (accountName) {
  38. case "nonce": {
  39. return {
  40. dataSize: NONCE_ACCOUNT_LENGTH,
  41. };
  42. }
  43. default: {
  44. throw new Error(`Invalid account name: ${accountName}`);
  45. }
  46. }
  47. }
  48. public size(idlAccount: IdlTypeDef): number {
  49. return accountSize(this.idl, idlAccount) ?? 0;
  50. }
  51. }
  52. function decodeNonceAccount<T = any>(ix: Buffer): T {
  53. return NONCE_ACCOUNT_LAYOUT.decode(ix) as T;
  54. }
  55. class WrappedLayout<T, U> extends BufferLayout.Layout<U> {
  56. layout: BufferLayout.Layout<T>;
  57. decoder: (data: T) => U;
  58. encoder: (src: U) => T;
  59. constructor(
  60. layout: BufferLayout.Layout<T>,
  61. decoder: (data: T) => U,
  62. encoder: (src: U) => T,
  63. property?: string
  64. ) {
  65. super(layout.span, property);
  66. this.layout = layout;
  67. this.decoder = decoder;
  68. this.encoder = encoder;
  69. }
  70. decode(b: Buffer, offset?: number): U {
  71. return this.decoder(this.layout.decode(b, offset));
  72. }
  73. encode(src: U, b: Buffer, offset?: number): number {
  74. return this.layout.encode(this.encoder(src), b, offset);
  75. }
  76. getSpan(b: Buffer, offset?: number): number {
  77. return this.layout.getSpan(b, offset);
  78. }
  79. }
  80. function publicKey(property?: string): BufferLayout.Layout<PublicKey> {
  81. return new WrappedLayout(
  82. BufferLayout.blob(32),
  83. (b: Buffer) => new PublicKey(b),
  84. (key: PublicKey) => key.toBuffer(),
  85. property
  86. );
  87. }
  88. const NONCE_ACCOUNT_LAYOUT = BufferLayout.struct([
  89. BufferLayout.u32("version"),
  90. BufferLayout.u32("state"),
  91. publicKey("authorizedPubkey"),
  92. publicKey("nonce"),
  93. BufferLayout.struct(
  94. [BufferLayout.nu64("lamportsPerSignature")],
  95. "feeCalculator"
  96. ),
  97. ]);