idl.ts 4.5 KB

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