UNPKG

ccxt

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges

217 lines (213 loc) • 9.14 kB
'use strict'; var uint256 = require('../cairoDataTypes/uint256.js'); var uint512 = require('../cairoDataTypes/uint512.js'); var encode = require('../encode.js'); var num = require('../num.js'); var shortString = require('../shortString.js'); var byteArray = require('./byteArray.js'); var cairo = require('./cairo.js'); var CairoCustomEnum = require('./enum/CairoCustomEnum.js'); var CairoOption = require('./enum/CairoOption.js'); var CairoResult = require('./enum/CairoResult.js'); var tuple = require('./tuple.js'); // ---------------------------------------------------------------------------- /** * Parse base types * @param type type of element * @param it iterator * @returns bigint | boolean */ function parseBaseTypes(type, it) { let temp; switch (true) { case cairo.isTypeBool(type): temp = it.next().value; return Boolean(BigInt(temp)); case uint256.CairoUint256.isAbiType(type): const low = it.next().value; const high = it.next().value; return new uint256.CairoUint256(low, high).toBigInt(); case uint512.CairoUint512.isAbiType(type): const limb0 = it.next().value; const limb1 = it.next().value; const limb2 = it.next().value; const limb3 = it.next().value; return new uint512.CairoUint512(limb0, limb1, limb2, limb3).toBigInt(); case type === 'core::starknet::eth_address::EthAddress': temp = it.next().value; return BigInt(temp); case type === 'core::bytes_31::bytes31': temp = it.next().value; return shortString.decodeShortString(temp); case cairo.isTypeSecp256k1Point(type): const xLow = encode.removeHexPrefix(it.next().value).padStart(32, '0'); const xHigh = encode.removeHexPrefix(it.next().value).padStart(32, '0'); const yLow = encode.removeHexPrefix(it.next().value).padStart(32, '0'); const yHigh = encode.removeHexPrefix(it.next().value).padStart(32, '0'); const pubK = BigInt(encode.addHexPrefix(xHigh + xLow + yHigh + yLow)); return pubK; default: temp = it.next().value; return BigInt(temp); } } /** * Parse of the response elements that are converted to Object (Struct) by using the abi * * @param responseIterator - iterator of the response * @param element - element of the field {name: string, type: string} * @param structs - structs from abi * @param enums * @return {any} - parsed arguments in format that contract is expecting */ function parseResponseValue(responseIterator, element, structs, enums) { if (element.type === '()') { return {}; } // type uint256 struct (c1v2) if (uint256.CairoUint256.isAbiType(element.type)) { const low = responseIterator.next().value; const high = responseIterator.next().value; return new uint256.CairoUint256(low, high).toBigInt(); } // type uint512 struct if (uint512.CairoUint512.isAbiType(element.type)) { const limb0 = responseIterator.next().value; const limb1 = responseIterator.next().value; const limb2 = responseIterator.next().value; const limb3 = responseIterator.next().value; return new uint512.CairoUint512(limb0, limb1, limb2, limb3).toBigInt(); } // type C1 ByteArray struct, representing a LongString if (cairo.isTypeByteArray(element.type)) { const parsedBytes31Arr = []; const bytes31ArrLen = BigInt(responseIterator.next().value); while (parsedBytes31Arr.length < bytes31ArrLen) { parsedBytes31Arr.push(num.toHex(responseIterator.next().value)); } const pending_word = num.toHex(responseIterator.next().value); const pending_word_len = BigInt(responseIterator.next().value); const myByteArray = { data: parsedBytes31Arr, pending_word, pending_word_len, }; return byteArray.stringFromByteArray(myByteArray); } // type c1 array if (cairo.isTypeArray(element.type)) { // eslint-disable-next-line no-case-declarations const parsedDataArr = []; const el = { name: '', type: cairo.getArrayType(element.type) }; const len = BigInt(responseIterator.next().value); // get length while (parsedDataArr.length < len) { parsedDataArr.push(parseResponseValue(responseIterator, el, structs, enums)); } return parsedDataArr; } // type struct if (structs && element.type in structs && structs[element.type]) { if (element.type === 'core::starknet::eth_address::EthAddress') { return parseBaseTypes(element.type, responseIterator); } return structs[element.type].members.reduce((acc, el) => { acc[el.name] = parseResponseValue(responseIterator, el, structs, enums); return acc; }, {}); } // type Enum (only CustomEnum) if (enums && element.type in enums && enums[element.type]) { const variantNum = Number(responseIterator.next().value); // get variant number const rawEnum = enums[element.type].variants.reduce((acc, variant, num) => { if (num === variantNum) { acc[variant.name] = parseResponseValue(responseIterator, { name: '', type: variant.type }, structs, enums); return acc; } acc[variant.name] = undefined; return acc; }, {}); // Option if (element.type.startsWith('core::option::Option')) { const content = variantNum === CairoOption.CairoOptionVariant.Some ? rawEnum.Some : undefined; return new CairoOption.CairoOption(variantNum, content); } // Result if (element.type.startsWith('core::result::Result')) { let content; if (variantNum === CairoResult.CairoResultVariant.Ok) { content = rawEnum.Ok; } else { content = rawEnum.Err; } return new CairoResult.CairoResult(variantNum, content); } // Cairo custom Enum const customEnum = new CairoCustomEnum.CairoCustomEnum(rawEnum); return customEnum; } // type tuple if (cairo.isTypeTuple(element.type)) { const memberTypes = tuple(element.type); return memberTypes.reduce((acc, it, idx) => { const name = it?.name ? it.name : idx; const type = it?.type ? it.type : it; const el = { name, type }; acc[name] = parseResponseValue(responseIterator, el, structs, enums); return acc; }, {}); } // type c1 array if (cairo.isTypeArray(element.type)) { // eslint-disable-next-line no-case-declarations const parsedDataArr = []; const el = { name: '', type: cairo.getArrayType(element.type) }; const len = BigInt(responseIterator.next().value); // get length while (parsedDataArr.length < len) { parsedDataArr.push(parseResponseValue(responseIterator, el, structs, enums)); } return parsedDataArr; } // base type return parseBaseTypes(element.type, responseIterator); } /** * Parse elements of the response and structuring them into one field by using output property from the abi for that method * * @param responseIterator - iterator of the response * @param output - output(field) information from the abi that will be used to parse the data * @param structs - structs from abi * @param parsedResult * @return - parsed response corresponding to the abi structure of the field */ function responseParser(responseIterator, output, structs, enums, parsedResult) { const { name, type } = output; let temp; switch (true) { case cairo.isLen(name): temp = responseIterator.next().value; return BigInt(temp); case (structs && type in structs) || cairo.isTypeTuple(type): return parseResponseValue(responseIterator, output, structs, enums); case enums && cairo.isTypeEnum(type, enums): return parseResponseValue(responseIterator, output, structs, enums); case cairo.isTypeArray(type): // C1 Array if (cairo.isCairo1Type(type)) { return parseResponseValue(responseIterator, output, structs, enums); } // C0 Array // eslint-disable-next-line no-case-declarations const parsedDataArr = []; if (parsedResult && parsedResult[`${name}_len`]) { const arrLen = parsedResult[`${name}_len`]; while (parsedDataArr.length < arrLen) { parsedDataArr.push(parseResponseValue(responseIterator, { name, type: output.type.replace('*', '') }, structs, enums)); } } return parsedDataArr; default: return parseBaseTypes(type, responseIterator); } } module.exports = responseParser;