idl.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import camelCase from "camelcase";
  2. import { Layout } from "buffer-layout";
  3. import * as borsh from "@project-serum/borsh";
  4. import { IdlField, IdlTypeDef, IdlEnumVariant, IdlType } from "../idl";
  5. import { IdlError } from "../error";
  6. export class IdlCoder {
  7. public static fieldLayout(field: IdlField, types?: IdlTypeDef[]): Layout {
  8. const fieldName =
  9. field.name !== undefined ? camelCase(field.name) : undefined;
  10. switch (field.type) {
  11. case "bool": {
  12. return borsh.bool(fieldName);
  13. }
  14. case "u8": {
  15. return borsh.u8(fieldName);
  16. }
  17. case "i8": {
  18. return borsh.i8(fieldName);
  19. }
  20. case "u16": {
  21. return borsh.u16(fieldName);
  22. }
  23. case "i16": {
  24. return borsh.i16(fieldName);
  25. }
  26. case "u32": {
  27. return borsh.u32(fieldName);
  28. }
  29. case "i32": {
  30. return borsh.i32(fieldName);
  31. }
  32. case "u64": {
  33. return borsh.u64(fieldName);
  34. }
  35. case "i64": {
  36. return borsh.i64(fieldName);
  37. }
  38. case "u128": {
  39. return borsh.u128(fieldName);
  40. }
  41. case "i128": {
  42. return borsh.i128(fieldName);
  43. }
  44. case "bytes": {
  45. return borsh.vecU8(fieldName);
  46. }
  47. case "string": {
  48. return borsh.str(fieldName);
  49. }
  50. case "publicKey": {
  51. return borsh.publicKey(fieldName);
  52. }
  53. default: {
  54. // @ts-ignore
  55. if (field.type.vec) {
  56. return borsh.vec(
  57. IdlCoder.fieldLayout(
  58. {
  59. name: undefined,
  60. // @ts-ignore
  61. type: field.type.vec,
  62. },
  63. types
  64. ),
  65. fieldName
  66. );
  67. // @ts-ignore
  68. } else if (field.type.option) {
  69. return borsh.option(
  70. IdlCoder.fieldLayout(
  71. {
  72. name: undefined,
  73. // @ts-ignore
  74. type: field.type.option,
  75. },
  76. types
  77. ),
  78. fieldName
  79. );
  80. // @ts-ignore
  81. } else if (field.type.defined) {
  82. // User defined type.
  83. if (types === undefined) {
  84. throw new IdlError("User defined types not provided");
  85. }
  86. // @ts-ignore
  87. const filtered = types.filter((t) => t.name === field.type.defined);
  88. if (filtered.length !== 1) {
  89. throw new IdlError(`Type not found: ${JSON.stringify(field)}`);
  90. }
  91. return IdlCoder.typeDefLayout(filtered[0], types, fieldName);
  92. // @ts-ignore
  93. } else if (field.type.array) {
  94. // @ts-ignore
  95. let arrayTy = field.type.array[0];
  96. // @ts-ignore
  97. let arrayLen = field.type.array[1];
  98. let innerLayout = IdlCoder.fieldLayout(
  99. {
  100. name: undefined,
  101. type: arrayTy,
  102. },
  103. types
  104. );
  105. return borsh.array(innerLayout, arrayLen, fieldName);
  106. } else {
  107. throw new Error(`Not yet implemented: ${field}`);
  108. }
  109. }
  110. }
  111. }
  112. public static typeDefLayout(
  113. typeDef: IdlTypeDef,
  114. types: IdlTypeDef[],
  115. name?: string
  116. ): Layout {
  117. if (typeDef.type.kind === "struct") {
  118. const fieldLayouts = typeDef.type.fields.map((field) => {
  119. const x = IdlCoder.fieldLayout(field, types);
  120. return x;
  121. });
  122. return borsh.struct(fieldLayouts, name);
  123. } else if (typeDef.type.kind === "enum") {
  124. let variants = typeDef.type.variants.map((variant: IdlEnumVariant) => {
  125. const name = camelCase(variant.name);
  126. if (variant.fields === undefined) {
  127. return borsh.struct([], name);
  128. }
  129. // @ts-ignore
  130. const fieldLayouts = variant.fields.map((f: IdlField | IdlType) => {
  131. // @ts-ignore
  132. if (f.name === undefined) {
  133. throw new Error("Tuple enum variants not yet implemented.");
  134. }
  135. // @ts-ignore
  136. return IdlCoder.fieldLayout(f, types);
  137. });
  138. return borsh.struct(fieldLayouts, name);
  139. });
  140. if (name !== undefined) {
  141. // Buffer-layout lib requires the name to be null (on construction)
  142. // when used as a field.
  143. return borsh.rustEnum(variants).replicate(name);
  144. }
  145. return borsh.rustEnum(variants, name);
  146. } else {
  147. throw new Error(`Unknown type kint: ${typeDef}`);
  148. }
  149. }
  150. }