@aeternity/aepp-calldata
Version:
Aeternity data serialization library
131 lines (99 loc) • 3.29 kB
JavaScript
import ContractEncoder from './ContractEncoder.js'
import TypeResolveError from './Errors/TypeResolveError.js'
import {
FateTypeVoid,
FateTypeTuple,
FateTypeEvent,
FateTypeList,
FateTypeMap,
FateTypeVariant,
FateTypeOracleAddress,
FateTypeOracleQueryAddress,
} from './FateTypes.js'
class BytecodeTypeResolver {
constructor(encodedContract) {
this._contractEncoder = new ContractEncoder()
this._encodedContract = encodedContract
this._contract = null
}
get _bytecode() {
if (this._contract === null) {
this._contract = this._contractEncoder.decode(this._encodedContract)
}
return this._contract.bytecode
}
getFunctionId(funName) {
const {symbols} = this._bytecode
return Object.keys(symbols).find(key => symbols[key] === funName)
}
getFunction(id) {
const {functions} = this._bytecode
return functions.find(f => f.id === id)
}
getFunctionName(id) {
const {name} = this.getFunction(id)
return name
}
getCallTypes(funName) {
const fun = this.getFunction(this.getFunctionId(funName))
if (fun) {
const types = fun.args.valueTypes.map(t => this.resolveType(t))
return {
types,
required: types.length
}
}
if (funName === 'init') {
return {types: [], required: 0}
}
throw new TypeResolveError(`Unknown function ${funName}`)
}
getReturnType(funName) {
if (funName === 'init') {
return FateTypeVoid()
}
const fun = this.getFunction(this.getFunctionId(funName))
if (fun) {
return this.resolveType(fun.returnType)
}
throw new TypeResolveError(`Unknown function ${funName}`)
}
getEventType(topics) {
const fun = this.getFunction(this.getFunctionId('Chain.event'))
if (!fun) {
throw new TypeResolveError('The contract does not have event declaration')
}
const variantType = fun.args.valueTypes[0]
return FateTypeEvent(this.resolveType(variantType), topics)
}
resolveType(type) {
if (type.name === 'variant') {
const variants = type.variants.map((el, idx) => {
const valueTypes = el.valueTypes.map(v => this.resolveType(v))
return {[idx]: valueTypes}
})
return FateTypeVariant(variants)
}
let resolvedTypes = []
if (Array.isArray(type.valueTypes)) {
resolvedTypes = type.valueTypes.map(t => this.resolveType(t))
}
if (type.name === 'tuple') {
return FateTypeTuple(resolvedTypes)
}
if (type.name === 'list') {
return FateTypeList(...resolvedTypes)
}
if (type.name === 'map') {
return FateTypeMap(...resolvedTypes)
}
if (type.name === 'oracle') {
return FateTypeOracleAddress(...resolvedTypes)
}
if (type.name === 'oracle_query') {
return FateTypeOracleQueryAddress(...resolvedTypes)
}
return type
}
}
export default BytecodeTypeResolver