-
Notifications
You must be signed in to change notification settings - Fork 718
/
cairo.ts
266 lines (256 loc) · 8.61 KB
/
cairo.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
import {
Abi,
AbiEnums,
AbiStructs,
BigNumberish,
ContractVersion,
Literal,
Uint,
Uint256,
Uint512,
} from '../../types';
import { CairoFelt } from '../cairoDataTypes/felt';
import { CairoUint256 } from '../cairoDataTypes/uint256';
import { CairoUint512 } from '../cairoDataTypes/uint512';
// Intended for internal usage, maybe should be exported somewhere else and not exported to utils
/**
* Checks if the given name ends with "_len".
*
* @param {string} name - The name to be checked.
* @returns - True if the name ends with "_len", false otherwise.
*/
export const isLen = (name: string) => /_len$/.test(name);
/**
* Checks if a given type is felt.
*
* @param {string} type - The type to check.
* @returns - True if the type is felt, false otherwise.
*/
export const isTypeFelt = (type: string) => type === 'felt' || type === 'core::felt252';
/**
* Checks if the given type is an array type.
*
* @param {string} type - The type to check.
* @returns - `true` if the type is an array type, `false` otherwise.
*/
export const isTypeArray = (type: string) =>
/\*/.test(type) ||
type.startsWith('core::array::Array::') ||
type.startsWith('core::array::Span::');
/**
* Checks if the given type is a tuple type.
*
* @param {string} type - The type to be checked.
* @returns - `true` if the type is a tuple type, otherwise `false`.
*/
export const isTypeTuple = (type: string) => /^\(.*\)$/i.test(type);
/**
* Checks whether a given type is a named tuple.
*
* @param {string} type - The type to be checked.
* @returns - True if the type is a named tuple, false otherwise.
*/
export const isTypeNamedTuple = (type: string) => /\(.*\)/i.test(type) && type.includes(':');
/**
* Checks if a given type is a struct.
*
* @param {string} type - The type to check for existence.
* @param {AbiStructs} structs - The collection of structs to search in.
* @returns - True if the type exists in the structs, false otherwise.
*/
export const isTypeStruct = (type: string, structs: AbiStructs) => type in structs;
/**
* Checks if a given type is an enum.
*
* @param {string} type - The type to check.
* @param {AbiEnums} enums - The enumeration to search in.
* @returns - True if the type exists in the enumeration, otherwise false.
*/
export const isTypeEnum = (type: string, enums: AbiEnums) => type in enums;
/**
* Determines if the given type is an Option type.
*
* @param {string} type - The type to check.
* @returns - True if the type is an Option type, false otherwise.
*/
export const isTypeOption = (type: string) => type.startsWith('core::option::Option::');
/**
* Checks whether a given type starts with 'core::result::Result::'.
*
* @param {string} type - The type to check.
* @returns - True if the type starts with 'core::result::Result::', false otherwise.
*/
export const isTypeResult = (type: string) => type.startsWith('core::result::Result::');
/**
* Checks if the given value is a valid Uint type.
*
* @param {string} type - The value to check.
* @returns - Returns true if the value is a valid Uint type, otherwise false.
*/
export const isTypeUint = (type: string) => Object.values(Uint).includes(type as Uint);
// Legacy Export
/**
* Checks if the given type is `uint256`.
*
* @param {string} type - The type to be checked.
* @returns - Returns true if the type is `uint256`, otherwise false.
*/
export const isTypeUint256 = (type: string) => CairoUint256.isAbiType(type);
/**
* Checks if the given type is a literal type.
*
* @param {string} type - The type to check.
* @returns - True if the type is a literal type, false otherwise.
*/
export const isTypeLiteral = (type: string) => Object.values(Literal).includes(type as Literal);
/**
* Checks if the given type is a boolean type.
*
* @param {string} type - The type to be checked.
* @returns - Returns true if the type is a boolean type, otherwise false.
*/
export const isTypeBool = (type: string) => type === 'core::bool';
/**
* Checks if the provided type is equal to 'core::starknet::contract_address::ContractAddress'.
* @param {string} type - The type to be checked.
* @returns - true if the type matches 'core::starknet::contract_address::ContractAddress', false otherwise.
*/
export const isTypeContractAddress = (type: string) =>
type === 'core::starknet::contract_address::ContractAddress';
/**
* Determines if the given type is an Ethereum address type.
*
* @param {string} type - The type to check.
* @returns - Returns true if the given type is 'core::starknet::eth_address::EthAddress', otherwise false.
*/
export const isTypeEthAddress = (type: string) =>
type === 'core::starknet::eth_address::EthAddress';
/**
* Checks if the given type is 'core::bytes_31::bytes31'.
*
* @param {string} type - The type to check.
* @returns - True if the type is 'core::bytes_31::bytes31', false otherwise.
*/
export const isTypeBytes31 = (type: string) => type === 'core::bytes_31::bytes31';
/**
* Checks if the given type is equal to the 'core::byte_array::ByteArray'.
*
* @param {string} type - The type to check.
* @returns - True if the given type is equal to 'core::byte_array::ByteArray', false otherwise.
*/
export const isTypeByteArray = (type: string) => type === 'core::byte_array::ByteArray';
export const isTypeSecp256k1Point = (type: string) =>
type === 'core::starknet::secp256k1::Secp256k1Point';
export const isCairo1Type = (type: string) => type.includes('::');
/**
* Retrieves the array type from the given type string.
*
* Works also for core::zeroable::NonZero type.
* @param {string} type - The type string.
* @returns - The array type.
*/
export const getArrayType = (type: string) => {
if (isCairo1Type(type)) {
return type.substring(type.indexOf('<') + 1, type.lastIndexOf('>'));
}
return type.replace('*', '');
};
/**
* Test if an ABI comes from a Cairo 1 contract
* @param abi representing the interface of a Cairo contract
* @returns TRUE if it is an ABI from a Cairo1 contract
* @example
* ```typescript
* const isCairo1: boolean = isCairo1Abi(myAbi: Abi);
* ```
*/
export function isCairo1Abi(abi: Abi): boolean {
const { cairo } = getAbiContractVersion(abi);
if (cairo === undefined) {
throw Error('Unable to determine Cairo version');
}
return cairo === '1';
}
/**
* Checks if the given type is a NonZero type.
*
* @param {string} type The type to check.
* @returns `true` if the type is NonZero type, `false` otherwise.
* @example
* ```typescript
* const result = cairo.isTypeNonZero("core::zeroable::NonZero::<u8>");
* //result = true
* ```
*/
export function isTypeNonZero(type: string): boolean {
return type.startsWith('core::zeroable::NonZero::');
}
/**
* Return ContractVersion (Abi version) based on Abi
* or undefined for unknown version
* @param abi
* @returns string
*/
export function getAbiContractVersion(abi: Abi): ContractVersion {
// determine by interface for "Cairo 1.2"
if (abi.find((it) => it.type === 'interface')) {
return { cairo: '1', compiler: '2' };
}
// determine by function io types "Cairo 1.1" or "Cairo 0.0"
// find first function with inputs or outputs
const testFunction = abi.find(
(it) => it.type === 'function' && (it.inputs.length || it.outputs.length)
);
if (!testFunction) {
return { cairo: undefined, compiler: undefined };
}
const io = testFunction.inputs.length ? testFunction.inputs : testFunction.outputs;
if (isCairo1Type(io[0].type)) {
return { cairo: '1', compiler: '1' };
}
return { cairo: '0', compiler: '0' };
}
/**
* named tuple cairo type is described as js object {}
* struct cairo type are described as js object {}
* array cairo type are described as js array []
*/
/**
* Create Uint256 Cairo type (helper for common struct type)
* @example
* ```typescript
* uint256('892349863487563453485768723498');
* ```
*/
export const uint256 = (it: BigNumberish): Uint256 => {
return new CairoUint256(it).toUint256DecimalString();
};
/**
* Create Uint512 Cairo type (helper for common struct type)
* @param it BigNumberish representation of a 512 bits unsigned number
* @returns Uint512 struct
* @example
* ```typescript
* uint512('345745685892349863487563453485768723498');
* ```
*/
export const uint512 = (it: BigNumberish): Uint512 => {
return new CairoUint512(it).toUint512DecimalString();
};
/**
* Create unnamed tuple Cairo type (helper same as common struct type)
* @example
* ```typescript
* tuple(1, '0x101', 16);
* ```
*/
export const tuple = (
...args: (BigNumberish | object | boolean)[]
): Record<number, BigNumberish | object | boolean> => ({ ...args });
/**
* Create felt Cairo type (cairo type helper)
* @returns format: felt-string
*/
export function felt(it: BigNumberish): string {
return CairoFelt(it);
}