/**
 * Disconnect the current connection client if one exists
 */
export async function disconnectConnectionClient() {
  const { focusedSessionId } = getState();
  const { connectionClient } = getState().getFocusedSession();

  if (connectionClient) {
    api
      .delete(`/api/connection-clients/${connectionClient.id}`)
      .then((json) => {
        if (json.error) {
          message.error(json.error);
        }
      });
  }

  setSession(focusedSessionId, {
    connectionClient: undefined,
  });
}


function cleanupConnectionClient(connectionClient?: ConnectionClient) {
  // Close connection client but do not wait for this to complete
  if (connectionClient) {
    api
      .delete(`/api/connection-clients/${connectionClient.id}`)
      .then((json) => {
        if (json.error) {
          message.error(json.error);
        }
      });
  }
}


/**
 * Select connection and disconnect connectionClient if it exists
 * @param connectionId
 */
export function selectConnectionId(connectionId: string) {
  const { focusedSessionId } = getState();
  const { connectionClient } = getState().getFocusedSession();

  localforage
    .setItem('selectedConnectionId', connectionId)
    .catch((error) => message.error(error));

  cleanupConnectionClient(connectionClient);

  setSession(focusedSessionId, {
    connectionId,
    connectionClient: undefined,
  });
}


export function toggleSchema() {
  const { focusedSessionId } = getState();
  const { showSchema } = getState().getFocusedSession();
  setSession(focusedSessionId, { showSchema: !showSchema });
}


export function toggleVisProperties() {
  const { focusedSessionId } = getState();
  const { showVisProperties } = getState().getFocusedSession();
  setSession(focusedSessionId, { showVisProperties: !showVisProperties });
}


export function setSchemaState(connectionId: string, schemaState: SchemaState) {
  const { schemaStates } = getState();
  const update = {
    ...schemaStates,
    [connectionId]: schemaState,
  };
  setState({ schemaStates: update });
}


/**
 * Get schema via API and store into editor store
 * @param connectionId - connection id to get schema for
 * @param reload - force cache refresh for schema
 */
export async function loadSchema(connectionId: string, reload?: boolean) {
  const { schemaStates, focusedSessionId } = getState();
  const { showSchema, schemaExpansions } = getState().getFocusedSession();

  if (!schemaStates[connectionId] || reload) {
    setSchemaState(connectionId, {
      loading: true,
    });

    const json = await api.getConnectionSchema(connectionId, reload);
    const { error, data } = json;

    if (error) {
      setSchemaState(connectionId, {
        loading: false,
        error,
      });
      // If sidebar is not shown, send error notification
      // It is otherwise shown in sidebar where schema would be
      if (!showSchema) {
        message.error(error);
      }
      return;
    }

    // Pre-expand schemas
    const expanded: { [key: string]: boolean } = {};
    // Added schemas length restriction before auto-expand.
    // This limit is there because there is no collapse-all function in the UI
    // and render time can explode quickly.
    // In datawarehousing there can be 100's of schema's each containing 50-100
    // tables and those containing each 5+ columns and manually collapsing
    // them is very annoying.
    // NOTE: the 5 here is completely arbitrary it may be preferable to not auto expand unless there is only 1.
    if (data?.schemas && data?.schemas.length <= 5) {
      data.schemas.forEach((schema) => {
        expanded[schema.name] = true;
      });
    }

    const stringCompare = new Intl.Collator('en', { sensitivity: 'base' });
    const nameCompare: { (a: { name: string }, b: { name: string }): number } =
      (a, b) => stringCompare.compare(a.name, b.name);
    if (data?.schemas) {
      data.schemas.sort(nameCompare);
      data.schemas.forEach((schema) => {
        schema.tables.sort(nameCompare);
        // NOTE: we do not sort columns that can be annoying with regards to creation order.
      });
    }
    if (data?.tables) {
      data.tables.sort(nameCompare);
    }

    setSchemaState(connectionId, {
      loading: false,
      connectionSchema: data,
      error: undefined,
    });

    setSession(focusedSessionId, {
      schemaExpansions: { ...schemaExpansions, [connectionId]: expanded },
    });
  }

  // Refresh completions
  const connectionSchema =
    getState().schemaStates[connectionId]?.connectionSchema;

  if (connectionSchema?.schemas || connectionSchema?.tables) {
    updateCompletions(connectionSchema);
  } else {
    updateCompletions({ schemas: [] });
  }
}


export function toggleSchemaItem(connectionId: string, item: { id: string }) {
  const { focusedSessionId } = getState();
  const { schemaExpansions } = getState().getFocusedSession();

  const expanded = { ...schemaExpansions[connectionId] };
  expanded[item.id] = !expanded[item.id];

  setSession(focusedSessionId, {
    schemaExpansions: { ...schemaExpansions, [connectionId]: expanded },
  });
}


/**
 * Sets the state for an asynchronous driver that will enable cancel queries
 * @param {boolean} setAsynchronousDriver
 */
export function setAsynchronousDriver(asynchronous?: boolean) {
  const { focusedSessionId } = getState();

  const isAsync = asynchronous ? true : false;
  setSession(focusedSessionId, {
    isDriverAsynchronous: isAsync,
  });
}


async () => {
  const { editorSessions } = getState();
  for (const sessionId of Object.keys(editorSessions)) {
    const { connectionClient } = getState().getSession(sessionId) || {};

    if (connectionClient) {
      const updateJson = await api.put(
        `/api/connection-clients/${connectionClient.id}`,
        {}
      );

      const currentConnectionClient =
        getState().getSession(sessionId)?.connectionClient;

      // If the connectionClient changed since hearbeat, do nothing
      if (
        !currentConnectionClient ||
        currentConnectionClient.id !== connectionClient?.id
      ) {
        return;
      }

      // If the PUT didn't return a connectionClient object or has an error,
      // the connectionClient has been disconnected
      if (updateJson.error || !updateJson.data) {
        setSession(sessionId, {
          connectionClient: undefined,
        });
      } else {
        setSession(sessionId, {
          connectionClient: updateJson.data,
        });
      }
    }
  }
}


async (
  config: AppInfo['config'],
  connections: Connection[]
) => {
  try {
    let [selectedConnectionId] = await Promise.all([
      localforage.getItem('selectedConnectionId'),
    ]);

    let initialConnectionId = '';

    if (connections.length === 1) {
      initialConnectionId = connections[0].id;
    } else {
      const { defaultConnectionId } = config || {};
      if (defaultConnectionId) {
        const foundDefault = connections.find(
          (c) => c.id === defaultConnectionId
        );
        if (Boolean(foundDefault)) {
          initialConnectionId = defaultConnectionId;
        }
      }

      if (typeof selectedConnectionId === 'string') {
        const selectedConnection = connections.find(
          (c) => c.id === selectedConnectionId
        );
        if (Boolean(selectedConnection)) {
          initialConnectionId = selectedConnectionId;
        }
      }

      const qs = queryString.parse(window.location.search);
      const qsConnectionName = qs.connectionName;
      if (qsConnectionName) {
        const selectedConnection = connections.find(
          (c) => c.name === qsConnectionName
        );
        if (selectedConnection?.id) {
          initialConnectionId = selectedConnection?.id;
        }
      }

      const qsConnectionId = qs.connectionId;
      if (qsConnectionId) {
        const selectedConnection = connections.find(
          (c) => c.id === qsConnectionId
        );
        if (selectedConnection?.id) {
          initialConnectionId = selectedConnection?.id;
        }
      }
    }

    const { focusedSessionId } = getState();
    setSession(focusedSessionId, { connectionId: initialConnectionId });
    if (initialConnectionId) {
      loadSchema(initialConnectionId);
    }
    setState({ initialized: true });
  } catch (error) {
    console.error(error);
    message.error('Error initializing application');
  }
}


(c) => c.id === defaultConnectionId


(c) => c.id === selectedConnectionId


(c) => c.name === qsConnectionName


(c) => c.id === qsConnectionId


(connection) => connection.id === connectionId


(json) => {
        if (json.error) {
          message.error(json.error);
        }
      }


(error) => message.error(error)


async () => {
  const { focusedSessionId } = getState();
  const { queryText, queryId } = getState().getFocusedSession();

  const json = await api.post('/api/format-sql', {
    query: queryText,
  });

  if (json.error) {
    message.error(json.error);
    return;
  }

  if (!json.data || !json.data.query) {
    console.warn('unexpected API result');
    return;
  }

  setLocalQueryText(queryId, json.data.query);
  setSession(focusedSessionId, {
    queryText: json.data.query,
    unsavedChanges: true,
  });
}


async (queryId: string) => {
  const response = await api.getQuery(queryId);

  const { error, data } = response;
  if (error || !data) {
    return response;
  }

  const { focusedSessionId } = getState();
  const { connectionClient, ...restOfCurrentSession } =
    getState().getFocusedSession();

  // Cleanup existing connection
  // Even if the connection isn't changing, the client should be refreshed
  // This is to prevent accidental state from carrying over
  // For example, if there is an open transaction,
  // we don't want that impacting the new query if same connectionId is used)
  cleanupConnectionClient(connectionClient);

  setSession(focusedSessionId, {
    ...restOfCurrentSession,
    // Map query object to flattened editor session data
    queryId,
    connectionId: data.connectionId,
    connectionClient: undefined,
    queryText: data.queryText,
    queryName: data.name,
    tags: data.tags,
    acl: data.acl,
    chartType: data?.chart?.chartType,
    chartFields: data?.chart?.fields,
    canDelete: data.canDelete,
    canRead: data.canRead,
    canWrite: data.canWrite,
    // Reset result/error/unsaved/running states
    batchId: '',
    selectedStatementId: '',
    isRunning: false,
    queryError: undefined,
    unsavedChanges: false,
  });

  return response;
}


async () => {
  const { focusedSessionId } = getState();
  const {
    queryId,
    queryName,
    queryText,
    chartType,
    chartFields,
    connectionId,
    connectionClient,
    selectedText,
    isDriverAsynchronous,
  } = getState().getFocusedSession();

  if (!connectionId) {
    return setSession(focusedSessionId, {
      queryError: 'Connection required',
      selectedStatementId: '',
    });
  }

  if (!queryText) {
    return setSession(focusedSessionId, {
      queryError: 'SQL text required',
      selectedStatementId: '',
    });
  }

  setSession(focusedSessionId, {
    batchId: undefined,
    isRunning: true,
    isExecutionStarting: false,
    runQueryStartTime: new Date(),
    selectedStatementId: '',
  });

  const postData = {
    connectionId,
    connectionClientId: connectionClient && connectionClient.id,
    queryId,
    name: queryName,
    batchText: queryText,
    selectedText,
    chart: {
      chartType,
      fields: chartFields,
    },
  };

  let res = await api.createBatch(postData);

  setSession(focusedSessionId, {
    isExecutionStarting: isDriverAsynchronous ? true : false,
  });

  let error = res.error;
  let batch = res.data;

  if (error) {
    return setSession(focusedSessionId, {
      queryError: error,
    });
  }

  if (!batch) {
    return setSession(focusedSessionId, {
      queryError: 'error creating batch',
    });
  }

  setBatch(focusedSessionId, batch.id, batch);

  while (
    batch?.id &&
    !(
      (batch?.status === 'finished' ||
        batch?.status === 'error' ||
        batch?.status === 'cancelled') &&
      !error
    )
  ) {
    await sleep(500);
    res = await api.getBatch(batch.id);
    error = res.error;
    batch = res.data;

    setSession(focusedSessionId, {
      batchId: batch?.id,
      queryError: error,
    });

    if (batch) {
      setBatch(focusedSessionId, batch.id, batch);
    }
  }

  setSession(focusedSessionId, {
    isRunning: false,
    isExecutionStarting: false,
  });
}


async () => {
  const { focusedSessionId } = getState();
  const { connectionId, isDriverAsynchronous, batchId } =
    getState().getFocusedSession();

  if (!isDriverAsynchronous) {
    return setSession(focusedSessionId, {
      queryError: 'Driver does not support cancellation',
      selectedStatementId: '',
    });
  }

  if (!batchId) {
    return setSession(focusedSessionId, {
      queryError: 'Batch ID required',
      selectedStatementId: '',
    });
  }
  if (!connectionId) {
    return setSession(focusedSessionId, {
      queryError: 'Connection required',
      selectedStatementId: '',
    });
  }

  setSession(focusedSessionId, {
    isRunning: true,
    isExecutionStarting: true,
    runQueryStartTime: new Date(),
    selectedStatementId: '',
  });

  const putData = {
    connectionId: connectionId,
  };

  await api.cancelBatch(batchId, putData);
  message.error('Query cancelled by user');
  return setSession(focusedSessionId, {
    batchId: undefined,
    isRunning: false,
    isExecutionStarting: false,
  });
}


async (
  batchHistoryItem: BatchHistoryItem
) => {
  const { focusedSessionId } = getState();

  // Statements might not exist if query result data is purged
  // In that case, just restore the SQL and chart config and similar
  // clear out batchId/selectedStatementId
  const hasStatements = batchHistoryItem.statements;

  setSession(focusedSessionId, {
    queryName: batchHistoryItem.name,
    queryText: batchHistoryItem.batchText,
    chartType: batchHistoryItem.chart?.chartType,
    chartFields: batchHistoryItem.chart?.fields,
    connectionId: batchHistoryItem.connectionId,
    connectionClient: undefined,
    selectedText: '',
    batchId: hasStatements ? batchHistoryItem.id : undefined,
    selectedStatementId: undefined,
    isRunning: false,
    runQueryStartTime: batchHistoryItem.startTime,
  });

  if (hasStatements) {
    setBatch(focusedSessionId, batchHistoryItem.id, batchHistoryItem);
  }
}


async (additionalUpdates?: Partial<EditorSession>) => {
  const { focusedSessionId } = getState();
  const session = getState().getFocusedSession();

  // If can't write, bail early
  if (!session.canWrite) {
    setSession(focusedSessionId, { showValidation: false });
    setState({ showQueryModal: false });
    return;
  }

  const mergedSession = { ...session, ...additionalUpdates };

  const {
    queryId,
    connectionId,
    queryName,
    queryText,
    chartFields,
    chartType,
    tags,
    acl,
  } = mergedSession;

  if (!queryName) {
    setSession(focusedSessionId, { showValidation: true });
    setState({ showQueryModal: true });
    return;
  }

  setSession(focusedSessionId, { isSaving: true, saveError: undefined });
  const queryData = {
    connectionId,
    name: queryName,
    queryText,
    acl,
    chart: {
      chartType,
      fields: chartFields,
    },
    tags,
  };

  if (queryId) {
    api.updateQuery(queryId, queryData).then((json) => {
      const { error, data } = json;
      if (error) {
        // If there was an error, show the save dialog.
        // It might be closed and it is where the error is placed.
        // This should be rare, and not sure what might trigger it at this point, but just in case
        setSession(focusedSessionId, { isSaving: false, saveError: error });
        setState({ showQueryModal: true });
        return;
      }
      // TypeScript doesn't know that if error did not exist we are dealing with data
      if (data) {
        removeLocalQueryText(data.id);
        setSession(focusedSessionId, {
          isSaving: false,
          unsavedChanges: false,
          connectionId: data.connectionId,
          queryId: data.id,
          queryText: data.queryText,
          queryName: data.name,
          tags: data.tags,
          acl: data.acl,
          chartType: data?.chart?.chartType,
          chartFields: data?.chart?.fields,
          canDelete: data.canDelete,
          canRead: data.canRead,
          canWrite: data.canWrite,
        });
        setState({ showQueryModal: false });
      }
    });
  } else {
    api.createQuery(queryData).then((json) => {
      const { error, data } = json;
      if (error) {
        // If there was an error, show the save dialog.
        // It might be closed and it is where the error is placed.
        // This should be rare, and not sure what might trigger it at this point, but just in case
        setSession(focusedSessionId, { isSaving: false, saveError: error });
        setState({ showQueryModal: true });
        return;
      }
      // TypeScript doesn't know that if error did not exist we are dealing with data
      if (data) {
        const history = getHistory();
        history?.push(`/queries/${data.id}`);
        removeLocalQueryText(data.id);
        setSession(focusedSessionId, {
          isSaving: false,
          unsavedChanges: false,
          connectionId: data.connectionId,
          queryId: data.id,
          queryText: data.queryText,
          queryName: data.name,
          tags: data.tags,
          acl: data.acl,
          chartType: data?.chart?.chartType,
          chartFields: data?.chart?.fields,
          canDelete: data.canDelete,
          canRead: data.canRead,
          canWrite: data.canWrite,
        });
        setState({ showQueryModal: false });
      }
    });
  }
}


(json) => {
      const { error, data } = json;
      if (error) {
        // If there was an error, show the save dialog.
        // It might be closed and it is where the error is placed.
        // This should be rare, and not sure what might trigger it at this point, but just in case
        setSession(focusedSessionId, { isSaving: false, saveError: error });
        setState({ showQueryModal: true });
        return;
      }
      // TypeScript doesn't know that if error did not exist we are dealing with data
      if (data) {
        removeLocalQueryText(data.id);
        setSession(focusedSessionId, {
          isSaving: false,
          unsavedChanges: false,
          connectionId: data.connectionId,
          queryId: data.id,
          queryText: data.queryText,
          queryName: data.name,
          tags: data.tags,
          acl: data.acl,
          chartType: data?.chart?.chartType,
          chartFields: data?.chart?.fields,
          canDelete: data.canDelete,
          canRead: data.canRead,
          canWrite: data.canWrite,
        });
        setState({ showQueryModal: false });
      }
    }


(json) => {
      const { error, data } = json;
      if (error) {
        // If there was an error, show the save dialog.
        // It might be closed and it is where the error is placed.
        // This should be rare, and not sure what might trigger it at this point, but just in case
        setSession(focusedSessionId, { isSaving: false, saveError: error });
        setState({ showQueryModal: true });
        return;
      }
      // TypeScript doesn't know that if error did not exist we are dealing with data
      if (data) {
        const history = getHistory();
        history?.push(`/queries/${data.id}`);
        removeLocalQueryText(data.id);
        setSession(focusedSessionId, {
          isSaving: false,
          unsavedChanges: false,
          connectionId: data.connectionId,
          queryId: data.id,
          queryText: data.queryText,
          queryName: data.name,
          tags: data.tags,
          acl: data.acl,
          chartType: data?.chart?.chartType,
          chartFields: data?.chart?.fields,
          canDelete: data.canDelete,
          canRead: data.canRead,
          canWrite: data.canWrite,
        });
        setState({ showQueryModal: false });
      }
    }


() => {
  const { focusedSessionId } = getState();
  const { queryName } = getState().getFocusedSession();
  const history = getHistory();
  setSession(focusedSessionId, {
    queryId: '',
    queryName: `Copy of ${queryName}`,
    unsavedChanges: true,
    canDelete: true,
    canWrite: true,
    canRead: true,
  });
  history?.push(`/queries/new`);
}


() => {
  const { focusedSessionId } = getState();

  // Get some editor state from current session and carry that on to new session
  const {
    showSchema,
    showVisProperties,
    schemaExpansions,
    connectionId,
    connectionClient,
  } = getState().getFocusedSession();

  const session = {
    ...INITIAL_SESSION,
    showSchema,
    showVisProperties,
    schemaExpansions,
    connectionId,
    connectionClient,
  };
  setSession(focusedSessionId, session);
}


(selectedStatementId: string) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { selectedStatementId });
}


(queryText: string) => {
  const { focusedSessionId } = getState();
  const { queryId } = getState().getFocusedSession();
  setLocalQueryText(queryId, queryText);
  setSession(focusedSessionId, { queryText, unsavedChanges: true });
}


(queryName: string) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { queryName, unsavedChanges: true });
}


(tags: string[]) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { tags, unsavedChanges: true });
}


(acl: Partial<ACLRecord>[]) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { acl, unsavedChanges: true });
}


(chartType: string) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { chartType, unsavedChanges: true });
}


(chartFields: ChartFields) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { chartFields, unsavedChanges: true });
}


(
  chartFieldId: string,
  queryResultField: string | boolean | number
) => {
  const { focusedSessionId } = getState();
  const { chartFields } = getState().getFocusedSession();

  setSession(focusedSessionId, {
    chartFields: { ...chartFields, [chartFieldId]: queryResultField },
    unsavedChanges: true,
  });
}


(selectedText: string) => {
  const { focusedSessionId } = getState();
  setSession(focusedSessionId, { selectedText });
}


(schema) => {
        expanded[schema.name] = true;
      }


(a, b) => stringCompare.compare(a.name, b.name)


(schema) => {
        schema.tables.sort(nameCompare);
        // NOTE: we do not sort columns that can be annoying with regards to creation order.
      }


() => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'get-stream-url'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('get-stream-url');
  });

  it('should render title', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('.content span').textContent).toContain('get-stream-url app is running!');
  });
}


() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('get-stream-url');
  }


() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('.content span').textContent).toContain('get-stream-url app is running!');
  }


projectData => {
              this.projects = projectData;
              this.select.emit(this.projects[0].id);
            }


error => {
              alert(error);
              console.log(error);
            }


() => console.log('Projects retrieved: ' + this.projects.length)


@Component({
  moduleId: module.id,
  selector: 'project-selector',
  template: `<div>
    <select #sel (change)="select.emit(sel.value)">
      <option *ngFor="let item of projects" [value]="item.id">{{item.code}}
      </option>
    </select>
  </div>`
})
export class ProjectSelector implements OnInit {
  private projects: Array<Project> = [];
  @Output() select = new EventEmitter();

  constructor(
      public projectService: ProjectService
  ) {}

  ngOnInit() {
    this.projectService.getProjects()
        .subscribe(
            projectData => {
              this.projects = projectData;
              this.select.emit(this.projects[0].id);
            },
            error => {
              alert(error);
              console.log(error);
            },
            () => console.log('Projects retrieved: ' + this.projects.length)
        )
  }
}


ngOnInit() {
    this.projectService.getProjects()
        .subscribe(
            projectData => {
              this.projects = projectData;
              this.select.emit(this.projects[0].id);
            },
            error => {
              alert(error);
              console.log(error);
            },
            () => console.log('Projects retrieved: ' + this.projects.length)
        )
  }


(a: any[], b: any[]) =>
  a.length === b.length && a.every((it, index) => it === b[index])


(it, index) => it === b[index]


(r) => r.key


(acc, route) => {
          acc[route.key] =
            props.descriptors[route.key] || state.descriptors[route.key];

          return acc;
        }


(acc, route) => {
            acc[route.key] = route;
            return acc;
          }


(route) => map[route.key] || route


(key: string) => {
      const descriptor = props.descriptors[key] || state.descriptors[key];

      return descriptor ? descriptor.options.animationEnabled !== false : true;
    }


(key: string) => {
      const descriptor = props.descriptors[key] || state.descriptors[key];

      return descriptor.options.animationTypeForReplace ?? 'push';
    }


(r) => r.key === nextFocusedRoute.key


(key) => key !== nextFocusedRoute.key


(r) => r.key === previousFocusedRoute.key


(key) => key !== previousFocusedRoute.key


({ key }) =>
          isAnimationEnabled(key)
            ? replacingRouteKeys.includes(key) || closingRouteKeys.includes(key)
            : false


(acc, route) => {
      acc[route.key] =
        props.descriptors[route.key] || state.descriptors[route.key];

      return acc;
    }


({ route }: { route: Route<string> }) => {
    const descriptor = this.state.descriptors[route.key];

    if (descriptor) {
      const { gestureEnabled, animationEnabled } = descriptor.options;

      if (animationEnabled === false) {
        // When animation is disabled, also disable gestures
        // The gesture to dismiss a route will look weird when not animated
        return false;
      }

      return gestureEnabled !== undefined
        ? gestureEnabled
        : Platform.OS !== 'android';
    }

    return false;
  }


({ route }: { route: Route<string> }) => {
    const { closingRouteKeys, replacingRouteKeys } = this.state;
    const routes = this.state.routes.filter(
      (r) =>
        r.key === route.key ||
        (!closingRouteKeys.includes(r.key) &&
          !replacingRouteKeys.includes(r.key))
    );

    const index = routes.findIndex((r) => r.key === route.key);

    return routes[index - 1];
  }


(r) =>
        r.key === route.key ||
        (!closingRouteKeys.includes(r.key) &&
          !replacingRouteKeys.includes(r.key))


(r) => r.key === route.key


({ route }: { route: Route<string> }) => {
    const descriptor =
      this.state.descriptors[route.key] || this.props.descriptors[route.key];

    if (!descriptor) {
      return null;
    }

    const { navigation, getComponent } = descriptor;
    const SceneComponent = getComponent();

    return (
      <SceneView
        screenProps={this.props.screenProps}
        navigation={navigation}
        component={SceneComponent}
      />
    );
  }


(props: HeaderContainerProps) => {
    return <HeaderContainer {...props} />;
  }


() => {
    const { state, navigation } = this.props;

    if (state.isTransitioning) {
      navigation.dispatch(
        StackActions.completeTransition({
          key: navigation.state.key,
          toChildKey: state.routes[state.index].key,
        })
      );
    }
  }


({ route }: { route: Route<string> }) => {
    const { state, navigation } = this.props;
    const { closingRouteKeys, replacingRouteKeys } = this.state;

    this.handleTransitionComplete();

    if (
      closingRouteKeys.some((key) => key === route.key) &&
      replacingRouteKeys.every((key) => key !== route.key) &&
      !state.routes.some((r) => r.key === route.key)
    ) {
      // If route isn't present in current state, but was closing, assume that a close animation was cancelled
      // So we need to add this route back to the state
      navigation.dispatch(NavigationActions.navigate(route));
    } else {
      this.setState((state) => ({
        routes: state.replacingRouteKeys.length
          ? state.routes.filter(
              (r) => !state.replacingRouteKeys.includes(r.key)
            )
          : state.routes,
        openingRouteKeys: state.openingRouteKeys.filter(
          (key) => key !== route.key
        ),
        closingRouteKeys: state.closingRouteKeys.filter(
          (key) => key !== route.key
        ),
        replacingRouteKeys: [],
      }));
    }
  }


(key) => key === route.key


(key) => key !== route.key


(state) => ({
        routes: state.replacingRouteKeys.length
          ? state.routes.filter(
              (r) => !state.replacingRouteKeys.includes(r.key)
            )
          : state.routes,
        openingRouteKeys: state.openingRouteKeys.filter(
          (key) => key !== route.key
        ),
        closingRouteKeys: state.closingRouteKeys.filter(
          (key) => key !== route.key
        ),
        replacingRouteKeys: [],
      })


(r) => !state.replacingRouteKeys.includes(r.key)


({ route }: { route: Route<string> }) => {
    const { state, navigation } = this.props;

    if (state.routes.some((r) => r.key === route.key)) {
      // If a route exists in state, trigger a pop
      // This will happen in when the route was closed from the card component
      // e.g. When the close animation triggered from a gesture ends
      // @ts-ignore
      navigation.dispatch(StackActions.pop({ key: route.key, prune: false }));
    } else {
      this.handleTransitionComplete();

      // We need to clean up any state tracking the route and pop it immediately
      this.setState((state) => ({
        routes: state.routes.filter((r) => r.key !== route.key),
        openingRouteKeys: state.openingRouteKeys.filter(
          (key) => key !== route.key
        ),
        closingRouteKeys: state.closingRouteKeys.filter(
          (key) => key !== route.key
        ),
      }));
    }
  }


(state) => ({
        routes: state.routes.filter((r) => r.key !== route.key),
        openingRouteKeys: state.openingRouteKeys.filter(
          (key) => key !== route.key
        ),
        closingRouteKeys: state.closingRouteKeys.filter(
          (key) => key !== route.key
        ),
      })


(r) => r.key !== route.key


(
    { route }: { route: Route<string> },
    closing: boolean
  ) => {
    const { descriptors } = this.props;
    const descriptor =
      descriptors[route.key] || this.state.descriptors[route.key];

    descriptor?.options.onTransitionStart?.({ closing });
  }


() => {
    // Do nothing
  }


type Props = StackNavigationConfig & {
  state: StackNavigationState;
  navigation: StackNavigationHelpers;
  descriptors: StackDescriptorMap;
  screenProps: unknown;
};


type State = {
  // Local copy of the routes which are actually rendered
  routes: Route<string>[];
  // Previous routes, to compare whether routes have changed or not
  previousRoutes: Route<string>[];
  // Previous descriptors, to compare whether descriptors have changed or not
  previousDescriptors: StackDescriptorMap;
  // List of routes being opened, we need to animate pushing of these new routes
  openingRouteKeys: string[];
  // List of routes being closed, we need to animate popping of these routes
  closingRouteKeys: string[];
  // List of routes being replaced, we need to keep a copy until the new route animates in
  replacingRouteKeys: string[];
  // Since the local routes can vary from the routes from props, we need to keep the descriptors for old routes
  // Otherwise we won't be able to access the options for routes that were removed
  descriptors: StackDescriptorMap;
};


render() {
    const {
      state,
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      navigation,
      keyboardHandlingEnabled,
      mode = 'card',
      headerMode = mode === 'card' && Platform.OS === 'ios'
        ? 'float'
        : 'screen',
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      descriptors: _,
      ...rest
    } = this.props;

    const {
      routes,
      descriptors,
      openingRouteKeys,
      closingRouteKeys,
    } = this.state;

    return (
      <>
        <GestureHandlerWrapper style={styles.container}>
          <SafeAreaProviderCompat>
            <SafeAreaConsumer>
              {(insets) => (
                <KeyboardManager enabled={keyboardHandlingEnabled !== false}


export interface ITerminalCustomWebSocketProviderOptions extends IBaseProviderOptions {
    customWebsocketProvider: WebsocketProvider;
    web3Version?: Web3Versions;
}


/** @public */
export interface ModelObserver<M extends Model = Model> extends ComponentObserver<M> {
  modelWillAttachParent?(parent: Model, model: M): void;

  modelDidAttachParent?(parent: Model, model: M): void;

  modelWillDetachParent?(parent: Model, model: M): void;

  modelDidDetachParent?(parent: Model, model: M): void;

  modelWillInsertChild?(child: Model, target: Model | null, model: M): void;

  modelDidInsertChild?(child: Model, target: Model | null, model: M): void;

  modelWillRemoveChild?(child: Model, model: M): void;

  modelDidRemoveChild?(child: Model, model: M): void;

  modelWillInsertTrait?(trait: Trait, target: Trait | null, model: M): void;

  modelDidInsertTrait?(trait: Trait, target: Trait | null, model: M): void;

  modelWillRemoveTrait?(trait: Trait, model: M): void;

  modelDidRemoveTrait?(trait: Trait, model: M): void;

  modelWillMount?(model: M): void;

  modelDidMount?(model: M): void;

  modelWillUnmount?(model: M): void;

  modelDidUnmount?(model: M): void;

  modelWillMutate?(modelContext: ModelContextType<M>, model: M): void;

  modelDidMutate?(modelContext: ModelContextType<M>, model: M): void;

  modelWillAggregate?(modelContext: ModelContextType<M>, model: M): void;

  modelDidAggregate?(modelContext: ModelContextType<M>, model: M): void;

  modelWillCorrelate?(modelContext: ModelContextType<M>, model: M): void;

  modelDidCorrelate?(modelContext: ModelContextType<M>, model: M): void;

  modelWillValidate?(modelContext: ModelContextType<M>, model: M): void;

  modelDidValidate?(modelContext: ModelContextType<M>, model: M): void;

  modelWillReconcile?(modelContext: ModelContextType<M>, model: M): void;

  modelDidReconcile?(modelContext: ModelContextType<M>, model: M): void;

  modelWillStartConsuming?(model: M): void;

  modelDidStartConsuming?(model: M): void;

  modelWillStopConsuming?(model: M): void;

  modelDidStopConsuming?(model: M): void;
}


function main_func() {
    let a = 10;

    function f() {
        assert(a == 10);
        print(a);
    }

    f();
}


function f() {
        assert(a == 10);
        print(a);
    }


function main_func2() {
    let a = 10;

    let m = function () {
        assert(a == 10);
        print(a);
    }

    m();
}


function main_func_in_object() {
    let a = 10;

    const s = {
        in: 20,
        f() {
            assert(this.in == 20);
            assert(a == 10);
            print(this.in, a);
        },
    };

    s.f();
}


function main_func_in_object2(a?: number) {
    const s = {
        f() {
            assert(a == 11);
            print(a);
        },
    };

    s.f();
}


function main_func_in_object3(a: number | undefined) {
    const s = {
        f() {
            assert(a == 11);
            print(a);
        },
    };

    s.f();
}


function main_func_in_object4(a?: number | undefined) {
    const s = {
        f() {
            assert(a == 11);
            print(a);
        },
    };

    s.f();
}


function lambda(k: number) {
        function inner() {
            print("inner inside", k);
        }
        print("inner");
        inner()
        print("exit inner");
    }


function inner() {
            print("inner inside", k);
        }


function lambda(k: number) {
    function inner() {
        print("inner inside", k);
    }
    print("inner");
    inner()
    print("exit inner");
}


function inner() {
        print("inner inside", k);
    }


function main_namespace_inner() {
    lambda(12);
    exceptions.lambda(12);
}


function main() {
    main_func();
    main_func2();
    main_func_in_object();
    main_func_in_object2(11);
    main_func_in_object3(11);
    main_func_in_object4(11);

    main_namespace_inner();

    print("done.");
}


f() {
            assert(this.in == 20);
            assert(a == 10);
            print(this.in, a);
        }


f() {
            assert(a == 11);
            print(a);
        }


(object: { code: string; name: string; author: string; description: string; difficulty: number; timestamp: string }): LevelData => {
	return {
		code: object.code,
		name: object.name,
		author: object.author,
		description: object.description,
		difficulty: object.difficulty,
		timestamp: new Date(object.timestamp)
	}
}


export interface LevelData {
	code: string

	name?: string
	author?: string
	description?: string

	difficulty?: number

	timestamp?: Date
}


export interface ServerConfig {
    origin: string;
    port: number;
}


() => {
	it("Login", async () => {
		const login = await request(BASE_URL)
			.get("/login")
			.query(USER_MOCK)
			.expect(200);
		expect(login.body.username).toBe("test");
		USER_MOCK.id = login.body.id;
		NUEVO_PROYECTO_MOCK.usuario_id = login.body.id;
	});
}


async () => {
		const login = await request(BASE_URL)
			.get("/login")
			.query(USER_MOCK)
			.expect(200);
		expect(login.body.username).toBe("test");
		USER_MOCK.id = login.body.id;
		NUEVO_PROYECTO_MOCK.usuario_id = login.body.id;
	}


() => {
	it("Crear un nuevo proyecto", async () => {
		const proyectoCreado = await request(BASE_URL)
			.post("/proyecto/createProyecto")
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(NUEVO_PROYECTO_MOCK)
			.send(USER_MOCK)
			.expect(200);
		expect(proyectoCreado.body[0].titulo).toBe("test");
		NUEVO_PROYECTO_MOCK.id = proyectoCreado.body[0].id;
		TAG_MOCK.proyecto_id = proyectoCreado.body[0].id;
		TODO_MOCK.proyecto_id = proyectoCreado.body[0].id;
	});
	it("Obtener todos los proyectos", async () => {
		const proyectoCreado = await request(BASE_URL)
			.get("/proyecto/getAllProyecto")
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(USER_MOCK)
			.expect(200);
		expect(proyectoCreado.body[0].titulo).toBe("test");
	});
}


async () => {
		const proyectoCreado = await request(BASE_URL)
			.post("/proyecto/createProyecto")
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(NUEVO_PROYECTO_MOCK)
			.send(USER_MOCK)
			.expect(200);
		expect(proyectoCreado.body[0].titulo).toBe("test");
		NUEVO_PROYECTO_MOCK.id = proyectoCreado.body[0].id;
		TAG_MOCK.proyecto_id = proyectoCreado.body[0].id;
		TODO_MOCK.proyecto_id = proyectoCreado.body[0].id;
	}


async () => {
		const proyectoCreado = await request(BASE_URL)
			.get("/proyecto/getAllProyecto")
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(USER_MOCK)
			.expect(200);
		expect(proyectoCreado.body[0].titulo).toBe("test");
	}


() => {
	it("Crear un tag", async () => {
		const tagCreado = await request(BASE_URL)
			.post("/tag/createTag/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TAG_MOCK)
			.send(USER_MOCK)
			.expect(201);
		expect(tagCreado.body[0].titulo).toBe("test");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
		TAG_MOCK.id = tagCreado.body[0].id;
		TODO_MOCK.tag[0].id = tagCreado.body[0].id;
	});
	it("Updateo un tag", async () => {
		TAG_MOCK.titulo = "EDITADO";
		const tagCreado = await request(BASE_URL)
			.put("/tag/updateSimpleTag/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send([TAG_MOCK])
			.send(USER_MOCK)
			.expect(200);
		expect(tagCreado.body[0].titulo).toBe("EDITADO");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
	});
}


async () => {
		const tagCreado = await request(BASE_URL)
			.post("/tag/createTag/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TAG_MOCK)
			.send(USER_MOCK)
			.expect(201);
		expect(tagCreado.body[0].titulo).toBe("test");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
		TAG_MOCK.id = tagCreado.body[0].id;
		TODO_MOCK.tag[0].id = tagCreado.body[0].id;
	}


async () => {
		TAG_MOCK.titulo = "EDITADO";
		const tagCreado = await request(BASE_URL)
			.put("/tag/updateSimpleTag/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send([TAG_MOCK])
			.send(USER_MOCK)
			.expect(200);
		expect(tagCreado.body[0].titulo).toBe("EDITADO");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
	}


() => {
	it("Crear un todo", async () => {
		const tagCreado = await request(BASE_URL)
			.post("/todo/createTodo/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TODO_MOCK)
			.send(USER_MOCK)
			.expect(201);
		expect(tagCreado.body[0].titulo).toBe("test1");
		expect(tagCreado.body[0].descripcion).toBe("test2");
		expect(tagCreado.body[0].orden).toBe(1);
		expect(tagCreado.body[0].completado).toBe(0);
		expect(tagCreado.body[0].tag[0].id).toBe(TAG_MOCK.id);
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
		TODO_MOCK.id = tagCreado.body[0].id;
	});
	it("Updateo un todo", async () => {
		TODO_MOCK.titulo = "EDITADO";
		const tagCreado = await request(BASE_URL)
			.put("/todo/updateSimpleTodo/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TODO_MOCK)
			.expect(200);
		expect(tagCreado.body[0].titulo).toBe("EDITADO");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
	});
}


async () => {
		const tagCreado = await request(BASE_URL)
			.post("/todo/createTodo/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TODO_MOCK)
			.send(USER_MOCK)
			.expect(201);
		expect(tagCreado.body[0].titulo).toBe("test1");
		expect(tagCreado.body[0].descripcion).toBe("test2");
		expect(tagCreado.body[0].orden).toBe(1);
		expect(tagCreado.body[0].completado).toBe(0);
		expect(tagCreado.body[0].tag[0].id).toBe(TAG_MOCK.id);
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
		TODO_MOCK.id = tagCreado.body[0].id;
	}


async () => {
		TODO_MOCK.titulo = "EDITADO";
		const tagCreado = await request(BASE_URL)
			.put("/todo/updateSimpleTodo/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(TODO_MOCK)
			.expect(200);
		expect(tagCreado.body[0].titulo).toBe("EDITADO");
		expect(tagCreado.body[0].proyecto_id).toBe(NUEVO_PROYECTO_MOCK.id);
	}


() => {
	it("Eliminar el proyecto creado para test", async () => {
		const proyectoCreado = await request(BASE_URL)
			.delete("/proyecto/eliminarProyecto/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(USER_MOCK)
			.expect(200);
	});
}


async () => {
		const proyectoCreado = await request(BASE_URL)
			.delete("/proyecto/eliminarProyecto/" + NUEVO_PROYECTO_MOCK.id)
			.set("Content-Type", "application/json")
			.set("Authorization", JWT_MOCK)
			.send(USER_MOCK)
			.expect(200);
	}


function Radio(props: Props) {
  const { value, checked = false, className = '', disabled = false, style, children, onChange, ...restProps } = props

  const handleChange = (evt: any) => {
    if (disabled) return
    onChange && onChange(value, evt)
  }

  return (
    <label className={`${radioPrefix} ${className}`}


(evt: any) => {
    if (disabled) return
    onChange && onChange(value, evt)
  }


interface Props {
  value: string | number
  checked?: boolean
  disabled?: boolean
  children: ReactElement
  style: CSSProperties
  className?: string
  onChange?: (value: string | number, event: any) => void
}


cls(`${radioPrefix


(set) => ({
      transactions: [],
      addTransaction: (transaction: Transaction) =>
        set((prev) => ({ transactions: [...prev.transactions, transaction] })),
    })


(transaction: Transaction) =>
        set((prev) => ({ transactions: [...prev.transactions, transaction] }))


(prev) => ({ transactions: [...prev.transactions, transaction] })


() => storage


interface Store {
  transactions: Transaction[];
  addTransaction: (transaction: Transaction) => void;
}


export class SignatureValidatorApproval extends EthereumEvent {
  get params(): SignatureValidatorApproval__Params {
    return new SignatureValidatorApproval__Params(this);
  }
}


export class SignatureValidatorApproval__Params {
  _event: SignatureValidatorApproval;

  constructor(event: SignatureValidatorApproval) {
    this._event = event;
  }

  get signerAddress(): Address {
    return this._event.parameters[0].value.toAddress();
  }

  get validatorAddress(): Address {
    return this._event.parameters[1].value.toAddress();
  }

  get approved(): boolean {
    return this._event.parameters[2].value.toBoolean();
  }
}


export class Fill extends EthereumEvent {
  get params(): Fill__Params {
    return new Fill__Params(this);
  }
}


export class Fill__Params {
  _event: Fill;

  constructor(event: Fill) {
    this._event = event;
  }

  get makerAddress(): Address {
    return this._event.parameters[0].value.toAddress();
  }

  get feeRecipientAddress(): Address {
    return this._event.parameters[1].value.toAddress();
  }

  get takerAddress(): Address {
    return this._event.parameters[2].value.toAddress();
  }

  get senderAddress(): Address {
    return this._event.parameters[3].value.toAddress();
  }

  get makerAssetFilledAmount(): BigInt {
    return this._event.parameters[4].value.toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this._event.parameters[5].value.toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this._event.parameters[6].value.toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this._event.parameters[7].value.toBigInt();
  }

  get orderHash(): Bytes {
    return this._event.parameters[8].value.toBytes();
  }

  get makerAssetData(): Bytes {
    return this._event.parameters[9].value.toBytes();
  }

  get takerAssetData(): Bytes {
    return this._event.parameters[10].value.toBytes();
  }
}


export class Cancel extends EthereumEvent {
  get params(): Cancel__Params {
    return new Cancel__Params(this);
  }
}


export class Cancel__Params {
  _event: Cancel;

  constructor(event: Cancel) {
    this._event = event;
  }

  get makerAddress(): Address {
    return this._event.parameters[0].value.toAddress();
  }

  get feeRecipientAddress(): Address {
    return this._event.parameters[1].value.toAddress();
  }

  get senderAddress(): Address {
    return this._event.parameters[2].value.toAddress();
  }

  get orderHash(): Bytes {
    return this._event.parameters[3].value.toBytes();
  }

  get makerAssetData(): Bytes {
    return this._event.parameters[4].value.toBytes();
  }

  get takerAssetData(): Bytes {
    return this._event.parameters[5].value.toBytes();
  }
}


export class CancelUpTo extends EthereumEvent {
  get params(): CancelUpTo__Params {
    return new CancelUpTo__Params(this);
  }
}


export class CancelUpTo__Params {
  _event: CancelUpTo;

  constructor(event: CancelUpTo) {
    this._event = event;
  }

  get makerAddress(): Address {
    return this._event.parameters[0].value.toAddress();
  }

  get senderAddress(): Address {
    return this._event.parameters[1].value.toAddress();
  }

  get orderEpoch(): BigInt {
    return this._event.parameters[2].value.toBigInt();
  }
}


export class AssetProxyRegistered extends EthereumEvent {
  get params(): AssetProxyRegistered__Params {
    return new AssetProxyRegistered__Params(this);
  }
}


export class AssetProxyRegistered__Params {
  _event: AssetProxyRegistered;

  constructor(event: AssetProxyRegistered) {
    this._event = event;
  }

  get id(): Bytes {
    return this._event.parameters[0].value.toBytes();
  }

  get assetProxy(): Address {
    return this._event.parameters[1].value.toAddress();
  }
}


export class Contract__batchFillOrdersResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__batchFillOrdersInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__matchOrdersResultMatchedFillResultsStruct extends EthereumTuple {
  get left(): Contract__matchOrdersResultMatchedFillResultsLeftStruct {
    return this[0].toTuple() as Contract__matchOrdersResultMatchedFillResultsLeftStruct;
  }

  get right(): Contract__matchOrdersResultMatchedFillResultsRightStruct {
    return this[1].toTuple() as Contract__matchOrdersResultMatchedFillResultsRightStruct;
  }

  get leftMakerAssetSpreadAmount(): BigInt {
    return this[2].toBigInt();
  }
}


export class Contract__matchOrdersResultMatchedFillResultsLeftStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__matchOrdersResultMatchedFillResultsRightStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__matchOrdersInputLeftOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__matchOrdersInputRightOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__fillOrderNoThrowResultFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__fillOrderNoThrowInputOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__batchFillOrKillOrdersResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__batchFillOrKillOrdersInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__batchFillOrdersNoThrowResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__batchFillOrdersNoThrowInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__fillOrKillOrderResultFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__fillOrKillOrderInputOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__marketSellOrdersResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__marketSellOrdersInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__getOrdersInfoResultValue0Struct extends EthereumTuple {
  get orderStatus(): i32 {
    return this[0].toI32();
  }

  get orderHash(): Bytes {
    return this[1].toBytes();
  }

  get orderTakerAssetFilledAmount(): BigInt {
    return this[2].toBigInt();
  }
}


export class Contract__getOrdersInfoInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__marketBuyOrdersNoThrowResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__marketBuyOrdersNoThrowInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__fillOrderResultFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__fillOrderInputOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__getOrderInfoResultOrderInfoStruct extends EthereumTuple {
  get orderStatus(): i32 {
    return this[0].toI32();
  }

  get orderHash(): Bytes {
    return this[1].toBytes();
  }

  get orderTakerAssetFilledAmount(): BigInt {
    return this[2].toBigInt();
  }
}


export class Contract__getOrderInfoInputOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__marketSellOrdersNoThrowResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__marketSellOrdersNoThrowInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class Contract__marketBuyOrdersResultTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class Contract__marketBuyOrdersInputOrdersStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class BatchFillOrdersCall extends EthereumCall {
  get inputs(): BatchFillOrdersCall__Inputs {
    return new BatchFillOrdersCall__Inputs(this);
  }

  get outputs(): BatchFillOrdersCall__Outputs {
    return new BatchFillOrdersCall__Outputs(this);
  }
}


export class BatchFillOrdersCall__Inputs {
  _call: BatchFillOrdersCall;

  constructor(call: BatchFillOrdersCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get takerAssetFillAmounts(): Array<BigInt> {
    return this._call.inputValues[1].value.toBigIntArray();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class BatchFillOrdersCall__Outputs {
  _call: BatchFillOrdersCall;

  constructor(call: BatchFillOrdersCall) {
    this._call = call;
  }

  get totalFillResults(): BatchFillOrdersCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as BatchFillOrdersCallTotalFillResultsStruct;
  }
}


export class BatchFillOrdersCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class PreSignCall extends EthereumCall {
  get inputs(): PreSignCall__Inputs {
    return new PreSignCall__Inputs(this);
  }

  get outputs(): PreSignCall__Outputs {
    return new PreSignCall__Outputs(this);
  }
}


export class PreSignCall__Inputs {
  _call: PreSignCall;

  constructor(call: PreSignCall) {
    this._call = call;
  }

  get hash(): Bytes {
    return this._call.inputValues[0].value.toBytes();
  }

  get signerAddress(): Address {
    return this._call.inputValues[1].value.toAddress();
  }

  get signature(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }
}


export class PreSignCall__Outputs {
  _call: PreSignCall;

  constructor(call: PreSignCall) {
    this._call = call;
  }
}


export class MatchOrdersCall extends EthereumCall {
  get inputs(): MatchOrdersCall__Inputs {
    return new MatchOrdersCall__Inputs(this);
  }

  get outputs(): MatchOrdersCall__Outputs {
    return new MatchOrdersCall__Outputs(this);
  }
}


export class MatchOrdersCall__Inputs {
  _call: MatchOrdersCall;

  constructor(call: MatchOrdersCall) {
    this._call = call;
  }

  get leftOrder(): MatchOrdersCallLeftOrderStruct {
    return this._call.inputValues[0].value.toTuple() as MatchOrdersCallLeftOrderStruct;
  }

  get rightOrder(): MatchOrdersCallRightOrderStruct {
    return this._call.inputValues[1].value.toTuple() as MatchOrdersCallRightOrderStruct;
  }

  get leftSignature(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }

  get rightSignature(): Bytes {
    return this._call.inputValues[3].value.toBytes();
  }
}


export class MatchOrdersCall__Outputs {
  _call: MatchOrdersCall;

  constructor(call: MatchOrdersCall) {
    this._call = call;
  }

  get matchedFillResults(): MatchOrdersCallMatchedFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as MatchOrdersCallMatchedFillResultsStruct;
  }
}


export class MatchOrdersCallLeftOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class MatchOrdersCallRightOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class MatchOrdersCallMatchedFillResultsStruct extends EthereumTuple {
  get left(): MatchOrdersCallMatchedFillResultsLeftStruct {
    return this[0].toTuple() as MatchOrdersCallMatchedFillResultsLeftStruct;
  }

  get right(): MatchOrdersCallMatchedFillResultsRightStruct {
    return this[1].toTuple() as MatchOrdersCallMatchedFillResultsRightStruct;
  }

  get leftMakerAssetSpreadAmount(): BigInt {
    return this[2].toBigInt();
  }
}


export class MatchOrdersCallMatchedFillResultsLeftStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class MatchOrdersCallMatchedFillResultsRightStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class FillOrderNoThrowCall extends EthereumCall {
  get inputs(): FillOrderNoThrowCall__Inputs {
    return new FillOrderNoThrowCall__Inputs(this);
  }

  get outputs(): FillOrderNoThrowCall__Outputs {
    return new FillOrderNoThrowCall__Outputs(this);
  }
}


export class FillOrderNoThrowCall__Inputs {
  _call: FillOrderNoThrowCall;

  constructor(call: FillOrderNoThrowCall) {
    this._call = call;
  }

  get order(): FillOrderNoThrowCallOrderStruct {
    return this._call.inputValues[0].value.toTuple() as FillOrderNoThrowCallOrderStruct;
  }

  get takerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signature(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }
}


export class FillOrderNoThrowCall__Outputs {
  _call: FillOrderNoThrowCall;

  constructor(call: FillOrderNoThrowCall) {
    this._call = call;
  }

  get fillResults(): FillOrderNoThrowCallFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as FillOrderNoThrowCallFillResultsStruct;
  }
}


export class FillOrderNoThrowCallOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class FillOrderNoThrowCallFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class BatchCancelOrdersCall extends EthereumCall {
  get inputs(): BatchCancelOrdersCall__Inputs {
    return new BatchCancelOrdersCall__Inputs(this);
  }

  get outputs(): BatchCancelOrdersCall__Outputs {
    return new BatchCancelOrdersCall__Outputs(this);
  }
}


export class BatchCancelOrdersCall__Inputs {
  _call: BatchCancelOrdersCall;

  constructor(call: BatchCancelOrdersCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }
}


export class BatchCancelOrdersCall__Outputs {
  _call: BatchCancelOrdersCall;

  constructor(call: BatchCancelOrdersCall) {
    this._call = call;
  }
}


export class BatchFillOrKillOrdersCall extends EthereumCall {
  get inputs(): BatchFillOrKillOrdersCall__Inputs {
    return new BatchFillOrKillOrdersCall__Inputs(this);
  }

  get outputs(): BatchFillOrKillOrdersCall__Outputs {
    return new BatchFillOrKillOrdersCall__Outputs(this);
  }
}


export class BatchFillOrKillOrdersCall__Inputs {
  _call: BatchFillOrKillOrdersCall;

  constructor(call: BatchFillOrKillOrdersCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get takerAssetFillAmounts(): Array<BigInt> {
    return this._call.inputValues[1].value.toBigIntArray();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class BatchFillOrKillOrdersCall__Outputs {
  _call: BatchFillOrKillOrdersCall;

  constructor(call: BatchFillOrKillOrdersCall) {
    this._call = call;
  }

  get totalFillResults(): BatchFillOrKillOrdersCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as BatchFillOrKillOrdersCallTotalFillResultsStruct;
  }
}


export class BatchFillOrKillOrdersCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class CancelOrdersUpToCall extends EthereumCall {
  get inputs(): CancelOrdersUpToCall__Inputs {
    return new CancelOrdersUpToCall__Inputs(this);
  }

  get outputs(): CancelOrdersUpToCall__Outputs {
    return new CancelOrdersUpToCall__Outputs(this);
  }
}


export class CancelOrdersUpToCall__Inputs {
  _call: CancelOrdersUpToCall;

  constructor(call: CancelOrdersUpToCall) {
    this._call = call;
  }

  get targetOrderEpoch(): BigInt {
    return this._call.inputValues[0].value.toBigInt();
  }
}


export class CancelOrdersUpToCall__Outputs {
  _call: CancelOrdersUpToCall;

  constructor(call: CancelOrdersUpToCall) {
    this._call = call;
  }
}


export class BatchFillOrdersNoThrowCall extends EthereumCall {
  get inputs(): BatchFillOrdersNoThrowCall__Inputs {
    return new BatchFillOrdersNoThrowCall__Inputs(this);
  }

  get outputs(): BatchFillOrdersNoThrowCall__Outputs {
    return new BatchFillOrdersNoThrowCall__Outputs(this);
  }
}


export class BatchFillOrdersNoThrowCall__Inputs {
  _call: BatchFillOrdersNoThrowCall;

  constructor(call: BatchFillOrdersNoThrowCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get takerAssetFillAmounts(): Array<BigInt> {
    return this._call.inputValues[1].value.toBigIntArray();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class BatchFillOrdersNoThrowCall__Outputs {
  _call: BatchFillOrdersNoThrowCall;

  constructor(call: BatchFillOrdersNoThrowCall) {
    this._call = call;
  }

  get totalFillResults(): BatchFillOrdersNoThrowCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as BatchFillOrdersNoThrowCallTotalFillResultsStruct;
  }
}


export class BatchFillOrdersNoThrowCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class FillOrKillOrderCall extends EthereumCall {
  get inputs(): FillOrKillOrderCall__Inputs {
    return new FillOrKillOrderCall__Inputs(this);
  }

  get outputs(): FillOrKillOrderCall__Outputs {
    return new FillOrKillOrderCall__Outputs(this);
  }
}


export class FillOrKillOrderCall__Inputs {
  _call: FillOrKillOrderCall;

  constructor(call: FillOrKillOrderCall) {
    this._call = call;
  }

  get order(): FillOrKillOrderCallOrderStruct {
    return this._call.inputValues[0].value.toTuple() as FillOrKillOrderCallOrderStruct;
  }

  get takerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signature(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }
}


export class FillOrKillOrderCall__Outputs {
  _call: FillOrKillOrderCall;

  constructor(call: FillOrKillOrderCall) {
    this._call = call;
  }

  get fillResults(): FillOrKillOrderCallFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as FillOrKillOrderCallFillResultsStruct;
  }
}


export class FillOrKillOrderCallOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class FillOrKillOrderCallFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class SetSignatureValidatorApprovalCall extends EthereumCall {
  get inputs(): SetSignatureValidatorApprovalCall__Inputs {
    return new SetSignatureValidatorApprovalCall__Inputs(this);
  }

  get outputs(): SetSignatureValidatorApprovalCall__Outputs {
    return new SetSignatureValidatorApprovalCall__Outputs(this);
  }
}


export class SetSignatureValidatorApprovalCall__Inputs {
  _call: SetSignatureValidatorApprovalCall;

  constructor(call: SetSignatureValidatorApprovalCall) {
    this._call = call;
  }

  get validatorAddress(): Address {
    return this._call.inputValues[0].value.toAddress();
  }

  get approval(): boolean {
    return this._call.inputValues[1].value.toBoolean();
  }
}


export class SetSignatureValidatorApprovalCall__Outputs {
  _call: SetSignatureValidatorApprovalCall;

  constructor(call: SetSignatureValidatorApprovalCall) {
    this._call = call;
  }
}


export class MarketSellOrdersCall extends EthereumCall {
  get inputs(): MarketSellOrdersCall__Inputs {
    return new MarketSellOrdersCall__Inputs(this);
  }

  get outputs(): MarketSellOrdersCall__Outputs {
    return new MarketSellOrdersCall__Outputs(this);
  }
}


export class MarketSellOrdersCall__Inputs {
  _call: MarketSellOrdersCall;

  constructor(call: MarketSellOrdersCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get takerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class MarketSellOrdersCall__Outputs {
  _call: MarketSellOrdersCall;

  constructor(call: MarketSellOrdersCall) {
    this._call = call;
  }

  get totalFillResults(): MarketSellOrdersCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as MarketSellOrdersCallTotalFillResultsStruct;
  }
}


export class MarketSellOrdersCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class MarketBuyOrdersNoThrowCall extends EthereumCall {
  get inputs(): MarketBuyOrdersNoThrowCall__Inputs {
    return new MarketBuyOrdersNoThrowCall__Inputs(this);
  }

  get outputs(): MarketBuyOrdersNoThrowCall__Outputs {
    return new MarketBuyOrdersNoThrowCall__Outputs(this);
  }
}


export class MarketBuyOrdersNoThrowCall__Inputs {
  _call: MarketBuyOrdersNoThrowCall;

  constructor(call: MarketBuyOrdersNoThrowCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get makerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class MarketBuyOrdersNoThrowCall__Outputs {
  _call: MarketBuyOrdersNoThrowCall;

  constructor(call: MarketBuyOrdersNoThrowCall) {
    this._call = call;
  }

  get totalFillResults(): MarketBuyOrdersNoThrowCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as MarketBuyOrdersNoThrowCallTotalFillResultsStruct;
  }
}


export class MarketBuyOrdersNoThrowCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class FillOrderCall extends EthereumCall {
  get inputs(): FillOrderCall__Inputs {
    return new FillOrderCall__Inputs(this);
  }

  get outputs(): FillOrderCall__Outputs {
    return new FillOrderCall__Outputs(this);
  }
}


export class FillOrderCall__Inputs {
  _call: FillOrderCall;

  constructor(call: FillOrderCall) {
    this._call = call;
  }

  get order(): FillOrderCallOrderStruct {
    return this._call.inputValues[0].value.toTuple() as FillOrderCallOrderStruct;
  }

  get takerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signature(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }
}


export class FillOrderCall__Outputs {
  _call: FillOrderCall;

  constructor(call: FillOrderCall) {
    this._call = call;
  }

  get fillResults(): FillOrderCallFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as FillOrderCallFillResultsStruct;
  }
}


export class FillOrderCallOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class FillOrderCallFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class ExecuteTransactionCall extends EthereumCall {
  get inputs(): ExecuteTransactionCall__Inputs {
    return new ExecuteTransactionCall__Inputs(this);
  }

  get outputs(): ExecuteTransactionCall__Outputs {
    return new ExecuteTransactionCall__Outputs(this);
  }
}


export class ExecuteTransactionCall__Inputs {
  _call: ExecuteTransactionCall;

  constructor(call: ExecuteTransactionCall) {
    this._call = call;
  }

  get salt(): BigInt {
    return this._call.inputValues[0].value.toBigInt();
  }

  get signerAddress(): Address {
    return this._call.inputValues[1].value.toAddress();
  }

  get data(): Bytes {
    return this._call.inputValues[2].value.toBytes();
  }

  get signature(): Bytes {
    return this._call.inputValues[3].value.toBytes();
  }
}


export class ExecuteTransactionCall__Outputs {
  _call: ExecuteTransactionCall;

  constructor(call: ExecuteTransactionCall) {
    this._call = call;
  }
}


export class RegisterAssetProxyCall extends EthereumCall {
  get inputs(): RegisterAssetProxyCall__Inputs {
    return new RegisterAssetProxyCall__Inputs(this);
  }

  get outputs(): RegisterAssetProxyCall__Outputs {
    return new RegisterAssetProxyCall__Outputs(this);
  }
}


export class RegisterAssetProxyCall__Inputs {
  _call: RegisterAssetProxyCall;

  constructor(call: RegisterAssetProxyCall) {
    this._call = call;
  }

  get assetProxy(): Address {
    return this._call.inputValues[0].value.toAddress();
  }
}


export class RegisterAssetProxyCall__Outputs {
  _call: RegisterAssetProxyCall;

  constructor(call: RegisterAssetProxyCall) {
    this._call = call;
  }
}


export class CancelOrderCall extends EthereumCall {
  get inputs(): CancelOrderCall__Inputs {
    return new CancelOrderCall__Inputs(this);
  }

  get outputs(): CancelOrderCall__Outputs {
    return new CancelOrderCall__Outputs(this);
  }
}


export class CancelOrderCall__Inputs {
  _call: CancelOrderCall;

  constructor(call: CancelOrderCall) {
    this._call = call;
  }

  get order(): CancelOrderCallOrderStruct {
    return this._call.inputValues[0].value.toTuple() as CancelOrderCallOrderStruct;
  }
}


export class CancelOrderCall__Outputs {
  _call: CancelOrderCall;

  constructor(call: CancelOrderCall) {
    this._call = call;
  }
}


export class CancelOrderCallOrderStruct extends EthereumTuple {
  get makerAddress(): Address {
    return this[0].toAddress();
  }

  get takerAddress(): Address {
    return this[1].toAddress();
  }

  get feeRecipientAddress(): Address {
    return this[2].toAddress();
  }

  get senderAddress(): Address {
    return this[3].toAddress();
  }

  get makerAssetAmount(): BigInt {
    return this[4].toBigInt();
  }

  get takerAssetAmount(): BigInt {
    return this[5].toBigInt();
  }

  get makerFee(): BigInt {
    return this[6].toBigInt();
  }

  get takerFee(): BigInt {
    return this[7].toBigInt();
  }

  get expirationTimeSeconds(): BigInt {
    return this[8].toBigInt();
  }

  get salt(): BigInt {
    return this[9].toBigInt();
  }

  get makerAssetData(): Bytes {
    return this[10].toBytes();
  }

  get takerAssetData(): Bytes {
    return this[11].toBytes();
  }
}


export class MarketSellOrdersNoThrowCall extends EthereumCall {
  get inputs(): MarketSellOrdersNoThrowCall__Inputs {
    return new MarketSellOrdersNoThrowCall__Inputs(this);
  }

  get outputs(): MarketSellOrdersNoThrowCall__Outputs {
    return new MarketSellOrdersNoThrowCall__Outputs(this);
  }
}


export class MarketSellOrdersNoThrowCall__Inputs {
  _call: MarketSellOrdersNoThrowCall;

  constructor(call: MarketSellOrdersNoThrowCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get takerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class MarketSellOrdersNoThrowCall__Outputs {
  _call: MarketSellOrdersNoThrowCall;

  constructor(call: MarketSellOrdersNoThrowCall) {
    this._call = call;
  }

  get totalFillResults(): MarketSellOrdersNoThrowCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as MarketSellOrdersNoThrowCallTotalFillResultsStruct;
  }
}


export class MarketSellOrdersNoThrowCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class MarketBuyOrdersCall extends EthereumCall {
  get inputs(): MarketBuyOrdersCall__Inputs {
    return new MarketBuyOrdersCall__Inputs(this);
  }

  get outputs(): MarketBuyOrdersCall__Outputs {
    return new MarketBuyOrdersCall__Outputs(this);
  }
}


export class MarketBuyOrdersCall__Inputs {
  _call: MarketBuyOrdersCall;

  constructor(call: MarketBuyOrdersCall) {
    this._call = call;
  }

  get orders(): Array<EthereumTuple> {
    return this._call.inputValues[0].value.toTupleArray<undefined>();
  }

  get makerAssetFillAmount(): BigInt {
    return this._call.inputValues[1].value.toBigInt();
  }

  get signatures(): Array<Bytes> {
    return this._call.inputValues[2].value.toBytesArray();
  }
}


export class MarketBuyOrdersCall__Outputs {
  _call: MarketBuyOrdersCall;

  constructor(call: MarketBuyOrdersCall) {
    this._call = call;
  }

  get totalFillResults(): MarketBuyOrdersCallTotalFillResultsStruct {
    return this._call.outputValues[0].value.toTuple() as MarketBuyOrdersCallTotalFillResultsStruct;
  }
}


export class MarketBuyOrdersCallTotalFillResultsStruct extends EthereumTuple {
  get makerAssetFilledAmount(): BigInt {
    return this[0].toBigInt();
  }

  get takerAssetFilledAmount(): BigInt {
    return this[1].toBigInt();
  }

  get makerFeePaid(): BigInt {
    return this[2].toBigInt();
  }

  get takerFeePaid(): BigInt {
    return this[3].toBigInt();
  }
}


export class TransferOwnershipCall extends EthereumCall {
  get inputs(): TransferOwnershipCall__Inputs {
    return new TransferOwnershipCall__Inputs(this);
  }

  get outputs(): TransferOwnershipCall__Outputs {
    return new TransferOwnershipCall__Outputs(this);
  }
}


export class ConstructorCall extends EthereumCall {
  get inputs(): ConstructorCall__Inputs {
    return new ConstructorCall__Inputs(this);
  }

  get outputs(): ConstructorCall__Outputs {
    return new ConstructorCall__Outputs(this);
  }
}


export class ConstructorCall__Inputs {
  _call: ConstructorCall;

  constructor(call: ConstructorCall) {
    this._call = call;
  }

  get _zrxAssetData(): Bytes {
    return this._call.inputValues[0].value.toBytes();
  }
}


static bind(address: Address): Contract {
    return new Contract("Contract", address);
  }


filled(param0: Bytes): BigInt {
    let result = super.call("filled", [EthereumValue.fromFixedBytes(param0)]);

    return result[0].toBigInt();
  }


try_filled(param0: Bytes): CallResult<BigInt> {
    let result = super.tryCall("filled", [
      EthereumValue.fromFixedBytes(param0)
    ]);
    if (result.reverted) {
      return new CallResult();
    }
    let value = result.value;
    return CallResult.fromValue(value[0].toBigInt());
  }


batchFillOrders(
    orders: Array<Contract__batchFillOrdersInputOrdersStruct>,
    takerAssetFillAmounts: Array<BigInt>,
    signatures: Array<Bytes>
  ): Contract__batchFillOrdersResultTotalFillResultsStruct {
    let result = super.call("batchFillOrders", [
      EthereumValue.fromTupleArray(orders),
      EthereumValue.fromUnsignedBigIntArray(takerAssetFillAmounts),
      EthereumValue.fromBytesArray(signatures)
    ]);

    return result[0].toTuple() as Contract__batchFillOrdersResultTotalFillResultsStruct;
  }


try_batchFillOrders(
    orders: Array<Contract__batchFillOrdersInputOrdersStruct>,
    takerAssetFillAmounts: Array<BigInt>,
    signatures: Array<Bytes>
  ): CallResult<Contract__batchFillOrdersResultTotalFillResultsStruct> {
    let result = super.tryCall("batchFillOrders", [
      EthereumValue.fromTupleArray(orders),
      EthereumValue.fromUnsignedBigIntArray(takerAssetFillAmounts),
      EthereumValue.fromBytesArray(signatures)
    ]);
    if (result.reverted) {
      return new CallResult();
    }
    let value = result.value;
    return CallResult.fromValue(
      value[0].toTuple() as Contract__batchFillOrdersResultTotalFillResultsStruct
    );
  }


cancelled(param0: Bytes): boolean {
    let result = super.call("cancelled", [
      EthereumValue.fromFixedBytes(param0)
    ]);

    return result[0].toBoolean();
  }


try_cancelled(param0: Bytes): CallResult<boolean> {
    let result = super.tryCall("cancelled", [
      EthereumValue.fromFixedBytes(param0)
    ]);
    if (result.reverted) {
      return new CallResult();
    }
    let value = result.value;
    return CallResult.fromValue(value[0].toBoolean());
  }


matchOrders(
    leftOrder: Contract__matchOrdersInputLeftOrderStruct,
    rightOrder: Contract__matchOrdersInputRightOrderStruct,
    leftSignature: Bytes,
    rightSignature: Bytes
  ): Contract__matchOrdersResultMatchedFillResultsStruct {
    let result = super.call("matchOrders", [
      EthereumValue.fromTuple(leftOrder),
      EthereumValue.fromTuple(rightOrder),
      EthereumValue.fromBytes(leftSignature),
      EthereumValue.fromBytes(rightSignature)
    ]);

    return result[0].toTuple() as Contract__matchOrdersResultMatchedFillResultsStruct;
  }


try_matchOrders(
    leftOrder: Contract__matchOrdersInputLeftOrderStruct,
    rightOrder: Contract__matchOrdersInputRightOrderStruct,
    leftSignature: Bytes,
    rightSignature: Bytes
  ): CallResult<Contract__matchOrdersResultMatchedFillResultsStruct> {
    let result = super.tryCall("matchOrders", [
      EthereumValue.fromTuple(leftOrder),
      EthereumValue.fromTuple(rightOrder),
      EthereumValue.fromBytes(leftSignature),
      EthereumValue.fromBytes(rightSignature)
    ]);
    if (result.reverted) {
      return new CallResult();
    }
    let value = result.value;
    return CallResult.fromValue(
      value[0].toTuple() as Contract__matchOrdersResultMatchedFillResultsStruct
    );
  }