Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/little-sloths-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@mimicprotocol/lib-ts": patch
"@mimicprotocol/cli": patch
"@mimicprotocol/test-ts": patch
---

Add api query
11 changes: 2 additions & 9 deletions packages/cli/src/lib/InputsInterfaceGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,10 @@ function generateImports(inputs: Record<string, string>): string {
}

function generateInputsMapping(inputs: Record<string, string>, originalInputs: ManifestInputs): string {
const variableTypes = new Set(['string', 'Address', 'Bytes', 'BigInt', 'BlockchainToken', 'TokenAmount'])
return Object.entries(inputs)
.map(([name, type]) => {
const declaration =
type === 'string' ||
type === 'Address' ||
type === 'Bytes' ||
type === 'BigInt' ||
type === 'BlockchainToken' ||
type === 'TokenAmount'
? `var ${name}: string | null`
: `const ${name}: ${type}`
const declaration = variableTypes.has(type) ? `var ${name}: string | null` : `const ${name}: ${type}`
Comment thread
PedroAraoz marked this conversation as resolved.

const originalInput = originalInputs[name]
const hasDescription = typeof originalInput === 'object' && !!originalInput.description
Expand Down
10 changes: 4 additions & 6 deletions packages/cli/src/lib/ManifestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as fs from 'fs'
import { load } from 'js-yaml'
import { ZodError } from 'zod'

import { DuplicateEntryError, EmptyManifestError, MoreThanOneEntryError } from '../errors'
import { DuplicateEntryError, EmptyManifestError, GENERIC_SUGGESTION, MoreThanOneEntryError } from '../errors'
import { Manifest } from '../types'
import { ManifestValidator } from '../validators'

Expand Down Expand Up @@ -41,9 +41,9 @@ export default {
},
}

function mergeIfUnique(list: Record<string, unknown>[]) {
function mergeIfUnique(list: Record<string, unknown>[] = []) {
const merged: Record<string, unknown> = {}
for (const obj of list || []) {
for (const obj of list) {
const entries = Object.entries(obj)
if (entries.length !== 1) throw new MoreThanOneEntryError(entries)
const [key, val] = entries[0]
Expand Down Expand Up @@ -72,9 +72,7 @@ function handleValidationError(command: Command, err: unknown): never {
suggestions = err.errors.map((e) => `Fix Field "${e.path.join('.')}" -- ${e.message}`)
} else {
;[message, code] = [`Unkown Error: ${err}`, 'UnknownError']
suggestions = [
'Contact the Mimic team for further assistance at our website https://www.mimic.fi/ or discord https://discord.com/invite/cpcyV9EsEg',
]
suggestions = GENERIC_SUGGESTION
}

command.error(message, { code, suggestions })
Expand Down
1 change: 1 addition & 0 deletions packages/lib-ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './src/evm'
export * from './src/helpers'
export * from './src/intents'
export * from './src/log'
export * from './src/queries'
export * from './src/storage'
export * from './src/svm'
export * from './src/tokens'
Expand Down
19 changes: 19 additions & 0 deletions packages/lib-ts/src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { evm } from './evm'
import { Consensus, ListType, MIMIC_HELPER_ADDRESS } from './helpers'
import { Intent } from './intents'
import {
ApiQuery,
ApiQueryResponse,
EvmCallQuery,
EvmCallQueryResponse,
RelevantTokensQuery,
Expand Down Expand Up @@ -38,6 +40,9 @@ export namespace environment {
@external('environment', '_subgraphQuery')
declare function _subgraphQuery(params: string): string

@external('environment', '_apiQuery')
declare function _apiQuery(params: string): string

@external('environment', '_svmAccountsInfoQuery')
declare function _svmAccountsInfoQuery(params: string): string

Expand Down Expand Up @@ -162,6 +167,20 @@ export namespace environment {
return SvmAccountsInfoQueryResponse.fromJson<SvmAccountsInfoQueryResponse>(responseStr).toResult()
}

/**
* Executes an HTTP API GET call and returns the raw (stringified) response body.
* @param url - The endpoint URL to call
* @param timestamp - Optional. Cache/snapshot timestamp used to fetch a previously cached response at the given point in time
* @returns A `Result` containing either the response body as a string or an error string
*/
export function apiQuery(
url: string,
timestamp: Date | null = null
): Result<string, string> {
const responseStr = _apiQuery(JSON.stringify(ApiQuery.from(url, timestamp)))
return ApiQueryResponse.fromJson<ApiQueryResponse>(responseStr).toResult()
}

/**
* Returns the current execution context containing environment information.
* @returns The Context object containing: user, settler, timestamp, consensusThreshold and triggerPayload
Expand Down
36 changes: 36 additions & 0 deletions packages/lib-ts/src/queries/ApiQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Result } from '../types'
Comment thread
PedroAraoz marked this conversation as resolved.

import { QueryResponseBase } from './QueryResponse'

@json
class ApiQueryBase {
constructor(public readonly url: string) {}
}

@json
export class ApiQuery extends ApiQueryBase {
public readonly timestamp: i64

constructor(url: string, timestamp: i64) {
super(url)
this.timestamp = timestamp
}

static from(url: string, timestamp: Date | null): ApiQueryBase {
return timestamp ? new ApiQuery(url, changetype<Date>(timestamp).getTime()) : new ApiQueryBase(url)
}
}

@json
export class ApiQueryResponse extends QueryResponseBase {
public data: string

constructor(success: string, data: string, error: string) {
super(success, error)
this.data = data
}

toResult(): Result<string, string> {
return this.buildResult<string>(this.data, 'Unknown error getting API response')
}
}
1 change: 1 addition & 0 deletions packages/lib-ts/src/queries/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './ApiQuery'
export * from './EvmCallQuery'
export * from './QueryResponse'
export * from './RelevantTokensQuery'
Expand Down
53 changes: 53 additions & 0 deletions packages/lib-ts/tests/queries/ApiQuery.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ApiQueryResponse } from '../../src/queries'

describe('ApiQueryResponse', () => {
describe('toResult', () => {
describe('when response is successful', () => {
describe('when data is provided', () => {
it('should return result with data', () => {
const responseData = '{"test": true}'
const response = new ApiQueryResponse('true', responseData, '')
const result = response.toResult()

expect(result.isOk).toBe(true)
const data = result.unwrap()
expect(data).toBe(responseData)
})
})

describe('when data is empty', () => {
it('should return empty string', () => {
const response = new ApiQueryResponse('true', '', '')
const result = response.toResult()

expect(result.isOk).toBe(true)
const data = result.unwrap()
expect(data).toBe('')
})
})
})

describe('when response is not successful', () => {
describe('when error message is provided', () => {
it('should return error with provided message', () => {
const errorMessage = 'Something went wrong'
const response = new ApiQueryResponse('false', '', errorMessage)
const result = response.toResult()

expect(result.isError).toBe(true)
expect(result.error).toBe(errorMessage)
})
})

describe('when error message is not provided', () => {
it('should return default error message', () => {
const response = new ApiQueryResponse('false', '', '')
const result = response.toResult()

expect(result.isError).toBe(true)
expect(result.error).toBe('Unknown error getting API response')
})
})
})
})
})
Loading