ndtr-dexter
Version:
Customizable Typescript SDK for interacting with Cardano DEXs
108 lines (107 loc) • 4.33 kB
JavaScript
import { datumJsonToCbor } from 'lucid-cardano';
import { DatumParameterKey } from './constants';
export class DefinitionBuilder {
/**
* Load a DEX definition file as a template for this builder.
*/
async loadDefinition(definition) {
this._definition = definition;
return this;
}
/**
* Push specified parameters to the definition template.
*/
pushParameters(parameters) {
if (!this._definition) {
throw new Error(`Definition file must be loaded before applying parameters`);
}
this._definition = this.applyParameters(this._definition, parameters);
return this;
}
/**
* Pull parameters of a datum using a definition template.
*/
pullParameters(definedDefinition) {
if (!this._definition) {
throw new Error(`Definition file must be loaded before pulling parameters`);
}
return this.extractParameters(definedDefinition, this._definition);
}
/**
* Retrieve the CBOR for the builder.
*/
getCbor() {
return datumJsonToCbor(JSON.parse(JSON.stringify(this._definition)));
}
/**
* Recursively set specified parameters.
*/
applyParameters(field, mappedParameters) {
if ('fields' in field) {
if (typeof field.constructor === 'string') {
const parameterValue = mappedParameters[field.constructor];
if (typeof parameterValue !== 'number') {
throw new Error(`Invalid parameter value '${parameterValue}' for constructor value`);
}
field.constructor = parameterValue;
}
field.fields = field.fields.map((fieldParameter) => {
return this.applyParameters(fieldParameter, mappedParameters);
});
}
if ('int' in field) {
let parameterValue = mappedParameters[field.int];
if (typeof parameterValue === 'bigint') {
parameterValue = Number(parameterValue);
}
if (typeof parameterValue !== 'number') {
throw new Error(`Invalid parameter value '${parameterValue}' for type 'int'`);
}
field.int = parameterValue;
}
if ('bytes' in field) {
const parameterValue = mappedParameters[field.bytes] ?? '';
if (typeof parameterValue !== 'string') {
throw new Error(`Invalid parameter value '${parameterValue}' for type 'bytes'`);
}
field.bytes = parameterValue;
}
return field;
}
/**
* Recursively pull parameters from datum using definition template.
*/
extractParameters(definedDefinition, templateDefinition, foundParameters = {}) {
if ('fields' in definedDefinition) {
if (!('fields' in templateDefinition)) {
throw new Error("Template definition does not match with 'fields'");
}
if (typeof templateDefinition.constructor !== 'number') {
foundParameters[templateDefinition.constructor] = definedDefinition.constructor;
}
definedDefinition.fields.map((fieldParameter, index) => {
return this.extractParameters(fieldParameter, templateDefinition.fields[index], foundParameters);
}).forEach((parameters) => {
foundParameters = { ...foundParameters, ...parameters };
});
}
if ('int' in definedDefinition) {
if (!('int' in templateDefinition)) {
throw new Error("Template definition does not match with 'int'");
}
if (typeof templateDefinition.int !== 'number') {
foundParameters[templateDefinition.int] = definedDefinition.int;
}
}
if ('bytes' in definedDefinition) {
if (!('bytes' in templateDefinition)) {
throw new Error("Template definition does not match with 'bytes'");
}
const datumKeys = Object.values(DatumParameterKey);
if (datumKeys.includes(templateDefinition.bytes)) {
foundParameters[templateDefinition.bytes] = definedDefinition.bytes;
}
}
return foundParameters;
}
}