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